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