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