xref: /freebsd/crypto/heimdal/lib/asn1/gen_template.c (revision ae77177087c655fc883075af4f425b37e032cd05)
1*ae771770SStanislav Sedov /*
2*ae771770SStanislav Sedov  * Copyright (c) 1997 - 2005 Kungliga Tekniska H�gskolan
3*ae771770SStanislav Sedov  * (Royal Institute of Technology, Stockholm, Sweden).
4*ae771770SStanislav Sedov  * All rights reserved.
5*ae771770SStanislav Sedov  *
6*ae771770SStanislav Sedov  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7*ae771770SStanislav Sedov  *
8*ae771770SStanislav Sedov  * Redistribution and use in source and binary forms, with or without
9*ae771770SStanislav Sedov  * modification, are permitted provided that the following conditions
10*ae771770SStanislav Sedov  * are met:
11*ae771770SStanislav Sedov  *
12*ae771770SStanislav Sedov  * 1. Redistributions of source code must retain the above copyright
13*ae771770SStanislav Sedov  *    notice, this list of conditions and the following disclaimer.
14*ae771770SStanislav Sedov  *
15*ae771770SStanislav Sedov  * 2. Redistributions in binary form must reproduce the above copyright
16*ae771770SStanislav Sedov  *    notice, this list of conditions and the following disclaimer in the
17*ae771770SStanislav Sedov  *    documentation and/or other materials provided with the distribution.
18*ae771770SStanislav Sedov  *
19*ae771770SStanislav Sedov  * 3. Neither the name of the Institute nor the names of its contributors
20*ae771770SStanislav Sedov  *    may be used to endorse or promote products derived from this software
21*ae771770SStanislav Sedov  *    without specific prior written permission.
22*ae771770SStanislav Sedov  *
23*ae771770SStanislav Sedov  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24*ae771770SStanislav Sedov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25*ae771770SStanislav Sedov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26*ae771770SStanislav Sedov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27*ae771770SStanislav Sedov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28*ae771770SStanislav Sedov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29*ae771770SStanislav Sedov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30*ae771770SStanislav Sedov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31*ae771770SStanislav Sedov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32*ae771770SStanislav Sedov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33*ae771770SStanislav Sedov  * SUCH DAMAGE.
34*ae771770SStanislav Sedov  */
35*ae771770SStanislav Sedov 
36*ae771770SStanislav Sedov #include "gen_locl.h"
37*ae771770SStanislav Sedov 
38*ae771770SStanislav Sedov static const char *symbol_name(const char *, const Type *);
39*ae771770SStanislav Sedov static void generate_template_type(const char *, const char **, const char *, const char *, const char *,
40*ae771770SStanislav Sedov 				   Type *, int, int, int);
41*ae771770SStanislav Sedov 
42*ae771770SStanislav Sedov static const char *
43*ae771770SStanislav Sedov ttype_symbol(const char *basename, const Type *t)
44*ae771770SStanislav Sedov {
45*ae771770SStanislav Sedov     return t->symbol->gen_name;
46*ae771770SStanislav Sedov }
47*ae771770SStanislav Sedov 
48*ae771770SStanislav Sedov static const char *
49*ae771770SStanislav Sedov integer_symbol(const char *basename, const Type *t)
50*ae771770SStanislav Sedov {
51*ae771770SStanislav Sedov     if (t->members)
52*ae771770SStanislav Sedov 	return "int"; /* XXX enum foo */
53*ae771770SStanislav Sedov     else if (t->range == NULL)
54*ae771770SStanislav Sedov 	return "heim_integer";
55*ae771770SStanislav Sedov     else if (t->range->min == INT_MIN && t->range->max == INT_MAX)
56*ae771770SStanislav Sedov 	return "int";
57*ae771770SStanislav Sedov     else if (t->range->min == 0 && t->range->max == UINT_MAX)
58*ae771770SStanislav Sedov 	return "unsigned";
59*ae771770SStanislav Sedov     else if (t->range->min == 0 && t->range->max == INT_MAX)
60*ae771770SStanislav Sedov 	return "unsigned";
61*ae771770SStanislav Sedov     else {
62*ae771770SStanislav Sedov 	abort();
63*ae771770SStanislav Sedov         UNREACHABLE(return NULL);
64*ae771770SStanislav Sedov     }
65*ae771770SStanislav Sedov }
66*ae771770SStanislav Sedov 
67*ae771770SStanislav Sedov static const char *
68*ae771770SStanislav Sedov boolean_symbol(const char *basename, const Type *t)
69*ae771770SStanislav Sedov {
70*ae771770SStanislav Sedov     return "int";
71*ae771770SStanislav Sedov }
72*ae771770SStanislav Sedov 
73*ae771770SStanislav Sedov 
74*ae771770SStanislav Sedov static const char *
75*ae771770SStanislav Sedov octetstring_symbol(const char *basename, const Type *t)
76*ae771770SStanislav Sedov {
77*ae771770SStanislav Sedov     return "heim_octet_string";
78*ae771770SStanislav Sedov }
79*ae771770SStanislav Sedov 
80*ae771770SStanislav Sedov static const char *
81*ae771770SStanislav Sedov sequence_symbol(const char *basename, const Type *t)
82*ae771770SStanislav Sedov {
83*ae771770SStanislav Sedov     return basename;
84*ae771770SStanislav Sedov }
85*ae771770SStanislav Sedov 
86*ae771770SStanislav Sedov static const char *
87*ae771770SStanislav Sedov time_symbol(const char *basename, const Type *t)
88*ae771770SStanislav Sedov {
89*ae771770SStanislav Sedov     return "time_t";
90*ae771770SStanislav Sedov }
91*ae771770SStanislav Sedov 
92*ae771770SStanislav Sedov static const char *
93*ae771770SStanislav Sedov tag_symbol(const char *basename, const Type *t)
94*ae771770SStanislav Sedov {
95*ae771770SStanislav Sedov     return symbol_name(basename, t->subtype);
96*ae771770SStanislav Sedov }
97*ae771770SStanislav Sedov 
98*ae771770SStanislav Sedov static const char *
99*ae771770SStanislav Sedov generalstring_symbol(const char *basename, const Type *t)
100*ae771770SStanislav Sedov {
101*ae771770SStanislav Sedov     return "heim_general_string";
102*ae771770SStanislav Sedov }
103*ae771770SStanislav Sedov 
104*ae771770SStanislav Sedov static const char *
105*ae771770SStanislav Sedov printablestring_symbol(const char *basename, const Type *t)
106*ae771770SStanislav Sedov {
107*ae771770SStanislav Sedov     return "heim_printable_string";
108*ae771770SStanislav Sedov }
109*ae771770SStanislav Sedov 
110*ae771770SStanislav Sedov static const char *
111*ae771770SStanislav Sedov ia5string_symbol(const char *basename, const Type *t)
112*ae771770SStanislav Sedov {
113*ae771770SStanislav Sedov     return "heim_ia5_string";
114*ae771770SStanislav Sedov }
115*ae771770SStanislav Sedov 
116*ae771770SStanislav Sedov static const char *
117*ae771770SStanislav Sedov visiblestring_symbol(const char *basename, const Type *t)
118*ae771770SStanislav Sedov {
119*ae771770SStanislav Sedov     return "heim_visible_string";
120*ae771770SStanislav Sedov }
121*ae771770SStanislav Sedov 
122*ae771770SStanislav Sedov static const char *
123*ae771770SStanislav Sedov utf8string_symbol(const char *basename, const Type *t)
124*ae771770SStanislav Sedov {
125*ae771770SStanislav Sedov     return "heim_utf8_string";
126*ae771770SStanislav Sedov }
127*ae771770SStanislav Sedov 
128*ae771770SStanislav Sedov static const char *
129*ae771770SStanislav Sedov bmpstring_symbol(const char *basename, const Type *t)
130*ae771770SStanislav Sedov {
131*ae771770SStanislav Sedov     return "heim_bmp_string";
132*ae771770SStanislav Sedov }
133*ae771770SStanislav Sedov 
134*ae771770SStanislav Sedov static const char *
135*ae771770SStanislav Sedov universalstring_symbol(const char *basename, const Type *t)
136*ae771770SStanislav Sedov {
137*ae771770SStanislav Sedov     return "heim_universal_string";
138*ae771770SStanislav Sedov }
139*ae771770SStanislav Sedov 
140*ae771770SStanislav Sedov static const char *
141*ae771770SStanislav Sedov oid_symbol(const char *basename, const Type *t)
142*ae771770SStanislav Sedov {
143*ae771770SStanislav Sedov     return "heim_oid";
144*ae771770SStanislav Sedov }
145*ae771770SStanislav Sedov 
146*ae771770SStanislav Sedov static const char *
147*ae771770SStanislav Sedov bitstring_symbol(const char *basename, const Type *t)
148*ae771770SStanislav Sedov {
149*ae771770SStanislav Sedov     if (t->members)
150*ae771770SStanislav Sedov 	return basename;
151*ae771770SStanislav Sedov     return "heim_bit_string";
152*ae771770SStanislav Sedov }
153*ae771770SStanislav Sedov 
154*ae771770SStanislav Sedov 
155*ae771770SStanislav Sedov 
156*ae771770SStanislav Sedov struct {
157*ae771770SStanislav Sedov     enum typetype type;
158*ae771770SStanislav Sedov     const char *(*symbol_name)(const char *, const Type *);
159*ae771770SStanislav Sedov     int is_struct;
160*ae771770SStanislav Sedov } types[] =  {
161*ae771770SStanislav Sedov     { TBMPString, bmpstring_symbol, 0 },
162*ae771770SStanislav Sedov     { TBitString, bitstring_symbol, 0 },
163*ae771770SStanislav Sedov     { TBoolean, boolean_symbol, 0 },
164*ae771770SStanislav Sedov     { TGeneralString, generalstring_symbol, 0 },
165*ae771770SStanislav Sedov     { TGeneralizedTime, time_symbol, 0 },
166*ae771770SStanislav Sedov     { TIA5String, ia5string_symbol, 0 },
167*ae771770SStanislav Sedov     { TInteger, integer_symbol, 0 },
168*ae771770SStanislav Sedov     { TOID, oid_symbol, 0 },
169*ae771770SStanislav Sedov     { TOctetString, octetstring_symbol, 0 },
170*ae771770SStanislav Sedov     { TPrintableString, printablestring_symbol, 0 },
171*ae771770SStanislav Sedov     { TSequence, sequence_symbol, 1 },
172*ae771770SStanislav Sedov     { TSequenceOf, tag_symbol, 1 },
173*ae771770SStanislav Sedov     { TSetOf, tag_symbol, 1 },
174*ae771770SStanislav Sedov     { TTag, tag_symbol, 1 },
175*ae771770SStanislav Sedov     { TType, ttype_symbol, 1 },
176*ae771770SStanislav Sedov     { TUTCTime, time_symbol, 0 },
177*ae771770SStanislav Sedov     { TUniversalString, universalstring_symbol, 0 },
178*ae771770SStanislav Sedov     { TVisibleString,  visiblestring_symbol, 0 },
179*ae771770SStanislav Sedov     { TUTF8String, utf8string_symbol, 0 },
180*ae771770SStanislav Sedov     { TChoice, sequence_symbol, 1 },
181*ae771770SStanislav Sedov     { TNull, integer_symbol, 1 }
182*ae771770SStanislav Sedov };
183*ae771770SStanislav Sedov 
184*ae771770SStanislav Sedov static FILE *
185*ae771770SStanislav Sedov get_code_file(void)
186*ae771770SStanislav Sedov {
187*ae771770SStanislav Sedov     if (!one_code_file)
188*ae771770SStanislav Sedov 	return templatefile;
189*ae771770SStanislav Sedov     return codefile;
190*ae771770SStanislav Sedov }
191*ae771770SStanislav Sedov 
192*ae771770SStanislav Sedov 
193*ae771770SStanislav Sedov static int
194*ae771770SStanislav Sedov is_supported_type_p(const Type *t)
195*ae771770SStanislav Sedov {
196*ae771770SStanislav Sedov     size_t i;
197*ae771770SStanislav Sedov 
198*ae771770SStanislav Sedov     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++)
199*ae771770SStanislav Sedov 	if (t->type == types[i].type)
200*ae771770SStanislav Sedov 	    return 1;
201*ae771770SStanislav Sedov     return 0;
202*ae771770SStanislav Sedov }
203*ae771770SStanislav Sedov 
204*ae771770SStanislav Sedov int
205*ae771770SStanislav Sedov is_template_compat (const Symbol *s)
206*ae771770SStanislav Sedov {
207*ae771770SStanislav Sedov     return is_supported_type_p(s->type);
208*ae771770SStanislav Sedov }
209*ae771770SStanislav Sedov 
210*ae771770SStanislav Sedov static const char *
211*ae771770SStanislav Sedov symbol_name(const char *basename, const Type *t)
212*ae771770SStanislav Sedov {
213*ae771770SStanislav Sedov     size_t i;
214*ae771770SStanislav Sedov 
215*ae771770SStanislav Sedov     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++)
216*ae771770SStanislav Sedov 	if (t->type == types[i].type)
217*ae771770SStanislav Sedov 	    return (types[i].symbol_name)(basename, t);
218*ae771770SStanislav Sedov     printf("unknown der type: %d\n", t->type);
219*ae771770SStanislav Sedov     exit(1);
220*ae771770SStanislav Sedov }
221*ae771770SStanislav Sedov 
222*ae771770SStanislav Sedov 
223*ae771770SStanislav Sedov static char *
224*ae771770SStanislav Sedov partial_offset(const char *basetype, const char *name, int need_offset)
225*ae771770SStanislav Sedov {
226*ae771770SStanislav Sedov     char *str;
227*ae771770SStanislav Sedov     if (name == NULL || need_offset == 0)
228*ae771770SStanislav Sedov 	return strdup("0");
229*ae771770SStanislav Sedov     if (asprintf(&str, "offsetof(struct %s, %s)", basetype, name) < 0 || str == NULL)
230*ae771770SStanislav Sedov 	errx(1, "malloc");
231*ae771770SStanislav Sedov     return str;
232*ae771770SStanislav Sedov }
233*ae771770SStanislav Sedov 
234*ae771770SStanislav Sedov struct template {
235*ae771770SStanislav Sedov     char *line;
236*ae771770SStanislav Sedov     char *tt;
237*ae771770SStanislav Sedov     char *offset;
238*ae771770SStanislav Sedov     char *ptr;
239*ae771770SStanislav Sedov     ASN1_TAILQ_ENTRY(template) members;
240*ae771770SStanislav Sedov };
241*ae771770SStanislav Sedov 
242*ae771770SStanislav Sedov ASN1_TAILQ_HEAD(templatehead, template);
243*ae771770SStanislav Sedov 
244*ae771770SStanislav Sedov struct tlist {
245*ae771770SStanislav Sedov     char *name;
246*ae771770SStanislav Sedov     char *header;
247*ae771770SStanislav Sedov     struct templatehead template;
248*ae771770SStanislav Sedov     ASN1_TAILQ_ENTRY(tlist) tmembers;
249*ae771770SStanislav Sedov };
250*ae771770SStanislav Sedov 
251*ae771770SStanislav Sedov ASN1_TAILQ_HEAD(tlisthead, tlist);
252*ae771770SStanislav Sedov 
253*ae771770SStanislav Sedov static void tlist_header(struct tlist *, const char *, ...) __attribute__((__format__(__printf__, 2, 3)));
254*ae771770SStanislav Sedov static struct template *
255*ae771770SStanislav Sedov     add_line(struct templatehead *, const char *, ...) __attribute__((__format__(__printf__, 2, 3)));
256*ae771770SStanislav Sedov static int tlist_cmp(const struct tlist *, const struct tlist *);
257*ae771770SStanislav Sedov 
258*ae771770SStanislav Sedov static void add_line_pointer(struct templatehead *, const char *, const char *, const char *, ...)
259*ae771770SStanislav Sedov     __attribute__((__format__(__printf__, 4, 5)));
260*ae771770SStanislav Sedov 
261*ae771770SStanislav Sedov 
262*ae771770SStanislav Sedov static struct tlisthead tlistmaster = ASN1_TAILQ_HEAD_INITIALIZER(tlistmaster);
263*ae771770SStanislav Sedov static unsigned long numdups = 0;
264*ae771770SStanislav Sedov 
265*ae771770SStanislav Sedov static struct tlist *
266*ae771770SStanislav Sedov tlist_new(const char *name)
267*ae771770SStanislav Sedov {
268*ae771770SStanislav Sedov     struct tlist *tl = calloc(1, sizeof(*tl));
269*ae771770SStanislav Sedov     tl->name = strdup(name);
270*ae771770SStanislav Sedov     ASN1_TAILQ_INIT(&tl->template);
271*ae771770SStanislav Sedov     return tl;
272*ae771770SStanislav Sedov }
273*ae771770SStanislav Sedov 
274*ae771770SStanislav Sedov static void
275*ae771770SStanislav Sedov tlist_header(struct tlist *t, const char *fmt, ...)
276*ae771770SStanislav Sedov {
277*ae771770SStanislav Sedov     va_list ap;
278*ae771770SStanislav Sedov     va_start(ap, fmt);
279*ae771770SStanislav Sedov     if (vasprintf(&t->header, fmt, ap) < 0 || t->header == NULL)
280*ae771770SStanislav Sedov 	errx(1, "malloc");
281*ae771770SStanislav Sedov     va_end(ap);
282*ae771770SStanislav Sedov }
283*ae771770SStanislav Sedov 
284*ae771770SStanislav Sedov static unsigned long
285*ae771770SStanislav Sedov tlist_count(struct tlist *tl)
286*ae771770SStanislav Sedov {
287*ae771770SStanislav Sedov     unsigned int count = 0;
288*ae771770SStanislav Sedov     struct template *q;
289*ae771770SStanislav Sedov 
290*ae771770SStanislav Sedov     ASN1_TAILQ_FOREACH(q, &tl->template, members) {
291*ae771770SStanislav Sedov 	count++;
292*ae771770SStanislav Sedov     }
293*ae771770SStanislav Sedov     return count;
294*ae771770SStanislav Sedov }
295*ae771770SStanislav Sedov 
296*ae771770SStanislav Sedov static void
297*ae771770SStanislav Sedov tlist_add(struct tlist *tl)
298*ae771770SStanislav Sedov {
299*ae771770SStanislav Sedov     ASN1_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers);
300*ae771770SStanislav Sedov }
301*ae771770SStanislav Sedov 
302*ae771770SStanislav Sedov static void
303*ae771770SStanislav Sedov tlist_print(struct tlist *tl)
304*ae771770SStanislav Sedov {
305*ae771770SStanislav Sedov     struct template *q;
306*ae771770SStanislav Sedov     unsigned int i = 1;
307*ae771770SStanislav Sedov     FILE *f = get_code_file();
308*ae771770SStanislav Sedov 
309*ae771770SStanislav Sedov     fprintf(f, "static const struct asn1_template asn1_%s[] = {\n", tl->name);
310*ae771770SStanislav Sedov     fprintf(f, "/* 0 */ %s,\n", tl->header);
311*ae771770SStanislav Sedov     ASN1_TAILQ_FOREACH(q, &tl->template, members) {
312*ae771770SStanislav Sedov 	int last = (ASN1_TAILQ_LAST(&tl->template, templatehead) == q);
313*ae771770SStanislav Sedov 	fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
314*ae771770SStanislav Sedov     }
315*ae771770SStanislav Sedov     fprintf(f, "};\n");
316*ae771770SStanislav Sedov }
317*ae771770SStanislav Sedov 
318*ae771770SStanislav Sedov static struct tlist *
319*ae771770SStanislav Sedov tlist_find_by_name(const char *name)
320*ae771770SStanislav Sedov {
321*ae771770SStanislav Sedov     struct tlist *ql;
322*ae771770SStanislav Sedov     ASN1_TAILQ_FOREACH(ql, &tlistmaster, tmembers) {
323*ae771770SStanislav Sedov 	if (strcmp(ql->name, name) == 0)
324*ae771770SStanislav Sedov 	    return ql;
325*ae771770SStanislav Sedov     }
326*ae771770SStanislav Sedov     return NULL;
327*ae771770SStanislav Sedov }
328*ae771770SStanislav Sedov 
329*ae771770SStanislav Sedov static int
330*ae771770SStanislav Sedov tlist_cmp_name(const char *tname, const char *qname)
331*ae771770SStanislav Sedov {
332*ae771770SStanislav Sedov     struct tlist *tl = tlist_find_by_name(tname);
333*ae771770SStanislav Sedov     struct tlist *ql = tlist_find_by_name(qname);
334*ae771770SStanislav Sedov     return tlist_cmp(tl, ql);
335*ae771770SStanislav Sedov }
336*ae771770SStanislav Sedov 
337*ae771770SStanislav Sedov static int
338*ae771770SStanislav Sedov tlist_cmp(const struct tlist *tl, const struct tlist *ql)
339*ae771770SStanislav Sedov {
340*ae771770SStanislav Sedov     int ret;
341*ae771770SStanislav Sedov     struct template *t, *q;
342*ae771770SStanislav Sedov 
343*ae771770SStanislav Sedov     ret = strcmp(tl->header, ql->header);
344*ae771770SStanislav Sedov     if (ret) return ret;
345*ae771770SStanislav Sedov 
346*ae771770SStanislav Sedov     q = ASN1_TAILQ_FIRST(&ql->template);
347*ae771770SStanislav Sedov     ASN1_TAILQ_FOREACH(t, &tl->template, members) {
348*ae771770SStanislav Sedov 	if (q == NULL) return 1;
349*ae771770SStanislav Sedov 
350*ae771770SStanislav Sedov 	if (t->ptr == NULL || q->ptr == NULL) {
351*ae771770SStanislav Sedov 	    ret = strcmp(t->line, q->line);
352*ae771770SStanislav Sedov 	    if (ret) return ret;
353*ae771770SStanislav Sedov 	} else {
354*ae771770SStanislav Sedov 	    ret = strcmp(t->tt, q->tt);
355*ae771770SStanislav Sedov 	    if (ret) return ret;
356*ae771770SStanislav Sedov 
357*ae771770SStanislav Sedov 	    ret = strcmp(t->offset, q->offset);
358*ae771770SStanislav Sedov 	    if (ret) return ret;
359*ae771770SStanislav Sedov 
360*ae771770SStanislav Sedov 	    if ((ret = strcmp(t->ptr, q->ptr)) != 0 ||
361*ae771770SStanislav Sedov 		(ret = tlist_cmp_name(t->ptr, q->ptr)) != 0)
362*ae771770SStanislav Sedov 		return ret;
363*ae771770SStanislav Sedov 	}
364*ae771770SStanislav Sedov 	q = ASN1_TAILQ_NEXT(q, members);
365*ae771770SStanislav Sedov     }
366*ae771770SStanislav Sedov     if (q != NULL) return -1;
367*ae771770SStanislav Sedov     return 0;
368*ae771770SStanislav Sedov }
369*ae771770SStanislav Sedov 
370*ae771770SStanislav Sedov 
371*ae771770SStanislav Sedov static const char *
372*ae771770SStanislav Sedov tlist_find_dup(const struct tlist *tl)
373*ae771770SStanislav Sedov {
374*ae771770SStanislav Sedov     struct tlist *ql;
375*ae771770SStanislav Sedov 
376*ae771770SStanislav Sedov     ASN1_TAILQ_FOREACH(ql, &tlistmaster, tmembers) {
377*ae771770SStanislav Sedov 	if (tlist_cmp(ql, tl) == 0) {
378*ae771770SStanislav Sedov 	    numdups++;
379*ae771770SStanislav Sedov 	    return ql->name;
380*ae771770SStanislav Sedov 	}
381*ae771770SStanislav Sedov     }
382*ae771770SStanislav Sedov     return NULL;
383*ae771770SStanislav Sedov }
384*ae771770SStanislav Sedov 
385*ae771770SStanislav Sedov 
386*ae771770SStanislav Sedov /*
387*ae771770SStanislav Sedov  *
388*ae771770SStanislav Sedov  */
389*ae771770SStanislav Sedov 
390*ae771770SStanislav Sedov static struct template *
391*ae771770SStanislav Sedov add_line(struct templatehead *t, const char *fmt, ...)
392*ae771770SStanislav Sedov {
393*ae771770SStanislav Sedov     struct template *q = calloc(1, sizeof(*q));
394*ae771770SStanislav Sedov     va_list ap;
395*ae771770SStanislav Sedov     va_start(ap, fmt);
396*ae771770SStanislav Sedov     if (vasprintf(&q->line, fmt, ap) < 0 || q->line == NULL)
397*ae771770SStanislav Sedov 	errx(1, "malloc");
398*ae771770SStanislav Sedov     va_end(ap);
399*ae771770SStanislav Sedov     ASN1_TAILQ_INSERT_TAIL(t, q, members);
400*ae771770SStanislav Sedov     return q;
401*ae771770SStanislav Sedov }
402*ae771770SStanislav Sedov 
403*ae771770SStanislav Sedov static void
404*ae771770SStanislav Sedov add_line_pointer(struct templatehead *t,
405*ae771770SStanislav Sedov 		 const char *ptr,
406*ae771770SStanislav Sedov 		 const char *offset,
407*ae771770SStanislav Sedov 		 const char *ttfmt,
408*ae771770SStanislav Sedov 		 ...)
409*ae771770SStanislav Sedov {
410*ae771770SStanislav Sedov     struct template *q;
411*ae771770SStanislav Sedov     va_list ap;
412*ae771770SStanislav Sedov     char *tt = NULL;
413*ae771770SStanislav Sedov 
414*ae771770SStanislav Sedov     va_start(ap, ttfmt);
415*ae771770SStanislav Sedov     if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL)
416*ae771770SStanislav Sedov 	errx(1, "malloc");
417*ae771770SStanislav Sedov     va_end(ap);
418*ae771770SStanislav Sedov 
419*ae771770SStanislav Sedov     q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr);
420*ae771770SStanislav Sedov     q->tt = tt;
421*ae771770SStanislav Sedov     q->offset = strdup(offset);
422*ae771770SStanislav Sedov     q->ptr = strdup(ptr);
423*ae771770SStanislav Sedov }
424*ae771770SStanislav Sedov 
425*ae771770SStanislav Sedov static int
426*ae771770SStanislav Sedov use_extern(const Symbol *s)
427*ae771770SStanislav Sedov {
428*ae771770SStanislav Sedov     if (s->type == NULL)
429*ae771770SStanislav Sedov 	return 1;
430*ae771770SStanislav Sedov     return 0;
431*ae771770SStanislav Sedov }
432*ae771770SStanislav Sedov 
433*ae771770SStanislav Sedov static int
434*ae771770SStanislav Sedov is_struct(Type *t, int isstruct)
435*ae771770SStanislav Sedov {
436*ae771770SStanislav Sedov     size_t i;
437*ae771770SStanislav Sedov 
438*ae771770SStanislav Sedov     if (t->type == TType)
439*ae771770SStanislav Sedov 	return 0;
440*ae771770SStanislav Sedov     if (t->type == TSequence || t->type == TSet || t->type == TChoice)
441*ae771770SStanislav Sedov 	return 1;
442*ae771770SStanislav Sedov     if (t->type == TTag)
443*ae771770SStanislav Sedov 	return is_struct(t->subtype, isstruct);
444*ae771770SStanislav Sedov 
445*ae771770SStanislav Sedov     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) {
446*ae771770SStanislav Sedov 	if (t->type == types[i].type) {
447*ae771770SStanislav Sedov 	    if (types[i].is_struct == 0)
448*ae771770SStanislav Sedov 		return 0;
449*ae771770SStanislav Sedov 	    else
450*ae771770SStanislav Sedov 		break;
451*ae771770SStanislav Sedov 	}
452*ae771770SStanislav Sedov     }
453*ae771770SStanislav Sedov 
454*ae771770SStanislav Sedov     return isstruct;
455*ae771770SStanislav Sedov }
456*ae771770SStanislav Sedov 
457*ae771770SStanislav Sedov static const Type *
458*ae771770SStanislav Sedov compact_tag(const Type *t)
459*ae771770SStanislav Sedov {
460*ae771770SStanislav Sedov     while (t->type == TTag)
461*ae771770SStanislav Sedov 	t = t->subtype;
462*ae771770SStanislav Sedov     return t;
463*ae771770SStanislav Sedov }
464*ae771770SStanislav Sedov 
465*ae771770SStanislav Sedov static void
466*ae771770SStanislav Sedov template_members(struct templatehead *temp, const char *basetype, const char *name, const Type *t, int optional, int isstruct, int need_offset)
467*ae771770SStanislav Sedov {
468*ae771770SStanislav Sedov     char *poffset = NULL;
469*ae771770SStanislav Sedov 
470*ae771770SStanislav Sedov     if (optional && t->type != TTag && t->type != TType)
471*ae771770SStanislav Sedov 	errx(1, "%s...%s is optional and not a (TTag or TType)", basetype, name);
472*ae771770SStanislav Sedov 
473*ae771770SStanislav Sedov     poffset = partial_offset(basetype, name, need_offset);
474*ae771770SStanislav Sedov 
475*ae771770SStanislav Sedov     switch (t->type) {
476*ae771770SStanislav Sedov     case TType:
477*ae771770SStanislav Sedov 	if (use_extern(t->symbol)) {
478*ae771770SStanislav Sedov 	    add_line(temp, "{ A1_OP_TYPE_EXTERN %s, %s, &asn1_extern_%s}",
479*ae771770SStanislav Sedov 		     optional ? "|A1_FLAG_OPTIONAL" : "",
480*ae771770SStanislav Sedov 		     poffset, t->symbol->gen_name);
481*ae771770SStanislav Sedov 	} else {
482*ae771770SStanislav Sedov 	    add_line_pointer(temp, t->symbol->gen_name, poffset,
483*ae771770SStanislav Sedov 			     "A1_OP_TYPE %s", optional ? "|A1_FLAG_OPTIONAL" : "");
484*ae771770SStanislav Sedov 	}
485*ae771770SStanislav Sedov 	break;
486*ae771770SStanislav Sedov     case TInteger: {
487*ae771770SStanislav Sedov 	char *itype = NULL;
488*ae771770SStanislav Sedov 
489*ae771770SStanislav Sedov 	if (t->members)
490*ae771770SStanislav Sedov 	    itype = "IMEMBER";
491*ae771770SStanislav Sedov 	else if (t->range == NULL)
492*ae771770SStanislav Sedov 	    itype = "HEIM_INTEGER";
493*ae771770SStanislav Sedov 	else if (t->range->min == INT_MIN && t->range->max == INT_MAX)
494*ae771770SStanislav Sedov 	    itype = "INTEGER";
495*ae771770SStanislav Sedov 	else if (t->range->min == 0 && t->range->max == UINT_MAX)
496*ae771770SStanislav Sedov 	    itype = "UNSIGNED";
497*ae771770SStanislav Sedov 	else if (t->range->min == 0 && t->range->max == INT_MAX)
498*ae771770SStanislav Sedov 	    itype = "UNSIGNED";
499*ae771770SStanislav Sedov 	else
500*ae771770SStanislav Sedov 	    errx(1, "%s: unsupported range %d -> %d",
501*ae771770SStanislav Sedov 		 name, t->range->min, t->range->max);
502*ae771770SStanislav Sedov 
503*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, NULL }", itype, poffset);
504*ae771770SStanislav Sedov 	break;
505*ae771770SStanislav Sedov     }
506*ae771770SStanislav Sedov     case TGeneralString:
507*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_GENERAL_STRING), %s, NULL }", poffset);
508*ae771770SStanislav Sedov 	break;
509*ae771770SStanislav Sedov     case TTeletexString:
510*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_TELETEX_STRING), %s, NULL }", poffset);
511*ae771770SStanislav Sedov 	break;
512*ae771770SStanislav Sedov     case TPrintableString:
513*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_PRINTABLE_STRING), %s, NULL }", poffset);
514*ae771770SStanislav Sedov 	break;
515*ae771770SStanislav Sedov     case TOctetString:
516*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_OCTET_STRING), %s, NULL }", poffset);
517*ae771770SStanislav Sedov 	break;
518*ae771770SStanislav Sedov     case TIA5String:
519*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_IA5_STRING), %s, NULL }", poffset);
520*ae771770SStanislav Sedov 	break;
521*ae771770SStanislav Sedov     case TBMPString:
522*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_BMP_STRING), %s, NULL }", poffset);
523*ae771770SStanislav Sedov 	break;
524*ae771770SStanislav Sedov     case TUniversalString:
525*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_UNIVERSAL_STRING), %s, NULL }", poffset);
526*ae771770SStanislav Sedov 	break;
527*ae771770SStanislav Sedov     case TVisibleString:
528*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_VISIBLE_STRING), %s, NULL }", poffset);
529*ae771770SStanislav Sedov 	break;
530*ae771770SStanislav Sedov     case TUTF8String:
531*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_UTF8_STRING), %s, NULL }", poffset);
532*ae771770SStanislav Sedov 	break;
533*ae771770SStanislav Sedov     case TGeneralizedTime:
534*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_GENERALIZED_TIME), %s, NULL }", poffset);
535*ae771770SStanislav Sedov 	break;
536*ae771770SStanislav Sedov     case TUTCTime:
537*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_UTC_TIME), %s, NULL }", poffset);
538*ae771770SStanislav Sedov 	break;
539*ae771770SStanislav Sedov     case TBoolean:
540*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_BOOLEAN), %s, NULL }", poffset);
541*ae771770SStanislav Sedov 	break;
542*ae771770SStanislav Sedov     case TOID:
543*ae771770SStanislav Sedov 	add_line(temp, "{ A1_PARSE_T(A1T_OID), %s, NULL }", poffset);
544*ae771770SStanislav Sedov 	break;
545*ae771770SStanislav Sedov     case TNull:
546*ae771770SStanislav Sedov 	break;
547*ae771770SStanislav Sedov     case TBitString: {
548*ae771770SStanislav Sedov 	struct templatehead template = ASN1_TAILQ_HEAD_INITIALIZER(template);
549*ae771770SStanislav Sedov 	struct template *q;
550*ae771770SStanislav Sedov 	Member *m;
551*ae771770SStanislav Sedov 	size_t count = 0, i;
552*ae771770SStanislav Sedov 	char *bname = NULL;
553*ae771770SStanislav Sedov 	FILE *f = get_code_file();
554*ae771770SStanislav Sedov 
555*ae771770SStanislav Sedov 	if (ASN1_TAILQ_EMPTY(t->members)) {
556*ae771770SStanislav Sedov 	    add_line(temp, "{ A1_PARSE_T(A1T_HEIM_BIT_STRING), %s, NULL }", poffset);
557*ae771770SStanislav Sedov 	    break;
558*ae771770SStanislav Sedov 	}
559*ae771770SStanislav Sedov 
560*ae771770SStanislav Sedov 	if (asprintf(&bname, "bmember_%s_%p", name ? name : "", t) < 0 || bname == NULL)
561*ae771770SStanislav Sedov 	    errx(1, "malloc");
562*ae771770SStanislav Sedov 	output_name(bname);
563*ae771770SStanislav Sedov 
564*ae771770SStanislav Sedov 	ASN1_TAILQ_FOREACH(m, t->members, members) {
565*ae771770SStanislav Sedov 	    add_line(&template, "{ 0, %d, 0 } /* %s */", m->val, m->gen_name);
566*ae771770SStanislav Sedov 	}
567*ae771770SStanislav Sedov 
568*ae771770SStanislav Sedov 	ASN1_TAILQ_FOREACH(q, &template, members) {
569*ae771770SStanislav Sedov 	    count++;
570*ae771770SStanislav Sedov 	}
571*ae771770SStanislav Sedov 
572*ae771770SStanislav Sedov 	fprintf(f, "static const struct asn1_template asn1_%s_%s[] = {\n", basetype, bname);
573*ae771770SStanislav Sedov 	fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)%lu) },\n",
574*ae771770SStanislav Sedov 		rfc1510_bitstring ? "|A1_HBF_RFC1510" : "",
575*ae771770SStanislav Sedov 		basetype, (unsigned long)count);
576*ae771770SStanislav Sedov 	i = 1;
577*ae771770SStanislav Sedov 	ASN1_TAILQ_FOREACH(q, &template, members) {
578*ae771770SStanislav Sedov 	    int last = (ASN1_TAILQ_LAST(&template, templatehead) == q);
579*ae771770SStanislav Sedov 	    fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
580*ae771770SStanislav Sedov 	}
581*ae771770SStanislav Sedov 	fprintf(f, "};\n");
582*ae771770SStanislav Sedov 
583*ae771770SStanislav Sedov 	add_line(temp, "{ A1_OP_BMEMBER, %s, asn1_%s_%s }", poffset, basetype, bname);
584*ae771770SStanislav Sedov 
585*ae771770SStanislav Sedov 	free(bname);
586*ae771770SStanislav Sedov 
587*ae771770SStanislav Sedov 	break;
588*ae771770SStanislav Sedov     }
589*ae771770SStanislav Sedov     case TSequence: {
590*ae771770SStanislav Sedov 	Member *m;
591*ae771770SStanislav Sedov 
592*ae771770SStanislav Sedov 	ASN1_TAILQ_FOREACH(m, t->members, members) {
593*ae771770SStanislav Sedov 	    char *newbasename = NULL;
594*ae771770SStanislav Sedov 
595*ae771770SStanislav Sedov 	    if (m->ellipsis)
596*ae771770SStanislav Sedov 		continue;
597*ae771770SStanislav Sedov 
598*ae771770SStanislav Sedov 	    if (name) {
599*ae771770SStanislav Sedov 		if (asprintf(&newbasename, "%s_%s", basetype, name) < 0)
600*ae771770SStanislav Sedov 		    errx(1, "malloc");
601*ae771770SStanislav Sedov 	    } else
602*ae771770SStanislav Sedov 		newbasename = strdup(basetype);
603*ae771770SStanislav Sedov 	    if (newbasename == NULL)
604*ae771770SStanislav Sedov 		errx(1, "malloc");
605*ae771770SStanislav Sedov 
606*ae771770SStanislav Sedov 	    template_members(temp, newbasename, m->gen_name, m->type, m->optional, isstruct, 1);
607*ae771770SStanislav Sedov 
608*ae771770SStanislav Sedov 	    free(newbasename);
609*ae771770SStanislav Sedov 	}
610*ae771770SStanislav Sedov 
611*ae771770SStanislav Sedov 	break;
612*ae771770SStanislav Sedov     }
613*ae771770SStanislav Sedov     case TTag: {
614*ae771770SStanislav Sedov 	char *tname = NULL, *elname = NULL;
615*ae771770SStanislav Sedov 	const char *sename, *dupname;
616*ae771770SStanislav Sedov 	int subtype_is_struct = is_struct(t->subtype, isstruct);
617*ae771770SStanislav Sedov 
618*ae771770SStanislav Sedov 	if (subtype_is_struct)
619*ae771770SStanislav Sedov 	    sename = basetype;
620*ae771770SStanislav Sedov 	else
621*ae771770SStanislav Sedov 	    sename = symbol_name(basetype, t->subtype);
622*ae771770SStanislav Sedov 
623*ae771770SStanislav Sedov 	if (asprintf(&tname, "tag_%s_%p", name ? name : "", t) < 0 || tname == NULL)
624*ae771770SStanislav Sedov 	    errx(1, "malloc");
625*ae771770SStanislav Sedov 	output_name(tname);
626*ae771770SStanislav Sedov 
627*ae771770SStanislav Sedov 	if (asprintf(&elname, "%s_%s", basetype, tname) < 0 || elname == NULL)
628*ae771770SStanislav Sedov 	    errx(1, "malloc");
629*ae771770SStanislav Sedov 
630*ae771770SStanislav Sedov 	generate_template_type(elname, &dupname, NULL, sename, name,
631*ae771770SStanislav Sedov 			       t->subtype, 0, subtype_is_struct, 0);
632*ae771770SStanislav Sedov 
633*ae771770SStanislav Sedov 	add_line_pointer(temp, dupname, poffset,
634*ae771770SStanislav Sedov 			 "A1_TAG_T(%s,%s,%s)%s",
635*ae771770SStanislav Sedov 			 classname(t->tag.tagclass),
636*ae771770SStanislav Sedov 			 is_primitive_type(t->subtype->type)  ? "PRIM" : "CONS",
637*ae771770SStanislav Sedov 			 valuename(t->tag.tagclass, t->tag.tagvalue),
638*ae771770SStanislav Sedov 			 optional ? "|A1_FLAG_OPTIONAL" : "");
639*ae771770SStanislav Sedov 
640*ae771770SStanislav Sedov 	free(tname);
641*ae771770SStanislav Sedov 	free(elname);
642*ae771770SStanislav Sedov 
643*ae771770SStanislav Sedov 	break;
644*ae771770SStanislav Sedov     }
645*ae771770SStanislav Sedov     case TSetOf:
646*ae771770SStanislav Sedov     case TSequenceOf: {
647*ae771770SStanislav Sedov 	const char *type = NULL, *tname, *dupname;
648*ae771770SStanislav Sedov 	char *sename = NULL, *elname = NULL;
649*ae771770SStanislav Sedov 	int subtype_is_struct = is_struct(t->subtype, 0);
650*ae771770SStanislav Sedov 
651*ae771770SStanislav Sedov 	if (name && subtype_is_struct) {
652*ae771770SStanislav Sedov 	    tname = "seofTstruct";
653*ae771770SStanislav Sedov 	    if (asprintf(&sename, "%s_%s_val", basetype, name) < 0)
654*ae771770SStanislav Sedov 		errx(1, "malloc");
655*ae771770SStanislav Sedov 	} else if (subtype_is_struct) {
656*ae771770SStanislav Sedov 	    tname = "seofTstruct";
657*ae771770SStanislav Sedov 	    if (asprintf(&sename, "%s_val", symbol_name(basetype, t->subtype)) < 0)
658*ae771770SStanislav Sedov 		errx(1, "malloc");
659*ae771770SStanislav Sedov 	} else {
660*ae771770SStanislav Sedov 	    if (name)
661*ae771770SStanislav Sedov 		tname = name;
662*ae771770SStanislav Sedov 	    else
663*ae771770SStanislav Sedov 		tname = "seofTstruct";
664*ae771770SStanislav Sedov 	    sename = strdup(symbol_name(basetype, t->subtype));
665*ae771770SStanislav Sedov 	}
666*ae771770SStanislav Sedov 	if (sename == NULL)
667*ae771770SStanislav Sedov 	    errx(1, "malloc");
668*ae771770SStanislav Sedov 
669*ae771770SStanislav Sedov 	if (t->type == TSetOf) type = "A1_OP_SETOF";
670*ae771770SStanislav Sedov 	else if (t->type == TSequenceOf) type = "A1_OP_SEQOF";
671*ae771770SStanislav Sedov 	else abort();
672*ae771770SStanislav Sedov 
673*ae771770SStanislav Sedov 	if (asprintf(&elname, "%s_%s_%p", basetype, tname, t) < 0 || elname == NULL)
674*ae771770SStanislav Sedov 	    errx(1, "malloc");
675*ae771770SStanislav Sedov 
676*ae771770SStanislav Sedov 	generate_template_type(elname, &dupname, NULL, sename, NULL, t->subtype,
677*ae771770SStanislav Sedov 			       0, subtype_is_struct, need_offset);
678*ae771770SStanislav Sedov 
679*ae771770SStanislav Sedov 	add_line(temp, "{ %s, %s, asn1_%s }", type, poffset, dupname);
680*ae771770SStanislav Sedov 	free(sename);
681*ae771770SStanislav Sedov 	break;
682*ae771770SStanislav Sedov     }
683*ae771770SStanislav Sedov     case TChoice: {
684*ae771770SStanislav Sedov 	struct templatehead template = ASN1_TAILQ_HEAD_INITIALIZER(template);
685*ae771770SStanislav Sedov 	struct template *q;
686*ae771770SStanislav Sedov 	size_t count = 0, i;
687*ae771770SStanislav Sedov 	char *tname = NULL;
688*ae771770SStanislav Sedov 	FILE *f = get_code_file();
689*ae771770SStanislav Sedov 	Member *m;
690*ae771770SStanislav Sedov 	int ellipsis = 0;
691*ae771770SStanislav Sedov 	char *e;
692*ae771770SStanislav Sedov 
693*ae771770SStanislav Sedov 	if (asprintf(&tname, "asn1_choice_%s_%s%x",
694*ae771770SStanislav Sedov 		     basetype, name ? name : "", (unsigned int)(uintptr_t)t) < 0 || tname == NULL)
695*ae771770SStanislav Sedov 	    errx(1, "malloc");
696*ae771770SStanislav Sedov 
697*ae771770SStanislav Sedov 	ASN1_TAILQ_FOREACH(m, t->members, members) {
698*ae771770SStanislav Sedov 	    const char *dupname;
699*ae771770SStanislav Sedov 	    char *elname = NULL;
700*ae771770SStanislav Sedov 	    char *newbasename = NULL;
701*ae771770SStanislav Sedov 	    int subtype_is_struct;
702*ae771770SStanislav Sedov 
703*ae771770SStanislav Sedov 	    if (m->ellipsis) {
704*ae771770SStanislav Sedov 		ellipsis = 1;
705*ae771770SStanislav Sedov 		continue;
706*ae771770SStanislav Sedov 	    }
707*ae771770SStanislav Sedov 
708*ae771770SStanislav Sedov 	    subtype_is_struct = is_struct(m->type, 0);
709*ae771770SStanislav Sedov 
710*ae771770SStanislav Sedov 	    if (asprintf(&elname, "%s_choice_%s", basetype, m->gen_name) < 0 || elname == NULL)
711*ae771770SStanislav Sedov 		errx(1, "malloc");
712*ae771770SStanislav Sedov 
713*ae771770SStanislav Sedov 	    if (subtype_is_struct) {
714*ae771770SStanislav Sedov 		if (asprintf(&newbasename, "%s_%s", basetype, m->gen_name) < 0)
715*ae771770SStanislav Sedov 		    errx(1, "malloc");
716*ae771770SStanislav Sedov 	    } else
717*ae771770SStanislav Sedov 		newbasename = strdup(basetype);
718*ae771770SStanislav Sedov 
719*ae771770SStanislav Sedov 	    if (newbasename == NULL)
720*ae771770SStanislav Sedov 		errx(1, "malloc");
721*ae771770SStanislav Sedov 
722*ae771770SStanislav Sedov 
723*ae771770SStanislav Sedov 	    generate_template_type(elname, &dupname, NULL,
724*ae771770SStanislav Sedov 				   symbol_name(newbasename, m->type),
725*ae771770SStanislav Sedov 				   NULL, m->type, 0, subtype_is_struct, 1);
726*ae771770SStanislav Sedov 
727*ae771770SStanislav Sedov 	    add_line(&template, "{ %s, offsetof(%s%s, u.%s), asn1_%s }",
728*ae771770SStanislav Sedov 		     m->label, isstruct ? "struct " : "",
729*ae771770SStanislav Sedov 		     basetype, m->gen_name,
730*ae771770SStanislav Sedov 		     dupname);
731*ae771770SStanislav Sedov 
732*ae771770SStanislav Sedov 	    free(elname);
733*ae771770SStanislav Sedov 	    free(newbasename);
734*ae771770SStanislav Sedov 	}
735*ae771770SStanislav Sedov 
736*ae771770SStanislav Sedov 	e = NULL;
737*ae771770SStanislav Sedov 	if (ellipsis) {
738*ae771770SStanislav Sedov 	    if (asprintf(&e, "offsetof(%s%s, u.asn1_ellipsis)", isstruct ? "struct " : "", basetype) < 0 || e == NULL)
739*ae771770SStanislav Sedov 		errx(1, "malloc");
740*ae771770SStanislav Sedov 	}
741*ae771770SStanislav Sedov 
742*ae771770SStanislav Sedov 	ASN1_TAILQ_FOREACH(q, &template, members) {
743*ae771770SStanislav Sedov 	    count++;
744*ae771770SStanislav Sedov 	}
745*ae771770SStanislav Sedov 
746*ae771770SStanislav Sedov 	fprintf(f, "static const struct asn1_template %s[] = {\n", tname);
747*ae771770SStanislav Sedov 	fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)%lu) },\n",
748*ae771770SStanislav Sedov 		e ? e : "0", isstruct ? "struct " : "", basetype, (unsigned long)count);
749*ae771770SStanislav Sedov 	i = 1;
750*ae771770SStanislav Sedov 	ASN1_TAILQ_FOREACH(q, &template, members) {
751*ae771770SStanislav Sedov 	    int last = (ASN1_TAILQ_LAST(&template, templatehead) == q);
752*ae771770SStanislav Sedov 	    fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
753*ae771770SStanislav Sedov 	}
754*ae771770SStanislav Sedov 	fprintf(f, "};\n");
755*ae771770SStanislav Sedov 
756*ae771770SStanislav Sedov 	add_line(temp, "{ A1_OP_CHOICE, %s, %s }", poffset, tname);
757*ae771770SStanislav Sedov 
758*ae771770SStanislav Sedov 	free(e);
759*ae771770SStanislav Sedov 	free(tname);
760*ae771770SStanislav Sedov 	break;
761*ae771770SStanislav Sedov     }
762*ae771770SStanislav Sedov     default:
763*ae771770SStanislav Sedov 	abort ();
764*ae771770SStanislav Sedov     }
765*ae771770SStanislav Sedov     if (poffset)
766*ae771770SStanislav Sedov 	free(poffset);
767*ae771770SStanislav Sedov }
768*ae771770SStanislav Sedov 
769*ae771770SStanislav Sedov static void
770*ae771770SStanislav Sedov gen_extern_stubs(FILE *f, const char *name)
771*ae771770SStanislav Sedov {
772*ae771770SStanislav Sedov     fprintf(f,
773*ae771770SStanislav Sedov 	    "static const struct asn1_type_func asn1_extern_%s = {\n"
774*ae771770SStanislav Sedov 	    "\t(asn1_type_encode)encode_%s,\n"
775*ae771770SStanislav Sedov 	    "\t(asn1_type_decode)decode_%s,\n"
776*ae771770SStanislav Sedov 	    "\t(asn1_type_length)length_%s,\n"
777*ae771770SStanislav Sedov 	    "\t(asn1_type_copy)copy_%s,\n"
778*ae771770SStanislav Sedov 	    "\t(asn1_type_release)free_%s,\n"
779*ae771770SStanislav Sedov 	    "\tsizeof(%s)\n"
780*ae771770SStanislav Sedov 	    "};\n",
781*ae771770SStanislav Sedov 	    name, name, name, name,
782*ae771770SStanislav Sedov 	    name, name, name);
783*ae771770SStanislav Sedov }
784*ae771770SStanislav Sedov 
785*ae771770SStanislav Sedov void
786*ae771770SStanislav Sedov gen_template_import(const Symbol *s)
787*ae771770SStanislav Sedov {
788*ae771770SStanislav Sedov     FILE *f = get_code_file();
789*ae771770SStanislav Sedov 
790*ae771770SStanislav Sedov     if (template_flag == 0)
791*ae771770SStanislav Sedov 	return;
792*ae771770SStanislav Sedov 
793*ae771770SStanislav Sedov     gen_extern_stubs(f, s->gen_name);
794*ae771770SStanislav Sedov }
795*ae771770SStanislav Sedov 
796*ae771770SStanislav Sedov static void
797*ae771770SStanislav Sedov generate_template_type(const char *varname,
798*ae771770SStanislav Sedov 		       const char **dupname,
799*ae771770SStanislav Sedov 		       const char *symname,
800*ae771770SStanislav Sedov 		       const char *basetype,
801*ae771770SStanislav Sedov 		       const char *name,
802*ae771770SStanislav Sedov 		       Type *type,
803*ae771770SStanislav Sedov 		       int optional, int isstruct, int need_offset)
804*ae771770SStanislav Sedov {
805*ae771770SStanislav Sedov     struct tlist *tl;
806*ae771770SStanislav Sedov     const char *dup;
807*ae771770SStanislav Sedov     int have_ellipsis = 0;
808*ae771770SStanislav Sedov 
809*ae771770SStanislav Sedov     tl = tlist_new(varname);
810*ae771770SStanislav Sedov 
811*ae771770SStanislav Sedov     template_members(&tl->template, basetype, name, type, optional, isstruct, need_offset);
812*ae771770SStanislav Sedov 
813*ae771770SStanislav Sedov     /* if its a sequence or set type, check if there is a ellipsis */
814*ae771770SStanislav Sedov     if (type->type == TSequence || type->type == TSet) {
815*ae771770SStanislav Sedov 	Member *m;
816*ae771770SStanislav Sedov 	ASN1_TAILQ_FOREACH(m, type->members, members) {
817*ae771770SStanislav Sedov 	    if (m->ellipsis)
818*ae771770SStanislav Sedov 		have_ellipsis = 1;
819*ae771770SStanislav Sedov 	}
820*ae771770SStanislav Sedov     }
821*ae771770SStanislav Sedov 
822*ae771770SStanislav Sedov     if (ASN1_TAILQ_EMPTY(&tl->template) && compact_tag(type)->type != TNull)
823*ae771770SStanislav Sedov 	errx(1, "Tag %s...%s with no content ?", basetype, name ? name : "");
824*ae771770SStanislav Sedov 
825*ae771770SStanislav Sedov     tlist_header(tl, "{ 0%s%s, sizeof(%s%s), ((void *)%lu) }",
826*ae771770SStanislav Sedov 		 (symname && preserve_type(symname)) ? "|A1_HF_PRESERVE" : "",
827*ae771770SStanislav Sedov 		 have_ellipsis ? "|A1_HF_ELLIPSIS" : "",
828*ae771770SStanislav Sedov 		 isstruct ? "struct " : "", basetype, tlist_count(tl));
829*ae771770SStanislav Sedov 
830*ae771770SStanislav Sedov     dup = tlist_find_dup(tl);
831*ae771770SStanislav Sedov     if (dup) {
832*ae771770SStanislav Sedov 	if (strcmp(dup, tl->name) == 0)
833*ae771770SStanislav Sedov 	    errx(1, "found dup of ourself");
834*ae771770SStanislav Sedov 	*dupname = dup;
835*ae771770SStanislav Sedov     } else {
836*ae771770SStanislav Sedov 	*dupname = tl->name;
837*ae771770SStanislav Sedov 	tlist_print(tl);
838*ae771770SStanislav Sedov 	tlist_add(tl);
839*ae771770SStanislav Sedov     }
840*ae771770SStanislav Sedov }
841*ae771770SStanislav Sedov 
842*ae771770SStanislav Sedov 
843*ae771770SStanislav Sedov void
844*ae771770SStanislav Sedov generate_template(const Symbol *s)
845*ae771770SStanislav Sedov {
846*ae771770SStanislav Sedov     FILE *f = get_code_file();
847*ae771770SStanislav Sedov     const char *dupname;
848*ae771770SStanislav Sedov 
849*ae771770SStanislav Sedov     if (use_extern(s)) {
850*ae771770SStanislav Sedov 	gen_extern_stubs(f, s->gen_name);
851*ae771770SStanislav Sedov 	return;
852*ae771770SStanislav Sedov     }
853*ae771770SStanislav Sedov 
854*ae771770SStanislav Sedov     generate_template_type(s->gen_name, &dupname, s->name, s->gen_name, NULL, s->type, 0, 0, 1);
855*ae771770SStanislav Sedov 
856*ae771770SStanislav Sedov     fprintf(f,
857*ae771770SStanislav Sedov 	    "\n"
858*ae771770SStanislav Sedov 	    "int\n"
859*ae771770SStanislav Sedov 	    "decode_%s(const unsigned char *p, size_t len, %s *data, size_t *size)\n"
860*ae771770SStanislav Sedov 	    "{\n"
861*ae771770SStanislav Sedov 	    "    return _asn1_decode_top(asn1_%s, 0|%s, p, len, data, size);\n"
862*ae771770SStanislav Sedov 	    "}\n"
863*ae771770SStanislav Sedov 	    "\n",
864*ae771770SStanislav Sedov 	    s->gen_name,
865*ae771770SStanislav Sedov 	    s->gen_name,
866*ae771770SStanislav Sedov 	    dupname,
867*ae771770SStanislav Sedov 	    support_ber ? "A1_PF_ALLOW_BER" : "0");
868*ae771770SStanislav Sedov 
869*ae771770SStanislav Sedov     fprintf(f,
870*ae771770SStanislav Sedov 	    "\n"
871*ae771770SStanislav Sedov 	    "int\n"
872*ae771770SStanislav Sedov 	    "encode_%s(unsigned char *p, size_t len, const %s *data, size_t *size)\n"
873*ae771770SStanislav Sedov 	    "{\n"
874*ae771770SStanislav Sedov 	    "    return _asn1_encode(asn1_%s, p, len, data, size);\n"
875*ae771770SStanislav Sedov 	    "}\n"
876*ae771770SStanislav Sedov 	    "\n",
877*ae771770SStanislav Sedov 	    s->gen_name,
878*ae771770SStanislav Sedov 	    s->gen_name,
879*ae771770SStanislav Sedov 	    dupname);
880*ae771770SStanislav Sedov 
881*ae771770SStanislav Sedov     fprintf(f,
882*ae771770SStanislav Sedov 	    "\n"
883*ae771770SStanislav Sedov 	    "size_t\n"
884*ae771770SStanislav Sedov 	    "length_%s(const %s *data)\n"
885*ae771770SStanislav Sedov 	    "{\n"
886*ae771770SStanislav Sedov 	    "    return _asn1_length(asn1_%s, data);\n"
887*ae771770SStanislav Sedov 	    "}\n"
888*ae771770SStanislav Sedov 	    "\n",
889*ae771770SStanislav Sedov 	    s->gen_name,
890*ae771770SStanislav Sedov 	    s->gen_name,
891*ae771770SStanislav Sedov 	    dupname);
892*ae771770SStanislav Sedov 
893*ae771770SStanislav Sedov 
894*ae771770SStanislav Sedov     fprintf(f,
895*ae771770SStanislav Sedov 	    "\n"
896*ae771770SStanislav Sedov 	    "void\n"
897*ae771770SStanislav Sedov 	    "free_%s(%s *data)\n"
898*ae771770SStanislav Sedov 	    "{\n"
899*ae771770SStanislav Sedov 	    "    _asn1_free(asn1_%s, data);\n"
900*ae771770SStanislav Sedov 	    "}\n"
901*ae771770SStanislav Sedov 	    "\n",
902*ae771770SStanislav Sedov 	    s->gen_name,
903*ae771770SStanislav Sedov 	    s->gen_name,
904*ae771770SStanislav Sedov 	    dupname);
905*ae771770SStanislav Sedov 
906*ae771770SStanislav Sedov     fprintf(f,
907*ae771770SStanislav Sedov 	    "\n"
908*ae771770SStanislav Sedov 	    "int\n"
909*ae771770SStanislav Sedov 	    "copy_%s(const %s *from, %s *to)\n"
910*ae771770SStanislav Sedov 	    "{\n"
911*ae771770SStanislav Sedov 	    "    return _asn1_copy_top(asn1_%s, from, to);\n"
912*ae771770SStanislav Sedov 	    "}\n"
913*ae771770SStanislav Sedov 	    "\n",
914*ae771770SStanislav Sedov 	    s->gen_name,
915*ae771770SStanislav Sedov 	    s->gen_name,
916*ae771770SStanislav Sedov 	    s->gen_name,
917*ae771770SStanislav Sedov 	    dupname);
918*ae771770SStanislav Sedov }
919