xref: /freebsd/crypto/heimdal/lib/asn1/gen.c (revision 195ebc7e9e4b129de810833791a19dfb4349d6a9)
1 /*
2  * Copyright (c) 1997 - 2005 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "gen_locl.h"
35 
36 RCSID("$Id: gen.c 22429 2008-01-13 10:25:50Z lha $");
37 
38 FILE *headerfile, *codefile, *logfile;
39 
40 #define STEM "asn1"
41 
42 static const char *orig_filename;
43 static char *header;
44 static const char *headerbase = STEM;
45 
46 /*
47  * list of all IMPORTs
48  */
49 
50 struct import {
51     const char *module;
52     struct import *next;
53 };
54 
55 static struct import *imports = NULL;
56 
57 void
58 add_import (const char *module)
59 {
60     struct import *tmp = emalloc (sizeof(*tmp));
61 
62     tmp->module = module;
63     tmp->next   = imports;
64     imports     = tmp;
65 
66     fprintf (headerfile, "#include <%s_asn1.h>\n", module);
67 }
68 
69 const char *
70 get_filename (void)
71 {
72     return orig_filename;
73 }
74 
75 void
76 init_generate (const char *filename, const char *base)
77 {
78     char *fn;
79 
80     orig_filename = filename;
81     if (base != NULL) {
82 	headerbase = strdup(base);
83 	if (headerbase == NULL)
84 	    errx(1, "strdup");
85     }
86     asprintf(&header, "%s.h", headerbase);
87     if (header == NULL)
88 	errx(1, "malloc");
89     headerfile = fopen (header, "w");
90     if (headerfile == NULL)
91 	err (1, "open %s", header);
92     fprintf (headerfile,
93 	     "/* Generated from %s */\n"
94 	     "/* Do not edit */\n\n",
95 	     filename);
96     fprintf (headerfile,
97 	     "#ifndef __%s_h__\n"
98 	     "#define __%s_h__\n\n", headerbase, headerbase);
99     fprintf (headerfile,
100 	     "#include <stddef.h>\n"
101 	     "#include <time.h>\n\n");
102     fprintf (headerfile,
103 	     "#ifndef __asn1_common_definitions__\n"
104 	     "#define __asn1_common_definitions__\n\n");
105     fprintf (headerfile,
106 	     "typedef struct heim_integer {\n"
107 	     "  size_t length;\n"
108 	     "  void *data;\n"
109 	     "  int negative;\n"
110 	     "} heim_integer;\n\n");
111     fprintf (headerfile,
112 	     "typedef struct heim_octet_string {\n"
113 	     "  size_t length;\n"
114 	     "  void *data;\n"
115 	     "} heim_octet_string;\n\n");
116     fprintf (headerfile,
117 	     "typedef char *heim_general_string;\n\n"
118 	     );
119     fprintf (headerfile,
120 	     "typedef char *heim_utf8_string;\n\n"
121 	     );
122     fprintf (headerfile,
123 	     "typedef char *heim_printable_string;\n\n"
124 	     );
125     fprintf (headerfile,
126 	     "typedef char *heim_ia5_string;\n\n"
127 	     );
128     fprintf (headerfile,
129 	     "typedef struct heim_bmp_string {\n"
130 	     "  size_t length;\n"
131 	     "  uint16_t *data;\n"
132 	     "} heim_bmp_string;\n\n");
133     fprintf (headerfile,
134 	     "typedef struct heim_universal_string {\n"
135 	     "  size_t length;\n"
136 	     "  uint32_t *data;\n"
137 	     "} heim_universal_string;\n\n");
138     fprintf (headerfile,
139 	     "typedef char *heim_visible_string;\n\n"
140 	     );
141     fprintf (headerfile,
142 	     "typedef struct heim_oid {\n"
143 	     "  size_t length;\n"
144 	     "  unsigned *components;\n"
145 	     "} heim_oid;\n\n");
146     fprintf (headerfile,
147 	     "typedef struct heim_bit_string {\n"
148 	     "  size_t length;\n"
149 	     "  void *data;\n"
150 	     "} heim_bit_string;\n\n");
151     fprintf (headerfile,
152 	     "typedef struct heim_octet_string heim_any;\n"
153 	     "typedef struct heim_octet_string heim_any_set;\n\n");
154     fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R)                  \\\n"
155 	  "  do {                                                         \\\n"
156 	  "    (BL) = length_##T((S));                                    \\\n"
157 	  "    (B) = malloc((BL));                                        \\\n"
158 	  "    if((B) == NULL) {                                          \\\n"
159 	  "      (R) = ENOMEM;                                            \\\n"
160 	  "    } else {                                                   \\\n"
161 	  "      (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \\\n"
162 	  "                       (S), (L));                              \\\n"
163 	  "      if((R) != 0) {                                           \\\n"
164 	  "        free((B));                                             \\\n"
165 	  "        (B) = NULL;                                            \\\n"
166 	  "      }                                                        \\\n"
167 	  "    }                                                          \\\n"
168 	  "  } while (0)\n\n",
169 	  headerfile);
170     fprintf (headerfile, "struct units;\n\n");
171     fprintf (headerfile, "#endif\n\n");
172     asprintf(&fn, "%s_files", base);
173     if (fn == NULL)
174 	errx(1, "malloc");
175     logfile = fopen(fn, "w");
176     if (logfile == NULL)
177 	err (1, "open %s", fn);
178 }
179 
180 void
181 close_generate (void)
182 {
183     fprintf (headerfile, "#endif /* __%s_h__ */\n", headerbase);
184 
185     fclose (headerfile);
186     fprintf (logfile, "\n");
187     fclose (logfile);
188 }
189 
190 void
191 gen_assign_defval(const char *var, struct value *val)
192 {
193     switch(val->type) {
194     case stringvalue:
195 	fprintf(codefile, "if((%s = strdup(\"%s\")) == NULL)\nreturn ENOMEM;\n", var, val->u.stringvalue);
196 	break;
197     case integervalue:
198 	fprintf(codefile, "%s = %d;\n", var, val->u.integervalue);
199 	break;
200     case booleanvalue:
201 	if(val->u.booleanvalue)
202 	    fprintf(codefile, "%s = TRUE;\n", var);
203 	else
204 	    fprintf(codefile, "%s = FALSE;\n", var);
205 	break;
206     default:
207 	abort();
208     }
209 }
210 
211 void
212 gen_compare_defval(const char *var, struct value *val)
213 {
214     switch(val->type) {
215     case stringvalue:
216 	fprintf(codefile, "if(strcmp(%s, \"%s\") != 0)\n", var, val->u.stringvalue);
217 	break;
218     case integervalue:
219 	fprintf(codefile, "if(%s != %d)\n", var, val->u.integervalue);
220 	break;
221     case booleanvalue:
222 	if(val->u.booleanvalue)
223 	    fprintf(codefile, "if(!%s)\n", var);
224 	else
225 	    fprintf(codefile, "if(%s)\n", var);
226 	break;
227     default:
228 	abort();
229     }
230 }
231 
232 static void
233 generate_header_of_codefile(const char *name)
234 {
235     char *filename;
236 
237     if (codefile != NULL)
238 	abort();
239 
240     asprintf (&filename, "%s_%s.x", STEM, name);
241     if (filename == NULL)
242 	errx(1, "malloc");
243     codefile = fopen (filename, "w");
244     if (codefile == NULL)
245 	err (1, "fopen %s", filename);
246     fprintf(logfile, "%s ", filename);
247     free(filename);
248     fprintf (codefile,
249 	     "/* Generated from %s */\n"
250 	     "/* Do not edit */\n\n"
251 	     "#include <stdio.h>\n"
252 	     "#include <stdlib.h>\n"
253 	     "#include <time.h>\n"
254 	     "#include <string.h>\n"
255 	     "#include <errno.h>\n"
256 	     "#include <limits.h>\n"
257 	     "#include <krb5-types.h>\n",
258 	     orig_filename);
259 
260     fprintf (codefile,
261 	     "#include <%s.h>\n",
262 	     headerbase);
263     fprintf (codefile,
264 	     "#include <asn1_err.h>\n"
265 	     "#include <der.h>\n"
266 	     "#include <parse_units.h>\n\n");
267 
268 }
269 
270 static void
271 close_codefile(void)
272 {
273     if (codefile == NULL)
274 	abort();
275 
276     fclose(codefile);
277     codefile = NULL;
278 }
279 
280 
281 void
282 generate_constant (const Symbol *s)
283 {
284     switch(s->value->type) {
285     case booleanvalue:
286 	break;
287     case integervalue:
288 	fprintf (headerfile, "enum { %s = %d };\n\n",
289 		 s->gen_name, s->value->u.integervalue);
290 	break;
291     case nullvalue:
292 	break;
293     case stringvalue:
294 	break;
295     case objectidentifiervalue: {
296 	struct objid *o, **list;
297 	int i, len;
298 
299 	generate_header_of_codefile(s->gen_name);
300 
301 	len = 0;
302 	for (o = s->value->u.objectidentifiervalue; o != NULL; o = o->next)
303 	    len++;
304 	list = emalloc(sizeof(*list) * len);
305 
306 	i = 0;
307 	for (o = s->value->u.objectidentifiervalue; o != NULL; o = o->next)
308 	    list[i++] = o;
309 
310 	fprintf (headerfile, "/* OBJECT IDENTIFIER %s ::= { ", s->name);
311 	for (i = len - 1 ; i >= 0; i--) {
312 	    o = list[i];
313 	    fprintf(headerfile, "%s(%d) ",
314 		    o->label ? o->label : "label-less", o->value);
315 	}
316 
317 	fprintf (headerfile, "} */\n");
318 	fprintf (headerfile, "const heim_oid *oid_%s(void);\n\n",
319 		 s->gen_name);
320 
321 	fprintf (codefile, "static unsigned oid_%s_variable_num[%d] =  {",
322 		 s->gen_name, len);
323 	for (i = len - 1 ; i >= 0; i--) {
324 	    fprintf(codefile, "%d%s ", list[i]->value, i > 0 ? "," : "");
325 	}
326 	fprintf(codefile, "};\n");
327 
328 	fprintf (codefile, "static const heim_oid oid_%s_variable = "
329 		 "{ %d, oid_%s_variable_num };\n\n",
330 		 s->gen_name, len, s->gen_name);
331 
332 	fprintf (codefile, "const heim_oid *oid_%s(void)\n"
333 		 "{\n"
334 		 "return &oid_%s_variable;\n"
335 		 "}\n\n",
336 		 s->gen_name, s->gen_name);
337 
338 	close_codefile();
339 
340 	break;
341     }
342     default:
343 	abort();
344     }
345 }
346 
347 static void
348 space(int level)
349 {
350     while(level-- > 0)
351 	fprintf(headerfile, "  ");
352 }
353 
354 static const char *
355 last_member_p(struct member *m)
356 {
357     struct member *n = ASN1_TAILQ_NEXT(m, members);
358     if (n == NULL)
359 	return "";
360     if (n->ellipsis && ASN1_TAILQ_NEXT(n, members) == NULL)
361 	return "";
362     return ",";
363 }
364 
365 static struct member *
366 have_ellipsis(Type *t)
367 {
368     struct member *m;
369     ASN1_TAILQ_FOREACH(m, t->members, members) {
370 	if (m->ellipsis)
371 	    return m;
372     }
373     return NULL;
374 }
375 
376 static void
377 define_asn1 (int level, Type *t)
378 {
379     switch (t->type) {
380     case TType:
381 	fprintf (headerfile, "%s", t->symbol->name);
382 	break;
383     case TInteger:
384 	if(t->members == NULL) {
385             fprintf (headerfile, "INTEGER");
386 	    if (t->range)
387 		fprintf (headerfile, " (%d..%d)",
388 			 t->range->min, t->range->max);
389         } else {
390 	    Member *m;
391             fprintf (headerfile, "INTEGER {\n");
392 	    ASN1_TAILQ_FOREACH(m, t->members, members) {
393                 space (level + 1);
394 		fprintf(headerfile, "%s(%d)%s\n", m->gen_name, m->val,
395 			last_member_p(m));
396             }
397 	    space(level);
398             fprintf (headerfile, "}");
399         }
400 	break;
401     case TBoolean:
402 	fprintf (headerfile, "BOOLEAN");
403 	break;
404     case TOctetString:
405 	fprintf (headerfile, "OCTET STRING");
406 	break;
407     case TEnumerated :
408     case TBitString: {
409 	Member *m;
410 
411 	space(level);
412 	if(t->type == TBitString)
413 	    fprintf (headerfile, "BIT STRING {\n");
414 	else
415 	    fprintf (headerfile, "ENUMERATED {\n");
416 	ASN1_TAILQ_FOREACH(m, t->members, members) {
417 	    space(level + 1);
418 	    fprintf (headerfile, "%s(%d)%s\n", m->name, m->val,
419 		     last_member_p(m));
420 	}
421 	space(level);
422 	fprintf (headerfile, "}");
423 	break;
424     }
425     case TChoice:
426     case TSet:
427     case TSequence: {
428 	Member *m;
429 	int max_width = 0;
430 
431 	if(t->type == TChoice)
432 	    fprintf(headerfile, "CHOICE {\n");
433 	else if(t->type == TSet)
434 	    fprintf(headerfile, "SET {\n");
435 	else
436 	    fprintf(headerfile, "SEQUENCE {\n");
437 	ASN1_TAILQ_FOREACH(m, t->members, members) {
438 	    if(strlen(m->name) > max_width)
439 		max_width = strlen(m->name);
440 	}
441 	max_width += 3;
442 	if(max_width < 16) max_width = 16;
443 	ASN1_TAILQ_FOREACH(m, t->members, members) {
444 	    int width = max_width;
445 	    space(level + 1);
446 	    if (m->ellipsis) {
447 		fprintf (headerfile, "...");
448 	    } else {
449 		width -= fprintf(headerfile, "%s", m->name);
450 		fprintf(headerfile, "%*s", width, "");
451 		define_asn1(level + 1, m->type);
452 		if(m->optional)
453 		    fprintf(headerfile, " OPTIONAL");
454 	    }
455 	    if(last_member_p(m))
456 		fprintf (headerfile, ",");
457 	    fprintf (headerfile, "\n");
458 	}
459 	space(level);
460 	fprintf (headerfile, "}");
461 	break;
462     }
463     case TSequenceOf:
464 	fprintf (headerfile, "SEQUENCE OF ");
465 	define_asn1 (0, t->subtype);
466 	break;
467     case TSetOf:
468 	fprintf (headerfile, "SET OF ");
469 	define_asn1 (0, t->subtype);
470 	break;
471     case TGeneralizedTime:
472 	fprintf (headerfile, "GeneralizedTime");
473 	break;
474     case TGeneralString:
475 	fprintf (headerfile, "GeneralString");
476 	break;
477     case TTag: {
478 	const char *classnames[] = { "UNIVERSAL ", "APPLICATION ",
479 				     "" /* CONTEXT */, "PRIVATE " };
480 	if(t->tag.tagclass != ASN1_C_UNIV)
481 	    fprintf (headerfile, "[%s%d] ",
482 		     classnames[t->tag.tagclass],
483 		     t->tag.tagvalue);
484 	if(t->tag.tagenv == TE_IMPLICIT)
485 	    fprintf (headerfile, "IMPLICIT ");
486 	define_asn1 (level, t->subtype);
487 	break;
488     }
489     case TUTCTime:
490 	fprintf (headerfile, "UTCTime");
491 	break;
492     case TUTF8String:
493 	space(level);
494 	fprintf (headerfile, "UTF8String");
495 	break;
496     case TPrintableString:
497 	space(level);
498 	fprintf (headerfile, "PrintableString");
499 	break;
500     case TIA5String:
501 	space(level);
502 	fprintf (headerfile, "IA5String");
503 	break;
504     case TBMPString:
505 	space(level);
506 	fprintf (headerfile, "BMPString");
507 	break;
508     case TUniversalString:
509 	space(level);
510 	fprintf (headerfile, "UniversalString");
511 	break;
512     case TVisibleString:
513 	space(level);
514 	fprintf (headerfile, "VisibleString");
515 	break;
516     case TOID :
517 	space(level);
518 	fprintf(headerfile, "OBJECT IDENTIFIER");
519 	break;
520     case TNull:
521 	space(level);
522 	fprintf (headerfile, "NULL");
523 	break;
524     default:
525 	abort ();
526     }
527 }
528 
529 static void
530 define_type (int level, const char *name, Type *t, int typedefp, int preservep)
531 {
532     switch (t->type) {
533     case TType:
534 	space(level);
535 	fprintf (headerfile, "%s %s;\n", t->symbol->gen_name, name);
536 	break;
537     case TInteger:
538 	space(level);
539 	if(t->members) {
540             Member *m;
541             fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
542 	    ASN1_TAILQ_FOREACH(m, t->members, members) {
543                 space (level + 1);
544                 fprintf(headerfile, "%s = %d%s\n", m->gen_name, m->val,
545                         last_member_p(m));
546             }
547             fprintf (headerfile, "} %s;\n", name);
548 	} else if (t->range == NULL) {
549 	    fprintf (headerfile, "heim_integer %s;\n", name);
550 	} else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
551 	    fprintf (headerfile, "int %s;\n", name);
552 	} else if (t->range->min == 0 && t->range->max == UINT_MAX) {
553 	    fprintf (headerfile, "unsigned int %s;\n", name);
554 	} else if (t->range->min == 0 && t->range->max == INT_MAX) {
555 	    fprintf (headerfile, "unsigned int %s;\n", name);
556 	} else
557 	    errx(1, "%s: unsupported range %d -> %d",
558 		 name, t->range->min, t->range->max);
559 	break;
560     case TBoolean:
561 	space(level);
562 	fprintf (headerfile, "int %s;\n", name);
563 	break;
564     case TOctetString:
565 	space(level);
566 	fprintf (headerfile, "heim_octet_string %s;\n", name);
567 	break;
568     case TBitString: {
569 	Member *m;
570 	Type i;
571 	struct range range = { 0, INT_MAX };
572 
573 	i.type = TInteger;
574 	i.range = &range;
575 	i.members = NULL;
576 	i.constraint = NULL;
577 
578 	space(level);
579 	if(ASN1_TAILQ_EMPTY(t->members))
580 	    fprintf (headerfile, "heim_bit_string %s;\n", name);
581 	else {
582 	    fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
583 	    ASN1_TAILQ_FOREACH(m, t->members, members) {
584 		char *n;
585 
586 		asprintf (&n, "%s:1", m->gen_name);
587 		if (n == NULL)
588 		    errx(1, "malloc");
589 		define_type (level + 1, n, &i, FALSE, FALSE);
590 		free (n);
591 	    }
592 	    space(level);
593 	    fprintf (headerfile, "} %s;\n\n", name);
594 	}
595 	break;
596     }
597     case TEnumerated: {
598 	Member *m;
599 
600 	space(level);
601 	fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
602 	ASN1_TAILQ_FOREACH(m, t->members, members) {
603 	    space(level + 1);
604 	    if (m->ellipsis)
605 		fprintf (headerfile, "/* ... */\n");
606 	    else
607 		fprintf (headerfile, "%s = %d%s\n", m->gen_name, m->val,
608 			 last_member_p(m));
609 	}
610 	space(level);
611 	fprintf (headerfile, "} %s;\n\n", name);
612 	break;
613     }
614     case TSet:
615     case TSequence: {
616 	Member *m;
617 
618 	space(level);
619 	fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
620 	if (t->type == TSequence && preservep) {
621 	    space(level + 1);
622 	    fprintf(headerfile, "heim_octet_string _save;\n");
623 	}
624 	ASN1_TAILQ_FOREACH(m, t->members, members) {
625 	    if (m->ellipsis) {
626 		;
627 	    } else if (m->optional) {
628 		char *n;
629 
630 		asprintf (&n, "*%s", m->gen_name);
631 		if (n == NULL)
632 		    errx(1, "malloc");
633 		define_type (level + 1, n, m->type, FALSE, FALSE);
634 		free (n);
635 	    } else
636 		define_type (level + 1, m->gen_name, m->type, FALSE, FALSE);
637 	}
638 	space(level);
639 	fprintf (headerfile, "} %s;\n", name);
640 	break;
641     }
642     case TSetOf:
643     case TSequenceOf: {
644 	Type i;
645 	struct range range = { 0, INT_MAX };
646 
647 	i.type = TInteger;
648 	i.range = &range;
649 	i.members = NULL;
650 	i.constraint = NULL;
651 
652 	space(level);
653 	fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
654 	define_type (level + 1, "len", &i, FALSE, FALSE);
655 	define_type (level + 1, "*val", t->subtype, FALSE, FALSE);
656 	space(level);
657 	fprintf (headerfile, "} %s;\n", name);
658 	break;
659     }
660     case TGeneralizedTime:
661 	space(level);
662 	fprintf (headerfile, "time_t %s;\n", name);
663 	break;
664     case TGeneralString:
665 	space(level);
666 	fprintf (headerfile, "heim_general_string %s;\n", name);
667 	break;
668     case TTag:
669 	define_type (level, name, t->subtype, typedefp, preservep);
670 	break;
671     case TChoice: {
672 	int first = 1;
673 	Member *m;
674 
675 	space(level);
676 	fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
677 	if (preservep) {
678 	    space(level + 1);
679 	    fprintf(headerfile, "heim_octet_string _save;\n");
680 	}
681 	space(level + 1);
682 	fprintf (headerfile, "enum {\n");
683 	m = have_ellipsis(t);
684 	if (m) {
685 	    space(level + 2);
686 	    fprintf (headerfile, "%s = 0,\n", m->label);
687 	    first = 0;
688 	}
689 	ASN1_TAILQ_FOREACH(m, t->members, members) {
690 	    space(level + 2);
691 	    if (m->ellipsis)
692 		fprintf (headerfile, "/* ... */\n");
693 	    else
694 		fprintf (headerfile, "%s%s%s\n", m->label,
695 			 first ? " = 1" : "",
696 			 last_member_p(m));
697 	    first = 0;
698 	}
699 	space(level + 1);
700 	fprintf (headerfile, "} element;\n");
701 	space(level + 1);
702 	fprintf (headerfile, "union {\n");
703 	ASN1_TAILQ_FOREACH(m, t->members, members) {
704 	    if (m->ellipsis) {
705 		space(level + 2);
706 		fprintf(headerfile, "heim_octet_string asn1_ellipsis;\n");
707 	    } else if (m->optional) {
708 		char *n;
709 
710 		asprintf (&n, "*%s", m->gen_name);
711 		if (n == NULL)
712 		    errx(1, "malloc");
713 		define_type (level + 2, n, m->type, FALSE, FALSE);
714 		free (n);
715 	    } else
716 		define_type (level + 2, m->gen_name, m->type, FALSE, FALSE);
717 	}
718 	space(level + 1);
719 	fprintf (headerfile, "} u;\n");
720 	space(level);
721 	fprintf (headerfile, "} %s;\n", name);
722 	break;
723     }
724     case TUTCTime:
725 	space(level);
726 	fprintf (headerfile, "time_t %s;\n", name);
727 	break;
728     case TUTF8String:
729 	space(level);
730 	fprintf (headerfile, "heim_utf8_string %s;\n", name);
731 	break;
732     case TPrintableString:
733 	space(level);
734 	fprintf (headerfile, "heim_printable_string %s;\n", name);
735 	break;
736     case TIA5String:
737 	space(level);
738 	fprintf (headerfile, "heim_ia5_string %s;\n", name);
739 	break;
740     case TBMPString:
741 	space(level);
742 	fprintf (headerfile, "heim_bmp_string %s;\n", name);
743 	break;
744     case TUniversalString:
745 	space(level);
746 	fprintf (headerfile, "heim_universal_string %s;\n", name);
747 	break;
748     case TVisibleString:
749 	space(level);
750 	fprintf (headerfile, "heim_visible_string %s;\n", name);
751 	break;
752     case TOID :
753 	space(level);
754 	fprintf (headerfile, "heim_oid %s;\n", name);
755 	break;
756     case TNull:
757 	space(level);
758 	fprintf (headerfile, "int %s;\n", name);
759 	break;
760     default:
761 	abort ();
762     }
763 }
764 
765 static void
766 generate_type_header (const Symbol *s)
767 {
768     int preservep = preserve_type(s->name) ? TRUE : FALSE;
769 
770     fprintf (headerfile, "/*\n");
771     fprintf (headerfile, "%s ::= ", s->name);
772     define_asn1 (0, s->type);
773     fprintf (headerfile, "\n*/\n\n");
774 
775     fprintf (headerfile, "typedef ");
776     define_type (0, s->gen_name, s->type, TRUE, preservep);
777 
778     fprintf (headerfile, "\n");
779 }
780 
781 
782 void
783 generate_type (const Symbol *s)
784 {
785     generate_header_of_codefile(s->gen_name);
786 
787     generate_type_header (s);
788     generate_type_encode (s);
789     generate_type_decode (s);
790     generate_type_free (s);
791     generate_type_length (s);
792     generate_type_copy (s);
793     generate_type_seq (s);
794     generate_glue (s->type, s->gen_name);
795     fprintf(headerfile, "\n\n");
796     close_codefile();
797 }
798