xref: /OK3568_Linux_fs/kernel/scripts/asn1_compiler.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* Simplified ASN.1 notation parser
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
5*4882a593Smuzhiyun  * Written by David Howells (dhowells@redhat.com)
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <stdarg.h>
9*4882a593Smuzhiyun #include <stdio.h>
10*4882a593Smuzhiyun #include <stdlib.h>
11*4882a593Smuzhiyun #include <stdint.h>
12*4882a593Smuzhiyun #include <stdbool.h>
13*4882a593Smuzhiyun #include <string.h>
14*4882a593Smuzhiyun #include <ctype.h>
15*4882a593Smuzhiyun #include <unistd.h>
16*4882a593Smuzhiyun #include <fcntl.h>
17*4882a593Smuzhiyun #include <sys/stat.h>
18*4882a593Smuzhiyun #include <linux/asn1_ber_bytecode.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun enum token_type {
21*4882a593Smuzhiyun 	DIRECTIVE_ABSENT,
22*4882a593Smuzhiyun 	DIRECTIVE_ALL,
23*4882a593Smuzhiyun 	DIRECTIVE_ANY,
24*4882a593Smuzhiyun 	DIRECTIVE_APPLICATION,
25*4882a593Smuzhiyun 	DIRECTIVE_AUTOMATIC,
26*4882a593Smuzhiyun 	DIRECTIVE_BEGIN,
27*4882a593Smuzhiyun 	DIRECTIVE_BIT,
28*4882a593Smuzhiyun 	DIRECTIVE_BMPString,
29*4882a593Smuzhiyun 	DIRECTIVE_BOOLEAN,
30*4882a593Smuzhiyun 	DIRECTIVE_BY,
31*4882a593Smuzhiyun 	DIRECTIVE_CHARACTER,
32*4882a593Smuzhiyun 	DIRECTIVE_CHOICE,
33*4882a593Smuzhiyun 	DIRECTIVE_CLASS,
34*4882a593Smuzhiyun 	DIRECTIVE_COMPONENT,
35*4882a593Smuzhiyun 	DIRECTIVE_COMPONENTS,
36*4882a593Smuzhiyun 	DIRECTIVE_CONSTRAINED,
37*4882a593Smuzhiyun 	DIRECTIVE_CONTAINING,
38*4882a593Smuzhiyun 	DIRECTIVE_DEFAULT,
39*4882a593Smuzhiyun 	DIRECTIVE_DEFINED,
40*4882a593Smuzhiyun 	DIRECTIVE_DEFINITIONS,
41*4882a593Smuzhiyun 	DIRECTIVE_EMBEDDED,
42*4882a593Smuzhiyun 	DIRECTIVE_ENCODED,
43*4882a593Smuzhiyun 	DIRECTIVE_ENCODING_CONTROL,
44*4882a593Smuzhiyun 	DIRECTIVE_END,
45*4882a593Smuzhiyun 	DIRECTIVE_ENUMERATED,
46*4882a593Smuzhiyun 	DIRECTIVE_EXCEPT,
47*4882a593Smuzhiyun 	DIRECTIVE_EXPLICIT,
48*4882a593Smuzhiyun 	DIRECTIVE_EXPORTS,
49*4882a593Smuzhiyun 	DIRECTIVE_EXTENSIBILITY,
50*4882a593Smuzhiyun 	DIRECTIVE_EXTERNAL,
51*4882a593Smuzhiyun 	DIRECTIVE_FALSE,
52*4882a593Smuzhiyun 	DIRECTIVE_FROM,
53*4882a593Smuzhiyun 	DIRECTIVE_GeneralString,
54*4882a593Smuzhiyun 	DIRECTIVE_GeneralizedTime,
55*4882a593Smuzhiyun 	DIRECTIVE_GraphicString,
56*4882a593Smuzhiyun 	DIRECTIVE_IA5String,
57*4882a593Smuzhiyun 	DIRECTIVE_IDENTIFIER,
58*4882a593Smuzhiyun 	DIRECTIVE_IMPLICIT,
59*4882a593Smuzhiyun 	DIRECTIVE_IMPLIED,
60*4882a593Smuzhiyun 	DIRECTIVE_IMPORTS,
61*4882a593Smuzhiyun 	DIRECTIVE_INCLUDES,
62*4882a593Smuzhiyun 	DIRECTIVE_INSTANCE,
63*4882a593Smuzhiyun 	DIRECTIVE_INSTRUCTIONS,
64*4882a593Smuzhiyun 	DIRECTIVE_INTEGER,
65*4882a593Smuzhiyun 	DIRECTIVE_INTERSECTION,
66*4882a593Smuzhiyun 	DIRECTIVE_ISO646String,
67*4882a593Smuzhiyun 	DIRECTIVE_MAX,
68*4882a593Smuzhiyun 	DIRECTIVE_MIN,
69*4882a593Smuzhiyun 	DIRECTIVE_MINUS_INFINITY,
70*4882a593Smuzhiyun 	DIRECTIVE_NULL,
71*4882a593Smuzhiyun 	DIRECTIVE_NumericString,
72*4882a593Smuzhiyun 	DIRECTIVE_OBJECT,
73*4882a593Smuzhiyun 	DIRECTIVE_OCTET,
74*4882a593Smuzhiyun 	DIRECTIVE_OF,
75*4882a593Smuzhiyun 	DIRECTIVE_OPTIONAL,
76*4882a593Smuzhiyun 	DIRECTIVE_ObjectDescriptor,
77*4882a593Smuzhiyun 	DIRECTIVE_PATTERN,
78*4882a593Smuzhiyun 	DIRECTIVE_PDV,
79*4882a593Smuzhiyun 	DIRECTIVE_PLUS_INFINITY,
80*4882a593Smuzhiyun 	DIRECTIVE_PRESENT,
81*4882a593Smuzhiyun 	DIRECTIVE_PRIVATE,
82*4882a593Smuzhiyun 	DIRECTIVE_PrintableString,
83*4882a593Smuzhiyun 	DIRECTIVE_REAL,
84*4882a593Smuzhiyun 	DIRECTIVE_RELATIVE_OID,
85*4882a593Smuzhiyun 	DIRECTIVE_SEQUENCE,
86*4882a593Smuzhiyun 	DIRECTIVE_SET,
87*4882a593Smuzhiyun 	DIRECTIVE_SIZE,
88*4882a593Smuzhiyun 	DIRECTIVE_STRING,
89*4882a593Smuzhiyun 	DIRECTIVE_SYNTAX,
90*4882a593Smuzhiyun 	DIRECTIVE_T61String,
91*4882a593Smuzhiyun 	DIRECTIVE_TAGS,
92*4882a593Smuzhiyun 	DIRECTIVE_TRUE,
93*4882a593Smuzhiyun 	DIRECTIVE_TeletexString,
94*4882a593Smuzhiyun 	DIRECTIVE_UNION,
95*4882a593Smuzhiyun 	DIRECTIVE_UNIQUE,
96*4882a593Smuzhiyun 	DIRECTIVE_UNIVERSAL,
97*4882a593Smuzhiyun 	DIRECTIVE_UTCTime,
98*4882a593Smuzhiyun 	DIRECTIVE_UTF8String,
99*4882a593Smuzhiyun 	DIRECTIVE_UniversalString,
100*4882a593Smuzhiyun 	DIRECTIVE_VideotexString,
101*4882a593Smuzhiyun 	DIRECTIVE_VisibleString,
102*4882a593Smuzhiyun 	DIRECTIVE_WITH,
103*4882a593Smuzhiyun 	NR__DIRECTIVES,
104*4882a593Smuzhiyun 	TOKEN_ASSIGNMENT = NR__DIRECTIVES,
105*4882a593Smuzhiyun 	TOKEN_OPEN_CURLY,
106*4882a593Smuzhiyun 	TOKEN_CLOSE_CURLY,
107*4882a593Smuzhiyun 	TOKEN_OPEN_SQUARE,
108*4882a593Smuzhiyun 	TOKEN_CLOSE_SQUARE,
109*4882a593Smuzhiyun 	TOKEN_OPEN_ACTION,
110*4882a593Smuzhiyun 	TOKEN_CLOSE_ACTION,
111*4882a593Smuzhiyun 	TOKEN_COMMA,
112*4882a593Smuzhiyun 	TOKEN_NUMBER,
113*4882a593Smuzhiyun 	TOKEN_TYPE_NAME,
114*4882a593Smuzhiyun 	TOKEN_ELEMENT_NAME,
115*4882a593Smuzhiyun 	NR__TOKENS
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun static const unsigned char token_to_tag[NR__TOKENS] = {
119*4882a593Smuzhiyun 	/* EOC goes first */
120*4882a593Smuzhiyun 	[DIRECTIVE_BOOLEAN]		= ASN1_BOOL,
121*4882a593Smuzhiyun 	[DIRECTIVE_INTEGER]		= ASN1_INT,
122*4882a593Smuzhiyun 	[DIRECTIVE_BIT]			= ASN1_BTS,
123*4882a593Smuzhiyun 	[DIRECTIVE_OCTET]		= ASN1_OTS,
124*4882a593Smuzhiyun 	[DIRECTIVE_NULL]		= ASN1_NULL,
125*4882a593Smuzhiyun 	[DIRECTIVE_OBJECT]		= ASN1_OID,
126*4882a593Smuzhiyun 	[DIRECTIVE_ObjectDescriptor]	= ASN1_ODE,
127*4882a593Smuzhiyun 	[DIRECTIVE_EXTERNAL]		= ASN1_EXT,
128*4882a593Smuzhiyun 	[DIRECTIVE_REAL]		= ASN1_REAL,
129*4882a593Smuzhiyun 	[DIRECTIVE_ENUMERATED]		= ASN1_ENUM,
130*4882a593Smuzhiyun 	[DIRECTIVE_EMBEDDED]		= 0,
131*4882a593Smuzhiyun 	[DIRECTIVE_UTF8String]		= ASN1_UTF8STR,
132*4882a593Smuzhiyun 	[DIRECTIVE_RELATIVE_OID]	= ASN1_RELOID,
133*4882a593Smuzhiyun 	/* 14 */
134*4882a593Smuzhiyun 	/* 15 */
135*4882a593Smuzhiyun 	[DIRECTIVE_SEQUENCE]		= ASN1_SEQ,
136*4882a593Smuzhiyun 	[DIRECTIVE_SET]			= ASN1_SET,
137*4882a593Smuzhiyun 	[DIRECTIVE_NumericString]	= ASN1_NUMSTR,
138*4882a593Smuzhiyun 	[DIRECTIVE_PrintableString]	= ASN1_PRNSTR,
139*4882a593Smuzhiyun 	[DIRECTIVE_T61String]		= ASN1_TEXSTR,
140*4882a593Smuzhiyun 	[DIRECTIVE_TeletexString]	= ASN1_TEXSTR,
141*4882a593Smuzhiyun 	[DIRECTIVE_VideotexString]	= ASN1_VIDSTR,
142*4882a593Smuzhiyun 	[DIRECTIVE_IA5String]		= ASN1_IA5STR,
143*4882a593Smuzhiyun 	[DIRECTIVE_UTCTime]		= ASN1_UNITIM,
144*4882a593Smuzhiyun 	[DIRECTIVE_GeneralizedTime]	= ASN1_GENTIM,
145*4882a593Smuzhiyun 	[DIRECTIVE_GraphicString]	= ASN1_GRASTR,
146*4882a593Smuzhiyun 	[DIRECTIVE_VisibleString]	= ASN1_VISSTR,
147*4882a593Smuzhiyun 	[DIRECTIVE_GeneralString]	= ASN1_GENSTR,
148*4882a593Smuzhiyun 	[DIRECTIVE_UniversalString]	= ASN1_UNITIM,
149*4882a593Smuzhiyun 	[DIRECTIVE_CHARACTER]		= ASN1_CHRSTR,
150*4882a593Smuzhiyun 	[DIRECTIVE_BMPString]		= ASN1_BMPSTR,
151*4882a593Smuzhiyun };
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun static const char asn1_classes[4][5] = {
154*4882a593Smuzhiyun 	[ASN1_UNIV]	= "UNIV",
155*4882a593Smuzhiyun 	[ASN1_APPL]	= "APPL",
156*4882a593Smuzhiyun 	[ASN1_CONT]	= "CONT",
157*4882a593Smuzhiyun 	[ASN1_PRIV]	= "PRIV"
158*4882a593Smuzhiyun };
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun static const char asn1_methods[2][5] = {
161*4882a593Smuzhiyun 	[ASN1_UNIV]	= "PRIM",
162*4882a593Smuzhiyun 	[ASN1_APPL]	= "CONS"
163*4882a593Smuzhiyun };
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun static const char *const asn1_universal_tags[32] = {
166*4882a593Smuzhiyun 	"EOC",
167*4882a593Smuzhiyun 	"BOOL",
168*4882a593Smuzhiyun 	"INT",
169*4882a593Smuzhiyun 	"BTS",
170*4882a593Smuzhiyun 	"OTS",
171*4882a593Smuzhiyun 	"NULL",
172*4882a593Smuzhiyun 	"OID",
173*4882a593Smuzhiyun 	"ODE",
174*4882a593Smuzhiyun 	"EXT",
175*4882a593Smuzhiyun 	"REAL",
176*4882a593Smuzhiyun 	"ENUM",
177*4882a593Smuzhiyun 	"EPDV",
178*4882a593Smuzhiyun 	"UTF8STR",
179*4882a593Smuzhiyun 	"RELOID",
180*4882a593Smuzhiyun 	NULL,		/* 14 */
181*4882a593Smuzhiyun 	NULL,		/* 15 */
182*4882a593Smuzhiyun 	"SEQ",
183*4882a593Smuzhiyun 	"SET",
184*4882a593Smuzhiyun 	"NUMSTR",
185*4882a593Smuzhiyun 	"PRNSTR",
186*4882a593Smuzhiyun 	"TEXSTR",
187*4882a593Smuzhiyun 	"VIDSTR",
188*4882a593Smuzhiyun 	"IA5STR",
189*4882a593Smuzhiyun 	"UNITIM",
190*4882a593Smuzhiyun 	"GENTIM",
191*4882a593Smuzhiyun 	"GRASTR",
192*4882a593Smuzhiyun 	"VISSTR",
193*4882a593Smuzhiyun 	"GENSTR",
194*4882a593Smuzhiyun 	"UNISTR",
195*4882a593Smuzhiyun 	"CHRSTR",
196*4882a593Smuzhiyun 	"BMPSTR",
197*4882a593Smuzhiyun 	NULL		/* 31 */
198*4882a593Smuzhiyun };
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun static const char *filename;
201*4882a593Smuzhiyun static const char *grammar_name;
202*4882a593Smuzhiyun static const char *outputname;
203*4882a593Smuzhiyun static const char *headername;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun static const char *const directives[NR__DIRECTIVES] = {
206*4882a593Smuzhiyun #define _(X) [DIRECTIVE_##X] = #X
207*4882a593Smuzhiyun 	_(ABSENT),
208*4882a593Smuzhiyun 	_(ALL),
209*4882a593Smuzhiyun 	_(ANY),
210*4882a593Smuzhiyun 	_(APPLICATION),
211*4882a593Smuzhiyun 	_(AUTOMATIC),
212*4882a593Smuzhiyun 	_(BEGIN),
213*4882a593Smuzhiyun 	_(BIT),
214*4882a593Smuzhiyun 	_(BMPString),
215*4882a593Smuzhiyun 	_(BOOLEAN),
216*4882a593Smuzhiyun 	_(BY),
217*4882a593Smuzhiyun 	_(CHARACTER),
218*4882a593Smuzhiyun 	_(CHOICE),
219*4882a593Smuzhiyun 	_(CLASS),
220*4882a593Smuzhiyun 	_(COMPONENT),
221*4882a593Smuzhiyun 	_(COMPONENTS),
222*4882a593Smuzhiyun 	_(CONSTRAINED),
223*4882a593Smuzhiyun 	_(CONTAINING),
224*4882a593Smuzhiyun 	_(DEFAULT),
225*4882a593Smuzhiyun 	_(DEFINED),
226*4882a593Smuzhiyun 	_(DEFINITIONS),
227*4882a593Smuzhiyun 	_(EMBEDDED),
228*4882a593Smuzhiyun 	_(ENCODED),
229*4882a593Smuzhiyun 	[DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
230*4882a593Smuzhiyun 	_(END),
231*4882a593Smuzhiyun 	_(ENUMERATED),
232*4882a593Smuzhiyun 	_(EXCEPT),
233*4882a593Smuzhiyun 	_(EXPLICIT),
234*4882a593Smuzhiyun 	_(EXPORTS),
235*4882a593Smuzhiyun 	_(EXTENSIBILITY),
236*4882a593Smuzhiyun 	_(EXTERNAL),
237*4882a593Smuzhiyun 	_(FALSE),
238*4882a593Smuzhiyun 	_(FROM),
239*4882a593Smuzhiyun 	_(GeneralString),
240*4882a593Smuzhiyun 	_(GeneralizedTime),
241*4882a593Smuzhiyun 	_(GraphicString),
242*4882a593Smuzhiyun 	_(IA5String),
243*4882a593Smuzhiyun 	_(IDENTIFIER),
244*4882a593Smuzhiyun 	_(IMPLICIT),
245*4882a593Smuzhiyun 	_(IMPLIED),
246*4882a593Smuzhiyun 	_(IMPORTS),
247*4882a593Smuzhiyun 	_(INCLUDES),
248*4882a593Smuzhiyun 	_(INSTANCE),
249*4882a593Smuzhiyun 	_(INSTRUCTIONS),
250*4882a593Smuzhiyun 	_(INTEGER),
251*4882a593Smuzhiyun 	_(INTERSECTION),
252*4882a593Smuzhiyun 	_(ISO646String),
253*4882a593Smuzhiyun 	_(MAX),
254*4882a593Smuzhiyun 	_(MIN),
255*4882a593Smuzhiyun 	[DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
256*4882a593Smuzhiyun 	[DIRECTIVE_NULL] = "NULL",
257*4882a593Smuzhiyun 	_(NumericString),
258*4882a593Smuzhiyun 	_(OBJECT),
259*4882a593Smuzhiyun 	_(OCTET),
260*4882a593Smuzhiyun 	_(OF),
261*4882a593Smuzhiyun 	_(OPTIONAL),
262*4882a593Smuzhiyun 	_(ObjectDescriptor),
263*4882a593Smuzhiyun 	_(PATTERN),
264*4882a593Smuzhiyun 	_(PDV),
265*4882a593Smuzhiyun 	[DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
266*4882a593Smuzhiyun 	_(PRESENT),
267*4882a593Smuzhiyun 	_(PRIVATE),
268*4882a593Smuzhiyun 	_(PrintableString),
269*4882a593Smuzhiyun 	_(REAL),
270*4882a593Smuzhiyun 	[DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
271*4882a593Smuzhiyun 	_(SEQUENCE),
272*4882a593Smuzhiyun 	_(SET),
273*4882a593Smuzhiyun 	_(SIZE),
274*4882a593Smuzhiyun 	_(STRING),
275*4882a593Smuzhiyun 	_(SYNTAX),
276*4882a593Smuzhiyun 	_(T61String),
277*4882a593Smuzhiyun 	_(TAGS),
278*4882a593Smuzhiyun 	_(TRUE),
279*4882a593Smuzhiyun 	_(TeletexString),
280*4882a593Smuzhiyun 	_(UNION),
281*4882a593Smuzhiyun 	_(UNIQUE),
282*4882a593Smuzhiyun 	_(UNIVERSAL),
283*4882a593Smuzhiyun 	_(UTCTime),
284*4882a593Smuzhiyun 	_(UTF8String),
285*4882a593Smuzhiyun 	_(UniversalString),
286*4882a593Smuzhiyun 	_(VideotexString),
287*4882a593Smuzhiyun 	_(VisibleString),
288*4882a593Smuzhiyun 	_(WITH)
289*4882a593Smuzhiyun };
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun struct action {
292*4882a593Smuzhiyun 	struct action	*next;
293*4882a593Smuzhiyun 	char		*name;
294*4882a593Smuzhiyun 	unsigned char	index;
295*4882a593Smuzhiyun };
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun static struct action *action_list;
298*4882a593Smuzhiyun static unsigned nr_actions;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun struct token {
301*4882a593Smuzhiyun 	unsigned short	line;
302*4882a593Smuzhiyun 	enum token_type	token_type : 8;
303*4882a593Smuzhiyun 	unsigned char	size;
304*4882a593Smuzhiyun 	struct action	*action;
305*4882a593Smuzhiyun 	char		*content;
306*4882a593Smuzhiyun 	struct type	*type;
307*4882a593Smuzhiyun };
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun static struct token *token_list;
310*4882a593Smuzhiyun static unsigned nr_tokens;
311*4882a593Smuzhiyun static bool verbose_opt;
312*4882a593Smuzhiyun static bool debug_opt;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun #define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)
315*4882a593Smuzhiyun #define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)
316*4882a593Smuzhiyun 
directive_compare(const void * _key,const void * _pdir)317*4882a593Smuzhiyun static int directive_compare(const void *_key, const void *_pdir)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	const struct token *token = _key;
320*4882a593Smuzhiyun 	const char *const *pdir = _pdir, *dir = *pdir;
321*4882a593Smuzhiyun 	size_t dlen, clen;
322*4882a593Smuzhiyun 	int val;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	dlen = strlen(dir);
325*4882a593Smuzhiyun 	clen = (dlen < token->size) ? dlen : token->size;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	//debug("cmp(%s,%s) = ", token->content, dir);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	val = memcmp(token->content, dir, clen);
330*4882a593Smuzhiyun 	if (val != 0) {
331*4882a593Smuzhiyun 		//debug("%d [cmp]\n", val);
332*4882a593Smuzhiyun 		return val;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (dlen == token->size) {
336*4882a593Smuzhiyun 		//debug("0\n");
337*4882a593Smuzhiyun 		return 0;
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 	//debug("%d\n", (int)dlen - (int)token->size);
340*4882a593Smuzhiyun 	return dlen - token->size; /* shorter -> negative */
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun /*
344*4882a593Smuzhiyun  * Tokenise an ASN.1 grammar
345*4882a593Smuzhiyun  */
tokenise(char * buffer,char * end)346*4882a593Smuzhiyun static void tokenise(char *buffer, char *end)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	struct token *tokens;
349*4882a593Smuzhiyun 	char *line, *nl, *start, *p, *q;
350*4882a593Smuzhiyun 	unsigned tix, lineno;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	/* Assume we're going to have half as many tokens as we have
353*4882a593Smuzhiyun 	 * characters
354*4882a593Smuzhiyun 	 */
355*4882a593Smuzhiyun 	token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
356*4882a593Smuzhiyun 	if (!tokens) {
357*4882a593Smuzhiyun 		perror(NULL);
358*4882a593Smuzhiyun 		exit(1);
359*4882a593Smuzhiyun 	}
360*4882a593Smuzhiyun 	tix = 0;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	lineno = 0;
363*4882a593Smuzhiyun 	while (buffer < end) {
364*4882a593Smuzhiyun 		/* First of all, break out a line */
365*4882a593Smuzhiyun 		lineno++;
366*4882a593Smuzhiyun 		line = buffer;
367*4882a593Smuzhiyun 		nl = memchr(line, '\n', end - buffer);
368*4882a593Smuzhiyun 		if (!nl) {
369*4882a593Smuzhiyun 			buffer = nl = end;
370*4882a593Smuzhiyun 		} else {
371*4882a593Smuzhiyun 			buffer = nl + 1;
372*4882a593Smuzhiyun 			*nl = '\0';
373*4882a593Smuzhiyun 		}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 		/* Remove "--" comments */
376*4882a593Smuzhiyun 		p = line;
377*4882a593Smuzhiyun 	next_comment:
378*4882a593Smuzhiyun 		while ((p = memchr(p, '-', nl - p))) {
379*4882a593Smuzhiyun 			if (p[1] == '-') {
380*4882a593Smuzhiyun 				/* Found a comment; see if there's a terminator */
381*4882a593Smuzhiyun 				q = p + 2;
382*4882a593Smuzhiyun 				while ((q = memchr(q, '-', nl - q))) {
383*4882a593Smuzhiyun 					if (q[1] == '-') {
384*4882a593Smuzhiyun 						/* There is - excise the comment */
385*4882a593Smuzhiyun 						q += 2;
386*4882a593Smuzhiyun 						memmove(p, q, nl - q);
387*4882a593Smuzhiyun 						goto next_comment;
388*4882a593Smuzhiyun 					}
389*4882a593Smuzhiyun 					q++;
390*4882a593Smuzhiyun 				}
391*4882a593Smuzhiyun 				*p = '\0';
392*4882a593Smuzhiyun 				nl = p;
393*4882a593Smuzhiyun 				break;
394*4882a593Smuzhiyun 			} else {
395*4882a593Smuzhiyun 				p++;
396*4882a593Smuzhiyun 			}
397*4882a593Smuzhiyun 		}
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 		p = line;
400*4882a593Smuzhiyun 		while (p < nl) {
401*4882a593Smuzhiyun 			/* Skip white space */
402*4882a593Smuzhiyun 			while (p < nl && isspace(*p))
403*4882a593Smuzhiyun 				*(p++) = 0;
404*4882a593Smuzhiyun 			if (p >= nl)
405*4882a593Smuzhiyun 				break;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 			tokens[tix].line = lineno;
408*4882a593Smuzhiyun 			start = p;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 			/* Handle string tokens */
411*4882a593Smuzhiyun 			if (isalpha(*p)) {
412*4882a593Smuzhiyun 				const char **dir;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 				/* Can be a directive, type name or element
415*4882a593Smuzhiyun 				 * name.  Find the end of the name.
416*4882a593Smuzhiyun 				 */
417*4882a593Smuzhiyun 				q = p + 1;
418*4882a593Smuzhiyun 				while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
419*4882a593Smuzhiyun 					q++;
420*4882a593Smuzhiyun 				tokens[tix].size = q - p;
421*4882a593Smuzhiyun 				p = q;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 				tokens[tix].content = malloc(tokens[tix].size + 1);
424*4882a593Smuzhiyun 				if (!tokens[tix].content) {
425*4882a593Smuzhiyun 					perror(NULL);
426*4882a593Smuzhiyun 					exit(1);
427*4882a593Smuzhiyun 				}
428*4882a593Smuzhiyun 				memcpy(tokens[tix].content, start, tokens[tix].size);
429*4882a593Smuzhiyun 				tokens[tix].content[tokens[tix].size] = 0;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 				/* If it begins with a lowercase letter then
432*4882a593Smuzhiyun 				 * it's an element name
433*4882a593Smuzhiyun 				 */
434*4882a593Smuzhiyun 				if (islower(tokens[tix].content[0])) {
435*4882a593Smuzhiyun 					tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
436*4882a593Smuzhiyun 					continue;
437*4882a593Smuzhiyun 				}
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 				/* Otherwise we need to search the directive
440*4882a593Smuzhiyun 				 * table
441*4882a593Smuzhiyun 				 */
442*4882a593Smuzhiyun 				dir = bsearch(&tokens[tix], directives,
443*4882a593Smuzhiyun 					      sizeof(directives) / sizeof(directives[1]),
444*4882a593Smuzhiyun 					      sizeof(directives[1]),
445*4882a593Smuzhiyun 					      directive_compare);
446*4882a593Smuzhiyun 				if (dir) {
447*4882a593Smuzhiyun 					tokens[tix++].token_type = dir - directives;
448*4882a593Smuzhiyun 					continue;
449*4882a593Smuzhiyun 				}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 				tokens[tix++].token_type = TOKEN_TYPE_NAME;
452*4882a593Smuzhiyun 				continue;
453*4882a593Smuzhiyun 			}
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 			/* Handle numbers */
456*4882a593Smuzhiyun 			if (isdigit(*p)) {
457*4882a593Smuzhiyun 				/* Find the end of the number */
458*4882a593Smuzhiyun 				q = p + 1;
459*4882a593Smuzhiyun 				while (q < nl && (isdigit(*q)))
460*4882a593Smuzhiyun 					q++;
461*4882a593Smuzhiyun 				tokens[tix].size = q - p;
462*4882a593Smuzhiyun 				p = q;
463*4882a593Smuzhiyun 				tokens[tix].content = malloc(tokens[tix].size + 1);
464*4882a593Smuzhiyun 				if (!tokens[tix].content) {
465*4882a593Smuzhiyun 					perror(NULL);
466*4882a593Smuzhiyun 					exit(1);
467*4882a593Smuzhiyun 				}
468*4882a593Smuzhiyun 				memcpy(tokens[tix].content, start, tokens[tix].size);
469*4882a593Smuzhiyun 				tokens[tix].content[tokens[tix].size] = 0;
470*4882a593Smuzhiyun 				tokens[tix++].token_type = TOKEN_NUMBER;
471*4882a593Smuzhiyun 				continue;
472*4882a593Smuzhiyun 			}
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 			if (nl - p >= 3) {
475*4882a593Smuzhiyun 				if (memcmp(p, "::=", 3) == 0) {
476*4882a593Smuzhiyun 					p += 3;
477*4882a593Smuzhiyun 					tokens[tix].size = 3;
478*4882a593Smuzhiyun 					tokens[tix].content = "::=";
479*4882a593Smuzhiyun 					tokens[tix++].token_type = TOKEN_ASSIGNMENT;
480*4882a593Smuzhiyun 					continue;
481*4882a593Smuzhiyun 				}
482*4882a593Smuzhiyun 			}
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 			if (nl - p >= 2) {
485*4882a593Smuzhiyun 				if (memcmp(p, "({", 2) == 0) {
486*4882a593Smuzhiyun 					p += 2;
487*4882a593Smuzhiyun 					tokens[tix].size = 2;
488*4882a593Smuzhiyun 					tokens[tix].content = "({";
489*4882a593Smuzhiyun 					tokens[tix++].token_type = TOKEN_OPEN_ACTION;
490*4882a593Smuzhiyun 					continue;
491*4882a593Smuzhiyun 				}
492*4882a593Smuzhiyun 				if (memcmp(p, "})", 2) == 0) {
493*4882a593Smuzhiyun 					p += 2;
494*4882a593Smuzhiyun 					tokens[tix].size = 2;
495*4882a593Smuzhiyun 					tokens[tix].content = "})";
496*4882a593Smuzhiyun 					tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
497*4882a593Smuzhiyun 					continue;
498*4882a593Smuzhiyun 				}
499*4882a593Smuzhiyun 			}
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 			if (nl - p >= 1) {
502*4882a593Smuzhiyun 				tokens[tix].size = 1;
503*4882a593Smuzhiyun 				switch (*p) {
504*4882a593Smuzhiyun 				case '{':
505*4882a593Smuzhiyun 					p += 1;
506*4882a593Smuzhiyun 					tokens[tix].content = "{";
507*4882a593Smuzhiyun 					tokens[tix++].token_type = TOKEN_OPEN_CURLY;
508*4882a593Smuzhiyun 					continue;
509*4882a593Smuzhiyun 				case '}':
510*4882a593Smuzhiyun 					p += 1;
511*4882a593Smuzhiyun 					tokens[tix].content = "}";
512*4882a593Smuzhiyun 					tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
513*4882a593Smuzhiyun 					continue;
514*4882a593Smuzhiyun 				case '[':
515*4882a593Smuzhiyun 					p += 1;
516*4882a593Smuzhiyun 					tokens[tix].content = "[";
517*4882a593Smuzhiyun 					tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
518*4882a593Smuzhiyun 					continue;
519*4882a593Smuzhiyun 				case ']':
520*4882a593Smuzhiyun 					p += 1;
521*4882a593Smuzhiyun 					tokens[tix].content = "]";
522*4882a593Smuzhiyun 					tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
523*4882a593Smuzhiyun 					continue;
524*4882a593Smuzhiyun 				case ',':
525*4882a593Smuzhiyun 					p += 1;
526*4882a593Smuzhiyun 					tokens[tix].content = ",";
527*4882a593Smuzhiyun 					tokens[tix++].token_type = TOKEN_COMMA;
528*4882a593Smuzhiyun 					continue;
529*4882a593Smuzhiyun 				default:
530*4882a593Smuzhiyun 					break;
531*4882a593Smuzhiyun 				}
532*4882a593Smuzhiyun 			}
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 			fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
535*4882a593Smuzhiyun 				filename, lineno, *p);
536*4882a593Smuzhiyun 			exit(1);
537*4882a593Smuzhiyun 		}
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	nr_tokens = tix;
541*4882a593Smuzhiyun 	verbose("Extracted %u tokens\n", nr_tokens);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun #if 0
544*4882a593Smuzhiyun 	{
545*4882a593Smuzhiyun 		int n;
546*4882a593Smuzhiyun 		for (n = 0; n < nr_tokens; n++)
547*4882a593Smuzhiyun 			debug("Token %3u: '%s'\n", n, token_list[n].content);
548*4882a593Smuzhiyun 	}
549*4882a593Smuzhiyun #endif
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun static void build_type_list(void);
553*4882a593Smuzhiyun static void parse(void);
554*4882a593Smuzhiyun static void dump_elements(void);
555*4882a593Smuzhiyun static void render(FILE *out, FILE *hdr);
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun /*
558*4882a593Smuzhiyun  *
559*4882a593Smuzhiyun  */
main(int argc,char ** argv)560*4882a593Smuzhiyun int main(int argc, char **argv)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun 	struct stat st;
563*4882a593Smuzhiyun 	ssize_t readlen;
564*4882a593Smuzhiyun 	FILE *out, *hdr;
565*4882a593Smuzhiyun 	char *buffer, *p;
566*4882a593Smuzhiyun 	char *kbuild_verbose;
567*4882a593Smuzhiyun 	int fd;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	kbuild_verbose = getenv("KBUILD_VERBOSE");
570*4882a593Smuzhiyun 	if (kbuild_verbose)
571*4882a593Smuzhiyun 		verbose_opt = atoi(kbuild_verbose);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	while (argc > 4) {
574*4882a593Smuzhiyun 		if (strcmp(argv[1], "-v") == 0)
575*4882a593Smuzhiyun 			verbose_opt = true;
576*4882a593Smuzhiyun 		else if (strcmp(argv[1], "-d") == 0)
577*4882a593Smuzhiyun 			debug_opt = true;
578*4882a593Smuzhiyun 		else
579*4882a593Smuzhiyun 			break;
580*4882a593Smuzhiyun 		memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *));
581*4882a593Smuzhiyun 		argc--;
582*4882a593Smuzhiyun 	}
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	if (argc != 4) {
585*4882a593Smuzhiyun 		fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n",
586*4882a593Smuzhiyun 			argv[0]);
587*4882a593Smuzhiyun 		exit(2);
588*4882a593Smuzhiyun 	}
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	filename = argv[1];
591*4882a593Smuzhiyun 	outputname = argv[2];
592*4882a593Smuzhiyun 	headername = argv[3];
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	fd = open(filename, O_RDONLY);
595*4882a593Smuzhiyun 	if (fd < 0) {
596*4882a593Smuzhiyun 		perror(filename);
597*4882a593Smuzhiyun 		exit(1);
598*4882a593Smuzhiyun 	}
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	if (fstat(fd, &st) < 0) {
601*4882a593Smuzhiyun 		perror(filename);
602*4882a593Smuzhiyun 		exit(1);
603*4882a593Smuzhiyun 	}
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	if (!(buffer = malloc(st.st_size + 1))) {
606*4882a593Smuzhiyun 		perror(NULL);
607*4882a593Smuzhiyun 		exit(1);
608*4882a593Smuzhiyun 	}
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	if ((readlen = read(fd, buffer, st.st_size)) < 0) {
611*4882a593Smuzhiyun 		perror(filename);
612*4882a593Smuzhiyun 		exit(1);
613*4882a593Smuzhiyun 	}
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	if (close(fd) < 0) {
616*4882a593Smuzhiyun 		perror(filename);
617*4882a593Smuzhiyun 		exit(1);
618*4882a593Smuzhiyun 	}
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	if (readlen != st.st_size) {
621*4882a593Smuzhiyun 		fprintf(stderr, "%s: Short read\n", filename);
622*4882a593Smuzhiyun 		exit(1);
623*4882a593Smuzhiyun 	}
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	p = strrchr(argv[1], '/');
626*4882a593Smuzhiyun 	p = p ? p + 1 : argv[1];
627*4882a593Smuzhiyun 	grammar_name = strdup(p);
628*4882a593Smuzhiyun 	if (!p) {
629*4882a593Smuzhiyun 		perror(NULL);
630*4882a593Smuzhiyun 		exit(1);
631*4882a593Smuzhiyun 	}
632*4882a593Smuzhiyun 	p = strchr(grammar_name, '.');
633*4882a593Smuzhiyun 	if (p)
634*4882a593Smuzhiyun 		*p = '\0';
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	buffer[readlen] = 0;
637*4882a593Smuzhiyun 	tokenise(buffer, buffer + readlen);
638*4882a593Smuzhiyun 	build_type_list();
639*4882a593Smuzhiyun 	parse();
640*4882a593Smuzhiyun 	dump_elements();
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	out = fopen(outputname, "w");
643*4882a593Smuzhiyun 	if (!out) {
644*4882a593Smuzhiyun 		perror(outputname);
645*4882a593Smuzhiyun 		exit(1);
646*4882a593Smuzhiyun 	}
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	hdr = fopen(headername, "w");
649*4882a593Smuzhiyun 	if (!hdr) {
650*4882a593Smuzhiyun 		perror(headername);
651*4882a593Smuzhiyun 		exit(1);
652*4882a593Smuzhiyun 	}
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	render(out, hdr);
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	if (fclose(out) < 0) {
657*4882a593Smuzhiyun 		perror(outputname);
658*4882a593Smuzhiyun 		exit(1);
659*4882a593Smuzhiyun 	}
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	if (fclose(hdr) < 0) {
662*4882a593Smuzhiyun 		perror(headername);
663*4882a593Smuzhiyun 		exit(1);
664*4882a593Smuzhiyun 	}
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	return 0;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun enum compound {
670*4882a593Smuzhiyun 	NOT_COMPOUND,
671*4882a593Smuzhiyun 	SET,
672*4882a593Smuzhiyun 	SET_OF,
673*4882a593Smuzhiyun 	SEQUENCE,
674*4882a593Smuzhiyun 	SEQUENCE_OF,
675*4882a593Smuzhiyun 	CHOICE,
676*4882a593Smuzhiyun 	ANY,
677*4882a593Smuzhiyun 	TYPE_REF,
678*4882a593Smuzhiyun 	TAG_OVERRIDE
679*4882a593Smuzhiyun };
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun struct element {
682*4882a593Smuzhiyun 	struct type	*type_def;
683*4882a593Smuzhiyun 	struct token	*name;
684*4882a593Smuzhiyun 	struct token	*type;
685*4882a593Smuzhiyun 	struct action	*action;
686*4882a593Smuzhiyun 	struct element	*children;
687*4882a593Smuzhiyun 	struct element	*next;
688*4882a593Smuzhiyun 	struct element	*render_next;
689*4882a593Smuzhiyun 	struct element	*list_next;
690*4882a593Smuzhiyun 	uint8_t		n_elements;
691*4882a593Smuzhiyun 	enum compound	compound : 8;
692*4882a593Smuzhiyun 	enum asn1_class	class : 8;
693*4882a593Smuzhiyun 	enum asn1_method method : 8;
694*4882a593Smuzhiyun 	uint8_t		tag;
695*4882a593Smuzhiyun 	unsigned	entry_index;
696*4882a593Smuzhiyun 	unsigned	flags;
697*4882a593Smuzhiyun #define ELEMENT_IMPLICIT	0x0001
698*4882a593Smuzhiyun #define ELEMENT_EXPLICIT	0x0002
699*4882a593Smuzhiyun #define ELEMENT_TAG_SPECIFIED	0x0004
700*4882a593Smuzhiyun #define ELEMENT_RENDERED	0x0008
701*4882a593Smuzhiyun #define ELEMENT_SKIPPABLE	0x0010
702*4882a593Smuzhiyun #define ELEMENT_CONDITIONAL	0x0020
703*4882a593Smuzhiyun };
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun struct type {
706*4882a593Smuzhiyun 	struct token	*name;
707*4882a593Smuzhiyun 	struct token	*def;
708*4882a593Smuzhiyun 	struct element	*element;
709*4882a593Smuzhiyun 	unsigned	ref_count;
710*4882a593Smuzhiyun 	unsigned	flags;
711*4882a593Smuzhiyun #define TYPE_STOP_MARKER	0x0001
712*4882a593Smuzhiyun #define TYPE_BEGIN		0x0002
713*4882a593Smuzhiyun };
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun static struct type *type_list;
716*4882a593Smuzhiyun static struct type **type_index;
717*4882a593Smuzhiyun static unsigned nr_types;
718*4882a593Smuzhiyun 
type_index_compare(const void * _a,const void * _b)719*4882a593Smuzhiyun static int type_index_compare(const void *_a, const void *_b)
720*4882a593Smuzhiyun {
721*4882a593Smuzhiyun 	const struct type *const *a = _a, *const *b = _b;
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	if ((*a)->name->size != (*b)->name->size)
724*4882a593Smuzhiyun 		return (*a)->name->size - (*b)->name->size;
725*4882a593Smuzhiyun 	else
726*4882a593Smuzhiyun 		return memcmp((*a)->name->content, (*b)->name->content,
727*4882a593Smuzhiyun 			      (*a)->name->size);
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun 
type_finder(const void * _key,const void * _ti)730*4882a593Smuzhiyun static int type_finder(const void *_key, const void *_ti)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun 	const struct token *token = _key;
733*4882a593Smuzhiyun 	const struct type *const *ti = _ti;
734*4882a593Smuzhiyun 	const struct type *type = *ti;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	if (token->size != type->name->size)
737*4882a593Smuzhiyun 		return token->size - type->name->size;
738*4882a593Smuzhiyun 	else
739*4882a593Smuzhiyun 		return memcmp(token->content, type->name->content,
740*4882a593Smuzhiyun 			      token->size);
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun /*
744*4882a593Smuzhiyun  * Build up a list of types and a sorted index to that list.
745*4882a593Smuzhiyun  */
build_type_list(void)746*4882a593Smuzhiyun static void build_type_list(void)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun 	struct type *types;
749*4882a593Smuzhiyun 	unsigned nr, t, n;
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	nr = 0;
752*4882a593Smuzhiyun 	for (n = 0; n < nr_tokens - 1; n++)
753*4882a593Smuzhiyun 		if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
754*4882a593Smuzhiyun 		    token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
755*4882a593Smuzhiyun 			nr++;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	if (nr == 0) {
758*4882a593Smuzhiyun 		fprintf(stderr, "%s: No defined types\n", filename);
759*4882a593Smuzhiyun 		exit(1);
760*4882a593Smuzhiyun 	}
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	nr_types = nr;
763*4882a593Smuzhiyun 	types = type_list = calloc(nr + 1, sizeof(type_list[0]));
764*4882a593Smuzhiyun 	if (!type_list) {
765*4882a593Smuzhiyun 		perror(NULL);
766*4882a593Smuzhiyun 		exit(1);
767*4882a593Smuzhiyun 	}
768*4882a593Smuzhiyun 	type_index = calloc(nr, sizeof(type_index[0]));
769*4882a593Smuzhiyun 	if (!type_index) {
770*4882a593Smuzhiyun 		perror(NULL);
771*4882a593Smuzhiyun 		exit(1);
772*4882a593Smuzhiyun 	}
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	t = 0;
775*4882a593Smuzhiyun 	types[t].flags |= TYPE_BEGIN;
776*4882a593Smuzhiyun 	for (n = 0; n < nr_tokens - 1; n++) {
777*4882a593Smuzhiyun 		if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
778*4882a593Smuzhiyun 		    token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
779*4882a593Smuzhiyun 			types[t].name = &token_list[n];
780*4882a593Smuzhiyun 			type_index[t] = &types[t];
781*4882a593Smuzhiyun 			t++;
782*4882a593Smuzhiyun 		}
783*4882a593Smuzhiyun 	}
784*4882a593Smuzhiyun 	types[t].name = &token_list[n + 1];
785*4882a593Smuzhiyun 	types[t].flags |= TYPE_STOP_MARKER;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	verbose("Extracted %u types\n", nr_types);
790*4882a593Smuzhiyun #if 0
791*4882a593Smuzhiyun 	for (n = 0; n < nr_types; n++) {
792*4882a593Smuzhiyun 		struct type *type = type_index[n];
793*4882a593Smuzhiyun 		debug("- %*.*s\n", type->name->content);
794*4882a593Smuzhiyun 	}
795*4882a593Smuzhiyun #endif
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun static struct element *parse_type(struct token **_cursor, struct token *stop,
799*4882a593Smuzhiyun 				  struct token *name);
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun /*
802*4882a593Smuzhiyun  * Parse the token stream
803*4882a593Smuzhiyun  */
parse(void)804*4882a593Smuzhiyun static void parse(void)
805*4882a593Smuzhiyun {
806*4882a593Smuzhiyun 	struct token *cursor;
807*4882a593Smuzhiyun 	struct type *type;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	/* Parse one type definition statement at a time */
810*4882a593Smuzhiyun 	type = type_list;
811*4882a593Smuzhiyun 	do {
812*4882a593Smuzhiyun 		cursor = type->name;
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 		if (cursor[0].token_type != TOKEN_TYPE_NAME ||
815*4882a593Smuzhiyun 		    cursor[1].token_type != TOKEN_ASSIGNMENT)
816*4882a593Smuzhiyun 			abort();
817*4882a593Smuzhiyun 		cursor += 2;
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 		type->element = parse_type(&cursor, type[1].name, NULL);
820*4882a593Smuzhiyun 		type->element->type_def = type;
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 		if (cursor != type[1].name) {
823*4882a593Smuzhiyun 			fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
824*4882a593Smuzhiyun 				filename, cursor->line, cursor->content);
825*4882a593Smuzhiyun 			exit(1);
826*4882a593Smuzhiyun 		}
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	} while (type++, !(type->flags & TYPE_STOP_MARKER));
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	verbose("Extracted %u actions\n", nr_actions);
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun static struct element *element_list;
834*4882a593Smuzhiyun 
alloc_elem(struct token * type)835*4882a593Smuzhiyun static struct element *alloc_elem(struct token *type)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun 	struct element *e = calloc(1, sizeof(*e));
838*4882a593Smuzhiyun 	if (!e) {
839*4882a593Smuzhiyun 		perror(NULL);
840*4882a593Smuzhiyun 		exit(1);
841*4882a593Smuzhiyun 	}
842*4882a593Smuzhiyun 	e->list_next = element_list;
843*4882a593Smuzhiyun 	element_list = e;
844*4882a593Smuzhiyun 	return e;
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun static struct element *parse_compound(struct token **_cursor, struct token *end,
848*4882a593Smuzhiyun 				      int alternates);
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun /*
851*4882a593Smuzhiyun  * Parse one type definition statement
852*4882a593Smuzhiyun  */
parse_type(struct token ** _cursor,struct token * end,struct token * name)853*4882a593Smuzhiyun static struct element *parse_type(struct token **_cursor, struct token *end,
854*4882a593Smuzhiyun 				  struct token *name)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun 	struct element *top, *element;
857*4882a593Smuzhiyun 	struct action *action, **ppaction;
858*4882a593Smuzhiyun 	struct token *cursor = *_cursor;
859*4882a593Smuzhiyun 	struct type **ref;
860*4882a593Smuzhiyun 	char *p;
861*4882a593Smuzhiyun 	int labelled = 0, implicit = 0;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	top = element = alloc_elem(cursor);
864*4882a593Smuzhiyun 	element->class = ASN1_UNIV;
865*4882a593Smuzhiyun 	element->method = ASN1_PRIM;
866*4882a593Smuzhiyun 	element->tag = token_to_tag[cursor->token_type];
867*4882a593Smuzhiyun 	element->name = name;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	/* Extract the tag value if one given */
870*4882a593Smuzhiyun 	if (cursor->token_type == TOKEN_OPEN_SQUARE) {
871*4882a593Smuzhiyun 		cursor++;
872*4882a593Smuzhiyun 		if (cursor >= end)
873*4882a593Smuzhiyun 			goto overrun_error;
874*4882a593Smuzhiyun 		switch (cursor->token_type) {
875*4882a593Smuzhiyun 		case DIRECTIVE_UNIVERSAL:
876*4882a593Smuzhiyun 			element->class = ASN1_UNIV;
877*4882a593Smuzhiyun 			cursor++;
878*4882a593Smuzhiyun 			break;
879*4882a593Smuzhiyun 		case DIRECTIVE_APPLICATION:
880*4882a593Smuzhiyun 			element->class = ASN1_APPL;
881*4882a593Smuzhiyun 			cursor++;
882*4882a593Smuzhiyun 			break;
883*4882a593Smuzhiyun 		case TOKEN_NUMBER:
884*4882a593Smuzhiyun 			element->class = ASN1_CONT;
885*4882a593Smuzhiyun 			break;
886*4882a593Smuzhiyun 		case DIRECTIVE_PRIVATE:
887*4882a593Smuzhiyun 			element->class = ASN1_PRIV;
888*4882a593Smuzhiyun 			cursor++;
889*4882a593Smuzhiyun 			break;
890*4882a593Smuzhiyun 		default:
891*4882a593Smuzhiyun 			fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
892*4882a593Smuzhiyun 				filename, cursor->line, cursor->content);
893*4882a593Smuzhiyun 			exit(1);
894*4882a593Smuzhiyun 		}
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 		if (cursor >= end)
897*4882a593Smuzhiyun 			goto overrun_error;
898*4882a593Smuzhiyun 		if (cursor->token_type != TOKEN_NUMBER) {
899*4882a593Smuzhiyun 			fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
900*4882a593Smuzhiyun 				filename, cursor->line, cursor->content);
901*4882a593Smuzhiyun 			exit(1);
902*4882a593Smuzhiyun 		}
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 		element->tag &= ~0x1f;
905*4882a593Smuzhiyun 		element->tag |= strtoul(cursor->content, &p, 10);
906*4882a593Smuzhiyun 		element->flags |= ELEMENT_TAG_SPECIFIED;
907*4882a593Smuzhiyun 		if (p - cursor->content != cursor->size)
908*4882a593Smuzhiyun 			abort();
909*4882a593Smuzhiyun 		cursor++;
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 		if (cursor >= end)
912*4882a593Smuzhiyun 			goto overrun_error;
913*4882a593Smuzhiyun 		if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
914*4882a593Smuzhiyun 			fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
915*4882a593Smuzhiyun 				filename, cursor->line, cursor->content);
916*4882a593Smuzhiyun 			exit(1);
917*4882a593Smuzhiyun 		}
918*4882a593Smuzhiyun 		cursor++;
919*4882a593Smuzhiyun 		if (cursor >= end)
920*4882a593Smuzhiyun 			goto overrun_error;
921*4882a593Smuzhiyun 		labelled = 1;
922*4882a593Smuzhiyun 	}
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	/* Handle implicit and explicit markers */
925*4882a593Smuzhiyun 	if (cursor->token_type == DIRECTIVE_IMPLICIT) {
926*4882a593Smuzhiyun 		element->flags |= ELEMENT_IMPLICIT;
927*4882a593Smuzhiyun 		implicit = 1;
928*4882a593Smuzhiyun 		cursor++;
929*4882a593Smuzhiyun 		if (cursor >= end)
930*4882a593Smuzhiyun 			goto overrun_error;
931*4882a593Smuzhiyun 	} else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
932*4882a593Smuzhiyun 		element->flags |= ELEMENT_EXPLICIT;
933*4882a593Smuzhiyun 		cursor++;
934*4882a593Smuzhiyun 		if (cursor >= end)
935*4882a593Smuzhiyun 			goto overrun_error;
936*4882a593Smuzhiyun 	}
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 	if (labelled) {
939*4882a593Smuzhiyun 		if (!implicit)
940*4882a593Smuzhiyun 			element->method |= ASN1_CONS;
941*4882a593Smuzhiyun 		element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
942*4882a593Smuzhiyun 		element->children = alloc_elem(cursor);
943*4882a593Smuzhiyun 		element = element->children;
944*4882a593Smuzhiyun 		element->class = ASN1_UNIV;
945*4882a593Smuzhiyun 		element->method = ASN1_PRIM;
946*4882a593Smuzhiyun 		element->tag = token_to_tag[cursor->token_type];
947*4882a593Smuzhiyun 		element->name = name;
948*4882a593Smuzhiyun 	}
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	/* Extract the type we're expecting here */
951*4882a593Smuzhiyun 	element->type = cursor;
952*4882a593Smuzhiyun 	switch (cursor->token_type) {
953*4882a593Smuzhiyun 	case DIRECTIVE_ANY:
954*4882a593Smuzhiyun 		element->compound = ANY;
955*4882a593Smuzhiyun 		cursor++;
956*4882a593Smuzhiyun 		break;
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	case DIRECTIVE_NULL:
959*4882a593Smuzhiyun 	case DIRECTIVE_BOOLEAN:
960*4882a593Smuzhiyun 	case DIRECTIVE_ENUMERATED:
961*4882a593Smuzhiyun 	case DIRECTIVE_INTEGER:
962*4882a593Smuzhiyun 		element->compound = NOT_COMPOUND;
963*4882a593Smuzhiyun 		cursor++;
964*4882a593Smuzhiyun 		break;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	case DIRECTIVE_EXTERNAL:
967*4882a593Smuzhiyun 		element->method = ASN1_CONS;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	case DIRECTIVE_BMPString:
970*4882a593Smuzhiyun 	case DIRECTIVE_GeneralString:
971*4882a593Smuzhiyun 	case DIRECTIVE_GraphicString:
972*4882a593Smuzhiyun 	case DIRECTIVE_IA5String:
973*4882a593Smuzhiyun 	case DIRECTIVE_ISO646String:
974*4882a593Smuzhiyun 	case DIRECTIVE_NumericString:
975*4882a593Smuzhiyun 	case DIRECTIVE_PrintableString:
976*4882a593Smuzhiyun 	case DIRECTIVE_T61String:
977*4882a593Smuzhiyun 	case DIRECTIVE_TeletexString:
978*4882a593Smuzhiyun 	case DIRECTIVE_UniversalString:
979*4882a593Smuzhiyun 	case DIRECTIVE_UTF8String:
980*4882a593Smuzhiyun 	case DIRECTIVE_VideotexString:
981*4882a593Smuzhiyun 	case DIRECTIVE_VisibleString:
982*4882a593Smuzhiyun 	case DIRECTIVE_ObjectDescriptor:
983*4882a593Smuzhiyun 	case DIRECTIVE_GeneralizedTime:
984*4882a593Smuzhiyun 	case DIRECTIVE_UTCTime:
985*4882a593Smuzhiyun 		element->compound = NOT_COMPOUND;
986*4882a593Smuzhiyun 		cursor++;
987*4882a593Smuzhiyun 		break;
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 	case DIRECTIVE_BIT:
990*4882a593Smuzhiyun 	case DIRECTIVE_OCTET:
991*4882a593Smuzhiyun 		element->compound = NOT_COMPOUND;
992*4882a593Smuzhiyun 		cursor++;
993*4882a593Smuzhiyun 		if (cursor >= end)
994*4882a593Smuzhiyun 			goto overrun_error;
995*4882a593Smuzhiyun 		if (cursor->token_type != DIRECTIVE_STRING)
996*4882a593Smuzhiyun 			goto parse_error;
997*4882a593Smuzhiyun 		cursor++;
998*4882a593Smuzhiyun 		break;
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun 	case DIRECTIVE_OBJECT:
1001*4882a593Smuzhiyun 		element->compound = NOT_COMPOUND;
1002*4882a593Smuzhiyun 		cursor++;
1003*4882a593Smuzhiyun 		if (cursor >= end)
1004*4882a593Smuzhiyun 			goto overrun_error;
1005*4882a593Smuzhiyun 		if (cursor->token_type != DIRECTIVE_IDENTIFIER)
1006*4882a593Smuzhiyun 			goto parse_error;
1007*4882a593Smuzhiyun 		cursor++;
1008*4882a593Smuzhiyun 		break;
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	case TOKEN_TYPE_NAME:
1011*4882a593Smuzhiyun 		element->compound = TYPE_REF;
1012*4882a593Smuzhiyun 		ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
1013*4882a593Smuzhiyun 			      type_finder);
1014*4882a593Smuzhiyun 		if (!ref) {
1015*4882a593Smuzhiyun 			fprintf(stderr, "%s:%d: Type '%s' undefined\n",
1016*4882a593Smuzhiyun 				filename, cursor->line, cursor->content);
1017*4882a593Smuzhiyun 			exit(1);
1018*4882a593Smuzhiyun 		}
1019*4882a593Smuzhiyun 		cursor->type = *ref;
1020*4882a593Smuzhiyun 		(*ref)->ref_count++;
1021*4882a593Smuzhiyun 		cursor++;
1022*4882a593Smuzhiyun 		break;
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	case DIRECTIVE_CHOICE:
1025*4882a593Smuzhiyun 		element->compound = CHOICE;
1026*4882a593Smuzhiyun 		cursor++;
1027*4882a593Smuzhiyun 		element->children = parse_compound(&cursor, end, 1);
1028*4882a593Smuzhiyun 		break;
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	case DIRECTIVE_SEQUENCE:
1031*4882a593Smuzhiyun 		element->compound = SEQUENCE;
1032*4882a593Smuzhiyun 		element->method = ASN1_CONS;
1033*4882a593Smuzhiyun 		cursor++;
1034*4882a593Smuzhiyun 		if (cursor >= end)
1035*4882a593Smuzhiyun 			goto overrun_error;
1036*4882a593Smuzhiyun 		if (cursor->token_type == DIRECTIVE_OF) {
1037*4882a593Smuzhiyun 			element->compound = SEQUENCE_OF;
1038*4882a593Smuzhiyun 			cursor++;
1039*4882a593Smuzhiyun 			if (cursor >= end)
1040*4882a593Smuzhiyun 				goto overrun_error;
1041*4882a593Smuzhiyun 			element->children = parse_type(&cursor, end, NULL);
1042*4882a593Smuzhiyun 		} else {
1043*4882a593Smuzhiyun 			element->children = parse_compound(&cursor, end, 0);
1044*4882a593Smuzhiyun 		}
1045*4882a593Smuzhiyun 		break;
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun 	case DIRECTIVE_SET:
1048*4882a593Smuzhiyun 		element->compound = SET;
1049*4882a593Smuzhiyun 		element->method = ASN1_CONS;
1050*4882a593Smuzhiyun 		cursor++;
1051*4882a593Smuzhiyun 		if (cursor >= end)
1052*4882a593Smuzhiyun 			goto overrun_error;
1053*4882a593Smuzhiyun 		if (cursor->token_type == DIRECTIVE_OF) {
1054*4882a593Smuzhiyun 			element->compound = SET_OF;
1055*4882a593Smuzhiyun 			cursor++;
1056*4882a593Smuzhiyun 			if (cursor >= end)
1057*4882a593Smuzhiyun 				goto parse_error;
1058*4882a593Smuzhiyun 			element->children = parse_type(&cursor, end, NULL);
1059*4882a593Smuzhiyun 		} else {
1060*4882a593Smuzhiyun 			element->children = parse_compound(&cursor, end, 1);
1061*4882a593Smuzhiyun 		}
1062*4882a593Smuzhiyun 		break;
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 	default:
1065*4882a593Smuzhiyun 		fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
1066*4882a593Smuzhiyun 			filename, cursor->line, cursor->content);
1067*4882a593Smuzhiyun 		exit(1);
1068*4882a593Smuzhiyun 	}
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	/* Handle elements that are optional */
1071*4882a593Smuzhiyun 	if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1072*4882a593Smuzhiyun 			     cursor->token_type == DIRECTIVE_DEFAULT)
1073*4882a593Smuzhiyun 	    ) {
1074*4882a593Smuzhiyun 		cursor++;
1075*4882a593Smuzhiyun 		top->flags |= ELEMENT_SKIPPABLE;
1076*4882a593Smuzhiyun 	}
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 	if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
1079*4882a593Smuzhiyun 		cursor++;
1080*4882a593Smuzhiyun 		if (cursor >= end)
1081*4882a593Smuzhiyun 			goto overrun_error;
1082*4882a593Smuzhiyun 		if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1083*4882a593Smuzhiyun 			fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
1084*4882a593Smuzhiyun 				filename, cursor->line, cursor->content);
1085*4882a593Smuzhiyun 			exit(1);
1086*4882a593Smuzhiyun 		}
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 		action = malloc(sizeof(struct action));
1089*4882a593Smuzhiyun 		if (!action) {
1090*4882a593Smuzhiyun 			perror(NULL);
1091*4882a593Smuzhiyun 			exit(1);
1092*4882a593Smuzhiyun 		}
1093*4882a593Smuzhiyun 		action->index = 0;
1094*4882a593Smuzhiyun 		action->name = cursor->content;
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 		for (ppaction = &action_list;
1097*4882a593Smuzhiyun 		     *ppaction;
1098*4882a593Smuzhiyun 		     ppaction = &(*ppaction)->next
1099*4882a593Smuzhiyun 		     ) {
1100*4882a593Smuzhiyun 			int cmp = strcmp(action->name, (*ppaction)->name);
1101*4882a593Smuzhiyun 			if (cmp == 0) {
1102*4882a593Smuzhiyun 				free(action);
1103*4882a593Smuzhiyun 				action = *ppaction;
1104*4882a593Smuzhiyun 				goto found;
1105*4882a593Smuzhiyun 			}
1106*4882a593Smuzhiyun 			if (cmp < 0) {
1107*4882a593Smuzhiyun 				action->next = *ppaction;
1108*4882a593Smuzhiyun 				*ppaction = action;
1109*4882a593Smuzhiyun 				nr_actions++;
1110*4882a593Smuzhiyun 				goto found;
1111*4882a593Smuzhiyun 			}
1112*4882a593Smuzhiyun 		}
1113*4882a593Smuzhiyun 		action->next = NULL;
1114*4882a593Smuzhiyun 		*ppaction = action;
1115*4882a593Smuzhiyun 		nr_actions++;
1116*4882a593Smuzhiyun 	found:
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 		element->action = action;
1119*4882a593Smuzhiyun 		cursor->action = action;
1120*4882a593Smuzhiyun 		cursor++;
1121*4882a593Smuzhiyun 		if (cursor >= end)
1122*4882a593Smuzhiyun 			goto overrun_error;
1123*4882a593Smuzhiyun 		if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1124*4882a593Smuzhiyun 			fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
1125*4882a593Smuzhiyun 				filename, cursor->line, cursor->content);
1126*4882a593Smuzhiyun 			exit(1);
1127*4882a593Smuzhiyun 		}
1128*4882a593Smuzhiyun 		cursor++;
1129*4882a593Smuzhiyun 	}
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun 	*_cursor = cursor;
1132*4882a593Smuzhiyun 	return top;
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun parse_error:
1135*4882a593Smuzhiyun 	fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
1136*4882a593Smuzhiyun 		filename, cursor->line, cursor->content);
1137*4882a593Smuzhiyun 	exit(1);
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun overrun_error:
1140*4882a593Smuzhiyun 	fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1141*4882a593Smuzhiyun 	exit(1);
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun 
1144*4882a593Smuzhiyun /*
1145*4882a593Smuzhiyun  * Parse a compound type list
1146*4882a593Smuzhiyun  */
parse_compound(struct token ** _cursor,struct token * end,int alternates)1147*4882a593Smuzhiyun static struct element *parse_compound(struct token **_cursor, struct token *end,
1148*4882a593Smuzhiyun 				      int alternates)
1149*4882a593Smuzhiyun {
1150*4882a593Smuzhiyun 	struct element *children, **child_p = &children, *element;
1151*4882a593Smuzhiyun 	struct token *cursor = *_cursor, *name;
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	if (cursor->token_type != TOKEN_OPEN_CURLY) {
1154*4882a593Smuzhiyun 		fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
1155*4882a593Smuzhiyun 			filename, cursor->line, cursor->content);
1156*4882a593Smuzhiyun 		exit(1);
1157*4882a593Smuzhiyun 	}
1158*4882a593Smuzhiyun 	cursor++;
1159*4882a593Smuzhiyun 	if (cursor >= end)
1160*4882a593Smuzhiyun 		goto overrun_error;
1161*4882a593Smuzhiyun 
1162*4882a593Smuzhiyun 	if (cursor->token_type == TOKEN_OPEN_CURLY) {
1163*4882a593Smuzhiyun 		fprintf(stderr, "%s:%d: Empty compound\n",
1164*4882a593Smuzhiyun 			filename, cursor->line);
1165*4882a593Smuzhiyun 		exit(1);
1166*4882a593Smuzhiyun 	}
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 	for (;;) {
1169*4882a593Smuzhiyun 		name = NULL;
1170*4882a593Smuzhiyun 		if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1171*4882a593Smuzhiyun 			name = cursor;
1172*4882a593Smuzhiyun 			cursor++;
1173*4882a593Smuzhiyun 			if (cursor >= end)
1174*4882a593Smuzhiyun 				goto overrun_error;
1175*4882a593Smuzhiyun 		}
1176*4882a593Smuzhiyun 
1177*4882a593Smuzhiyun 		element = parse_type(&cursor, end, name);
1178*4882a593Smuzhiyun 		if (alternates)
1179*4882a593Smuzhiyun 			element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun 		*child_p = element;
1182*4882a593Smuzhiyun 		child_p = &element->next;
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 		if (cursor >= end)
1185*4882a593Smuzhiyun 			goto overrun_error;
1186*4882a593Smuzhiyun 		if (cursor->token_type != TOKEN_COMMA)
1187*4882a593Smuzhiyun 			break;
1188*4882a593Smuzhiyun 		cursor++;
1189*4882a593Smuzhiyun 		if (cursor >= end)
1190*4882a593Smuzhiyun 			goto overrun_error;
1191*4882a593Smuzhiyun 	}
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	children->flags &= ~ELEMENT_CONDITIONAL;
1194*4882a593Smuzhiyun 
1195*4882a593Smuzhiyun 	if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1196*4882a593Smuzhiyun 		fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
1197*4882a593Smuzhiyun 			filename, cursor->line, cursor->content);
1198*4882a593Smuzhiyun 		exit(1);
1199*4882a593Smuzhiyun 	}
1200*4882a593Smuzhiyun 	cursor++;
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	*_cursor = cursor;
1203*4882a593Smuzhiyun 	return children;
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun overrun_error:
1206*4882a593Smuzhiyun 	fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1207*4882a593Smuzhiyun 	exit(1);
1208*4882a593Smuzhiyun }
1209*4882a593Smuzhiyun 
dump_element(const struct element * e,int level)1210*4882a593Smuzhiyun static void dump_element(const struct element *e, int level)
1211*4882a593Smuzhiyun {
1212*4882a593Smuzhiyun 	const struct element *c;
1213*4882a593Smuzhiyun 	const struct type *t = e->type_def;
1214*4882a593Smuzhiyun 	const char *name = e->name ? e->name->content : ".";
1215*4882a593Smuzhiyun 	const char *tname = t && t->name ? t->name->content : ".";
1216*4882a593Smuzhiyun 	char tag[32];
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 	if (e->class == 0 && e->method == 0 && e->tag == 0)
1219*4882a593Smuzhiyun 		strcpy(tag, "<...>");
1220*4882a593Smuzhiyun 	else if (e->class == ASN1_UNIV)
1221*4882a593Smuzhiyun 		sprintf(tag, "%s %s %s",
1222*4882a593Smuzhiyun 			asn1_classes[e->class],
1223*4882a593Smuzhiyun 			asn1_methods[e->method],
1224*4882a593Smuzhiyun 			asn1_universal_tags[e->tag]);
1225*4882a593Smuzhiyun 	else
1226*4882a593Smuzhiyun 		sprintf(tag, "%s %s %u",
1227*4882a593Smuzhiyun 			asn1_classes[e->class],
1228*4882a593Smuzhiyun 			asn1_methods[e->method],
1229*4882a593Smuzhiyun 			e->tag);
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun 	printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
1232*4882a593Smuzhiyun 	       e->flags & ELEMENT_IMPLICIT ? 'I' : '-',
1233*4882a593Smuzhiyun 	       e->flags & ELEMENT_EXPLICIT ? 'E' : '-',
1234*4882a593Smuzhiyun 	       e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-',
1235*4882a593Smuzhiyun 	       e->flags & ELEMENT_SKIPPABLE ? 'S' : '-',
1236*4882a593Smuzhiyun 	       e->flags & ELEMENT_CONDITIONAL ? 'C' : '-',
1237*4882a593Smuzhiyun 	       "-tTqQcaro"[e->compound],
1238*4882a593Smuzhiyun 	       level, "",
1239*4882a593Smuzhiyun 	       tag,
1240*4882a593Smuzhiyun 	       tname,
1241*4882a593Smuzhiyun 	       name,
1242*4882a593Smuzhiyun 	       e->action ? e->action->name : "");
1243*4882a593Smuzhiyun 	if (e->compound == TYPE_REF)
1244*4882a593Smuzhiyun 		dump_element(e->type->type->element, level + 3);
1245*4882a593Smuzhiyun 	else
1246*4882a593Smuzhiyun 		for (c = e->children; c; c = c->next)
1247*4882a593Smuzhiyun 			dump_element(c, level + 3);
1248*4882a593Smuzhiyun }
1249*4882a593Smuzhiyun 
dump_elements(void)1250*4882a593Smuzhiyun static void dump_elements(void)
1251*4882a593Smuzhiyun {
1252*4882a593Smuzhiyun 	if (debug_opt)
1253*4882a593Smuzhiyun 		dump_element(type_list[0].element, 0);
1254*4882a593Smuzhiyun }
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun static void render_element(FILE *out, struct element *e, struct element *tag);
1257*4882a593Smuzhiyun static void render_out_of_line_list(FILE *out);
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun static int nr_entries;
1260*4882a593Smuzhiyun static int render_depth = 1;
1261*4882a593Smuzhiyun static struct element *render_list, **render_list_p = &render_list;
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun __attribute__((format(printf, 2, 3)))
render_opcode(FILE * out,const char * fmt,...)1264*4882a593Smuzhiyun static void render_opcode(FILE *out, const char *fmt, ...)
1265*4882a593Smuzhiyun {
1266*4882a593Smuzhiyun 	va_list va;
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	if (out) {
1269*4882a593Smuzhiyun 		fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1270*4882a593Smuzhiyun 		va_start(va, fmt);
1271*4882a593Smuzhiyun 		vfprintf(out, fmt, va);
1272*4882a593Smuzhiyun 		va_end(va);
1273*4882a593Smuzhiyun 	}
1274*4882a593Smuzhiyun 	nr_entries++;
1275*4882a593Smuzhiyun }
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun __attribute__((format(printf, 2, 3)))
render_more(FILE * out,const char * fmt,...)1278*4882a593Smuzhiyun static void render_more(FILE *out, const char *fmt, ...)
1279*4882a593Smuzhiyun {
1280*4882a593Smuzhiyun 	va_list va;
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 	if (out) {
1283*4882a593Smuzhiyun 		va_start(va, fmt);
1284*4882a593Smuzhiyun 		vfprintf(out, fmt, va);
1285*4882a593Smuzhiyun 		va_end(va);
1286*4882a593Smuzhiyun 	}
1287*4882a593Smuzhiyun }
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun /*
1290*4882a593Smuzhiyun  * Render the grammar into a state machine definition.
1291*4882a593Smuzhiyun  */
render(FILE * out,FILE * hdr)1292*4882a593Smuzhiyun static void render(FILE *out, FILE *hdr)
1293*4882a593Smuzhiyun {
1294*4882a593Smuzhiyun 	struct element *e;
1295*4882a593Smuzhiyun 	struct action *action;
1296*4882a593Smuzhiyun 	struct type *root;
1297*4882a593Smuzhiyun 	int index;
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun 	fprintf(hdr, "/*\n");
1300*4882a593Smuzhiyun 	fprintf(hdr, " * Automatically generated by asn1_compiler.  Do not edit\n");
1301*4882a593Smuzhiyun 	fprintf(hdr, " *\n");
1302*4882a593Smuzhiyun 	fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
1303*4882a593Smuzhiyun 	fprintf(hdr, " */\n");
1304*4882a593Smuzhiyun 	fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
1305*4882a593Smuzhiyun 	fprintf(hdr, "\n");
1306*4882a593Smuzhiyun 	fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
1307*4882a593Smuzhiyun 	if (ferror(hdr)) {
1308*4882a593Smuzhiyun 		perror(headername);
1309*4882a593Smuzhiyun 		exit(1);
1310*4882a593Smuzhiyun 	}
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun 	fprintf(out, "/*\n");
1313*4882a593Smuzhiyun 	fprintf(out, " * Automatically generated by asn1_compiler.  Do not edit\n");
1314*4882a593Smuzhiyun 	fprintf(out, " *\n");
1315*4882a593Smuzhiyun 	fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
1316*4882a593Smuzhiyun 	fprintf(out, " */\n");
1317*4882a593Smuzhiyun 	fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
1318*4882a593Smuzhiyun 	fprintf(out, "#include \"%s.asn1.h\"\n", grammar_name);
1319*4882a593Smuzhiyun 	fprintf(out, "\n");
1320*4882a593Smuzhiyun 	if (ferror(out)) {
1321*4882a593Smuzhiyun 		perror(outputname);
1322*4882a593Smuzhiyun 		exit(1);
1323*4882a593Smuzhiyun 	}
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 	/* Tabulate the action functions we might have to call */
1326*4882a593Smuzhiyun 	fprintf(hdr, "\n");
1327*4882a593Smuzhiyun 	index = 0;
1328*4882a593Smuzhiyun 	for (action = action_list; action; action = action->next) {
1329*4882a593Smuzhiyun 		action->index = index++;
1330*4882a593Smuzhiyun 		fprintf(hdr,
1331*4882a593Smuzhiyun 			"extern int %s(void *, size_t, unsigned char,"
1332*4882a593Smuzhiyun 			" const void *, size_t);\n",
1333*4882a593Smuzhiyun 			action->name);
1334*4882a593Smuzhiyun 	}
1335*4882a593Smuzhiyun 	fprintf(hdr, "\n");
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun 	fprintf(out, "enum %s_actions {\n", grammar_name);
1338*4882a593Smuzhiyun 	for (action = action_list; action; action = action->next)
1339*4882a593Smuzhiyun 		fprintf(out, "\tACT_%s = %u,\n",
1340*4882a593Smuzhiyun 			action->name, action->index);
1341*4882a593Smuzhiyun 	fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
1342*4882a593Smuzhiyun 	fprintf(out, "};\n");
1343*4882a593Smuzhiyun 
1344*4882a593Smuzhiyun 	fprintf(out, "\n");
1345*4882a593Smuzhiyun 	fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1346*4882a593Smuzhiyun 		grammar_name, grammar_name);
1347*4882a593Smuzhiyun 	for (action = action_list; action; action = action->next)
1348*4882a593Smuzhiyun 		fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
1349*4882a593Smuzhiyun 	fprintf(out, "};\n");
1350*4882a593Smuzhiyun 
1351*4882a593Smuzhiyun 	if (ferror(out)) {
1352*4882a593Smuzhiyun 		perror(outputname);
1353*4882a593Smuzhiyun 		exit(1);
1354*4882a593Smuzhiyun 	}
1355*4882a593Smuzhiyun 
1356*4882a593Smuzhiyun 	/* We do two passes - the first one calculates all the offsets */
1357*4882a593Smuzhiyun 	verbose("Pass 1\n");
1358*4882a593Smuzhiyun 	nr_entries = 0;
1359*4882a593Smuzhiyun 	root = &type_list[0];
1360*4882a593Smuzhiyun 	render_element(NULL, root->element, NULL);
1361*4882a593Smuzhiyun 	render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
1362*4882a593Smuzhiyun 	render_out_of_line_list(NULL);
1363*4882a593Smuzhiyun 
1364*4882a593Smuzhiyun 	for (e = element_list; e; e = e->list_next)
1365*4882a593Smuzhiyun 		e->flags &= ~ELEMENT_RENDERED;
1366*4882a593Smuzhiyun 
1367*4882a593Smuzhiyun 	/* And then we actually render */
1368*4882a593Smuzhiyun 	verbose("Pass 2\n");
1369*4882a593Smuzhiyun 	fprintf(out, "\n");
1370*4882a593Smuzhiyun 	fprintf(out, "static const unsigned char %s_machine[] = {\n",
1371*4882a593Smuzhiyun 		grammar_name);
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 	nr_entries = 0;
1374*4882a593Smuzhiyun 	root = &type_list[0];
1375*4882a593Smuzhiyun 	render_element(out, root->element, NULL);
1376*4882a593Smuzhiyun 	render_opcode(out, "ASN1_OP_COMPLETE,\n");
1377*4882a593Smuzhiyun 	render_out_of_line_list(out);
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun 	fprintf(out, "};\n");
1380*4882a593Smuzhiyun 
1381*4882a593Smuzhiyun 	fprintf(out, "\n");
1382*4882a593Smuzhiyun 	fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
1383*4882a593Smuzhiyun 	fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
1384*4882a593Smuzhiyun 	fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
1385*4882a593Smuzhiyun 	fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
1386*4882a593Smuzhiyun 	fprintf(out, "};\n");
1387*4882a593Smuzhiyun }
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun /*
1390*4882a593Smuzhiyun  * Render the out-of-line elements
1391*4882a593Smuzhiyun  */
render_out_of_line_list(FILE * out)1392*4882a593Smuzhiyun static void render_out_of_line_list(FILE *out)
1393*4882a593Smuzhiyun {
1394*4882a593Smuzhiyun 	struct element *e, *ce;
1395*4882a593Smuzhiyun 	const char *act;
1396*4882a593Smuzhiyun 	int entry;
1397*4882a593Smuzhiyun 
1398*4882a593Smuzhiyun 	while ((e = render_list)) {
1399*4882a593Smuzhiyun 		render_list = e->render_next;
1400*4882a593Smuzhiyun 		if (!render_list)
1401*4882a593Smuzhiyun 			render_list_p = &render_list;
1402*4882a593Smuzhiyun 
1403*4882a593Smuzhiyun 		render_more(out, "\n");
1404*4882a593Smuzhiyun 		e->entry_index = entry = nr_entries;
1405*4882a593Smuzhiyun 		render_depth++;
1406*4882a593Smuzhiyun 		for (ce = e->children; ce; ce = ce->next)
1407*4882a593Smuzhiyun 			render_element(out, ce, NULL);
1408*4882a593Smuzhiyun 		render_depth--;
1409*4882a593Smuzhiyun 
1410*4882a593Smuzhiyun 		act = e->action ? "_ACT" : "";
1411*4882a593Smuzhiyun 		switch (e->compound) {
1412*4882a593Smuzhiyun 		case SEQUENCE:
1413*4882a593Smuzhiyun 			render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1414*4882a593Smuzhiyun 			break;
1415*4882a593Smuzhiyun 		case SEQUENCE_OF:
1416*4882a593Smuzhiyun 			render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1417*4882a593Smuzhiyun 			render_opcode(out, "_jump_target(%u),\n", entry);
1418*4882a593Smuzhiyun 			break;
1419*4882a593Smuzhiyun 		case SET:
1420*4882a593Smuzhiyun 			render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1421*4882a593Smuzhiyun 			break;
1422*4882a593Smuzhiyun 		case SET_OF:
1423*4882a593Smuzhiyun 			render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1424*4882a593Smuzhiyun 			render_opcode(out, "_jump_target(%u),\n", entry);
1425*4882a593Smuzhiyun 			break;
1426*4882a593Smuzhiyun 		default:
1427*4882a593Smuzhiyun 			break;
1428*4882a593Smuzhiyun 		}
1429*4882a593Smuzhiyun 		if (e->action)
1430*4882a593Smuzhiyun 			render_opcode(out, "_action(ACT_%s),\n",
1431*4882a593Smuzhiyun 				      e->action->name);
1432*4882a593Smuzhiyun 		render_opcode(out, "ASN1_OP_RETURN,\n");
1433*4882a593Smuzhiyun 	}
1434*4882a593Smuzhiyun }
1435*4882a593Smuzhiyun 
1436*4882a593Smuzhiyun /*
1437*4882a593Smuzhiyun  * Render an element.
1438*4882a593Smuzhiyun  */
render_element(FILE * out,struct element * e,struct element * tag)1439*4882a593Smuzhiyun static void render_element(FILE *out, struct element *e, struct element *tag)
1440*4882a593Smuzhiyun {
1441*4882a593Smuzhiyun 	struct element *ec, *x;
1442*4882a593Smuzhiyun 	const char *cond, *act;
1443*4882a593Smuzhiyun 	int entry, skippable = 0, outofline = 0;
1444*4882a593Smuzhiyun 
1445*4882a593Smuzhiyun 	if (e->flags & ELEMENT_SKIPPABLE ||
1446*4882a593Smuzhiyun 	    (tag && tag->flags & ELEMENT_SKIPPABLE))
1447*4882a593Smuzhiyun 		skippable = 1;
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 	if ((e->type_def && e->type_def->ref_count > 1) ||
1450*4882a593Smuzhiyun 	    skippable)
1451*4882a593Smuzhiyun 		outofline = 1;
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun 	if (e->type_def && out) {
1454*4882a593Smuzhiyun 		render_more(out, "\t// %s\n", e->type_def->name->content);
1455*4882a593Smuzhiyun 	}
1456*4882a593Smuzhiyun 
1457*4882a593Smuzhiyun 	/* Render the operation */
1458*4882a593Smuzhiyun 	cond = (e->flags & ELEMENT_CONDITIONAL ||
1459*4882a593Smuzhiyun 		(tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
1460*4882a593Smuzhiyun 	act = e->action ? "_ACT" : "";
1461*4882a593Smuzhiyun 	switch (e->compound) {
1462*4882a593Smuzhiyun 	case ANY:
1463*4882a593Smuzhiyun 		render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
1464*4882a593Smuzhiyun 			      cond, act, skippable ? "_OR_SKIP" : "");
1465*4882a593Smuzhiyun 		if (e->name)
1466*4882a593Smuzhiyun 			render_more(out, "\t\t// %s", e->name->content);
1467*4882a593Smuzhiyun 		render_more(out, "\n");
1468*4882a593Smuzhiyun 		goto dont_render_tag;
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun 	case TAG_OVERRIDE:
1471*4882a593Smuzhiyun 		render_element(out, e->children, e);
1472*4882a593Smuzhiyun 		return;
1473*4882a593Smuzhiyun 
1474*4882a593Smuzhiyun 	case SEQUENCE:
1475*4882a593Smuzhiyun 	case SEQUENCE_OF:
1476*4882a593Smuzhiyun 	case SET:
1477*4882a593Smuzhiyun 	case SET_OF:
1478*4882a593Smuzhiyun 		render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1479*4882a593Smuzhiyun 			      cond,
1480*4882a593Smuzhiyun 			      outofline ? "_JUMP" : "",
1481*4882a593Smuzhiyun 			      skippable ? "_OR_SKIP" : "");
1482*4882a593Smuzhiyun 		break;
1483*4882a593Smuzhiyun 
1484*4882a593Smuzhiyun 	case CHOICE:
1485*4882a593Smuzhiyun 		goto dont_render_tag;
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun 	case TYPE_REF:
1488*4882a593Smuzhiyun 		if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1489*4882a593Smuzhiyun 			goto dont_render_tag;
1490*4882a593Smuzhiyun 	default:
1491*4882a593Smuzhiyun 		render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1492*4882a593Smuzhiyun 			      cond, act,
1493*4882a593Smuzhiyun 			      skippable ? "_OR_SKIP" : "");
1494*4882a593Smuzhiyun 		break;
1495*4882a593Smuzhiyun 	}
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun 	x = tag ?: e;
1498*4882a593Smuzhiyun 	if (x->name)
1499*4882a593Smuzhiyun 		render_more(out, "\t\t// %s", x->name->content);
1500*4882a593Smuzhiyun 	render_more(out, "\n");
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun 	/* Render the tag */
1503*4882a593Smuzhiyun 	if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
1504*4882a593Smuzhiyun 		tag = e;
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun 	if (tag->class == ASN1_UNIV &&
1507*4882a593Smuzhiyun 	    tag->tag != 14 &&
1508*4882a593Smuzhiyun 	    tag->tag != 15 &&
1509*4882a593Smuzhiyun 	    tag->tag != 31)
1510*4882a593Smuzhiyun 		render_opcode(out, "_tag(%s, %s, %s),\n",
1511*4882a593Smuzhiyun 			      asn1_classes[tag->class],
1512*4882a593Smuzhiyun 			      asn1_methods[tag->method | e->method],
1513*4882a593Smuzhiyun 			      asn1_universal_tags[tag->tag]);
1514*4882a593Smuzhiyun 	else
1515*4882a593Smuzhiyun 		render_opcode(out, "_tagn(%s, %s, %2u),\n",
1516*4882a593Smuzhiyun 			      asn1_classes[tag->class],
1517*4882a593Smuzhiyun 			      asn1_methods[tag->method | e->method],
1518*4882a593Smuzhiyun 			      tag->tag);
1519*4882a593Smuzhiyun 	tag = NULL;
1520*4882a593Smuzhiyun dont_render_tag:
1521*4882a593Smuzhiyun 
1522*4882a593Smuzhiyun 	/* Deal with compound types */
1523*4882a593Smuzhiyun 	switch (e->compound) {
1524*4882a593Smuzhiyun 	case TYPE_REF:
1525*4882a593Smuzhiyun 		render_element(out, e->type->type->element, tag);
1526*4882a593Smuzhiyun 		if (e->action)
1527*4882a593Smuzhiyun 			render_opcode(out, "ASN1_OP_%sACT,\n",
1528*4882a593Smuzhiyun 				      skippable ? "MAYBE_" : "");
1529*4882a593Smuzhiyun 		break;
1530*4882a593Smuzhiyun 
1531*4882a593Smuzhiyun 	case SEQUENCE:
1532*4882a593Smuzhiyun 		if (outofline) {
1533*4882a593Smuzhiyun 			/* Render out-of-line for multiple use or
1534*4882a593Smuzhiyun 			 * skipability */
1535*4882a593Smuzhiyun 			render_opcode(out, "_jump_target(%u),", e->entry_index);
1536*4882a593Smuzhiyun 			if (e->type_def && e->type_def->name)
1537*4882a593Smuzhiyun 				render_more(out, "\t\t// --> %s",
1538*4882a593Smuzhiyun 					    e->type_def->name->content);
1539*4882a593Smuzhiyun 			render_more(out, "\n");
1540*4882a593Smuzhiyun 			if (!(e->flags & ELEMENT_RENDERED)) {
1541*4882a593Smuzhiyun 				e->flags |= ELEMENT_RENDERED;
1542*4882a593Smuzhiyun 				*render_list_p = e;
1543*4882a593Smuzhiyun 				render_list_p = &e->render_next;
1544*4882a593Smuzhiyun 			}
1545*4882a593Smuzhiyun 			return;
1546*4882a593Smuzhiyun 		} else {
1547*4882a593Smuzhiyun 			/* Render inline for single use */
1548*4882a593Smuzhiyun 			render_depth++;
1549*4882a593Smuzhiyun 			for (ec = e->children; ec; ec = ec->next)
1550*4882a593Smuzhiyun 				render_element(out, ec, NULL);
1551*4882a593Smuzhiyun 			render_depth--;
1552*4882a593Smuzhiyun 			render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1553*4882a593Smuzhiyun 		}
1554*4882a593Smuzhiyun 		break;
1555*4882a593Smuzhiyun 
1556*4882a593Smuzhiyun 	case SEQUENCE_OF:
1557*4882a593Smuzhiyun 	case SET_OF:
1558*4882a593Smuzhiyun 		if (outofline) {
1559*4882a593Smuzhiyun 			/* Render out-of-line for multiple use or
1560*4882a593Smuzhiyun 			 * skipability */
1561*4882a593Smuzhiyun 			render_opcode(out, "_jump_target(%u),", e->entry_index);
1562*4882a593Smuzhiyun 			if (e->type_def && e->type_def->name)
1563*4882a593Smuzhiyun 				render_more(out, "\t\t// --> %s",
1564*4882a593Smuzhiyun 					    e->type_def->name->content);
1565*4882a593Smuzhiyun 			render_more(out, "\n");
1566*4882a593Smuzhiyun 			if (!(e->flags & ELEMENT_RENDERED)) {
1567*4882a593Smuzhiyun 				e->flags |= ELEMENT_RENDERED;
1568*4882a593Smuzhiyun 				*render_list_p = e;
1569*4882a593Smuzhiyun 				render_list_p = &e->render_next;
1570*4882a593Smuzhiyun 			}
1571*4882a593Smuzhiyun 			return;
1572*4882a593Smuzhiyun 		} else {
1573*4882a593Smuzhiyun 			/* Render inline for single use */
1574*4882a593Smuzhiyun 			entry = nr_entries;
1575*4882a593Smuzhiyun 			render_depth++;
1576*4882a593Smuzhiyun 			render_element(out, e->children, NULL);
1577*4882a593Smuzhiyun 			render_depth--;
1578*4882a593Smuzhiyun 			if (e->compound == SEQUENCE_OF)
1579*4882a593Smuzhiyun 				render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1580*4882a593Smuzhiyun 			else
1581*4882a593Smuzhiyun 				render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1582*4882a593Smuzhiyun 			render_opcode(out, "_jump_target(%u),\n", entry);
1583*4882a593Smuzhiyun 		}
1584*4882a593Smuzhiyun 		break;
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	case SET:
1587*4882a593Smuzhiyun 		/* I can't think of a nice way to do SET support without having
1588*4882a593Smuzhiyun 		 * a stack of bitmasks to make sure no element is repeated.
1589*4882a593Smuzhiyun 		 * The bitmask has also to be checked that no non-optional
1590*4882a593Smuzhiyun 		 * elements are left out whilst not preventing optional
1591*4882a593Smuzhiyun 		 * elements from being left out.
1592*4882a593Smuzhiyun 		 */
1593*4882a593Smuzhiyun 		fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1594*4882a593Smuzhiyun 		exit(1);
1595*4882a593Smuzhiyun 
1596*4882a593Smuzhiyun 	case CHOICE:
1597*4882a593Smuzhiyun 		for (ec = e->children; ec; ec = ec->next)
1598*4882a593Smuzhiyun 			render_element(out, ec, ec);
1599*4882a593Smuzhiyun 		if (!skippable)
1600*4882a593Smuzhiyun 			render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1601*4882a593Smuzhiyun 		if (e->action)
1602*4882a593Smuzhiyun 			render_opcode(out, "ASN1_OP_ACT,\n");
1603*4882a593Smuzhiyun 		break;
1604*4882a593Smuzhiyun 
1605*4882a593Smuzhiyun 	default:
1606*4882a593Smuzhiyun 		break;
1607*4882a593Smuzhiyun 	}
1608*4882a593Smuzhiyun 
1609*4882a593Smuzhiyun 	if (e->action)
1610*4882a593Smuzhiyun 		render_opcode(out, "_action(ACT_%s),\n", e->action->name);
1611*4882a593Smuzhiyun }
1612