diff --git a/src/asn1-gentables.c b/src/asn1-gentables.c index c418fe1..aba642c 100644 --- a/src/asn1-gentables.c +++ b/src/asn1-gentables.c @@ -1,391 +1,398 @@ /* asn1-gentables.c - Tool to create required ASN tables * Copyright (C) 2001, 2008 g10 Code GmbH * * This file is part of KSBA. * * KSBA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * KSBA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gen-help.h" #include "asn1-func.h" #define PGMNAME "asn1-gentables" #if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )) # define ATTR_PRINTF(a,b) __attribute__ ((format (printf,a,b))) #else # define ATTR_PRINTF(a,b) #endif #ifdef _WIN32 #define DEVNULL_NAME "nul" #else #define DEVNULL_NAME "/dev/null" #endif /* keep track of parsing error */ static int error_counter; /* option --dump */ static int dump_only; /* option --check */ static int check_only; struct name_list_s { struct name_list_s *next; char name[1]; }; static struct name_list_s *string_table, **string_table_tail; static size_t string_table_offset; static void print_error (const char *fmt, ... ) ATTR_PRINTF(1,2); static void print_error (const char *fmt, ... ) { va_list arg_ptr ; va_start (arg_ptr, fmt); fputs (PGMNAME ": ", stderr); vfprintf (stderr, fmt, arg_ptr); va_end (arg_ptr); error_counter++; } static size_t insert_string (const char *name) { struct name_list_s *item; size_t off, n; if (!string_table_tail) { string_table_tail = &string_table; insert_string (""); } if (string_table_offset && !*name) return 0; for (item = string_table,off = 0; item; item = item->next) { for (n=0; item->name[n]; n++) if (!strcmp (item->name+n, name)) return off + n; off += strlen (item->name) + 1; } item = xmalloc ( sizeof *item + strlen (name)); strcpy (item->name, name); item->next = NULL; *string_table_tail = item; string_table_tail = &item->next; off = string_table_offset; string_table_offset += strlen (name) + 1; return off; } static int cmp_string (const void *aptr, const void *bptr) { - const struct name_list_s **a = (const struct name_list_s **)aptr; - const struct name_list_s **b = (const struct name_list_s **)bptr; + const char *a = (*(const struct name_list_s **)aptr)->name; + const char *b = (*(const struct name_list_s **)bptr)->name; - return strlen ((*a)->name) < strlen ((*b)->name); + const size_t len_a = strlen(a); + const size_t len_b = strlen(b); + + if (len_a < len_b) + return -1; + if (len_a > len_b) + return +1; + return strcmp(a, b); } static void sort_string_table (void) { struct name_list_s *item; struct name_list_s **array; size_t i, arraylen; if (!string_table || !string_table->next) return; /* Nothing to sort. */ for (item = string_table,arraylen = 0; item; item = item->next) arraylen++; array = xcalloc (arraylen, sizeof *array); for (item = string_table,arraylen = 0; item; item = item->next) array[arraylen++] = item; qsort (array, arraylen, sizeof *array, cmp_string); /* Replace table by sorted one. */ string_table_tail = NULL; string_table = NULL; string_table_offset = 0; for (i=0; i < arraylen; i++) insert_string (array[i]->name); xfree (array); /* for (item = string_table,arraylen = 0; item; item = item->next) */ /* fprintf (stderr, " `%s'\n", item->name); */ } static void write_string_table (FILE *fp) { struct name_list_s *item; const char *s; int count = 0; int pos; if (!string_table) insert_string (""); fputs ("static const char string_table[] = {\n ", fp); for (item = string_table; item; item = item->next) { for (s=item->name, pos=0; *s; s++) { if (!(pos++ % 16)) fprintf (fp, "%s ", pos>1? "\n":""); fprintf (fp, "'%c',", *s); } fputs ("'\\0',\n", fp); count++; } /* (we use an extra \0 to get rid of the last comma) */ fprintf (fp, " '\\0' };\n/* (%d strings) */\n", count); } static struct name_list_s * create_static_structure (AsnNode pointer, const char *file_name, FILE *fp) { AsnNode p; struct name_list_s *structure_name; const char *char_p, *slash_p, *dot_p; char numbuf[50]; char_p = file_name; slash_p = file_name; while ((char_p = strchr (char_p, '/'))) { char_p++; slash_p = char_p; } char_p = slash_p; dot_p = file_name + strlen (file_name); while ((char_p = strchr (char_p, '.'))) { dot_p = char_p; char_p++; } structure_name = xmalloc (sizeof *structure_name + dot_p - slash_p + 100); structure_name->next = NULL; memcpy (structure_name->name, slash_p, dot_p - slash_p); structure_name->name[dot_p - slash_p] = 0; fprintf (fp, "static const static_asn %s_asn1_tab[] = {\n", structure_name->name); for (p = pointer; p; p = _ksba_asn_walk_tree (pointer, p)) { /* set the help flags */ p->flags.help_down = !!p->down; p->flags.help_right = !!p->right; /* write a structure line */ fputs (" {", fp); if (p->name) fprintf (fp, "%u", (unsigned int)insert_string (p->name)); else fprintf (fp, "0"); fprintf (fp, ",%u", p->type); fputs (", {", fp); fprintf (fp, "%u", p->flags.class); fputs (p->flags.explicit ? ",1":",0", fp); fputs (p->flags.implicit ? ",1":",0", fp); fputs (p->flags.has_imports ? ",1":",0", fp); fputs (p->flags.assignment ? ",1":",0", fp); fputs (p->flags.one_param ? ",1":",0", fp); fputs (p->flags.has_tag ? ",1":",0", fp); fputs (p->flags.has_size ? ",1":",0", fp); fputs (p->flags.has_list ? ",1":",0", fp); fputs (p->flags.has_min_max ? ",1":",0", fp); fputs (p->flags.has_defined_by ? ",1":",0", fp); fputs (p->flags.is_false ? ",1":",0", fp); fputs (p->flags.is_true ? ",1":",0", fp); fputs (p->flags.has_default ? ",1":",0", fp); fputs (p->flags.is_optional ? ",1":",0", fp); fputs (p->flags.is_implicit ? ",1":",0", fp); fputs (p->flags.in_set ? ",1":",0", fp); fputs (p->flags.in_choice ? ",1":",0", fp); fputs (p->flags.in_array ? ",1":",0", fp); fputs (p->flags.is_any ? ",1":",0", fp); fputs (p->flags.not_used ? ",1":",0", fp); fputs (p->flags.help_down ? ",1":",0", fp); fputs (p->flags.help_right ? ",1":",0", fp); fputs ("}", fp); if (p->valuetype == VALTYPE_CSTR) fprintf (fp, ",%u", (unsigned int)insert_string (p->value.v_cstr)); else if (p->valuetype == VALTYPE_LONG && p->type == TYPE_INTEGER && p->flags.assignment) { snprintf (numbuf, sizeof numbuf, "%ld", p->value.v_long); fprintf (fp, ",%u", (unsigned int)insert_string (numbuf)); } else if (p->valuetype == VALTYPE_ULONG) { snprintf (numbuf, sizeof numbuf, "%lu", p->value.v_ulong); fprintf (fp, ",%u", (unsigned int)insert_string (numbuf)); } else { if (p->valuetype) print_error ("can't store a value of type %d\n", p->valuetype); fprintf (fp, ",0"); } fputs ("},\n", fp); } fprintf (fp, " {0,0}\n};\n"); return structure_name; } static struct name_list_s * one_file (const char *fname, int *count, FILE *fp) { ksba_asn_tree_t tree; int rc; rc = ksba_asn_parse_file (fname, &tree, check_only); if (rc) print_error ("error parsing `%s': %s\n", fname, gpg_strerror (rc) ); else if (!check_only) { if (dump_only) ksba_asn_tree_dump (tree, dump_only==2? "<":NULL, fp); else { if (!*count) fprintf (fp,"\n" "#include \n" "#include \n" "#include \n" "#include \"ksba.h\"\n" "#include \"asn1-func.h\"\n" "\n"); ++*count; return create_static_structure (tree->parse_tree, fname, fp); } } return 0; } int main (int argc, char **argv) { int count = 0; struct name_list_s *all_names = NULL, *nl; int i; if (!argc || (argc > 1 && (!strcmp (argv[1],"--help") || !strcmp (argv[1],"-h"))) ) { fputs ("usage: asn1-gentables [--check] [--dump[-expanded]] [files.asn]\n", stderr); return 0; } argc--; argv++; if (argc && !strcmp (*argv,"--check")) { argc--; argv++; check_only = 1; } else if (argc && !strcmp (*argv,"--dump")) { argc--; argv++; dump_only = 1; } else if (argc && !strcmp (*argv,"--dump-expanded")) { argc--; argv++; dump_only = 2; } if (!argc) all_names = one_file ("-", &count, stdout); else { FILE *nullfp; /* We first parse it to /dev/null to build up the string table. */ nullfp = fopen (DEVNULL_NAME, "w"); if (!nullfp) { print_error ("can't open `%s': %s\n", DEVNULL_NAME, strerror (errno)); exit (2); } for (i=0; i < argc; i++) one_file (argv[i], &count, nullfp); fclose (nullfp); sort_string_table (); count = 0; for (; argc; argc--, argv++) { nl = one_file (*argv, &count, stdout); if (nl) { nl->next = all_names; all_names = nl; } } } if (all_names && !error_counter) { /* Write the string table. */ putchar ('\n'); write_string_table (stdout); /* Write the lookup function */ printf ("\n\nconst static_asn *\n" "_ksba_asn_lookup_table (const char *name," " const char **stringtbl)\n" "{\n" " *stringtbl = string_table;\n" ); for (nl=all_names; nl; nl = nl->next) printf (" if (!strcmp (name, \"%s\"))\n" " return %s_asn1_tab;\n", nl->name, nl->name); printf ("\n return NULL;\n}\n"); } return error_counter? 1:0; }