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