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