/* 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;
return strlen ((*a)->name) < strlen ((*b)->name);
}
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;
}