xref: /openbmc/linux/scripts/asn1_compiler.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1b4d0d230SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24520c6a4SDavid Howells /* Simplified ASN.1 notation parser
34520c6a4SDavid Howells  *
44520c6a4SDavid Howells  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
54520c6a4SDavid Howells  * Written by David Howells (dhowells@redhat.com)
64520c6a4SDavid Howells  */
74520c6a4SDavid Howells 
84520c6a4SDavid Howells #include <stdarg.h>
94520c6a4SDavid Howells #include <stdio.h>
104520c6a4SDavid Howells #include <stdlib.h>
114520c6a4SDavid Howells #include <stdint.h>
12ae44a2f6SDavid Howells #include <stdbool.h>
134520c6a4SDavid Howells #include <string.h>
144520c6a4SDavid Howells #include <ctype.h>
154520c6a4SDavid Howells #include <unistd.h>
164520c6a4SDavid Howells #include <fcntl.h>
174520c6a4SDavid Howells #include <sys/stat.h>
184520c6a4SDavid Howells #include <linux/asn1_ber_bytecode.h>
194520c6a4SDavid Howells 
204520c6a4SDavid Howells enum token_type {
214520c6a4SDavid Howells 	DIRECTIVE_ABSENT,
224520c6a4SDavid Howells 	DIRECTIVE_ALL,
234520c6a4SDavid Howells 	DIRECTIVE_ANY,
244520c6a4SDavid Howells 	DIRECTIVE_APPLICATION,
254520c6a4SDavid Howells 	DIRECTIVE_AUTOMATIC,
264520c6a4SDavid Howells 	DIRECTIVE_BEGIN,
274520c6a4SDavid Howells 	DIRECTIVE_BIT,
284520c6a4SDavid Howells 	DIRECTIVE_BMPString,
294520c6a4SDavid Howells 	DIRECTIVE_BOOLEAN,
304520c6a4SDavid Howells 	DIRECTIVE_BY,
314520c6a4SDavid Howells 	DIRECTIVE_CHARACTER,
324520c6a4SDavid Howells 	DIRECTIVE_CHOICE,
334520c6a4SDavid Howells 	DIRECTIVE_CLASS,
344520c6a4SDavid Howells 	DIRECTIVE_COMPONENT,
354520c6a4SDavid Howells 	DIRECTIVE_COMPONENTS,
364520c6a4SDavid Howells 	DIRECTIVE_CONSTRAINED,
374520c6a4SDavid Howells 	DIRECTIVE_CONTAINING,
384520c6a4SDavid Howells 	DIRECTIVE_DEFAULT,
394520c6a4SDavid Howells 	DIRECTIVE_DEFINED,
404520c6a4SDavid Howells 	DIRECTIVE_DEFINITIONS,
414520c6a4SDavid Howells 	DIRECTIVE_EMBEDDED,
424520c6a4SDavid Howells 	DIRECTIVE_ENCODED,
434520c6a4SDavid Howells 	DIRECTIVE_ENCODING_CONTROL,
444520c6a4SDavid Howells 	DIRECTIVE_END,
454520c6a4SDavid Howells 	DIRECTIVE_ENUMERATED,
464520c6a4SDavid Howells 	DIRECTIVE_EXCEPT,
474520c6a4SDavid Howells 	DIRECTIVE_EXPLICIT,
484520c6a4SDavid Howells 	DIRECTIVE_EXPORTS,
494520c6a4SDavid Howells 	DIRECTIVE_EXTENSIBILITY,
504520c6a4SDavid Howells 	DIRECTIVE_EXTERNAL,
514520c6a4SDavid Howells 	DIRECTIVE_FALSE,
524520c6a4SDavid Howells 	DIRECTIVE_FROM,
534520c6a4SDavid Howells 	DIRECTIVE_GeneralString,
544520c6a4SDavid Howells 	DIRECTIVE_GeneralizedTime,
554520c6a4SDavid Howells 	DIRECTIVE_GraphicString,
564520c6a4SDavid Howells 	DIRECTIVE_IA5String,
574520c6a4SDavid Howells 	DIRECTIVE_IDENTIFIER,
584520c6a4SDavid Howells 	DIRECTIVE_IMPLICIT,
594520c6a4SDavid Howells 	DIRECTIVE_IMPLIED,
604520c6a4SDavid Howells 	DIRECTIVE_IMPORTS,
614520c6a4SDavid Howells 	DIRECTIVE_INCLUDES,
624520c6a4SDavid Howells 	DIRECTIVE_INSTANCE,
634520c6a4SDavid Howells 	DIRECTIVE_INSTRUCTIONS,
644520c6a4SDavid Howells 	DIRECTIVE_INTEGER,
654520c6a4SDavid Howells 	DIRECTIVE_INTERSECTION,
664520c6a4SDavid Howells 	DIRECTIVE_ISO646String,
674520c6a4SDavid Howells 	DIRECTIVE_MAX,
684520c6a4SDavid Howells 	DIRECTIVE_MIN,
694520c6a4SDavid Howells 	DIRECTIVE_MINUS_INFINITY,
704520c6a4SDavid Howells 	DIRECTIVE_NULL,
714520c6a4SDavid Howells 	DIRECTIVE_NumericString,
724520c6a4SDavid Howells 	DIRECTIVE_OBJECT,
734520c6a4SDavid Howells 	DIRECTIVE_OCTET,
744520c6a4SDavid Howells 	DIRECTIVE_OF,
754520c6a4SDavid Howells 	DIRECTIVE_OPTIONAL,
764520c6a4SDavid Howells 	DIRECTIVE_ObjectDescriptor,
774520c6a4SDavid Howells 	DIRECTIVE_PATTERN,
784520c6a4SDavid Howells 	DIRECTIVE_PDV,
794520c6a4SDavid Howells 	DIRECTIVE_PLUS_INFINITY,
804520c6a4SDavid Howells 	DIRECTIVE_PRESENT,
814520c6a4SDavid Howells 	DIRECTIVE_PRIVATE,
824520c6a4SDavid Howells 	DIRECTIVE_PrintableString,
834520c6a4SDavid Howells 	DIRECTIVE_REAL,
844520c6a4SDavid Howells 	DIRECTIVE_RELATIVE_OID,
854520c6a4SDavid Howells 	DIRECTIVE_SEQUENCE,
864520c6a4SDavid Howells 	DIRECTIVE_SET,
874520c6a4SDavid Howells 	DIRECTIVE_SIZE,
884520c6a4SDavid Howells 	DIRECTIVE_STRING,
894520c6a4SDavid Howells 	DIRECTIVE_SYNTAX,
904520c6a4SDavid Howells 	DIRECTIVE_T61String,
914520c6a4SDavid Howells 	DIRECTIVE_TAGS,
924520c6a4SDavid Howells 	DIRECTIVE_TRUE,
934520c6a4SDavid Howells 	DIRECTIVE_TeletexString,
944520c6a4SDavid Howells 	DIRECTIVE_UNION,
954520c6a4SDavid Howells 	DIRECTIVE_UNIQUE,
964520c6a4SDavid Howells 	DIRECTIVE_UNIVERSAL,
974520c6a4SDavid Howells 	DIRECTIVE_UTCTime,
984520c6a4SDavid Howells 	DIRECTIVE_UTF8String,
994520c6a4SDavid Howells 	DIRECTIVE_UniversalString,
1004520c6a4SDavid Howells 	DIRECTIVE_VideotexString,
1014520c6a4SDavid Howells 	DIRECTIVE_VisibleString,
1024520c6a4SDavid Howells 	DIRECTIVE_WITH,
1034520c6a4SDavid Howells 	NR__DIRECTIVES,
1044520c6a4SDavid Howells 	TOKEN_ASSIGNMENT = NR__DIRECTIVES,
1054520c6a4SDavid Howells 	TOKEN_OPEN_CURLY,
1064520c6a4SDavid Howells 	TOKEN_CLOSE_CURLY,
1074520c6a4SDavid Howells 	TOKEN_OPEN_SQUARE,
1084520c6a4SDavid Howells 	TOKEN_CLOSE_SQUARE,
1094520c6a4SDavid Howells 	TOKEN_OPEN_ACTION,
1104520c6a4SDavid Howells 	TOKEN_CLOSE_ACTION,
1114520c6a4SDavid Howells 	TOKEN_COMMA,
1124520c6a4SDavid Howells 	TOKEN_NUMBER,
1134520c6a4SDavid Howells 	TOKEN_TYPE_NAME,
1144520c6a4SDavid Howells 	TOKEN_ELEMENT_NAME,
1154520c6a4SDavid Howells 	NR__TOKENS
1164520c6a4SDavid Howells };
1174520c6a4SDavid Howells 
1184520c6a4SDavid Howells static const unsigned char token_to_tag[NR__TOKENS] = {
1194520c6a4SDavid Howells 	/* EOC goes first */
1204520c6a4SDavid Howells 	[DIRECTIVE_BOOLEAN]		= ASN1_BOOL,
1214520c6a4SDavid Howells 	[DIRECTIVE_INTEGER]		= ASN1_INT,
1224520c6a4SDavid Howells 	[DIRECTIVE_BIT]			= ASN1_BTS,
1234520c6a4SDavid Howells 	[DIRECTIVE_OCTET]		= ASN1_OTS,
1244520c6a4SDavid Howells 	[DIRECTIVE_NULL]		= ASN1_NULL,
1254520c6a4SDavid Howells 	[DIRECTIVE_OBJECT]		= ASN1_OID,
1264520c6a4SDavid Howells 	[DIRECTIVE_ObjectDescriptor]	= ASN1_ODE,
1274520c6a4SDavid Howells 	[DIRECTIVE_EXTERNAL]		= ASN1_EXT,
1284520c6a4SDavid Howells 	[DIRECTIVE_REAL]		= ASN1_REAL,
1294520c6a4SDavid Howells 	[DIRECTIVE_ENUMERATED]		= ASN1_ENUM,
1304520c6a4SDavid Howells 	[DIRECTIVE_EMBEDDED]		= 0,
1314520c6a4SDavid Howells 	[DIRECTIVE_UTF8String]		= ASN1_UTF8STR,
1324520c6a4SDavid Howells 	[DIRECTIVE_RELATIVE_OID]	= ASN1_RELOID,
1334520c6a4SDavid Howells 	/* 14 */
1344520c6a4SDavid Howells 	/* 15 */
1354520c6a4SDavid Howells 	[DIRECTIVE_SEQUENCE]		= ASN1_SEQ,
1364520c6a4SDavid Howells 	[DIRECTIVE_SET]			= ASN1_SET,
1374520c6a4SDavid Howells 	[DIRECTIVE_NumericString]	= ASN1_NUMSTR,
1384520c6a4SDavid Howells 	[DIRECTIVE_PrintableString]	= ASN1_PRNSTR,
1394520c6a4SDavid Howells 	[DIRECTIVE_T61String]		= ASN1_TEXSTR,
1404520c6a4SDavid Howells 	[DIRECTIVE_TeletexString]	= ASN1_TEXSTR,
1414520c6a4SDavid Howells 	[DIRECTIVE_VideotexString]	= ASN1_VIDSTR,
1424520c6a4SDavid Howells 	[DIRECTIVE_IA5String]		= ASN1_IA5STR,
1434520c6a4SDavid Howells 	[DIRECTIVE_UTCTime]		= ASN1_UNITIM,
1444520c6a4SDavid Howells 	[DIRECTIVE_GeneralizedTime]	= ASN1_GENTIM,
1454520c6a4SDavid Howells 	[DIRECTIVE_GraphicString]	= ASN1_GRASTR,
1464520c6a4SDavid Howells 	[DIRECTIVE_VisibleString]	= ASN1_VISSTR,
1474520c6a4SDavid Howells 	[DIRECTIVE_GeneralString]	= ASN1_GENSTR,
1484520c6a4SDavid Howells 	[DIRECTIVE_UniversalString]	= ASN1_UNITIM,
1494520c6a4SDavid Howells 	[DIRECTIVE_CHARACTER]		= ASN1_CHRSTR,
1504520c6a4SDavid Howells 	[DIRECTIVE_BMPString]		= ASN1_BMPSTR,
1514520c6a4SDavid Howells };
1524520c6a4SDavid Howells 
1534520c6a4SDavid Howells static const char asn1_classes[4][5] = {
1544520c6a4SDavid Howells 	[ASN1_UNIV]	= "UNIV",
1554520c6a4SDavid Howells 	[ASN1_APPL]	= "APPL",
1564520c6a4SDavid Howells 	[ASN1_CONT]	= "CONT",
1574520c6a4SDavid Howells 	[ASN1_PRIV]	= "PRIV"
1584520c6a4SDavid Howells };
1594520c6a4SDavid Howells 
1604520c6a4SDavid Howells static const char asn1_methods[2][5] = {
1614520c6a4SDavid Howells 	[ASN1_UNIV]	= "PRIM",
1624520c6a4SDavid Howells 	[ASN1_APPL]	= "CONS"
1634520c6a4SDavid Howells };
1644520c6a4SDavid Howells 
1654520c6a4SDavid Howells static const char *const asn1_universal_tags[32] = {
1664520c6a4SDavid Howells 	"EOC",
1674520c6a4SDavid Howells 	"BOOL",
1684520c6a4SDavid Howells 	"INT",
1694520c6a4SDavid Howells 	"BTS",
1704520c6a4SDavid Howells 	"OTS",
1714520c6a4SDavid Howells 	"NULL",
1724520c6a4SDavid Howells 	"OID",
1734520c6a4SDavid Howells 	"ODE",
1744520c6a4SDavid Howells 	"EXT",
1754520c6a4SDavid Howells 	"REAL",
1764520c6a4SDavid Howells 	"ENUM",
1774520c6a4SDavid Howells 	"EPDV",
1784520c6a4SDavid Howells 	"UTF8STR",
1794520c6a4SDavid Howells 	"RELOID",
1804520c6a4SDavid Howells 	NULL,		/* 14 */
1814520c6a4SDavid Howells 	NULL,		/* 15 */
1824520c6a4SDavid Howells 	"SEQ",
1834520c6a4SDavid Howells 	"SET",
1844520c6a4SDavid Howells 	"NUMSTR",
1854520c6a4SDavid Howells 	"PRNSTR",
1864520c6a4SDavid Howells 	"TEXSTR",
1874520c6a4SDavid Howells 	"VIDSTR",
1884520c6a4SDavid Howells 	"IA5STR",
1894520c6a4SDavid Howells 	"UNITIM",
1904520c6a4SDavid Howells 	"GENTIM",
1914520c6a4SDavid Howells 	"GRASTR",
1924520c6a4SDavid Howells 	"VISSTR",
1934520c6a4SDavid Howells 	"GENSTR",
1944520c6a4SDavid Howells 	"UNISTR",
1954520c6a4SDavid Howells 	"CHRSTR",
1964520c6a4SDavid Howells 	"BMPSTR",
1974520c6a4SDavid Howells 	NULL		/* 31 */
1984520c6a4SDavid Howells };
1994520c6a4SDavid Howells 
2004520c6a4SDavid Howells static const char *filename;
2014520c6a4SDavid Howells static const char *grammar_name;
2024520c6a4SDavid Howells static const char *outputname;
2034520c6a4SDavid Howells static const char *headername;
2044520c6a4SDavid Howells 
2054520c6a4SDavid Howells static const char *const directives[NR__DIRECTIVES] = {
2064520c6a4SDavid Howells #define _(X) [DIRECTIVE_##X] = #X
2074520c6a4SDavid Howells 	_(ABSENT),
2084520c6a4SDavid Howells 	_(ALL),
2094520c6a4SDavid Howells 	_(ANY),
2104520c6a4SDavid Howells 	_(APPLICATION),
2114520c6a4SDavid Howells 	_(AUTOMATIC),
2124520c6a4SDavid Howells 	_(BEGIN),
2134520c6a4SDavid Howells 	_(BIT),
2144520c6a4SDavid Howells 	_(BMPString),
2154520c6a4SDavid Howells 	_(BOOLEAN),
2164520c6a4SDavid Howells 	_(BY),
2174520c6a4SDavid Howells 	_(CHARACTER),
2184520c6a4SDavid Howells 	_(CHOICE),
2194520c6a4SDavid Howells 	_(CLASS),
2204520c6a4SDavid Howells 	_(COMPONENT),
2214520c6a4SDavid Howells 	_(COMPONENTS),
2224520c6a4SDavid Howells 	_(CONSTRAINED),
2234520c6a4SDavid Howells 	_(CONTAINING),
2244520c6a4SDavid Howells 	_(DEFAULT),
2254520c6a4SDavid Howells 	_(DEFINED),
2264520c6a4SDavid Howells 	_(DEFINITIONS),
2274520c6a4SDavid Howells 	_(EMBEDDED),
2284520c6a4SDavid Howells 	_(ENCODED),
2294520c6a4SDavid Howells 	[DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
2304520c6a4SDavid Howells 	_(END),
2314520c6a4SDavid Howells 	_(ENUMERATED),
2324520c6a4SDavid Howells 	_(EXCEPT),
2334520c6a4SDavid Howells 	_(EXPLICIT),
2344520c6a4SDavid Howells 	_(EXPORTS),
2354520c6a4SDavid Howells 	_(EXTENSIBILITY),
2364520c6a4SDavid Howells 	_(EXTERNAL),
2374520c6a4SDavid Howells 	_(FALSE),
2384520c6a4SDavid Howells 	_(FROM),
2394520c6a4SDavid Howells 	_(GeneralString),
2404520c6a4SDavid Howells 	_(GeneralizedTime),
2414520c6a4SDavid Howells 	_(GraphicString),
2424520c6a4SDavid Howells 	_(IA5String),
2434520c6a4SDavid Howells 	_(IDENTIFIER),
2444520c6a4SDavid Howells 	_(IMPLICIT),
2454520c6a4SDavid Howells 	_(IMPLIED),
2464520c6a4SDavid Howells 	_(IMPORTS),
2474520c6a4SDavid Howells 	_(INCLUDES),
2484520c6a4SDavid Howells 	_(INSTANCE),
2494520c6a4SDavid Howells 	_(INSTRUCTIONS),
2504520c6a4SDavid Howells 	_(INTEGER),
2514520c6a4SDavid Howells 	_(INTERSECTION),
2524520c6a4SDavid Howells 	_(ISO646String),
2534520c6a4SDavid Howells 	_(MAX),
2544520c6a4SDavid Howells 	_(MIN),
2554520c6a4SDavid Howells 	[DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
2564520c6a4SDavid Howells 	[DIRECTIVE_NULL] = "NULL",
2574520c6a4SDavid Howells 	_(NumericString),
2584520c6a4SDavid Howells 	_(OBJECT),
2594520c6a4SDavid Howells 	_(OCTET),
2604520c6a4SDavid Howells 	_(OF),
2614520c6a4SDavid Howells 	_(OPTIONAL),
2624520c6a4SDavid Howells 	_(ObjectDescriptor),
2634520c6a4SDavid Howells 	_(PATTERN),
2644520c6a4SDavid Howells 	_(PDV),
2654520c6a4SDavid Howells 	[DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
2664520c6a4SDavid Howells 	_(PRESENT),
2674520c6a4SDavid Howells 	_(PRIVATE),
2684520c6a4SDavid Howells 	_(PrintableString),
2694520c6a4SDavid Howells 	_(REAL),
2704520c6a4SDavid Howells 	[DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
2714520c6a4SDavid Howells 	_(SEQUENCE),
2724520c6a4SDavid Howells 	_(SET),
2734520c6a4SDavid Howells 	_(SIZE),
2744520c6a4SDavid Howells 	_(STRING),
2754520c6a4SDavid Howells 	_(SYNTAX),
2764520c6a4SDavid Howells 	_(T61String),
2774520c6a4SDavid Howells 	_(TAGS),
2784520c6a4SDavid Howells 	_(TRUE),
2794520c6a4SDavid Howells 	_(TeletexString),
2804520c6a4SDavid Howells 	_(UNION),
2814520c6a4SDavid Howells 	_(UNIQUE),
2824520c6a4SDavid Howells 	_(UNIVERSAL),
2834520c6a4SDavid Howells 	_(UTCTime),
2844520c6a4SDavid Howells 	_(UTF8String),
2854520c6a4SDavid Howells 	_(UniversalString),
2864520c6a4SDavid Howells 	_(VideotexString),
2874520c6a4SDavid Howells 	_(VisibleString),
2884520c6a4SDavid Howells 	_(WITH)
2894520c6a4SDavid Howells };
2904520c6a4SDavid Howells 
2914520c6a4SDavid Howells struct action {
2924520c6a4SDavid Howells 	struct action	*next;
293c05cae9aSDavid Howells 	char		*name;
2944520c6a4SDavid Howells 	unsigned char	index;
2954520c6a4SDavid Howells };
2964520c6a4SDavid Howells 
2974520c6a4SDavid Howells static struct action *action_list;
2984520c6a4SDavid Howells static unsigned nr_actions;
2994520c6a4SDavid Howells 
3004520c6a4SDavid Howells struct token {
3014520c6a4SDavid Howells 	unsigned short	line;
3024520c6a4SDavid Howells 	enum token_type	token_type : 8;
3034520c6a4SDavid Howells 	unsigned char	size;
3044520c6a4SDavid Howells 	struct action	*action;
305c05cae9aSDavid Howells 	char		*content;
3064520c6a4SDavid Howells 	struct type	*type;
3074520c6a4SDavid Howells };
3084520c6a4SDavid Howells 
3094520c6a4SDavid Howells static struct token *token_list;
3104520c6a4SDavid Howells static unsigned nr_tokens;
311ae44a2f6SDavid Howells static bool verbose_opt;
312ae44a2f6SDavid Howells static bool debug_opt;
313e994393aSArnd Bergmann 
314ae44a2f6SDavid Howells #define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)
315ae44a2f6SDavid Howells #define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)
3164520c6a4SDavid Howells 
directive_compare(const void * _key,const void * _pdir)3174520c6a4SDavid Howells static int directive_compare(const void *_key, const void *_pdir)
3184520c6a4SDavid Howells {
3194520c6a4SDavid Howells 	const struct token *token = _key;
3204520c6a4SDavid Howells 	const char *const *pdir = _pdir, *dir = *pdir;
3214520c6a4SDavid Howells 	size_t dlen, clen;
3224520c6a4SDavid Howells 	int val;
3234520c6a4SDavid Howells 
3244520c6a4SDavid Howells 	dlen = strlen(dir);
3254520c6a4SDavid Howells 	clen = (dlen < token->size) ? dlen : token->size;
3264520c6a4SDavid Howells 
327c05cae9aSDavid Howells 	//debug("cmp(%s,%s) = ", token->content, dir);
3284520c6a4SDavid Howells 
329c05cae9aSDavid Howells 	val = memcmp(token->content, dir, clen);
3304520c6a4SDavid Howells 	if (val != 0) {
331e994393aSArnd Bergmann 		//debug("%d [cmp]\n", val);
3324520c6a4SDavid Howells 		return val;
3334520c6a4SDavid Howells 	}
3344520c6a4SDavid Howells 
3354520c6a4SDavid Howells 	if (dlen == token->size) {
336e994393aSArnd Bergmann 		//debug("0\n");
3374520c6a4SDavid Howells 		return 0;
3384520c6a4SDavid Howells 	}
339e994393aSArnd Bergmann 	//debug("%d\n", (int)dlen - (int)token->size);
3404520c6a4SDavid Howells 	return dlen - token->size; /* shorter -> negative */
3414520c6a4SDavid Howells }
3424520c6a4SDavid Howells 
3434520c6a4SDavid Howells /*
3444520c6a4SDavid Howells  * Tokenise an ASN.1 grammar
3454520c6a4SDavid Howells  */
tokenise(char * buffer,char * end)3464520c6a4SDavid Howells static void tokenise(char *buffer, char *end)
3474520c6a4SDavid Howells {
3484520c6a4SDavid Howells 	struct token *tokens;
349c05cae9aSDavid Howells 	char *line, *nl, *start, *p, *q;
3504520c6a4SDavid Howells 	unsigned tix, lineno;
3514520c6a4SDavid Howells 
3524520c6a4SDavid Howells 	/* Assume we're going to have half as many tokens as we have
3534520c6a4SDavid Howells 	 * characters
3544520c6a4SDavid Howells 	 */
3554520c6a4SDavid Howells 	token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
3564520c6a4SDavid Howells 	if (!tokens) {
3574520c6a4SDavid Howells 		perror(NULL);
3584520c6a4SDavid Howells 		exit(1);
3594520c6a4SDavid Howells 	}
3604520c6a4SDavid Howells 	tix = 0;
3614520c6a4SDavid Howells 
3624520c6a4SDavid Howells 	lineno = 0;
3634520c6a4SDavid Howells 	while (buffer < end) {
3644520c6a4SDavid Howells 		/* First of all, break out a line */
3654520c6a4SDavid Howells 		lineno++;
3664520c6a4SDavid Howells 		line = buffer;
3674520c6a4SDavid Howells 		nl = memchr(line, '\n', end - buffer);
3684520c6a4SDavid Howells 		if (!nl) {
3694520c6a4SDavid Howells 			buffer = nl = end;
3704520c6a4SDavid Howells 		} else {
3714520c6a4SDavid Howells 			buffer = nl + 1;
3724520c6a4SDavid Howells 			*nl = '\0';
3734520c6a4SDavid Howells 		}
3744520c6a4SDavid Howells 
3754520c6a4SDavid Howells 		/* Remove "--" comments */
3764520c6a4SDavid Howells 		p = line;
3774520c6a4SDavid Howells 	next_comment:
3784520c6a4SDavid Howells 		while ((p = memchr(p, '-', nl - p))) {
3794520c6a4SDavid Howells 			if (p[1] == '-') {
3804520c6a4SDavid Howells 				/* Found a comment; see if there's a terminator */
3814520c6a4SDavid Howells 				q = p + 2;
3824520c6a4SDavid Howells 				while ((q = memchr(q, '-', nl - q))) {
3834520c6a4SDavid Howells 					if (q[1] == '-') {
3844520c6a4SDavid Howells 						/* There is - excise the comment */
3854520c6a4SDavid Howells 						q += 2;
3864520c6a4SDavid Howells 						memmove(p, q, nl - q);
3874520c6a4SDavid Howells 						goto next_comment;
3884520c6a4SDavid Howells 					}
3894520c6a4SDavid Howells 					q++;
3904520c6a4SDavid Howells 				}
3914520c6a4SDavid Howells 				*p = '\0';
3924520c6a4SDavid Howells 				nl = p;
3934520c6a4SDavid Howells 				break;
3944520c6a4SDavid Howells 			} else {
3954520c6a4SDavid Howells 				p++;
3964520c6a4SDavid Howells 			}
3974520c6a4SDavid Howells 		}
3984520c6a4SDavid Howells 
3994520c6a4SDavid Howells 		p = line;
4004520c6a4SDavid Howells 		while (p < nl) {
4014520c6a4SDavid Howells 			/* Skip white space */
4024520c6a4SDavid Howells 			while (p < nl && isspace(*p))
4034520c6a4SDavid Howells 				*(p++) = 0;
4044520c6a4SDavid Howells 			if (p >= nl)
4054520c6a4SDavid Howells 				break;
4064520c6a4SDavid Howells 
4074520c6a4SDavid Howells 			tokens[tix].line = lineno;
408c05cae9aSDavid Howells 			start = p;
4094520c6a4SDavid Howells 
4104520c6a4SDavid Howells 			/* Handle string tokens */
4114520c6a4SDavid Howells 			if (isalpha(*p)) {
4129e1e8194SLeonardo Bras 				const char **dir;
4134520c6a4SDavid Howells 
4144520c6a4SDavid Howells 				/* Can be a directive, type name or element
4154520c6a4SDavid Howells 				 * name.  Find the end of the name.
4164520c6a4SDavid Howells 				 */
4174520c6a4SDavid Howells 				q = p + 1;
4184520c6a4SDavid Howells 				while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
4194520c6a4SDavid Howells 					q++;
4204520c6a4SDavid Howells 				tokens[tix].size = q - p;
4214520c6a4SDavid Howells 				p = q;
4224520c6a4SDavid Howells 
423c05cae9aSDavid Howells 				tokens[tix].content = malloc(tokens[tix].size + 1);
424c05cae9aSDavid Howells 				if (!tokens[tix].content) {
425c05cae9aSDavid Howells 					perror(NULL);
426c05cae9aSDavid Howells 					exit(1);
427c05cae9aSDavid Howells 				}
428c05cae9aSDavid Howells 				memcpy(tokens[tix].content, start, tokens[tix].size);
429c05cae9aSDavid Howells 				tokens[tix].content[tokens[tix].size] = 0;
430c05cae9aSDavid Howells 
4314520c6a4SDavid Howells 				/* If it begins with a lowercase letter then
4324520c6a4SDavid Howells 				 * it's an element name
4334520c6a4SDavid Howells 				 */
434c05cae9aSDavid Howells 				if (islower(tokens[tix].content[0])) {
4354520c6a4SDavid Howells 					tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
4364520c6a4SDavid Howells 					continue;
4374520c6a4SDavid Howells 				}
4384520c6a4SDavid Howells 
4394520c6a4SDavid Howells 				/* Otherwise we need to search the directive
4404520c6a4SDavid Howells 				 * table
4414520c6a4SDavid Howells 				 */
4424520c6a4SDavid Howells 				dir = bsearch(&tokens[tix], directives,
4434520c6a4SDavid Howells 					      sizeof(directives) / sizeof(directives[1]),
4444520c6a4SDavid Howells 					      sizeof(directives[1]),
4454520c6a4SDavid Howells 					      directive_compare);
4464520c6a4SDavid Howells 				if (dir) {
4474520c6a4SDavid Howells 					tokens[tix++].token_type = dir - directives;
4484520c6a4SDavid Howells 					continue;
4494520c6a4SDavid Howells 				}
4504520c6a4SDavid Howells 
4514520c6a4SDavid Howells 				tokens[tix++].token_type = TOKEN_TYPE_NAME;
4524520c6a4SDavid Howells 				continue;
4534520c6a4SDavid Howells 			}
4544520c6a4SDavid Howells 
4554520c6a4SDavid Howells 			/* Handle numbers */
4564520c6a4SDavid Howells 			if (isdigit(*p)) {
4574520c6a4SDavid Howells 				/* Find the end of the number */
4584520c6a4SDavid Howells 				q = p + 1;
4594520c6a4SDavid Howells 				while (q < nl && (isdigit(*q)))
4604520c6a4SDavid Howells 					q++;
4614520c6a4SDavid Howells 				tokens[tix].size = q - p;
4624520c6a4SDavid Howells 				p = q;
463c05cae9aSDavid Howells 				tokens[tix].content = malloc(tokens[tix].size + 1);
464c05cae9aSDavid Howells 				if (!tokens[tix].content) {
465c05cae9aSDavid Howells 					perror(NULL);
466c05cae9aSDavid Howells 					exit(1);
467c05cae9aSDavid Howells 				}
468c05cae9aSDavid Howells 				memcpy(tokens[tix].content, start, tokens[tix].size);
469c05cae9aSDavid Howells 				tokens[tix].content[tokens[tix].size] = 0;
4704520c6a4SDavid Howells 				tokens[tix++].token_type = TOKEN_NUMBER;
4714520c6a4SDavid Howells 				continue;
4724520c6a4SDavid Howells 			}
4734520c6a4SDavid Howells 
4744520c6a4SDavid Howells 			if (nl - p >= 3) {
4754520c6a4SDavid Howells 				if (memcmp(p, "::=", 3) == 0) {
4764520c6a4SDavid Howells 					p += 3;
4774520c6a4SDavid Howells 					tokens[tix].size = 3;
478c05cae9aSDavid Howells 					tokens[tix].content = "::=";
4794520c6a4SDavid Howells 					tokens[tix++].token_type = TOKEN_ASSIGNMENT;
4804520c6a4SDavid Howells 					continue;
4814520c6a4SDavid Howells 				}
4824520c6a4SDavid Howells 			}
4834520c6a4SDavid Howells 
4844520c6a4SDavid Howells 			if (nl - p >= 2) {
4854520c6a4SDavid Howells 				if (memcmp(p, "({", 2) == 0) {
4864520c6a4SDavid Howells 					p += 2;
4874520c6a4SDavid Howells 					tokens[tix].size = 2;
488c05cae9aSDavid Howells 					tokens[tix].content = "({";
4894520c6a4SDavid Howells 					tokens[tix++].token_type = TOKEN_OPEN_ACTION;
4904520c6a4SDavid Howells 					continue;
4914520c6a4SDavid Howells 				}
4924520c6a4SDavid Howells 				if (memcmp(p, "})", 2) == 0) {
4934520c6a4SDavid Howells 					p += 2;
4944520c6a4SDavid Howells 					tokens[tix].size = 2;
495c05cae9aSDavid Howells 					tokens[tix].content = "})";
4964520c6a4SDavid Howells 					tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
4974520c6a4SDavid Howells 					continue;
4984520c6a4SDavid Howells 				}
4994520c6a4SDavid Howells 			}
5004520c6a4SDavid Howells 
5014520c6a4SDavid Howells 			if (nl - p >= 1) {
5024520c6a4SDavid Howells 				tokens[tix].size = 1;
5034520c6a4SDavid Howells 				switch (*p) {
5044520c6a4SDavid Howells 				case '{':
5054520c6a4SDavid Howells 					p += 1;
506c05cae9aSDavid Howells 					tokens[tix].content = "{";
5074520c6a4SDavid Howells 					tokens[tix++].token_type = TOKEN_OPEN_CURLY;
5084520c6a4SDavid Howells 					continue;
5094520c6a4SDavid Howells 				case '}':
5104520c6a4SDavid Howells 					p += 1;
511c05cae9aSDavid Howells 					tokens[tix].content = "}";
5124520c6a4SDavid Howells 					tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
5134520c6a4SDavid Howells 					continue;
5144520c6a4SDavid Howells 				case '[':
5154520c6a4SDavid Howells 					p += 1;
516c05cae9aSDavid Howells 					tokens[tix].content = "[";
5174520c6a4SDavid Howells 					tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
5184520c6a4SDavid Howells 					continue;
5194520c6a4SDavid Howells 				case ']':
5204520c6a4SDavid Howells 					p += 1;
521c05cae9aSDavid Howells 					tokens[tix].content = "]";
5224520c6a4SDavid Howells 					tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
5234520c6a4SDavid Howells 					continue;
5244520c6a4SDavid Howells 				case ',':
5254520c6a4SDavid Howells 					p += 1;
526c05cae9aSDavid Howells 					tokens[tix].content = ",";
5274520c6a4SDavid Howells 					tokens[tix++].token_type = TOKEN_COMMA;
5284520c6a4SDavid Howells 					continue;
5294520c6a4SDavid Howells 				default:
5304520c6a4SDavid Howells 					break;
5314520c6a4SDavid Howells 				}
5324520c6a4SDavid Howells 			}
5334520c6a4SDavid Howells 
5344520c6a4SDavid Howells 			fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
5354520c6a4SDavid Howells 				filename, lineno, *p);
5364520c6a4SDavid Howells 			exit(1);
5374520c6a4SDavid Howells 		}
5384520c6a4SDavid Howells 	}
5394520c6a4SDavid Howells 
5404520c6a4SDavid Howells 	nr_tokens = tix;
541ae44a2f6SDavid Howells 	verbose("Extracted %u tokens\n", nr_tokens);
5424520c6a4SDavid Howells 
5434520c6a4SDavid Howells #if 0
5444520c6a4SDavid Howells 	{
5454520c6a4SDavid Howells 		int n;
5464520c6a4SDavid Howells 		for (n = 0; n < nr_tokens; n++)
547c05cae9aSDavid Howells 			debug("Token %3u: '%s'\n", n, token_list[n].content);
5484520c6a4SDavid Howells 	}
5494520c6a4SDavid Howells #endif
5504520c6a4SDavid Howells }
5514520c6a4SDavid Howells 
5524520c6a4SDavid Howells static void build_type_list(void);
5534520c6a4SDavid Howells static void parse(void);
554ae44a2f6SDavid Howells static void dump_elements(void);
5554520c6a4SDavid Howells static void render(FILE *out, FILE *hdr);
5564520c6a4SDavid Howells 
5574520c6a4SDavid Howells /*
5584520c6a4SDavid Howells  *
5594520c6a4SDavid Howells  */
main(int argc,char ** argv)5604520c6a4SDavid Howells int main(int argc, char **argv)
5614520c6a4SDavid Howells {
5624520c6a4SDavid Howells 	struct stat st;
5634520c6a4SDavid Howells 	ssize_t readlen;
5644520c6a4SDavid Howells 	FILE *out, *hdr;
5654520c6a4SDavid Howells 	char *buffer, *p;
566e994393aSArnd Bergmann 	char *kbuild_verbose;
5674520c6a4SDavid Howells 	int fd;
5684520c6a4SDavid Howells 
569ae44a2f6SDavid Howells 	kbuild_verbose = getenv("KBUILD_VERBOSE");
570c0d3b831SMasahiro Yamada 	if (kbuild_verbose && strchr(kbuild_verbose, '1'))
571c0d3b831SMasahiro Yamada 		verbose_opt = true;
572ae44a2f6SDavid Howells 
573ae44a2f6SDavid Howells 	while (argc > 4) {
574ae44a2f6SDavid Howells 		if (strcmp(argv[1], "-v") == 0)
575ae44a2f6SDavid Howells 			verbose_opt = true;
576ae44a2f6SDavid Howells 		else if (strcmp(argv[1], "-d") == 0)
577ae44a2f6SDavid Howells 			debug_opt = true;
578ae44a2f6SDavid Howells 		else
579ae44a2f6SDavid Howells 			break;
580ae44a2f6SDavid Howells 		memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *));
581ae44a2f6SDavid Howells 		argc--;
582ae44a2f6SDavid Howells 	}
583ae44a2f6SDavid Howells 
5844520c6a4SDavid Howells 	if (argc != 4) {
585ae44a2f6SDavid Howells 		fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n",
5864520c6a4SDavid Howells 			argv[0]);
5874520c6a4SDavid Howells 		exit(2);
5884520c6a4SDavid Howells 	}
5894520c6a4SDavid Howells 
5904520c6a4SDavid Howells 	filename = argv[1];
5914520c6a4SDavid Howells 	outputname = argv[2];
5924520c6a4SDavid Howells 	headername = argv[3];
5934520c6a4SDavid Howells 
5944520c6a4SDavid Howells 	fd = open(filename, O_RDONLY);
5954520c6a4SDavid Howells 	if (fd < 0) {
5964520c6a4SDavid Howells 		perror(filename);
5974520c6a4SDavid Howells 		exit(1);
5984520c6a4SDavid Howells 	}
5994520c6a4SDavid Howells 
6004520c6a4SDavid Howells 	if (fstat(fd, &st) < 0) {
6014520c6a4SDavid Howells 		perror(filename);
6024520c6a4SDavid Howells 		exit(1);
6034520c6a4SDavid Howells 	}
6044520c6a4SDavid Howells 
6054520c6a4SDavid Howells 	if (!(buffer = malloc(st.st_size + 1))) {
6064520c6a4SDavid Howells 		perror(NULL);
6074520c6a4SDavid Howells 		exit(1);
6084520c6a4SDavid Howells 	}
6094520c6a4SDavid Howells 
6104520c6a4SDavid Howells 	if ((readlen = read(fd, buffer, st.st_size)) < 0) {
6114520c6a4SDavid Howells 		perror(filename);
6124520c6a4SDavid Howells 		exit(1);
6134520c6a4SDavid Howells 	}
6144520c6a4SDavid Howells 
6154520c6a4SDavid Howells 	if (close(fd) < 0) {
6164520c6a4SDavid Howells 		perror(filename);
6174520c6a4SDavid Howells 		exit(1);
6184520c6a4SDavid Howells 	}
6194520c6a4SDavid Howells 
6204520c6a4SDavid Howells 	if (readlen != st.st_size) {
6214520c6a4SDavid Howells 		fprintf(stderr, "%s: Short read\n", filename);
6224520c6a4SDavid Howells 		exit(1);
6234520c6a4SDavid Howells 	}
6244520c6a4SDavid Howells 
6254520c6a4SDavid Howells 	p = strrchr(argv[1], '/');
6264520c6a4SDavid Howells 	p = p ? p + 1 : argv[1];
6274520c6a4SDavid Howells 	grammar_name = strdup(p);
628*5a43001cSEkaterina Orlova 	if (!grammar_name) {
6294520c6a4SDavid Howells 		perror(NULL);
6304520c6a4SDavid Howells 		exit(1);
6314520c6a4SDavid Howells 	}
6324520c6a4SDavid Howells 	p = strchr(grammar_name, '.');
6334520c6a4SDavid Howells 	if (p)
6344520c6a4SDavid Howells 		*p = '\0';
6354520c6a4SDavid Howells 
6364520c6a4SDavid Howells 	buffer[readlen] = 0;
6374520c6a4SDavid Howells 	tokenise(buffer, buffer + readlen);
6384520c6a4SDavid Howells 	build_type_list();
6394520c6a4SDavid Howells 	parse();
640ae44a2f6SDavid Howells 	dump_elements();
6414520c6a4SDavid Howells 
6424520c6a4SDavid Howells 	out = fopen(outputname, "w");
6434520c6a4SDavid Howells 	if (!out) {
6444520c6a4SDavid Howells 		perror(outputname);
6454520c6a4SDavid Howells 		exit(1);
6464520c6a4SDavid Howells 	}
6474520c6a4SDavid Howells 
6484520c6a4SDavid Howells 	hdr = fopen(headername, "w");
649952cca6aSColin Ian King 	if (!hdr) {
6504520c6a4SDavid Howells 		perror(headername);
6514520c6a4SDavid Howells 		exit(1);
6524520c6a4SDavid Howells 	}
6534520c6a4SDavid Howells 
6544520c6a4SDavid Howells 	render(out, hdr);
6554520c6a4SDavid Howells 
6564520c6a4SDavid Howells 	if (fclose(out) < 0) {
6574520c6a4SDavid Howells 		perror(outputname);
6584520c6a4SDavid Howells 		exit(1);
6594520c6a4SDavid Howells 	}
6604520c6a4SDavid Howells 
6614520c6a4SDavid Howells 	if (fclose(hdr) < 0) {
6624520c6a4SDavid Howells 		perror(headername);
6634520c6a4SDavid Howells 		exit(1);
6644520c6a4SDavid Howells 	}
6654520c6a4SDavid Howells 
6664520c6a4SDavid Howells 	return 0;
6674520c6a4SDavid Howells }
6684520c6a4SDavid Howells 
6694520c6a4SDavid Howells enum compound {
6704520c6a4SDavid Howells 	NOT_COMPOUND,
6714520c6a4SDavid Howells 	SET,
6724520c6a4SDavid Howells 	SET_OF,
6734520c6a4SDavid Howells 	SEQUENCE,
6744520c6a4SDavid Howells 	SEQUENCE_OF,
6754520c6a4SDavid Howells 	CHOICE,
6764520c6a4SDavid Howells 	ANY,
6774520c6a4SDavid Howells 	TYPE_REF,
6784520c6a4SDavid Howells 	TAG_OVERRIDE
6794520c6a4SDavid Howells };
6804520c6a4SDavid Howells 
6814520c6a4SDavid Howells struct element {
6824520c6a4SDavid Howells 	struct type	*type_def;
6834520c6a4SDavid Howells 	struct token	*name;
6844520c6a4SDavid Howells 	struct token	*type;
6854520c6a4SDavid Howells 	struct action	*action;
6864520c6a4SDavid Howells 	struct element	*children;
6874520c6a4SDavid Howells 	struct element	*next;
6884520c6a4SDavid Howells 	struct element	*render_next;
6894520c6a4SDavid Howells 	struct element	*list_next;
6904520c6a4SDavid Howells 	uint8_t		n_elements;
6914520c6a4SDavid Howells 	enum compound	compound : 8;
6924520c6a4SDavid Howells 	enum asn1_class	class : 8;
6934520c6a4SDavid Howells 	enum asn1_method method : 8;
6944520c6a4SDavid Howells 	uint8_t		tag;
6954520c6a4SDavid Howells 	unsigned	entry_index;
6964520c6a4SDavid Howells 	unsigned	flags;
6974520c6a4SDavid Howells #define ELEMENT_IMPLICIT	0x0001
6984520c6a4SDavid Howells #define ELEMENT_EXPLICIT	0x0002
6998d9b21dcSDavid Howells #define ELEMENT_TAG_SPECIFIED	0x0004
7004520c6a4SDavid Howells #define ELEMENT_RENDERED	0x0008
7014520c6a4SDavid Howells #define ELEMENT_SKIPPABLE	0x0010
7024520c6a4SDavid Howells #define ELEMENT_CONDITIONAL	0x0020
7034520c6a4SDavid Howells };
7044520c6a4SDavid Howells 
7054520c6a4SDavid Howells struct type {
7064520c6a4SDavid Howells 	struct token	*name;
7074520c6a4SDavid Howells 	struct token	*def;
7084520c6a4SDavid Howells 	struct element	*element;
7094520c6a4SDavid Howells 	unsigned	ref_count;
7104520c6a4SDavid Howells 	unsigned	flags;
7114520c6a4SDavid Howells #define TYPE_STOP_MARKER	0x0001
7124520c6a4SDavid Howells #define TYPE_BEGIN		0x0002
7134520c6a4SDavid Howells };
7144520c6a4SDavid Howells 
7154520c6a4SDavid Howells static struct type *type_list;
7164520c6a4SDavid Howells static struct type **type_index;
7174520c6a4SDavid Howells static unsigned nr_types;
7184520c6a4SDavid Howells 
type_index_compare(const void * _a,const void * _b)7194520c6a4SDavid Howells static int type_index_compare(const void *_a, const void *_b)
7204520c6a4SDavid Howells {
7214520c6a4SDavid Howells 	const struct type *const *a = _a, *const *b = _b;
7224520c6a4SDavid Howells 
7234520c6a4SDavid Howells 	if ((*a)->name->size != (*b)->name->size)
7244520c6a4SDavid Howells 		return (*a)->name->size - (*b)->name->size;
7254520c6a4SDavid Howells 	else
726c05cae9aSDavid Howells 		return memcmp((*a)->name->content, (*b)->name->content,
7274520c6a4SDavid Howells 			      (*a)->name->size);
7284520c6a4SDavid Howells }
7294520c6a4SDavid Howells 
type_finder(const void * _key,const void * _ti)7304520c6a4SDavid Howells static int type_finder(const void *_key, const void *_ti)
7314520c6a4SDavid Howells {
7324520c6a4SDavid Howells 	const struct token *token = _key;
7334520c6a4SDavid Howells 	const struct type *const *ti = _ti;
7344520c6a4SDavid Howells 	const struct type *type = *ti;
7354520c6a4SDavid Howells 
7364520c6a4SDavid Howells 	if (token->size != type->name->size)
7374520c6a4SDavid Howells 		return token->size - type->name->size;
7384520c6a4SDavid Howells 	else
739c05cae9aSDavid Howells 		return memcmp(token->content, type->name->content,
7404520c6a4SDavid Howells 			      token->size);
7414520c6a4SDavid Howells }
7424520c6a4SDavid Howells 
7434520c6a4SDavid Howells /*
7444520c6a4SDavid Howells  * Build up a list of types and a sorted index to that list.
7454520c6a4SDavid Howells  */
build_type_list(void)7464520c6a4SDavid Howells static void build_type_list(void)
7474520c6a4SDavid Howells {
7484520c6a4SDavid Howells 	struct type *types;
7494520c6a4SDavid Howells 	unsigned nr, t, n;
7504520c6a4SDavid Howells 
7514520c6a4SDavid Howells 	nr = 0;
7524520c6a4SDavid Howells 	for (n = 0; n < nr_tokens - 1; n++)
7534520c6a4SDavid Howells 		if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
7544520c6a4SDavid Howells 		    token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
7554520c6a4SDavid Howells 			nr++;
7564520c6a4SDavid Howells 
7574520c6a4SDavid Howells 	if (nr == 0) {
7584520c6a4SDavid Howells 		fprintf(stderr, "%s: No defined types\n", filename);
7594520c6a4SDavid Howells 		exit(1);
7604520c6a4SDavid Howells 	}
7614520c6a4SDavid Howells 
7624520c6a4SDavid Howells 	nr_types = nr;
7634520c6a4SDavid Howells 	types = type_list = calloc(nr + 1, sizeof(type_list[0]));
7644520c6a4SDavid Howells 	if (!type_list) {
7654520c6a4SDavid Howells 		perror(NULL);
7664520c6a4SDavid Howells 		exit(1);
7674520c6a4SDavid Howells 	}
7684520c6a4SDavid Howells 	type_index = calloc(nr, sizeof(type_index[0]));
7694520c6a4SDavid Howells 	if (!type_index) {
7704520c6a4SDavid Howells 		perror(NULL);
7714520c6a4SDavid Howells 		exit(1);
7724520c6a4SDavid Howells 	}
7734520c6a4SDavid Howells 
7744520c6a4SDavid Howells 	t = 0;
7754520c6a4SDavid Howells 	types[t].flags |= TYPE_BEGIN;
7764520c6a4SDavid Howells 	for (n = 0; n < nr_tokens - 1; n++) {
7774520c6a4SDavid Howells 		if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
7784520c6a4SDavid Howells 		    token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
7794520c6a4SDavid Howells 			types[t].name = &token_list[n];
7804520c6a4SDavid Howells 			type_index[t] = &types[t];
7814520c6a4SDavid Howells 			t++;
7824520c6a4SDavid Howells 		}
7834520c6a4SDavid Howells 	}
7844520c6a4SDavid Howells 	types[t].name = &token_list[n + 1];
7854520c6a4SDavid Howells 	types[t].flags |= TYPE_STOP_MARKER;
7864520c6a4SDavid Howells 
7874520c6a4SDavid Howells 	qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
7884520c6a4SDavid Howells 
789ae44a2f6SDavid Howells 	verbose("Extracted %u types\n", nr_types);
7904520c6a4SDavid Howells #if 0
7914520c6a4SDavid Howells 	for (n = 0; n < nr_types; n++) {
7924520c6a4SDavid Howells 		struct type *type = type_index[n];
793c05cae9aSDavid Howells 		debug("- %*.*s\n", type->name->content);
7944520c6a4SDavid Howells 	}
7954520c6a4SDavid Howells #endif
7964520c6a4SDavid Howells }
7974520c6a4SDavid Howells 
7984520c6a4SDavid Howells static struct element *parse_type(struct token **_cursor, struct token *stop,
7994520c6a4SDavid Howells 				  struct token *name);
8004520c6a4SDavid Howells 
8014520c6a4SDavid Howells /*
8024520c6a4SDavid Howells  * Parse the token stream
8034520c6a4SDavid Howells  */
parse(void)8044520c6a4SDavid Howells static void parse(void)
8054520c6a4SDavid Howells {
8064520c6a4SDavid Howells 	struct token *cursor;
8074520c6a4SDavid Howells 	struct type *type;
8084520c6a4SDavid Howells 
8094520c6a4SDavid Howells 	/* Parse one type definition statement at a time */
8104520c6a4SDavid Howells 	type = type_list;
8114520c6a4SDavid Howells 	do {
8124520c6a4SDavid Howells 		cursor = type->name;
8134520c6a4SDavid Howells 
8144520c6a4SDavid Howells 		if (cursor[0].token_type != TOKEN_TYPE_NAME ||
8154520c6a4SDavid Howells 		    cursor[1].token_type != TOKEN_ASSIGNMENT)
8164520c6a4SDavid Howells 			abort();
8174520c6a4SDavid Howells 		cursor += 2;
8184520c6a4SDavid Howells 
8194520c6a4SDavid Howells 		type->element = parse_type(&cursor, type[1].name, NULL);
8204520c6a4SDavid Howells 		type->element->type_def = type;
8214520c6a4SDavid Howells 
8224520c6a4SDavid Howells 		if (cursor != type[1].name) {
823c05cae9aSDavid Howells 			fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
824c05cae9aSDavid Howells 				filename, cursor->line, cursor->content);
8254520c6a4SDavid Howells 			exit(1);
8264520c6a4SDavid Howells 		}
8274520c6a4SDavid Howells 
8284520c6a4SDavid Howells 	} while (type++, !(type->flags & TYPE_STOP_MARKER));
8294520c6a4SDavid Howells 
830ae44a2f6SDavid Howells 	verbose("Extracted %u actions\n", nr_actions);
8314520c6a4SDavid Howells }
8324520c6a4SDavid Howells 
8334520c6a4SDavid Howells static struct element *element_list;
8344520c6a4SDavid Howells 
alloc_elem(void)835a8d56926SZeng Heng static struct element *alloc_elem(void)
8364520c6a4SDavid Howells {
8374520c6a4SDavid Howells 	struct element *e = calloc(1, sizeof(*e));
8384520c6a4SDavid Howells 	if (!e) {
8394520c6a4SDavid Howells 		perror(NULL);
8404520c6a4SDavid Howells 		exit(1);
8414520c6a4SDavid Howells 	}
8424520c6a4SDavid Howells 	e->list_next = element_list;
8434520c6a4SDavid Howells 	element_list = e;
8444520c6a4SDavid Howells 	return e;
8454520c6a4SDavid Howells }
8464520c6a4SDavid Howells 
8474520c6a4SDavid Howells static struct element *parse_compound(struct token **_cursor, struct token *end,
8484520c6a4SDavid Howells 				      int alternates);
8494520c6a4SDavid Howells 
8504520c6a4SDavid Howells /*
8514520c6a4SDavid Howells  * Parse one type definition statement
8524520c6a4SDavid Howells  */
parse_type(struct token ** _cursor,struct token * end,struct token * name)8534520c6a4SDavid Howells static struct element *parse_type(struct token **_cursor, struct token *end,
8544520c6a4SDavid Howells 				  struct token *name)
8554520c6a4SDavid Howells {
8564520c6a4SDavid Howells 	struct element *top, *element;
8574520c6a4SDavid Howells 	struct action *action, **ppaction;
8584520c6a4SDavid Howells 	struct token *cursor = *_cursor;
8594520c6a4SDavid Howells 	struct type **ref;
8604520c6a4SDavid Howells 	char *p;
8614520c6a4SDavid Howells 	int labelled = 0, implicit = 0;
8624520c6a4SDavid Howells 
863a8d56926SZeng Heng 	top = element = alloc_elem();
8644520c6a4SDavid Howells 	element->class = ASN1_UNIV;
8654520c6a4SDavid Howells 	element->method = ASN1_PRIM;
8664520c6a4SDavid Howells 	element->tag = token_to_tag[cursor->token_type];
8674520c6a4SDavid Howells 	element->name = name;
8684520c6a4SDavid Howells 
8694520c6a4SDavid Howells 	/* Extract the tag value if one given */
8704520c6a4SDavid Howells 	if (cursor->token_type == TOKEN_OPEN_SQUARE) {
8714520c6a4SDavid Howells 		cursor++;
8724520c6a4SDavid Howells 		if (cursor >= end)
8734520c6a4SDavid Howells 			goto overrun_error;
8744520c6a4SDavid Howells 		switch (cursor->token_type) {
8754520c6a4SDavid Howells 		case DIRECTIVE_UNIVERSAL:
8764520c6a4SDavid Howells 			element->class = ASN1_UNIV;
8774520c6a4SDavid Howells 			cursor++;
8784520c6a4SDavid Howells 			break;
8794520c6a4SDavid Howells 		case DIRECTIVE_APPLICATION:
8804520c6a4SDavid Howells 			element->class = ASN1_APPL;
8814520c6a4SDavid Howells 			cursor++;
8824520c6a4SDavid Howells 			break;
8834520c6a4SDavid Howells 		case TOKEN_NUMBER:
8844520c6a4SDavid Howells 			element->class = ASN1_CONT;
8854520c6a4SDavid Howells 			break;
8864520c6a4SDavid Howells 		case DIRECTIVE_PRIVATE:
8874520c6a4SDavid Howells 			element->class = ASN1_PRIV;
8884520c6a4SDavid Howells 			cursor++;
8894520c6a4SDavid Howells 			break;
8904520c6a4SDavid Howells 		default:
891c05cae9aSDavid Howells 			fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
892c05cae9aSDavid Howells 				filename, cursor->line, cursor->content);
8934520c6a4SDavid Howells 			exit(1);
8944520c6a4SDavid Howells 		}
8954520c6a4SDavid Howells 
8964520c6a4SDavid Howells 		if (cursor >= end)
8974520c6a4SDavid Howells 			goto overrun_error;
8984520c6a4SDavid Howells 		if (cursor->token_type != TOKEN_NUMBER) {
899c05cae9aSDavid Howells 			fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
900c05cae9aSDavid Howells 				filename, cursor->line, cursor->content);
9014520c6a4SDavid Howells 			exit(1);
9024520c6a4SDavid Howells 		}
9034520c6a4SDavid Howells 
9044520c6a4SDavid Howells 		element->tag &= ~0x1f;
905c05cae9aSDavid Howells 		element->tag |= strtoul(cursor->content, &p, 10);
9068d9b21dcSDavid Howells 		element->flags |= ELEMENT_TAG_SPECIFIED;
907c05cae9aSDavid Howells 		if (p - cursor->content != cursor->size)
9084520c6a4SDavid Howells 			abort();
9094520c6a4SDavid Howells 		cursor++;
9104520c6a4SDavid Howells 
9114520c6a4SDavid Howells 		if (cursor >= end)
9124520c6a4SDavid Howells 			goto overrun_error;
9134520c6a4SDavid Howells 		if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
914c05cae9aSDavid Howells 			fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
915c05cae9aSDavid Howells 				filename, cursor->line, cursor->content);
9164520c6a4SDavid Howells 			exit(1);
9174520c6a4SDavid Howells 		}
9184520c6a4SDavid Howells 		cursor++;
9194520c6a4SDavid Howells 		if (cursor >= end)
9204520c6a4SDavid Howells 			goto overrun_error;
9214520c6a4SDavid Howells 		labelled = 1;
9224520c6a4SDavid Howells 	}
9234520c6a4SDavid Howells 
9244520c6a4SDavid Howells 	/* Handle implicit and explicit markers */
9254520c6a4SDavid Howells 	if (cursor->token_type == DIRECTIVE_IMPLICIT) {
9264520c6a4SDavid Howells 		element->flags |= ELEMENT_IMPLICIT;
9274520c6a4SDavid Howells 		implicit = 1;
9284520c6a4SDavid Howells 		cursor++;
9294520c6a4SDavid Howells 		if (cursor >= end)
9304520c6a4SDavid Howells 			goto overrun_error;
9314520c6a4SDavid Howells 	} else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
9324520c6a4SDavid Howells 		element->flags |= ELEMENT_EXPLICIT;
9334520c6a4SDavid Howells 		cursor++;
9344520c6a4SDavid Howells 		if (cursor >= end)
9354520c6a4SDavid Howells 			goto overrun_error;
9364520c6a4SDavid Howells 	}
9374520c6a4SDavid Howells 
9384520c6a4SDavid Howells 	if (labelled) {
9394520c6a4SDavid Howells 		if (!implicit)
9404520c6a4SDavid Howells 			element->method |= ASN1_CONS;
9414520c6a4SDavid Howells 		element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
942a8d56926SZeng Heng 		element->children = alloc_elem();
9434520c6a4SDavid Howells 		element = element->children;
9444520c6a4SDavid Howells 		element->class = ASN1_UNIV;
9454520c6a4SDavid Howells 		element->method = ASN1_PRIM;
9464520c6a4SDavid Howells 		element->tag = token_to_tag[cursor->token_type];
9474520c6a4SDavid Howells 		element->name = name;
9484520c6a4SDavid Howells 	}
9494520c6a4SDavid Howells 
9504520c6a4SDavid Howells 	/* Extract the type we're expecting here */
9514520c6a4SDavid Howells 	element->type = cursor;
9524520c6a4SDavid Howells 	switch (cursor->token_type) {
9534520c6a4SDavid Howells 	case DIRECTIVE_ANY:
9544520c6a4SDavid Howells 		element->compound = ANY;
9554520c6a4SDavid Howells 		cursor++;
9564520c6a4SDavid Howells 		break;
9574520c6a4SDavid Howells 
9584520c6a4SDavid Howells 	case DIRECTIVE_NULL:
9594520c6a4SDavid Howells 	case DIRECTIVE_BOOLEAN:
9604520c6a4SDavid Howells 	case DIRECTIVE_ENUMERATED:
9614520c6a4SDavid Howells 	case DIRECTIVE_INTEGER:
9624520c6a4SDavid Howells 		element->compound = NOT_COMPOUND;
9634520c6a4SDavid Howells 		cursor++;
9644520c6a4SDavid Howells 		break;
9654520c6a4SDavid Howells 
9664520c6a4SDavid Howells 	case DIRECTIVE_EXTERNAL:
9674520c6a4SDavid Howells 		element->method = ASN1_CONS;
9684520c6a4SDavid Howells 
9694520c6a4SDavid Howells 	case DIRECTIVE_BMPString:
9704520c6a4SDavid Howells 	case DIRECTIVE_GeneralString:
9714520c6a4SDavid Howells 	case DIRECTIVE_GraphicString:
9724520c6a4SDavid Howells 	case DIRECTIVE_IA5String:
9734520c6a4SDavid Howells 	case DIRECTIVE_ISO646String:
9744520c6a4SDavid Howells 	case DIRECTIVE_NumericString:
9754520c6a4SDavid Howells 	case DIRECTIVE_PrintableString:
9764520c6a4SDavid Howells 	case DIRECTIVE_T61String:
9774520c6a4SDavid Howells 	case DIRECTIVE_TeletexString:
9784520c6a4SDavid Howells 	case DIRECTIVE_UniversalString:
9794520c6a4SDavid Howells 	case DIRECTIVE_UTF8String:
9804520c6a4SDavid Howells 	case DIRECTIVE_VideotexString:
9814520c6a4SDavid Howells 	case DIRECTIVE_VisibleString:
9824520c6a4SDavid Howells 	case DIRECTIVE_ObjectDescriptor:
9834520c6a4SDavid Howells 	case DIRECTIVE_GeneralizedTime:
9844520c6a4SDavid Howells 	case DIRECTIVE_UTCTime:
9854520c6a4SDavid Howells 		element->compound = NOT_COMPOUND;
9864520c6a4SDavid Howells 		cursor++;
9874520c6a4SDavid Howells 		break;
9884520c6a4SDavid Howells 
9894520c6a4SDavid Howells 	case DIRECTIVE_BIT:
9904520c6a4SDavid Howells 	case DIRECTIVE_OCTET:
9914520c6a4SDavid Howells 		element->compound = NOT_COMPOUND;
9924520c6a4SDavid Howells 		cursor++;
9934520c6a4SDavid Howells 		if (cursor >= end)
9944520c6a4SDavid Howells 			goto overrun_error;
9954520c6a4SDavid Howells 		if (cursor->token_type != DIRECTIVE_STRING)
9964520c6a4SDavid Howells 			goto parse_error;
9974520c6a4SDavid Howells 		cursor++;
9984520c6a4SDavid Howells 		break;
9994520c6a4SDavid Howells 
10004520c6a4SDavid Howells 	case DIRECTIVE_OBJECT:
10014520c6a4SDavid Howells 		element->compound = NOT_COMPOUND;
10024520c6a4SDavid Howells 		cursor++;
10034520c6a4SDavid Howells 		if (cursor >= end)
10044520c6a4SDavid Howells 			goto overrun_error;
10054520c6a4SDavid Howells 		if (cursor->token_type != DIRECTIVE_IDENTIFIER)
10064520c6a4SDavid Howells 			goto parse_error;
10074520c6a4SDavid Howells 		cursor++;
10084520c6a4SDavid Howells 		break;
10094520c6a4SDavid Howells 
10104520c6a4SDavid Howells 	case TOKEN_TYPE_NAME:
10114520c6a4SDavid Howells 		element->compound = TYPE_REF;
10124520c6a4SDavid Howells 		ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
10134520c6a4SDavid Howells 			      type_finder);
10144520c6a4SDavid Howells 		if (!ref) {
1015c05cae9aSDavid Howells 			fprintf(stderr, "%s:%d: Type '%s' undefined\n",
1016c05cae9aSDavid Howells 				filename, cursor->line, cursor->content);
10174520c6a4SDavid Howells 			exit(1);
10184520c6a4SDavid Howells 		}
10194520c6a4SDavid Howells 		cursor->type = *ref;
10204520c6a4SDavid Howells 		(*ref)->ref_count++;
10214520c6a4SDavid Howells 		cursor++;
10224520c6a4SDavid Howells 		break;
10234520c6a4SDavid Howells 
10244520c6a4SDavid Howells 	case DIRECTIVE_CHOICE:
10254520c6a4SDavid Howells 		element->compound = CHOICE;
10264520c6a4SDavid Howells 		cursor++;
10274520c6a4SDavid Howells 		element->children = parse_compound(&cursor, end, 1);
10284520c6a4SDavid Howells 		break;
10294520c6a4SDavid Howells 
10304520c6a4SDavid Howells 	case DIRECTIVE_SEQUENCE:
10314520c6a4SDavid Howells 		element->compound = SEQUENCE;
10324520c6a4SDavid Howells 		element->method = ASN1_CONS;
10334520c6a4SDavid Howells 		cursor++;
10344520c6a4SDavid Howells 		if (cursor >= end)
10354520c6a4SDavid Howells 			goto overrun_error;
10364520c6a4SDavid Howells 		if (cursor->token_type == DIRECTIVE_OF) {
10374520c6a4SDavid Howells 			element->compound = SEQUENCE_OF;
10384520c6a4SDavid Howells 			cursor++;
10394520c6a4SDavid Howells 			if (cursor >= end)
10404520c6a4SDavid Howells 				goto overrun_error;
10414520c6a4SDavid Howells 			element->children = parse_type(&cursor, end, NULL);
10424520c6a4SDavid Howells 		} else {
10434520c6a4SDavid Howells 			element->children = parse_compound(&cursor, end, 0);
10444520c6a4SDavid Howells 		}
10454520c6a4SDavid Howells 		break;
10464520c6a4SDavid Howells 
10474520c6a4SDavid Howells 	case DIRECTIVE_SET:
10484520c6a4SDavid Howells 		element->compound = SET;
10494520c6a4SDavid Howells 		element->method = ASN1_CONS;
10504520c6a4SDavid Howells 		cursor++;
10514520c6a4SDavid Howells 		if (cursor >= end)
10524520c6a4SDavid Howells 			goto overrun_error;
10534520c6a4SDavid Howells 		if (cursor->token_type == DIRECTIVE_OF) {
10544520c6a4SDavid Howells 			element->compound = SET_OF;
10554520c6a4SDavid Howells 			cursor++;
10564520c6a4SDavid Howells 			if (cursor >= end)
10574520c6a4SDavid Howells 				goto parse_error;
10584520c6a4SDavid Howells 			element->children = parse_type(&cursor, end, NULL);
10594520c6a4SDavid Howells 		} else {
10604520c6a4SDavid Howells 			element->children = parse_compound(&cursor, end, 1);
10614520c6a4SDavid Howells 		}
10624520c6a4SDavid Howells 		break;
10634520c6a4SDavid Howells 
10644520c6a4SDavid Howells 	default:
1065c05cae9aSDavid Howells 		fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
1066c05cae9aSDavid Howells 			filename, cursor->line, cursor->content);
10674520c6a4SDavid Howells 		exit(1);
10684520c6a4SDavid Howells 	}
10694520c6a4SDavid Howells 
10704520c6a4SDavid Howells 	/* Handle elements that are optional */
10714520c6a4SDavid Howells 	if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
10724520c6a4SDavid Howells 			     cursor->token_type == DIRECTIVE_DEFAULT)
10734520c6a4SDavid Howells 	    ) {
10744520c6a4SDavid Howells 		cursor++;
10754520c6a4SDavid Howells 		top->flags |= ELEMENT_SKIPPABLE;
10764520c6a4SDavid Howells 	}
10774520c6a4SDavid Howells 
10784520c6a4SDavid Howells 	if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
10794520c6a4SDavid Howells 		cursor++;
10804520c6a4SDavid Howells 		if (cursor >= end)
10814520c6a4SDavid Howells 			goto overrun_error;
10824520c6a4SDavid Howells 		if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1083c05cae9aSDavid Howells 			fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
1084c05cae9aSDavid Howells 				filename, cursor->line, cursor->content);
10854520c6a4SDavid Howells 			exit(1);
10864520c6a4SDavid Howells 		}
10874520c6a4SDavid Howells 
1088c05cae9aSDavid Howells 		action = malloc(sizeof(struct action));
10894520c6a4SDavid Howells 		if (!action) {
10904520c6a4SDavid Howells 			perror(NULL);
10914520c6a4SDavid Howells 			exit(1);
10924520c6a4SDavid Howells 		}
10934520c6a4SDavid Howells 		action->index = 0;
1094c05cae9aSDavid Howells 		action->name = cursor->content;
10954520c6a4SDavid Howells 
10964520c6a4SDavid Howells 		for (ppaction = &action_list;
10974520c6a4SDavid Howells 		     *ppaction;
10984520c6a4SDavid Howells 		     ppaction = &(*ppaction)->next
10994520c6a4SDavid Howells 		     ) {
11004520c6a4SDavid Howells 			int cmp = strcmp(action->name, (*ppaction)->name);
11014520c6a4SDavid Howells 			if (cmp == 0) {
11024520c6a4SDavid Howells 				free(action);
11034520c6a4SDavid Howells 				action = *ppaction;
11044520c6a4SDavid Howells 				goto found;
11054520c6a4SDavid Howells 			}
11064520c6a4SDavid Howells 			if (cmp < 0) {
11074520c6a4SDavid Howells 				action->next = *ppaction;
11084520c6a4SDavid Howells 				*ppaction = action;
11094520c6a4SDavid Howells 				nr_actions++;
11104520c6a4SDavid Howells 				goto found;
11114520c6a4SDavid Howells 			}
11124520c6a4SDavid Howells 		}
11134520c6a4SDavid Howells 		action->next = NULL;
11144520c6a4SDavid Howells 		*ppaction = action;
11154520c6a4SDavid Howells 		nr_actions++;
11164520c6a4SDavid Howells 	found:
11174520c6a4SDavid Howells 
11184520c6a4SDavid Howells 		element->action = action;
11194520c6a4SDavid Howells 		cursor->action = action;
11204520c6a4SDavid Howells 		cursor++;
11214520c6a4SDavid Howells 		if (cursor >= end)
11224520c6a4SDavid Howells 			goto overrun_error;
11234520c6a4SDavid Howells 		if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1124c05cae9aSDavid Howells 			fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
1125c05cae9aSDavid Howells 				filename, cursor->line, cursor->content);
11264520c6a4SDavid Howells 			exit(1);
11274520c6a4SDavid Howells 		}
11284520c6a4SDavid Howells 		cursor++;
11294520c6a4SDavid Howells 	}
11304520c6a4SDavid Howells 
11314520c6a4SDavid Howells 	*_cursor = cursor;
11324520c6a4SDavid Howells 	return top;
11334520c6a4SDavid Howells 
11344520c6a4SDavid Howells parse_error:
1135c05cae9aSDavid Howells 	fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
1136c05cae9aSDavid Howells 		filename, cursor->line, cursor->content);
11374520c6a4SDavid Howells 	exit(1);
11384520c6a4SDavid Howells 
11394520c6a4SDavid Howells overrun_error:
11404520c6a4SDavid Howells 	fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
11414520c6a4SDavid Howells 	exit(1);
11424520c6a4SDavid Howells }
11434520c6a4SDavid Howells 
11444520c6a4SDavid Howells /*
11454520c6a4SDavid Howells  * Parse a compound type list
11464520c6a4SDavid Howells  */
parse_compound(struct token ** _cursor,struct token * end,int alternates)11474520c6a4SDavid Howells static struct element *parse_compound(struct token **_cursor, struct token *end,
11484520c6a4SDavid Howells 				      int alternates)
11494520c6a4SDavid Howells {
11504520c6a4SDavid Howells 	struct element *children, **child_p = &children, *element;
11514520c6a4SDavid Howells 	struct token *cursor = *_cursor, *name;
11524520c6a4SDavid Howells 
11534520c6a4SDavid Howells 	if (cursor->token_type != TOKEN_OPEN_CURLY) {
1154c05cae9aSDavid Howells 		fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
1155c05cae9aSDavid Howells 			filename, cursor->line, cursor->content);
11564520c6a4SDavid Howells 		exit(1);
11574520c6a4SDavid Howells 	}
11584520c6a4SDavid Howells 	cursor++;
11594520c6a4SDavid Howells 	if (cursor >= end)
11604520c6a4SDavid Howells 		goto overrun_error;
11614520c6a4SDavid Howells 
11624520c6a4SDavid Howells 	if (cursor->token_type == TOKEN_OPEN_CURLY) {
11634520c6a4SDavid Howells 		fprintf(stderr, "%s:%d: Empty compound\n",
11644520c6a4SDavid Howells 			filename, cursor->line);
11654520c6a4SDavid Howells 		exit(1);
11664520c6a4SDavid Howells 	}
11674520c6a4SDavid Howells 
11684520c6a4SDavid Howells 	for (;;) {
11694520c6a4SDavid Howells 		name = NULL;
11704520c6a4SDavid Howells 		if (cursor->token_type == TOKEN_ELEMENT_NAME) {
11714520c6a4SDavid Howells 			name = cursor;
11724520c6a4SDavid Howells 			cursor++;
11734520c6a4SDavid Howells 			if (cursor >= end)
11744520c6a4SDavid Howells 				goto overrun_error;
11754520c6a4SDavid Howells 		}
11764520c6a4SDavid Howells 
11774520c6a4SDavid Howells 		element = parse_type(&cursor, end, name);
11784520c6a4SDavid Howells 		if (alternates)
11794520c6a4SDavid Howells 			element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
11804520c6a4SDavid Howells 
11814520c6a4SDavid Howells 		*child_p = element;
11824520c6a4SDavid Howells 		child_p = &element->next;
11834520c6a4SDavid Howells 
11844520c6a4SDavid Howells 		if (cursor >= end)
11854520c6a4SDavid Howells 			goto overrun_error;
11864520c6a4SDavid Howells 		if (cursor->token_type != TOKEN_COMMA)
11874520c6a4SDavid Howells 			break;
11884520c6a4SDavid Howells 		cursor++;
11894520c6a4SDavid Howells 		if (cursor >= end)
11904520c6a4SDavid Howells 			goto overrun_error;
11914520c6a4SDavid Howells 	}
11924520c6a4SDavid Howells 
11934520c6a4SDavid Howells 	children->flags &= ~ELEMENT_CONDITIONAL;
11944520c6a4SDavid Howells 
11954520c6a4SDavid Howells 	if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1196c05cae9aSDavid Howells 		fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
1197c05cae9aSDavid Howells 			filename, cursor->line, cursor->content);
11984520c6a4SDavid Howells 		exit(1);
11994520c6a4SDavid Howells 	}
12004520c6a4SDavid Howells 	cursor++;
12014520c6a4SDavid Howells 
12024520c6a4SDavid Howells 	*_cursor = cursor;
12034520c6a4SDavid Howells 	return children;
12044520c6a4SDavid Howells 
12054520c6a4SDavid Howells overrun_error:
12064520c6a4SDavid Howells 	fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
12074520c6a4SDavid Howells 	exit(1);
12084520c6a4SDavid Howells }
12094520c6a4SDavid Howells 
dump_element(const struct element * e,int level)1210ae44a2f6SDavid Howells static void dump_element(const struct element *e, int level)
1211ae44a2f6SDavid Howells {
1212ae44a2f6SDavid Howells 	const struct element *c;
1213ae44a2f6SDavid Howells 	const struct type *t = e->type_def;
1214c05cae9aSDavid Howells 	const char *name = e->name ? e->name->content : ".";
1215c05cae9aSDavid Howells 	const char *tname = t && t->name ? t->name->content : ".";
1216ae44a2f6SDavid Howells 	char tag[32];
1217ae44a2f6SDavid Howells 
1218ae44a2f6SDavid Howells 	if (e->class == 0 && e->method == 0 && e->tag == 0)
1219ae44a2f6SDavid Howells 		strcpy(tag, "<...>");
1220ae44a2f6SDavid Howells 	else if (e->class == ASN1_UNIV)
1221ae44a2f6SDavid Howells 		sprintf(tag, "%s %s %s",
1222ae44a2f6SDavid Howells 			asn1_classes[e->class],
1223ae44a2f6SDavid Howells 			asn1_methods[e->method],
1224ae44a2f6SDavid Howells 			asn1_universal_tags[e->tag]);
1225ae44a2f6SDavid Howells 	else
1226ae44a2f6SDavid Howells 		sprintf(tag, "%s %s %u",
1227ae44a2f6SDavid Howells 			asn1_classes[e->class],
1228ae44a2f6SDavid Howells 			asn1_methods[e->method],
1229ae44a2f6SDavid Howells 			e->tag);
1230ae44a2f6SDavid Howells 
1231c05cae9aSDavid Howells 	printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
1232ae44a2f6SDavid Howells 	       e->flags & ELEMENT_IMPLICIT ? 'I' : '-',
1233ae44a2f6SDavid Howells 	       e->flags & ELEMENT_EXPLICIT ? 'E' : '-',
1234ae44a2f6SDavid Howells 	       e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-',
1235ae44a2f6SDavid Howells 	       e->flags & ELEMENT_SKIPPABLE ? 'S' : '-',
1236ae44a2f6SDavid Howells 	       e->flags & ELEMENT_CONDITIONAL ? 'C' : '-',
1237ae44a2f6SDavid Howells 	       "-tTqQcaro"[e->compound],
1238ae44a2f6SDavid Howells 	       level, "",
1239ae44a2f6SDavid Howells 	       tag,
1240c05cae9aSDavid Howells 	       tname,
1241c05cae9aSDavid Howells 	       name,
1242ae44a2f6SDavid Howells 	       e->action ? e->action->name : "");
1243ae44a2f6SDavid Howells 	if (e->compound == TYPE_REF)
1244ae44a2f6SDavid Howells 		dump_element(e->type->type->element, level + 3);
1245ae44a2f6SDavid Howells 	else
1246ae44a2f6SDavid Howells 		for (c = e->children; c; c = c->next)
1247ae44a2f6SDavid Howells 			dump_element(c, level + 3);
1248ae44a2f6SDavid Howells }
1249ae44a2f6SDavid Howells 
dump_elements(void)1250ae44a2f6SDavid Howells static void dump_elements(void)
1251ae44a2f6SDavid Howells {
1252ae44a2f6SDavid Howells 	if (debug_opt)
1253ae44a2f6SDavid Howells 		dump_element(type_list[0].element, 0);
1254ae44a2f6SDavid Howells }
1255ae44a2f6SDavid Howells 
12564520c6a4SDavid Howells static void render_element(FILE *out, struct element *e, struct element *tag);
12574520c6a4SDavid Howells static void render_out_of_line_list(FILE *out);
12584520c6a4SDavid Howells 
12594520c6a4SDavid Howells static int nr_entries;
12604520c6a4SDavid Howells static int render_depth = 1;
12614520c6a4SDavid Howells static struct element *render_list, **render_list_p = &render_list;
12624520c6a4SDavid Howells 
12634520c6a4SDavid Howells __attribute__((format(printf, 2, 3)))
render_opcode(FILE * out,const char * fmt,...)12644520c6a4SDavid Howells static void render_opcode(FILE *out, const char *fmt, ...)
12654520c6a4SDavid Howells {
12664520c6a4SDavid Howells 	va_list va;
12674520c6a4SDavid Howells 
12684520c6a4SDavid Howells 	if (out) {
12694520c6a4SDavid Howells 		fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
12704520c6a4SDavid Howells 		va_start(va, fmt);
12714520c6a4SDavid Howells 		vfprintf(out, fmt, va);
12724520c6a4SDavid Howells 		va_end(va);
12734520c6a4SDavid Howells 	}
12744520c6a4SDavid Howells 	nr_entries++;
12754520c6a4SDavid Howells }
12764520c6a4SDavid Howells 
12774520c6a4SDavid Howells __attribute__((format(printf, 2, 3)))
render_more(FILE * out,const char * fmt,...)12784520c6a4SDavid Howells static void render_more(FILE *out, const char *fmt, ...)
12794520c6a4SDavid Howells {
12804520c6a4SDavid Howells 	va_list va;
12814520c6a4SDavid Howells 
12824520c6a4SDavid Howells 	if (out) {
12834520c6a4SDavid Howells 		va_start(va, fmt);
12844520c6a4SDavid Howells 		vfprintf(out, fmt, va);
12854520c6a4SDavid Howells 		va_end(va);
12864520c6a4SDavid Howells 	}
12874520c6a4SDavid Howells }
12884520c6a4SDavid Howells 
12894520c6a4SDavid Howells /*
12904520c6a4SDavid Howells  * Render the grammar into a state machine definition.
12914520c6a4SDavid Howells  */
render(FILE * out,FILE * hdr)12924520c6a4SDavid Howells static void render(FILE *out, FILE *hdr)
12934520c6a4SDavid Howells {
12944520c6a4SDavid Howells 	struct element *e;
12954520c6a4SDavid Howells 	struct action *action;
12964520c6a4SDavid Howells 	struct type *root;
12974520c6a4SDavid Howells 	int index;
12984520c6a4SDavid Howells 
12994520c6a4SDavid Howells 	fprintf(hdr, "/*\n");
13004520c6a4SDavid Howells 	fprintf(hdr, " * Automatically generated by asn1_compiler.  Do not edit\n");
13014520c6a4SDavid Howells 	fprintf(hdr, " *\n");
13024520c6a4SDavid Howells 	fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
13034520c6a4SDavid Howells 	fprintf(hdr, " */\n");
13044520c6a4SDavid Howells 	fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
13054520c6a4SDavid Howells 	fprintf(hdr, "\n");
13064520c6a4SDavid Howells 	fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
13074520c6a4SDavid Howells 	if (ferror(hdr)) {
13084520c6a4SDavid Howells 		perror(headername);
13094520c6a4SDavid Howells 		exit(1);
13104520c6a4SDavid Howells 	}
13114520c6a4SDavid Howells 
13124520c6a4SDavid Howells 	fprintf(out, "/*\n");
13134520c6a4SDavid Howells 	fprintf(out, " * Automatically generated by asn1_compiler.  Do not edit\n");
13144520c6a4SDavid Howells 	fprintf(out, " *\n");
13154520c6a4SDavid Howells 	fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
13164520c6a4SDavid Howells 	fprintf(out, " */\n");
13174520c6a4SDavid Howells 	fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
13184fa8bc94SMasahiro Yamada 	fprintf(out, "#include \"%s.asn1.h\"\n", grammar_name);
13194520c6a4SDavid Howells 	fprintf(out, "\n");
13204520c6a4SDavid Howells 	if (ferror(out)) {
13214520c6a4SDavid Howells 		perror(outputname);
13224520c6a4SDavid Howells 		exit(1);
13234520c6a4SDavid Howells 	}
13244520c6a4SDavid Howells 
13254520c6a4SDavid Howells 	/* Tabulate the action functions we might have to call */
13264520c6a4SDavid Howells 	fprintf(hdr, "\n");
13274520c6a4SDavid Howells 	index = 0;
13284520c6a4SDavid Howells 	for (action = action_list; action; action = action->next) {
13294520c6a4SDavid Howells 		action->index = index++;
13304520c6a4SDavid Howells 		fprintf(hdr,
13314520c6a4SDavid Howells 			"extern int %s(void *, size_t, unsigned char,"
13324520c6a4SDavid Howells 			" const void *, size_t);\n",
13334520c6a4SDavid Howells 			action->name);
13344520c6a4SDavid Howells 	}
13354520c6a4SDavid Howells 	fprintf(hdr, "\n");
13364520c6a4SDavid Howells 
13374520c6a4SDavid Howells 	fprintf(out, "enum %s_actions {\n", grammar_name);
13384520c6a4SDavid Howells 	for (action = action_list; action; action = action->next)
13394520c6a4SDavid Howells 		fprintf(out, "\tACT_%s = %u,\n",
13404520c6a4SDavid Howells 			action->name, action->index);
13414520c6a4SDavid Howells 	fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
13424520c6a4SDavid Howells 	fprintf(out, "};\n");
13434520c6a4SDavid Howells 
13444520c6a4SDavid Howells 	fprintf(out, "\n");
13454520c6a4SDavid Howells 	fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
13464520c6a4SDavid Howells 		grammar_name, grammar_name);
13474520c6a4SDavid Howells 	for (action = action_list; action; action = action->next)
13484520c6a4SDavid Howells 		fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
13494520c6a4SDavid Howells 	fprintf(out, "};\n");
13504520c6a4SDavid Howells 
13514520c6a4SDavid Howells 	if (ferror(out)) {
13524520c6a4SDavid Howells 		perror(outputname);
13534520c6a4SDavid Howells 		exit(1);
13544520c6a4SDavid Howells 	}
13554520c6a4SDavid Howells 
13564520c6a4SDavid Howells 	/* We do two passes - the first one calculates all the offsets */
1357ae44a2f6SDavid Howells 	verbose("Pass 1\n");
13584520c6a4SDavid Howells 	nr_entries = 0;
13594520c6a4SDavid Howells 	root = &type_list[0];
13604520c6a4SDavid Howells 	render_element(NULL, root->element, NULL);
13614520c6a4SDavid Howells 	render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
13624520c6a4SDavid Howells 	render_out_of_line_list(NULL);
13634520c6a4SDavid Howells 
13644520c6a4SDavid Howells 	for (e = element_list; e; e = e->list_next)
13654520c6a4SDavid Howells 		e->flags &= ~ELEMENT_RENDERED;
13664520c6a4SDavid Howells 
13674520c6a4SDavid Howells 	/* And then we actually render */
1368ae44a2f6SDavid Howells 	verbose("Pass 2\n");
13694520c6a4SDavid Howells 	fprintf(out, "\n");
13704520c6a4SDavid Howells 	fprintf(out, "static const unsigned char %s_machine[] = {\n",
13714520c6a4SDavid Howells 		grammar_name);
13724520c6a4SDavid Howells 
13734520c6a4SDavid Howells 	nr_entries = 0;
13744520c6a4SDavid Howells 	root = &type_list[0];
13754520c6a4SDavid Howells 	render_element(out, root->element, NULL);
13764520c6a4SDavid Howells 	render_opcode(out, "ASN1_OP_COMPLETE,\n");
13774520c6a4SDavid Howells 	render_out_of_line_list(out);
13784520c6a4SDavid Howells 
13794520c6a4SDavid Howells 	fprintf(out, "};\n");
13804520c6a4SDavid Howells 
13814520c6a4SDavid Howells 	fprintf(out, "\n");
13824520c6a4SDavid Howells 	fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
13834520c6a4SDavid Howells 	fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
13844520c6a4SDavid Howells 	fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
13854520c6a4SDavid Howells 	fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
13864520c6a4SDavid Howells 	fprintf(out, "};\n");
13874520c6a4SDavid Howells }
13884520c6a4SDavid Howells 
13894520c6a4SDavid Howells /*
13904520c6a4SDavid Howells  * Render the out-of-line elements
13914520c6a4SDavid Howells  */
render_out_of_line_list(FILE * out)13924520c6a4SDavid Howells static void render_out_of_line_list(FILE *out)
13934520c6a4SDavid Howells {
13944520c6a4SDavid Howells 	struct element *e, *ce;
13954520c6a4SDavid Howells 	const char *act;
13964520c6a4SDavid Howells 	int entry;
13974520c6a4SDavid Howells 
13984520c6a4SDavid Howells 	while ((e = render_list)) {
13994520c6a4SDavid Howells 		render_list = e->render_next;
14004520c6a4SDavid Howells 		if (!render_list)
14014520c6a4SDavid Howells 			render_list_p = &render_list;
14024520c6a4SDavid Howells 
14034520c6a4SDavid Howells 		render_more(out, "\n");
14044520c6a4SDavid Howells 		e->entry_index = entry = nr_entries;
14054520c6a4SDavid Howells 		render_depth++;
14064520c6a4SDavid Howells 		for (ce = e->children; ce; ce = ce->next)
14074520c6a4SDavid Howells 			render_element(out, ce, NULL);
14084520c6a4SDavid Howells 		render_depth--;
14094520c6a4SDavid Howells 
14104520c6a4SDavid Howells 		act = e->action ? "_ACT" : "";
14114520c6a4SDavid Howells 		switch (e->compound) {
14124520c6a4SDavid Howells 		case SEQUENCE:
14134520c6a4SDavid Howells 			render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
14144520c6a4SDavid Howells 			break;
14154520c6a4SDavid Howells 		case SEQUENCE_OF:
14164520c6a4SDavid Howells 			render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
14174520c6a4SDavid Howells 			render_opcode(out, "_jump_target(%u),\n", entry);
14184520c6a4SDavid Howells 			break;
14194520c6a4SDavid Howells 		case SET:
14204520c6a4SDavid Howells 			render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
14214520c6a4SDavid Howells 			break;
14224520c6a4SDavid Howells 		case SET_OF:
14234520c6a4SDavid Howells 			render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
14244520c6a4SDavid Howells 			render_opcode(out, "_jump_target(%u),\n", entry);
14254520c6a4SDavid Howells 			break;
1426eb8948a0SAntonio Alecrim Jr 		default:
1427eb8948a0SAntonio Alecrim Jr 			break;
14284520c6a4SDavid Howells 		}
14294520c6a4SDavid Howells 		if (e->action)
14304520c6a4SDavid Howells 			render_opcode(out, "_action(ACT_%s),\n",
14314520c6a4SDavid Howells 				      e->action->name);
14324520c6a4SDavid Howells 		render_opcode(out, "ASN1_OP_RETURN,\n");
14334520c6a4SDavid Howells 	}
14344520c6a4SDavid Howells }
14354520c6a4SDavid Howells 
14364520c6a4SDavid Howells /*
14374520c6a4SDavid Howells  * Render an element.
14384520c6a4SDavid Howells  */
render_element(FILE * out,struct element * e,struct element * tag)14394520c6a4SDavid Howells static void render_element(FILE *out, struct element *e, struct element *tag)
14404520c6a4SDavid Howells {
14418d9b21dcSDavid Howells 	struct element *ec, *x;
14424520c6a4SDavid Howells 	const char *cond, *act;
14434520c6a4SDavid Howells 	int entry, skippable = 0, outofline = 0;
14444520c6a4SDavid Howells 
14454520c6a4SDavid Howells 	if (e->flags & ELEMENT_SKIPPABLE ||
14464520c6a4SDavid Howells 	    (tag && tag->flags & ELEMENT_SKIPPABLE))
14474520c6a4SDavid Howells 		skippable = 1;
14484520c6a4SDavid Howells 
14494520c6a4SDavid Howells 	if ((e->type_def && e->type_def->ref_count > 1) ||
14504520c6a4SDavid Howells 	    skippable)
14514520c6a4SDavid Howells 		outofline = 1;
14524520c6a4SDavid Howells 
14534520c6a4SDavid Howells 	if (e->type_def && out) {
1454c05cae9aSDavid Howells 		render_more(out, "\t// %s\n", e->type_def->name->content);
14554520c6a4SDavid Howells 	}
14564520c6a4SDavid Howells 
14574520c6a4SDavid Howells 	/* Render the operation */
14584520c6a4SDavid Howells 	cond = (e->flags & ELEMENT_CONDITIONAL ||
14594520c6a4SDavid Howells 		(tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
14604520c6a4SDavid Howells 	act = e->action ? "_ACT" : "";
14614520c6a4SDavid Howells 	switch (e->compound) {
14624520c6a4SDavid Howells 	case ANY:
1463233ce79dSDavid Howells 		render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
1464233ce79dSDavid Howells 			      cond, act, skippable ? "_OR_SKIP" : "");
14654520c6a4SDavid Howells 		if (e->name)
1466c05cae9aSDavid Howells 			render_more(out, "\t\t// %s", e->name->content);
14674520c6a4SDavid Howells 		render_more(out, "\n");
14684520c6a4SDavid Howells 		goto dont_render_tag;
14694520c6a4SDavid Howells 
14704520c6a4SDavid Howells 	case TAG_OVERRIDE:
14714520c6a4SDavid Howells 		render_element(out, e->children, e);
14724520c6a4SDavid Howells 		return;
14734520c6a4SDavid Howells 
14744520c6a4SDavid Howells 	case SEQUENCE:
14754520c6a4SDavid Howells 	case SEQUENCE_OF:
14764520c6a4SDavid Howells 	case SET:
14774520c6a4SDavid Howells 	case SET_OF:
14784520c6a4SDavid Howells 		render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
14794520c6a4SDavid Howells 			      cond,
14804520c6a4SDavid Howells 			      outofline ? "_JUMP" : "",
14814520c6a4SDavid Howells 			      skippable ? "_OR_SKIP" : "");
14824520c6a4SDavid Howells 		break;
14834520c6a4SDavid Howells 
14844520c6a4SDavid Howells 	case CHOICE:
14854520c6a4SDavid Howells 		goto dont_render_tag;
14864520c6a4SDavid Howells 
14874520c6a4SDavid Howells 	case TYPE_REF:
14884520c6a4SDavid Howells 		if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
14894520c6a4SDavid Howells 			goto dont_render_tag;
14904520c6a4SDavid Howells 	default:
14914520c6a4SDavid Howells 		render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
14924520c6a4SDavid Howells 			      cond, act,
14934520c6a4SDavid Howells 			      skippable ? "_OR_SKIP" : "");
14944520c6a4SDavid Howells 		break;
14954520c6a4SDavid Howells 	}
14964520c6a4SDavid Howells 
14978d9b21dcSDavid Howells 	x = tag ?: e;
14988d9b21dcSDavid Howells 	if (x->name)
1499c05cae9aSDavid Howells 		render_more(out, "\t\t// %s", x->name->content);
15004520c6a4SDavid Howells 	render_more(out, "\n");
15014520c6a4SDavid Howells 
15024520c6a4SDavid Howells 	/* Render the tag */
15038d9b21dcSDavid Howells 	if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
15044520c6a4SDavid Howells 		tag = e;
15058d9b21dcSDavid Howells 
15064520c6a4SDavid Howells 	if (tag->class == ASN1_UNIV &&
15074520c6a4SDavid Howells 	    tag->tag != 14 &&
15084520c6a4SDavid Howells 	    tag->tag != 15 &&
15094520c6a4SDavid Howells 	    tag->tag != 31)
15104520c6a4SDavid Howells 		render_opcode(out, "_tag(%s, %s, %s),\n",
15114520c6a4SDavid Howells 			      asn1_classes[tag->class],
15124520c6a4SDavid Howells 			      asn1_methods[tag->method | e->method],
15134520c6a4SDavid Howells 			      asn1_universal_tags[tag->tag]);
15144520c6a4SDavid Howells 	else
15154520c6a4SDavid Howells 		render_opcode(out, "_tagn(%s, %s, %2u),\n",
15164520c6a4SDavid Howells 			      asn1_classes[tag->class],
15174520c6a4SDavid Howells 			      asn1_methods[tag->method | e->method],
15184520c6a4SDavid Howells 			      tag->tag);
15194520c6a4SDavid Howells 	tag = NULL;
15204520c6a4SDavid Howells dont_render_tag:
15214520c6a4SDavid Howells 
15224520c6a4SDavid Howells 	/* Deal with compound types */
15234520c6a4SDavid Howells 	switch (e->compound) {
15244520c6a4SDavid Howells 	case TYPE_REF:
15254520c6a4SDavid Howells 		render_element(out, e->type->type->element, tag);
15264520c6a4SDavid Howells 		if (e->action)
15273f3af97dSDavid Howells 			render_opcode(out, "ASN1_OP_%sACT,\n",
15283f3af97dSDavid Howells 				      skippable ? "MAYBE_" : "");
15294520c6a4SDavid Howells 		break;
15304520c6a4SDavid Howells 
15314520c6a4SDavid Howells 	case SEQUENCE:
15324520c6a4SDavid Howells 		if (outofline) {
15334520c6a4SDavid Howells 			/* Render out-of-line for multiple use or
15344520c6a4SDavid Howells 			 * skipability */
15354520c6a4SDavid Howells 			render_opcode(out, "_jump_target(%u),", e->entry_index);
15364520c6a4SDavid Howells 			if (e->type_def && e->type_def->name)
1537c05cae9aSDavid Howells 				render_more(out, "\t\t// --> %s",
1538c05cae9aSDavid Howells 					    e->type_def->name->content);
15394520c6a4SDavid Howells 			render_more(out, "\n");
15404520c6a4SDavid Howells 			if (!(e->flags & ELEMENT_RENDERED)) {
15414520c6a4SDavid Howells 				e->flags |= ELEMENT_RENDERED;
15424520c6a4SDavid Howells 				*render_list_p = e;
15434520c6a4SDavid Howells 				render_list_p = &e->render_next;
15444520c6a4SDavid Howells 			}
15454520c6a4SDavid Howells 			return;
15464520c6a4SDavid Howells 		} else {
15474520c6a4SDavid Howells 			/* Render inline for single use */
15484520c6a4SDavid Howells 			render_depth++;
15494520c6a4SDavid Howells 			for (ec = e->children; ec; ec = ec->next)
15504520c6a4SDavid Howells 				render_element(out, ec, NULL);
15514520c6a4SDavid Howells 			render_depth--;
15524520c6a4SDavid Howells 			render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
15534520c6a4SDavid Howells 		}
15544520c6a4SDavid Howells 		break;
15554520c6a4SDavid Howells 
15564520c6a4SDavid Howells 	case SEQUENCE_OF:
15574520c6a4SDavid Howells 	case SET_OF:
15584520c6a4SDavid Howells 		if (outofline) {
15594520c6a4SDavid Howells 			/* Render out-of-line for multiple use or
15604520c6a4SDavid Howells 			 * skipability */
15614520c6a4SDavid Howells 			render_opcode(out, "_jump_target(%u),", e->entry_index);
15624520c6a4SDavid Howells 			if (e->type_def && e->type_def->name)
1563c05cae9aSDavid Howells 				render_more(out, "\t\t// --> %s",
1564c05cae9aSDavid Howells 					    e->type_def->name->content);
15654520c6a4SDavid Howells 			render_more(out, "\n");
15664520c6a4SDavid Howells 			if (!(e->flags & ELEMENT_RENDERED)) {
15674520c6a4SDavid Howells 				e->flags |= ELEMENT_RENDERED;
15684520c6a4SDavid Howells 				*render_list_p = e;
15694520c6a4SDavid Howells 				render_list_p = &e->render_next;
15704520c6a4SDavid Howells 			}
15714520c6a4SDavid Howells 			return;
15724520c6a4SDavid Howells 		} else {
15734520c6a4SDavid Howells 			/* Render inline for single use */
15744520c6a4SDavid Howells 			entry = nr_entries;
15754520c6a4SDavid Howells 			render_depth++;
15764520c6a4SDavid Howells 			render_element(out, e->children, NULL);
15774520c6a4SDavid Howells 			render_depth--;
15784520c6a4SDavid Howells 			if (e->compound == SEQUENCE_OF)
15794520c6a4SDavid Howells 				render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
15804520c6a4SDavid Howells 			else
15814520c6a4SDavid Howells 				render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
15824520c6a4SDavid Howells 			render_opcode(out, "_jump_target(%u),\n", entry);
15834520c6a4SDavid Howells 		}
15844520c6a4SDavid Howells 		break;
15854520c6a4SDavid Howells 
15864520c6a4SDavid Howells 	case SET:
15874520c6a4SDavid Howells 		/* I can't think of a nice way to do SET support without having
15884520c6a4SDavid Howells 		 * a stack of bitmasks to make sure no element is repeated.
15894520c6a4SDavid Howells 		 * The bitmask has also to be checked that no non-optional
15904520c6a4SDavid Howells 		 * elements are left out whilst not preventing optional
15914520c6a4SDavid Howells 		 * elements from being left out.
15924520c6a4SDavid Howells 		 */
15934520c6a4SDavid Howells 		fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
15944520c6a4SDavid Howells 		exit(1);
15954520c6a4SDavid Howells 
15964520c6a4SDavid Howells 	case CHOICE:
15974520c6a4SDavid Howells 		for (ec = e->children; ec; ec = ec->next)
15988d9b21dcSDavid Howells 			render_element(out, ec, ec);
15994520c6a4SDavid Howells 		if (!skippable)
16004520c6a4SDavid Howells 			render_opcode(out, "ASN1_OP_COND_FAIL,\n");
16014520c6a4SDavid Howells 		if (e->action)
16024520c6a4SDavid Howells 			render_opcode(out, "ASN1_OP_ACT,\n");
16034520c6a4SDavid Howells 		break;
16044520c6a4SDavid Howells 
16054520c6a4SDavid Howells 	default:
16064520c6a4SDavid Howells 		break;
16074520c6a4SDavid Howells 	}
16084520c6a4SDavid Howells 
16094520c6a4SDavid Howells 	if (e->action)
16104520c6a4SDavid Howells 		render_opcode(out, "_action(ACT_%s),\n", e->action->name);
16114520c6a4SDavid Howells }
1612