Home | History | Annotate | Line # | Download | only in asn1
      1 /*	$NetBSD: gen.c,v 1.6 2023/06/19 21:41:42 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 - 2005 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  *
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  *
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  *
     21  * 3. Neither the name of the Institute nor the names of its contributors
     22  *    may be used to endorse or promote products derived from this software
     23  *    without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  */
     37 
     38 #include "gen_locl.h"
     39 #include <libgen.h>
     40 
     41 __RCSID("$NetBSD: gen.c,v 1.6 2023/06/19 21:41:42 christos Exp $");
     42 
     43 FILE *privheaderfile, *headerfile, *codefile, *logfile, *templatefile;
     44 
     45 #define STEM "asn1"
     46 
     47 static const char *orig_filename;
     48 static char *privheader, *header, *template;
     49 static const char *headerbase = STEM;
     50 
     51 /*
     52  * list of all IMPORTs
     53  */
     54 
     55 struct import {
     56     const char *module;
     57     struct import *next;
     58 };
     59 
     60 static struct import *imports = NULL;
     61 
     62 void
     63 add_import (const char *module)
     64 {
     65     struct import *tmp = emalloc (sizeof(*tmp));
     66 
     67     tmp->module = module;
     68     tmp->next   = imports;
     69     imports     = tmp;
     70 
     71     fprintf (headerfile, "#include <%s_asn1.h>\n", module);
     72 }
     73 
     74 /*
     75  * List of all exported symbols
     76  */
     77 
     78 struct sexport {
     79     const char *name;
     80     int defined;
     81     struct sexport *next;
     82 };
     83 
     84 static struct sexport *exports = NULL;
     85 
     86 void
     87 add_export (const char *name)
     88 {
     89     struct sexport *tmp = emalloc (sizeof(*tmp));
     90 
     91     tmp->name   = name;
     92     tmp->next   = exports;
     93     exports     = tmp;
     94 }
     95 
     96 int
     97 is_export(const char *name)
     98 {
     99     struct sexport *tmp;
    100 
    101     if (exports == NULL) /* no export list, all exported */
    102 	return 1;
    103 
    104     for (tmp = exports; tmp != NULL; tmp = tmp->next) {
    105 	if (strcmp(tmp->name, name) == 0) {
    106 	    tmp->defined = 1;
    107 	    return 1;
    108 	}
    109     }
    110     return 0;
    111 }
    112 
    113 const char *
    114 get_filename (void)
    115 {
    116     return orig_filename;
    117 }
    118 
    119 void
    120 init_generate (const char *filename, const char *base)
    121 {
    122     char *fn = NULL;
    123 
    124     orig_filename = filename;
    125     if (base != NULL) {
    126 	headerbase = strdup(base);
    127 	if (headerbase == NULL)
    128 	    errx(1, "strdup");
    129     }
    130 
    131     /* public header file */
    132     if (asprintf(&header, "%s.h", headerbase) < 0 || header == NULL)
    133 	errx(1, "malloc");
    134     if (asprintf(&fn, "%s.hx", headerbase) < 0 || fn == NULL)
    135 	errx(1, "malloc");
    136     headerfile = fopen (fn, "w");
    137     if (headerfile == NULL)
    138 	err (1, "open %s", fn);
    139     free(fn);
    140     fn = NULL;
    141 
    142     /* private header file */
    143     if (asprintf(&privheader, "%s-priv.h", headerbase) < 0 || privheader == NULL)
    144 	errx(1, "malloc");
    145     if (asprintf(&fn, "%s-priv.hx", headerbase) < 0 || fn == NULL)
    146 	errx(1, "malloc");
    147     privheaderfile = fopen (fn, "w");
    148     if (privheaderfile == NULL)
    149 	err (1, "open %s", fn);
    150     free(fn);
    151     fn = NULL;
    152 
    153     /* template file */
    154     if (asprintf(&template, "%s-template.x", headerbase) < 0 || template == NULL)
    155 	errx(1, "malloc");
    156     char *copy = estrdup(filename);
    157     char *bn = basename(copy);
    158     fprintf (headerfile,
    159 	     "/* Generated from %s */\n"
    160 	     "/* Do not edit */\n\n",
    161 	     bn);
    162     fprintf (headerfile,
    163 	     "#ifndef __%s_h__\n"
    164 	     "#define __%s_h__\n\n", headerbase, headerbase);
    165     fprintf (headerfile,
    166 	     "#include <stddef.h>\n"
    167 	     "#include <time.h>\n\n");
    168     fprintf (headerfile,
    169 	     "#ifndef __asn1_common_definitions__\n"
    170 	     "#define __asn1_common_definitions__\n\n");
    171 	fprintf (headerfile,
    172 		 "#ifndef __HEIM_BASE_DATA__\n"
    173 		 "#define __HEIM_BASE_DATA__ 1\n"
    174 		 "struct heim_base_data {\n"
    175 		 "    size_t length;\n"
    176 		 "    void *data;\n"
    177 		 "};\n"
    178 		 "typedef struct heim_base_data heim_octet_string;\n"
    179 		 "#endif\n\n");
    180     fprintf (headerfile,
    181 	     "typedef struct heim_integer {\n"
    182 	     "  size_t length;\n"
    183 	     "  void *data;\n"
    184 	     "  int negative;\n"
    185 	     "} heim_integer;\n\n");
    186     fprintf (headerfile,
    187 	     "typedef char *heim_general_string;\n\n"
    188 	     );
    189     fprintf (headerfile,
    190 	     "typedef char *heim_utf8_string;\n\n"
    191 	     );
    192     fprintf (headerfile,
    193 	     "typedef struct heim_base_data heim_printable_string;\n\n"
    194 	     );
    195     fprintf (headerfile,
    196 	     "typedef struct heim_base_data heim_ia5_string;\n\n"
    197 	     );
    198     fprintf (headerfile,
    199 	     "typedef struct heim_bmp_string {\n"
    200 	     "  size_t length;\n"
    201 	     "  uint16_t *data;\n"
    202 	     "} heim_bmp_string;\n\n");
    203     fprintf (headerfile,
    204 	     "typedef struct heim_universal_string {\n"
    205 	     "  size_t length;\n"
    206 	     "  uint32_t *data;\n"
    207 	     "} heim_universal_string;\n\n");
    208     fprintf (headerfile,
    209 	     "typedef char *heim_visible_string;\n\n"
    210 	     );
    211     fprintf (headerfile,
    212 	     "typedef struct heim_oid {\n"
    213 	     "  size_t length;\n"
    214 	     "  unsigned *components;\n"
    215 	     "} heim_oid;\n\n");
    216     fprintf (headerfile,
    217 	     "typedef struct heim_bit_string {\n"
    218 	     "  size_t length;\n"
    219 	     "  void *data;\n"
    220 	     "} heim_bit_string;\n\n");
    221     fprintf (headerfile,
    222 	     "typedef struct heim_base_data heim_any;\n"
    223 	     "typedef struct heim_base_data heim_any_set;\n\n");
    224     fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R)                  \\\n"
    225 	  "  do {                                                         \\\n"
    226 	  "    (BL) = length_##T((S));                                    \\\n"
    227 	  "    (B) = malloc((BL));                                        \\\n"
    228 	  "    if((B) == NULL) {                                          \\\n"
    229 	  "      (R) = ENOMEM;                                            \\\n"
    230 	  "    } else {                                                   \\\n"
    231 	  "      (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \\\n"
    232 	  "                       (S), (L));                              \\\n"
    233 	  "      if((R) != 0) {                                           \\\n"
    234 	  "        free((B));                                             \\\n"
    235 	  "        (B) = NULL;                                            \\\n"
    236 	  "      }                                                        \\\n"
    237 	  "    }                                                          \\\n"
    238 	  "  } while (0)\n\n",
    239 	  headerfile);
    240     fputs("#ifdef _WIN32\n"
    241 	  "#ifndef ASN1_LIB\n"
    242 	  "#define ASN1EXP  __declspec(dllimport)\n"
    243 	  "#else\n"
    244 	  "#define ASN1EXP\n"
    245 	  "#endif\n"
    246 	  "#define ASN1CALL __stdcall\n"
    247 	  "#else\n"
    248 	  "#define ASN1EXP\n"
    249 	  "#define ASN1CALL\n"
    250 	  "#endif\n",
    251 	  headerfile);
    252     fprintf (headerfile, "struct units;\n\n");
    253     fprintf (headerfile, "#endif\n\n");
    254     if (asprintf(&fn, "%s_files", base) < 0 || fn == NULL)
    255 	errx(1, "malloc");
    256     logfile = fopen(fn, "w");
    257     if (logfile == NULL)
    258 	err (1, "open %s", fn);
    259 
    260     /* if one code file, write into the one codefile */
    261     if (one_code_file)
    262 	return;
    263 
    264     templatefile = fopen (template, "w");
    265     if (templatefile == NULL)
    266 	err (1, "open %s", template);
    267 
    268     fprintf (templatefile,
    269 	     "/* Generated from %s */\n"
    270 	     "/* Do not edit */\n\n"
    271 	     "#include <stdio.h>\n"
    272 	     "#include <stdlib.h>\n"
    273 	     "#include <time.h>\n"
    274 	     "#include <string.h>\n"
    275 	     "#include <errno.h>\n"
    276 	     "#include <limits.h>\n"
    277 	     "#include <krb5/%s.h>\n",
    278 	     bn,
    279 	     type_file_string);
    280     free(copy);
    281 
    282     fprintf (templatefile,
    283 	     "#include <%s>\n"
    284 	     "#include <%s>\n"
    285 	     "#include <krb5/der.h>\n"
    286 	     "#include <asn1-template.h>\n",
    287 	     header, privheader);
    288 
    289 
    290 }
    291 
    292 void
    293 close_generate (void)
    294 {
    295     fprintf (headerfile, "#endif /* __%s_h__ */\n", headerbase);
    296 
    297     if (headerfile)
    298         fclose (headerfile);
    299     if (privheaderfile)
    300         fclose (privheaderfile);
    301     if (templatefile)
    302         fclose (templatefile);
    303     if (logfile) {
    304         fprintf (logfile, "\n");
    305         fclose (logfile);
    306     }
    307 }
    308 
    309 void
    310 gen_assign_defval(const char *var, struct value *val)
    311 {
    312     switch(val->type) {
    313     case stringvalue:
    314 	fprintf(codefile, "if((%s = strdup(\"%s\")) == NULL)\nreturn ENOMEM;\n", var, val->u.stringvalue);
    315 	break;
    316     case integervalue:
    317 	fprintf(codefile, "%s = %lld;\n",
    318 		var, (long long)val->u.integervalue);
    319 	break;
    320     case booleanvalue:
    321 	if(val->u.booleanvalue)
    322 	    fprintf(codefile, "%s = TRUE;\n", var);
    323 	else
    324 	    fprintf(codefile, "%s = FALSE;\n", var);
    325 	break;
    326     default:
    327 	abort();
    328     }
    329 }
    330 
    331 void
    332 gen_compare_defval(const char *var, struct value *val)
    333 {
    334     switch(val->type) {
    335     case stringvalue:
    336 	fprintf(codefile, "if(strcmp(%s, \"%s\") != 0)\n", var, val->u.stringvalue);
    337 	break;
    338     case integervalue:
    339 	fprintf(codefile, "if(%s != %lld)\n",
    340 		var, (long long)val->u.integervalue);
    341 	break;
    342     case booleanvalue:
    343 	if(val->u.booleanvalue)
    344 	    fprintf(codefile, "if(!%s)\n", var);
    345 	else
    346 	    fprintf(codefile, "if(%s)\n", var);
    347 	break;
    348     default:
    349 	abort();
    350     }
    351 }
    352 
    353 void
    354 generate_header_of_codefile(const char *name)
    355 {
    356     char *filename = NULL;
    357 
    358     if (codefile != NULL)
    359 	abort();
    360 
    361     if (asprintf (&filename, "%s_%s.x", STEM, name) < 0 || filename == NULL)
    362 	errx(1, "malloc");
    363     codefile = fopen (filename, "w");
    364     if (codefile == NULL)
    365 	err (1, "fopen %s", filename);
    366     if (logfile)
    367         fprintf(logfile, "%s ", filename);
    368     free(filename);
    369     filename = NULL;
    370     char *copy = estrdup(orig_filename);
    371     char *bn = basename(copy);
    372     fprintf (codefile,
    373 	     "/* Generated from %s */\n"
    374 	     "/* Do not edit */\n\n"
    375 	     "#define  ASN1_LIB\n\n"
    376 	     "#include <stdio.h>\n"
    377 	     "#include <stdlib.h>\n"
    378 	     "#include <time.h>\n"
    379 	     "#include <string.h>\n"
    380 	     "#include <errno.h>\n"
    381 	     "#include <limits.h>\n"
    382 	     "#include <krb5/%s>\n",
    383 	     bn,
    384 	     type_file_string);
    385     free(copy);
    386 
    387     fprintf (codefile,
    388 	     "#include \"%s\"\n"
    389 	     "#include \"%s\"\n",
    390 	     header, privheader);
    391     fprintf (codefile,
    392 	     "#include <krb5/asn1_err.h>\n"
    393 	     "#include <krb5/der.h>\n"
    394 	     "#include <asn1-template.h>\n\n");
    395 
    396     if (parse_units_flag)
    397 	fprintf (codefile,
    398 		 "#include <krb5/parse_units.h>\n\n");
    399 
    400 }
    401 
    402 void
    403 close_codefile(void)
    404 {
    405     if (codefile == NULL)
    406 	abort();
    407 
    408     fclose(codefile);
    409     codefile = NULL;
    410 }
    411 
    412 
    413 void
    414 generate_constant (const Symbol *s)
    415 {
    416     switch(s->value->type) {
    417     case booleanvalue:
    418 	break;
    419     case integervalue:
    420 	fprintf (headerfile, "enum { %s = %lld };\n\n",
    421 		 s->gen_name,
    422 		 (long long)s->value->u.integervalue);
    423 	break;
    424     case nullvalue:
    425 	break;
    426     case stringvalue:
    427 	break;
    428     case objectidentifiervalue: {
    429 	struct objid *o, **list;
    430 	size_t i, len;
    431 	char *gen_upper;
    432 
    433 	if (!one_code_file)
    434 	    generate_header_of_codefile(s->gen_name);
    435 
    436 	len = 0;
    437 	for (o = s->value->u.objectidentifiervalue; o != NULL; o = o->next)
    438 	    len++;
    439 	if (len == 0) {
    440 	    printf("s->gen_name: %s",s->gen_name);
    441 	    fflush(stdout);
    442 	    break;
    443 	}
    444 	list = emalloc(sizeof(*list) * len);
    445 
    446 	i = 0;
    447 	for (o = s->value->u.objectidentifiervalue; o != NULL; o = o->next)
    448 	    list[i++] = o;
    449 
    450 	fprintf (headerfile, "/* OBJECT IDENTIFIER %s ::= { ", s->name);
    451 	for (i = len ; i > 0; i--) {
    452 	    o = list[i - 1];
    453 	    fprintf(headerfile, "%s(%d) ",
    454 		    o->label ? o->label : "label-less", o->value);
    455 	}
    456 
    457 	fprintf (codefile, "static unsigned oid_%s_variable_num[%lu] =  {",
    458 		 s->gen_name, (unsigned long)len);
    459 	for (i = len ; i > 0; i--) {
    460 	    fprintf(codefile, "%d%s ", list[i - 1]->value, i > 1 ? "," : "");
    461 	}
    462 	fprintf(codefile, "};\n");
    463 
    464 	fprintf (codefile, "const heim_oid asn1_oid_%s = "
    465 		 "{ %lu, oid_%s_variable_num };\n\n",
    466 		 s->gen_name, (unsigned long)len, s->gen_name);
    467 
    468 	free(list);
    469 
    470 	/* header file */
    471 
    472 	gen_upper = strdup(s->gen_name);
    473 	len = strlen(gen_upper);
    474 	for (i = 0; i < len; i++)
    475 	    gen_upper[i] = toupper((int)s->gen_name[i]);
    476 
    477 	fprintf (headerfile, "} */\n");
    478 	fprintf (headerfile,
    479 		 "extern ASN1EXP const heim_oid asn1_oid_%s;\n"
    480 		 "#define ASN1_OID_%s (&asn1_oid_%s)\n\n",
    481 		 s->gen_name,
    482 		 gen_upper,
    483 		 s->gen_name);
    484 
    485 	free(gen_upper);
    486 
    487 	if (!one_code_file)
    488 	    close_codefile();
    489 
    490 	break;
    491     }
    492     default:
    493 	abort();
    494     }
    495 }
    496 
    497 int
    498 is_primitive_type(int type)
    499 {
    500     switch(type) {
    501     case TInteger:
    502     case TBoolean:
    503     case TOctetString:
    504     case TBitString:
    505     case TEnumerated:
    506     case TGeneralizedTime:
    507     case TGeneralString:
    508     case TTeletexString:
    509     case TOID:
    510     case TUTCTime:
    511     case TUTF8String:
    512     case TPrintableString:
    513     case TIA5String:
    514     case TBMPString:
    515     case TUniversalString:
    516     case TVisibleString:
    517     case TNull:
    518 	return 1;
    519     default:
    520 	return 0;
    521     }
    522 }
    523 
    524 static void
    525 space(int level)
    526 {
    527     while(level-- > 0)
    528 	fprintf(headerfile, "  ");
    529 }
    530 
    531 static const char *
    532 last_member_p(struct member *m)
    533 {
    534     struct member *n = ASN1_TAILQ_NEXT(m, members);
    535     if (n == NULL)
    536 	return "";
    537     if (n->ellipsis && ASN1_TAILQ_NEXT(n, members) == NULL)
    538 	return "";
    539     return ",";
    540 }
    541 
    542 static struct member *
    543 have_ellipsis(Type *t)
    544 {
    545     struct member *m;
    546     ASN1_TAILQ_FOREACH(m, t->members, members) {
    547 	if (m->ellipsis)
    548 	    return m;
    549     }
    550     return NULL;
    551 }
    552 
    553 static void
    554 define_asn1 (int level, Type *t)
    555 {
    556     switch (t->type) {
    557     case TType:
    558 	fprintf (headerfile, "%s", t->symbol->name);
    559 	break;
    560     case TInteger:
    561 	if(t->members == NULL) {
    562             fprintf (headerfile, "INTEGER");
    563 	    if (t->range)
    564 		fprintf (headerfile, " (%lld..%lld)",
    565 			 (long long)t->range->min,
    566 			 (long long)t->range->max);
    567         } else {
    568 	    Member *m;
    569             fprintf (headerfile, "INTEGER {\n");
    570 	    ASN1_TAILQ_FOREACH(m, t->members, members) {
    571                 space (level + 1);
    572 		fprintf(headerfile, "%s(%d)%s\n", m->gen_name, m->val,
    573 			last_member_p(m));
    574             }
    575 	    space(level);
    576             fprintf (headerfile, "}");
    577         }
    578 	break;
    579     case TBoolean:
    580 	fprintf (headerfile, "BOOLEAN");
    581 	break;
    582     case TOctetString:
    583 	fprintf (headerfile, "OCTET STRING");
    584 	break;
    585     case TEnumerated :
    586     case TBitString: {
    587 	Member *m;
    588 
    589 	space(level);
    590 	if(t->type == TBitString)
    591 	    fprintf (headerfile, "BIT STRING {\n");
    592 	else
    593 	    fprintf (headerfile, "ENUMERATED {\n");
    594 	ASN1_TAILQ_FOREACH(m, t->members, members) {
    595 	    space(level + 1);
    596 	    fprintf (headerfile, "%s(%d)%s\n", m->name, m->val,
    597 		     last_member_p(m));
    598 	}
    599 	space(level);
    600 	fprintf (headerfile, "}");
    601 	break;
    602     }
    603     case TChoice:
    604     case TSet:
    605     case TSequence: {
    606 	Member *m;
    607 	size_t max_width = 0;
    608 
    609 	if(t->type == TChoice)
    610 	    fprintf(headerfile, "CHOICE {\n");
    611 	else if(t->type == TSet)
    612 	    fprintf(headerfile, "SET {\n");
    613 	else
    614 	    fprintf(headerfile, "SEQUENCE {\n");
    615 	ASN1_TAILQ_FOREACH(m, t->members, members) {
    616 	    if(strlen(m->name) > max_width)
    617 		max_width = strlen(m->name);
    618 	}
    619 	max_width += 3;
    620 	if(max_width < 16) max_width = 16;
    621 	ASN1_TAILQ_FOREACH(m, t->members, members) {
    622 	    size_t width = max_width;
    623 	    space(level + 1);
    624 	    if (m->ellipsis) {
    625 		fprintf (headerfile, "...");
    626 	    } else {
    627 		width -= fprintf(headerfile, "%s", m->name);
    628 		fprintf(headerfile, "%*s", (int)width, "");
    629 		define_asn1(level + 1, m->type);
    630 		if(m->optional)
    631 		    fprintf(headerfile, " OPTIONAL");
    632 	    }
    633 	    if(last_member_p(m))
    634 		fprintf (headerfile, ",");
    635 	    fprintf (headerfile, "\n");
    636 	}
    637 	space(level);
    638 	fprintf (headerfile, "}");
    639 	break;
    640     }
    641     case TSequenceOf:
    642 	fprintf (headerfile, "SEQUENCE OF ");
    643 	define_asn1 (0, t->subtype);
    644 	break;
    645     case TSetOf:
    646 	fprintf (headerfile, "SET OF ");
    647 	define_asn1 (0, t->subtype);
    648 	break;
    649     case TGeneralizedTime:
    650 	fprintf (headerfile, "GeneralizedTime");
    651 	break;
    652     case TGeneralString:
    653 	fprintf (headerfile, "GeneralString");
    654 	break;
    655     case TTeletexString:
    656 	fprintf (headerfile, "TeletexString");
    657 	break;
    658     case TTag: {
    659 	const char *classnames[] = { "UNIVERSAL ", "APPLICATION ",
    660 				     "" /* CONTEXT */, "PRIVATE " };
    661 	if(t->tag.tagclass != ASN1_C_UNIV)
    662 	    fprintf (headerfile, "[%s%d] ",
    663 		     classnames[t->tag.tagclass],
    664 		     t->tag.tagvalue);
    665 	if(t->tag.tagenv == TE_IMPLICIT)
    666 	    fprintf (headerfile, "IMPLICIT ");
    667 	define_asn1 (level, t->subtype);
    668 	break;
    669     }
    670     case TUTCTime:
    671 	fprintf (headerfile, "UTCTime");
    672 	break;
    673     case TUTF8String:
    674 	space(level);
    675 	fprintf (headerfile, "UTF8String");
    676 	break;
    677     case TPrintableString:
    678 	space(level);
    679 	fprintf (headerfile, "PrintableString");
    680 	break;
    681     case TIA5String:
    682 	space(level);
    683 	fprintf (headerfile, "IA5String");
    684 	break;
    685     case TBMPString:
    686 	space(level);
    687 	fprintf (headerfile, "BMPString");
    688 	break;
    689     case TUniversalString:
    690 	space(level);
    691 	fprintf (headerfile, "UniversalString");
    692 	break;
    693     case TVisibleString:
    694 	space(level);
    695 	fprintf (headerfile, "VisibleString");
    696 	break;
    697     case TOID :
    698 	space(level);
    699 	fprintf(headerfile, "OBJECT IDENTIFIER");
    700 	break;
    701     case TNull:
    702 	space(level);
    703 	fprintf (headerfile, "NULL");
    704 	break;
    705     default:
    706 	abort ();
    707     }
    708 }
    709 
    710 static void
    711 getnewbasename(char **newbasename, int typedefp, const char *basename, const char *name)
    712 {
    713     if (typedefp)
    714 	*newbasename = strdup(name);
    715     else {
    716 	if (name[0] == '*')
    717 	    name++;
    718 	if (asprintf(newbasename, "%s_%s", basename, name) < 0)
    719 	    errx(1, "malloc");
    720     }
    721     if (*newbasename == NULL)
    722 	err(1, "malloc");
    723 }
    724 
    725 static void
    726 define_type (int level, const char *name, const char *basename, Type *t, int typedefp, int preservep)
    727 {
    728     char *newbasename = NULL;
    729 
    730     switch (t->type) {
    731     case TType:
    732 	space(level);
    733 	fprintf (headerfile, "%s %s;\n", t->symbol->gen_name, name);
    734 	break;
    735     case TInteger:
    736 	space(level);
    737 	if(t->members) {
    738             Member *m;
    739             fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
    740 	    ASN1_TAILQ_FOREACH(m, t->members, members) {
    741                 space (level + 1);
    742                 fprintf(headerfile, "%s = %d%s\n", m->gen_name, m->val,
    743                         last_member_p(m));
    744             }
    745             fprintf (headerfile, "} %s;\n", name);
    746 	} else if (t->range == NULL) {
    747 	    fprintf (headerfile, "heim_integer %s;\n", name);
    748 	} else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) {
    749 	    fprintf (headerfile, "int64_t %s;\n", name);
    750 	} else if (t->range->min >= 0 && t->range->max > UINT_MAX) {
    751 	    fprintf (headerfile, "uint64_t %s;\n", name);
    752 	} else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) {
    753 	    fprintf (headerfile, "int %s;\n", name);
    754 	} else if (t->range->min >= 0 && t->range->max <= UINT_MAX) {
    755 	    fprintf (headerfile, "unsigned int %s;\n", name);
    756 	} else
    757 	    errx(1, "%s: unsupported range %lld -> %lld",
    758 		 name, (long long)t->range->min, (long long)t->range->max);
    759 	break;
    760     case TBoolean:
    761 	space(level);
    762 	fprintf (headerfile, "int %s;\n", name);
    763 	break;
    764     case TOctetString:
    765 	space(level);
    766 	fprintf (headerfile, "heim_octet_string %s;\n", name);
    767 	break;
    768     case TBitString: {
    769 	Member *m;
    770 	Type i;
    771 	struct range range = { 0, UINT_MAX };
    772 
    773 	i.type = TInteger;
    774 	i.range = &range;
    775 	i.members = NULL;
    776 	i.constraint = NULL;
    777 
    778 	space(level);
    779 	if(ASN1_TAILQ_EMPTY(t->members))
    780 	    fprintf (headerfile, "heim_bit_string %s;\n", name);
    781 	else {
    782 	    int pos = 0;
    783 	    getnewbasename(&newbasename, typedefp, basename, name);
    784 
    785 	    fprintf (headerfile, "struct %s {\n", newbasename);
    786 	    ASN1_TAILQ_FOREACH(m, t->members, members) {
    787 		char *n = NULL;
    788 
    789 		/* pad unused */
    790 		while (pos < m->val) {
    791 		    if (asprintf (&n, "_unused%d:1", pos) < 0 || n == NULL)
    792 			errx(1, "malloc");
    793 		    define_type (level + 1, n, newbasename, &i, FALSE, FALSE);
    794 		    free(n);
    795 		    pos++;
    796 		}
    797 
    798 		n = NULL;
    799 		if (asprintf (&n, "%s:1", m->gen_name) < 0 || n == NULL)
    800 		    errx(1, "malloc");
    801 		define_type (level + 1, n, newbasename, &i, FALSE, FALSE);
    802 		free (n);
    803 		n = NULL;
    804 		pos++;
    805 	    }
    806 	    /* pad to 32 elements */
    807 	    while (pos < 32) {
    808 		char *n = NULL;
    809 		if (asprintf (&n, "_unused%d:1", pos) < 0 || n == NULL)
    810 		    errx(1, "malloc");
    811 		define_type (level + 1, n, newbasename, &i, FALSE, FALSE);
    812 		free(n);
    813 		pos++;
    814 	    }
    815 
    816 	    space(level);
    817 	    fprintf (headerfile, "} %s;\n\n", name);
    818 	}
    819 	break;
    820     }
    821     case TEnumerated: {
    822 	Member *m;
    823 
    824 	space(level);
    825 	fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
    826 	ASN1_TAILQ_FOREACH(m, t->members, members) {
    827 	    space(level + 1);
    828 	    if (m->ellipsis)
    829 		fprintf (headerfile, "/* ... */\n");
    830 	    else
    831 		fprintf (headerfile, "%s = %d%s\n", m->gen_name, m->val,
    832 			 last_member_p(m));
    833 	}
    834 	space(level);
    835 	fprintf (headerfile, "} %s;\n\n", name);
    836 	break;
    837     }
    838     case TSet:
    839     case TSequence: {
    840 	Member *m;
    841 
    842 	getnewbasename(&newbasename, typedefp, basename, name);
    843 
    844 	space(level);
    845 	fprintf (headerfile, "struct %s {\n", newbasename);
    846 	if (t->type == TSequence && preservep) {
    847 	    space(level + 1);
    848 	    fprintf(headerfile, "heim_octet_string _save;\n");
    849 	}
    850 	ASN1_TAILQ_FOREACH(m, t->members, members) {
    851 	    if (m->ellipsis) {
    852 		;
    853 	    } else if (m->optional) {
    854 		char *n = NULL;
    855 
    856 		if (asprintf (&n, "*%s", m->gen_name) < 0 || n == NULL)
    857 		    errx(1, "malloc");
    858 		define_type (level + 1, n, newbasename, m->type, FALSE, FALSE);
    859 		free (n);
    860 	    } else
    861 		define_type (level + 1, m->gen_name, newbasename, m->type, FALSE, FALSE);
    862 	}
    863 	space(level);
    864 	fprintf (headerfile, "} %s;\n", name);
    865 	break;
    866     }
    867     case TSetOf:
    868     case TSequenceOf: {
    869 	Type i;
    870 	struct range range = { 0, UINT_MAX };
    871 
    872 	getnewbasename(&newbasename, typedefp, basename, name);
    873 
    874 	i.type = TInteger;
    875 	i.range = &range;
    876 	i.members = NULL;
    877 	i.constraint = NULL;
    878 
    879 	space(level);
    880 	fprintf (headerfile, "struct %s {\n", newbasename);
    881 	define_type (level + 1, "len", newbasename, &i, FALSE, FALSE);
    882 	define_type (level + 1, "*val", newbasename, t->subtype, FALSE, FALSE);
    883 	space(level);
    884 	fprintf (headerfile, "} %s;\n", name);
    885 	break;
    886     }
    887     case TGeneralizedTime:
    888 	space(level);
    889 	fprintf (headerfile, "time_t %s;\n", name);
    890 	break;
    891     case TGeneralString:
    892 	space(level);
    893 	fprintf (headerfile, "heim_general_string %s;\n", name);
    894 	break;
    895     case TTeletexString:
    896 	space(level);
    897 	fprintf (headerfile, "heim_general_string %s;\n", name);
    898 	break;
    899     case TTag:
    900 	define_type (level, name, basename, t->subtype, typedefp, preservep);
    901 	break;
    902     case TChoice: {
    903 	int first = 1;
    904 	Member *m;
    905 
    906 	getnewbasename(&newbasename, typedefp, basename, name);
    907 
    908 	space(level);
    909 	fprintf (headerfile, "struct %s {\n", newbasename);
    910 	if (preservep) {
    911 	    space(level + 1);
    912 	    fprintf(headerfile, "heim_octet_string _save;\n");
    913 	}
    914 	space(level + 1);
    915 	fprintf (headerfile, "enum %s_enum {\n", newbasename);
    916 	m = have_ellipsis(t);
    917 	if (m) {
    918 	    space(level + 2);
    919 	    fprintf (headerfile, "%s = 0,\n", m->label);
    920 	    first = 0;
    921 	}
    922 	ASN1_TAILQ_FOREACH(m, t->members, members) {
    923 	    space(level + 2);
    924 	    if (m->ellipsis)
    925 		fprintf (headerfile, "/* ... */\n");
    926 	    else
    927 		fprintf (headerfile, "%s%s%s\n", m->label,
    928 			 first ? " = 1" : "",
    929 			 last_member_p(m));
    930 	    first = 0;
    931 	}
    932 	space(level + 1);
    933 	fprintf (headerfile, "} element;\n");
    934 	space(level + 1);
    935 	fprintf (headerfile, "union {\n");
    936 	ASN1_TAILQ_FOREACH(m, t->members, members) {
    937 	    if (m->ellipsis) {
    938 		space(level + 2);
    939 		fprintf(headerfile, "heim_octet_string asn1_ellipsis;\n");
    940 	    } else if (m->optional) {
    941 		char *n = NULL;
    942 
    943 		if (asprintf (&n, "*%s", m->gen_name) < 0 || n == NULL)
    944 		    errx(1, "malloc");
    945 		define_type (level + 2, n, newbasename, m->type, FALSE, FALSE);
    946 		free (n);
    947 	    } else
    948 		define_type (level + 2, m->gen_name, newbasename, m->type, FALSE, FALSE);
    949 	}
    950 	space(level + 1);
    951 	fprintf (headerfile, "} u;\n");
    952 	space(level);
    953 	fprintf (headerfile, "} %s;\n", name);
    954 	break;
    955     }
    956     case TUTCTime:
    957 	space(level);
    958 	fprintf (headerfile, "time_t %s;\n", name);
    959 	break;
    960     case TUTF8String:
    961 	space(level);
    962 	fprintf (headerfile, "heim_utf8_string %s;\n", name);
    963 	break;
    964     case TPrintableString:
    965 	space(level);
    966 	fprintf (headerfile, "heim_printable_string %s;\n", name);
    967 	break;
    968     case TIA5String:
    969 	space(level);
    970 	fprintf (headerfile, "heim_ia5_string %s;\n", name);
    971 	break;
    972     case TBMPString:
    973 	space(level);
    974 	fprintf (headerfile, "heim_bmp_string %s;\n", name);
    975 	break;
    976     case TUniversalString:
    977 	space(level);
    978 	fprintf (headerfile, "heim_universal_string %s;\n", name);
    979 	break;
    980     case TVisibleString:
    981 	space(level);
    982 	fprintf (headerfile, "heim_visible_string %s;\n", name);
    983 	break;
    984     case TOID :
    985 	space(level);
    986 	fprintf (headerfile, "heim_oid %s;\n", name);
    987 	break;
    988     case TNull:
    989 	space(level);
    990 	fprintf (headerfile, "int %s;\n", name);
    991 	break;
    992     default:
    993 	abort ();
    994     }
    995     if (newbasename)
    996 	free(newbasename);
    997 }
    998 
    999 static void
   1000 generate_type_header (const Symbol *s)
   1001 {
   1002     int preservep = preserve_type(s->name) ? TRUE : FALSE;
   1003 
   1004     fprintf (headerfile, "/*\n");
   1005     fprintf (headerfile, "%s ::= ", s->name);
   1006     define_asn1 (0, s->type);
   1007     fprintf (headerfile, "\n*/\n\n");
   1008 
   1009     fprintf (headerfile, "typedef ");
   1010     define_type (0, s->gen_name, s->gen_name, s->type, TRUE, preservep);
   1011 
   1012     fprintf (headerfile, "\n");
   1013 }
   1014 
   1015 void
   1016 generate_type (const Symbol *s)
   1017 {
   1018     FILE *h;
   1019     const char * exp;
   1020 
   1021     if (!one_code_file)
   1022 	generate_header_of_codefile(s->gen_name);
   1023 
   1024     generate_type_header (s);
   1025 
   1026     if (template_flag)
   1027 	generate_template(s);
   1028 
   1029     if (template_flag == 0 || is_template_compat(s) == 0) {
   1030 	generate_type_encode (s);
   1031 	generate_type_decode (s);
   1032 	generate_type_free (s);
   1033 	generate_type_length (s);
   1034 	generate_type_copy (s);
   1035     }
   1036     generate_type_seq (s);
   1037     generate_glue (s->type, s->gen_name);
   1038 
   1039     /* generate prototypes */
   1040 
   1041     if (is_export(s->name)) {
   1042 	h = headerfile;
   1043 	exp = "ASN1EXP ";
   1044     } else {
   1045 	h = privheaderfile;
   1046 	exp = "";
   1047     }
   1048 
   1049     fprintf (h,
   1050 	     "%sint    ASN1CALL "
   1051 	     "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n",
   1052 	     exp,
   1053 	     s->gen_name, s->gen_name);
   1054     fprintf (h,
   1055 	     "%sint    ASN1CALL "
   1056 	     "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n",
   1057 	     exp,
   1058 	     s->gen_name, s->gen_name);
   1059     fprintf (h,
   1060 	     "%ssize_t ASN1CALL length_%s(const %s *);\n",
   1061 	     exp,
   1062 	     s->gen_name, s->gen_name);
   1063     fprintf (h,
   1064 	     "%sint    ASN1CALL copy_%s  (const %s *, %s *);\n",
   1065 	     exp,
   1066 	     s->gen_name, s->gen_name, s->gen_name);
   1067     fprintf (h,
   1068 	     "%svoid   ASN1CALL free_%s  (%s *);\n",
   1069 	     exp,
   1070 	     s->gen_name, s->gen_name);
   1071 
   1072     fprintf(h, "\n\n");
   1073 
   1074     if (!one_code_file) {
   1075 	fprintf(codefile, "\n\n");
   1076 	close_codefile();
   1077 	}
   1078 }
   1079