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