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