Imported Upstream version 1.6.3
[platform/upstream/libksba.git] / src / asn1-gentables.c
1 /* asn1-gentables.c - Tool to create required ASN tables
2  *      Copyright (C) 2001, 2008 g10 Code GmbH
3  *
4  * This file is part of KSBA.
5  *
6  * KSBA is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * KSBA is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <stdarg.h>
25
26 #include "gen-help.h"
27 #include "asn1-func.h"
28
29 #define PGMNAME "asn1-gentables"
30
31 #if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ))
32 # define  ATTR_PRINTF(a,b)  __attribute__ ((format (printf,a,b)))
33 #else
34 # define  ATTR_PRINTF(a,b)
35 #endif
36
37 #ifdef _WIN32
38 #define DEVNULL_NAME "nul"
39 #else
40 #define DEVNULL_NAME "/dev/null"
41 #endif
42
43
44 /* keep track of parsing error */
45 static int error_counter;
46
47 /* option --dump */
48 static int dump_only;
49 /* option --check */
50 static int check_only;
51
52 struct name_list_s {
53   struct name_list_s *next;
54   char name[1];
55 };
56
57 static struct name_list_s *string_table, **string_table_tail;
58 static size_t string_table_offset;
59
60 static void print_error (const char *fmt, ... )  ATTR_PRINTF(1,2);
61
62
63 static void
64 print_error (const char *fmt, ... )
65 {
66   va_list arg_ptr ;
67
68   va_start (arg_ptr, fmt);
69   fputs (PGMNAME ": ", stderr);
70   vfprintf (stderr, fmt, arg_ptr);
71   va_end (arg_ptr);
72   error_counter++;
73
74 }
75
76 static size_t
77 insert_string (const char *name)
78 {
79   struct name_list_s *item;
80   size_t off, n;
81
82   if (!string_table_tail)
83     {
84       string_table_tail = &string_table;
85       insert_string ("");
86     }
87
88   if (string_table_offset && !*name)
89     return 0;
90
91   for (item = string_table,off = 0; item; item = item->next)
92     {
93       for (n=0; item->name[n]; n++)
94         if (!strcmp (item->name+n, name))
95           return off + n;
96       off += strlen (item->name) + 1;
97     }
98
99   item = xmalloc ( sizeof *item + strlen (name));
100   strcpy (item->name, name);
101   item->next = NULL;
102   *string_table_tail = item;
103   string_table_tail = &item->next;
104   off = string_table_offset;
105   string_table_offset += strlen (name) + 1;
106   return off;
107 }
108
109 static int
110 cmp_string (const void *aptr, const void *bptr)
111 {
112   const char *a = (*(const struct name_list_s **)aptr)->name;
113   const char *b = (*(const struct name_list_s **)bptr)->name;
114
115   const size_t len_a = strlen(a);
116   const size_t len_b = strlen(b);
117
118   if (len_a < len_b)
119     return -1;
120   if (len_a > len_b)
121     return +1;
122   return strcmp(a, b);
123 }
124
125 static void
126 sort_string_table (void)
127 {
128   struct name_list_s *item;
129   struct name_list_s **array;
130   size_t i, arraylen;
131
132   if (!string_table || !string_table->next)
133     return; /* Nothing to sort.  */
134
135   for (item = string_table,arraylen = 0; item; item = item->next)
136     arraylen++;
137   array = xcalloc (arraylen, sizeof *array);
138   for (item = string_table,arraylen = 0; item; item = item->next)
139     array[arraylen++] = item;
140   qsort (array, arraylen, sizeof *array, cmp_string);
141   /* Replace table by sorted one.  */
142   string_table_tail = NULL;
143   string_table = NULL;
144   string_table_offset = 0;
145   for (i=0; i < arraylen; i++)
146     insert_string (array[i]->name);
147   xfree (array);
148   /* for (item = string_table,arraylen = 0; item; item = item->next) */
149   /*   fprintf (stderr, "  `%s'\n", item->name); */
150 }
151
152
153 static void
154 write_string_table (FILE *fp)
155 {
156   struct name_list_s *item;
157   const char *s;
158   int count = 0;
159   int pos;
160
161   if (!string_table)
162     insert_string ("");
163
164   fputs ("static const char string_table[] = {\n  ", fp);
165   for (item = string_table; item; item = item->next)
166     {
167       for (s=item->name, pos=0; *s; s++)
168         {
169           if (!(pos++ % 16))
170             fprintf (fp, "%s  ", pos>1? "\n":"");
171           fprintf (fp, "'%c',", *s);
172         }
173       fputs ("'\\0',\n", fp);
174       count++;
175     }
176   /* (we use an extra \0 to get rid of the last comma) */
177   fprintf (fp, "  '\\0' };\n/* (%d strings) */\n", count);
178 }
179
180
181 static struct name_list_s *
182 create_static_structure (AsnNode pointer, const char *file_name, FILE *fp)
183 {
184   AsnNode p;
185   struct name_list_s *structure_name;
186   const char *char_p, *slash_p, *dot_p;
187   char numbuf[50];
188
189   char_p = file_name;
190   slash_p = file_name;
191   while ((char_p = strchr (char_p, '/')))
192     {
193       char_p++;
194       slash_p = char_p;
195     }
196
197   char_p = slash_p;
198   dot_p = file_name + strlen (file_name);
199
200   while ((char_p = strchr (char_p, '.')))
201     {
202       dot_p = char_p;
203       char_p++;
204     }
205
206   structure_name = xmalloc (sizeof *structure_name + dot_p - slash_p + 100);
207   structure_name->next = NULL;
208   memcpy (structure_name->name, slash_p, dot_p - slash_p);
209   structure_name->name[dot_p - slash_p] = 0;
210
211   fprintf (fp, "static const static_asn %s_asn1_tab[] = {\n",
212            structure_name->name);
213
214   for (p = pointer; p; p = _ksba_asn_walk_tree (pointer, p))
215     {
216       /* set the help flags */
217       p->flags.help_down  = !!p->down;
218       p->flags.help_right = !!p->right;
219
220       /* write a structure line */
221       fputs ("  {", fp);
222       if (p->name)
223         fprintf (fp, "%u", (unsigned int)insert_string (p->name));
224       else
225         fprintf (fp, "0");
226       fprintf (fp, ",%u", p->type);
227
228       fputs (", {", fp);
229       fprintf (fp, "%u", p->flags.class);
230       fputs (p->flags.explicit       ? ",1":",0", fp);
231       fputs (p->flags.implicit       ? ",1":",0", fp);
232       fputs (p->flags.has_imports    ? ",1":",0", fp);
233       fputs (p->flags.assignment     ? ",1":",0", fp);
234       fputs (p->flags.one_param      ? ",1":",0", fp);
235       fputs (p->flags.has_tag        ? ",1":",0", fp);
236       fputs (p->flags.has_size       ? ",1":",0", fp);
237       fputs (p->flags.has_list       ? ",1":",0", fp);
238       fputs (p->flags.has_min_max    ? ",1":",0", fp);
239       fputs (p->flags.has_defined_by ? ",1":",0", fp);
240       fputs (p->flags.is_false       ? ",1":",0", fp);
241       fputs (p->flags.is_true        ? ",1":",0", fp);
242       fputs (p->flags.has_default     ? ",1":",0", fp);
243       fputs (p->flags.is_optional    ? ",1":",0", fp);
244       fputs (p->flags.is_implicit    ? ",1":",0", fp);
245       fputs (p->flags.in_set         ? ",1":",0", fp);
246       fputs (p->flags.in_choice      ? ",1":",0", fp);
247       fputs (p->flags.in_array       ? ",1":",0", fp);
248       fputs (p->flags.is_any         ? ",1":",0", fp);
249       fputs (p->flags.not_used       ? ",1":",0", fp);
250       fputs (p->flags.help_down      ? ",1":",0", fp);
251       fputs (p->flags.help_right     ? ",1":",0", fp);
252       fputs ("}", fp);
253
254       if (p->valuetype == VALTYPE_CSTR)
255         fprintf (fp, ",%u",
256                  (unsigned int)insert_string (p->value.v_cstr));
257       else if (p->valuetype == VALTYPE_LONG
258                && p->type == TYPE_INTEGER && p->flags.assignment)
259         {
260           snprintf (numbuf, sizeof numbuf, "%ld", p->value.v_long);
261           fprintf (fp, ",%u", (unsigned int)insert_string (numbuf));
262         }
263       else if (p->valuetype == VALTYPE_ULONG)
264         {
265           snprintf (numbuf, sizeof numbuf, "%lu", p->value.v_ulong);
266           fprintf (fp, ",%u", (unsigned int)insert_string (numbuf));
267         }
268       else
269         {
270           if (p->valuetype)
271             print_error ("can't store a value of type %d\n", p->valuetype);
272           fprintf (fp, ",0");
273         }
274       fputs ("},\n", fp);
275     }
276
277   fprintf (fp, "  {0,0}\n};\n");
278
279   return structure_name;
280 }
281
282
283
284 static struct name_list_s *
285 one_file (const char *fname, int *count, FILE *fp)
286 {
287   ksba_asn_tree_t tree;
288   int rc;
289
290   rc = ksba_asn_parse_file (fname, &tree, check_only);
291   if (rc)
292     print_error ("error parsing `%s': %s\n", fname, gpg_strerror (rc) );
293   else if (!check_only)
294     {
295       if (dump_only)
296         ksba_asn_tree_dump (tree, dump_only==2? "<":NULL, fp);
297       else
298         {
299           if (!*count)
300             fprintf (fp,"\n"
301                      "#include <config.h>\n"
302                      "#include <stdio.h>\n"
303                      "#include <string.h>\n"
304                      "#include \"ksba.h\"\n"
305                      "#include \"asn1-func.h\"\n"
306                      "\n");
307           ++*count;
308           return create_static_structure (tree->parse_tree, fname, fp);
309         }
310     }
311   return 0;
312 }
313
314
315 int
316 main (int argc, char **argv)
317 {
318   int count = 0;
319   struct name_list_s *all_names = NULL, *nl;
320   int i;
321
322   if (!argc || (argc > 1 &&
323                 (!strcmp (argv[1],"--help") || !strcmp (argv[1],"-h"))) )
324     {
325       fputs ("usage: asn1-gentables [--check] [--dump[-expanded]] [files.asn]\n",
326              stderr);
327       return 0;
328     }
329
330   argc--; argv++;
331   if (argc && !strcmp (*argv,"--check"))
332     {
333       argc--; argv++;
334       check_only = 1;
335     }
336   else if (argc && !strcmp (*argv,"--dump"))
337     {
338       argc--; argv++;
339       dump_only = 1;
340     }
341   else if (argc && !strcmp (*argv,"--dump-expanded"))
342     {
343       argc--; argv++;
344       dump_only = 2;
345     }
346
347
348   if (!argc)
349     all_names = one_file ("-", &count, stdout);
350   else
351     {
352       FILE *nullfp;
353
354       /* We first parse it to /dev/null to build up the string table.  */
355       nullfp = fopen (DEVNULL_NAME, "w");
356       if (!nullfp)
357         {
358           print_error ("can't open `%s': %s\n", DEVNULL_NAME, strerror (errno));
359           exit (2);
360         }
361       for (i=0; i < argc; i++)
362         one_file (argv[i], &count, nullfp);
363       fclose (nullfp);
364
365       sort_string_table ();
366
367       count = 0;
368       for (; argc; argc--, argv++)
369         {
370           nl = one_file (*argv, &count, stdout);
371           if (nl)
372             {
373               nl->next = all_names;
374               all_names = nl;
375             }
376         }
377     }
378
379   if (all_names && !error_counter)
380     {
381       /* Write the string table. */
382       putchar ('\n');
383       write_string_table (stdout);
384       /* Write the lookup function */
385       printf ("\n\nconst static_asn *\n"
386               "_ksba_asn_lookup_table (const char *name,"
387               " const char **stringtbl)\n"
388               "{\n"
389               "  *stringtbl = string_table;\n"
390               );
391       for (nl=all_names; nl; nl = nl->next)
392         printf ("  if (!strcmp (name, \"%s\"))\n"
393                 "    return %s_asn1_tab;\n", nl->name, nl->name);
394       printf ("\n  return NULL;\n}\n");
395     }
396
397   return error_counter? 1:0;
398 }