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