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