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