18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* Simplified ASN.1 notation parser
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <stdarg.h>
98c2ecf20Sopenharmony_ci#include <stdio.h>
108c2ecf20Sopenharmony_ci#include <stdlib.h>
118c2ecf20Sopenharmony_ci#include <stdint.h>
128c2ecf20Sopenharmony_ci#include <stdbool.h>
138c2ecf20Sopenharmony_ci#include <string.h>
148c2ecf20Sopenharmony_ci#include <ctype.h>
158c2ecf20Sopenharmony_ci#include <unistd.h>
168c2ecf20Sopenharmony_ci#include <fcntl.h>
178c2ecf20Sopenharmony_ci#include <sys/stat.h>
188c2ecf20Sopenharmony_ci#include <linux/asn1_ber_bytecode.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cienum token_type {
218c2ecf20Sopenharmony_ci	DIRECTIVE_ABSENT,
228c2ecf20Sopenharmony_ci	DIRECTIVE_ALL,
238c2ecf20Sopenharmony_ci	DIRECTIVE_ANY,
248c2ecf20Sopenharmony_ci	DIRECTIVE_APPLICATION,
258c2ecf20Sopenharmony_ci	DIRECTIVE_AUTOMATIC,
268c2ecf20Sopenharmony_ci	DIRECTIVE_BEGIN,
278c2ecf20Sopenharmony_ci	DIRECTIVE_BIT,
288c2ecf20Sopenharmony_ci	DIRECTIVE_BMPString,
298c2ecf20Sopenharmony_ci	DIRECTIVE_BOOLEAN,
308c2ecf20Sopenharmony_ci	DIRECTIVE_BY,
318c2ecf20Sopenharmony_ci	DIRECTIVE_CHARACTER,
328c2ecf20Sopenharmony_ci	DIRECTIVE_CHOICE,
338c2ecf20Sopenharmony_ci	DIRECTIVE_CLASS,
348c2ecf20Sopenharmony_ci	DIRECTIVE_COMPONENT,
358c2ecf20Sopenharmony_ci	DIRECTIVE_COMPONENTS,
368c2ecf20Sopenharmony_ci	DIRECTIVE_CONSTRAINED,
378c2ecf20Sopenharmony_ci	DIRECTIVE_CONTAINING,
388c2ecf20Sopenharmony_ci	DIRECTIVE_DEFAULT,
398c2ecf20Sopenharmony_ci	DIRECTIVE_DEFINED,
408c2ecf20Sopenharmony_ci	DIRECTIVE_DEFINITIONS,
418c2ecf20Sopenharmony_ci	DIRECTIVE_EMBEDDED,
428c2ecf20Sopenharmony_ci	DIRECTIVE_ENCODED,
438c2ecf20Sopenharmony_ci	DIRECTIVE_ENCODING_CONTROL,
448c2ecf20Sopenharmony_ci	DIRECTIVE_END,
458c2ecf20Sopenharmony_ci	DIRECTIVE_ENUMERATED,
468c2ecf20Sopenharmony_ci	DIRECTIVE_EXCEPT,
478c2ecf20Sopenharmony_ci	DIRECTIVE_EXPLICIT,
488c2ecf20Sopenharmony_ci	DIRECTIVE_EXPORTS,
498c2ecf20Sopenharmony_ci	DIRECTIVE_EXTENSIBILITY,
508c2ecf20Sopenharmony_ci	DIRECTIVE_EXTERNAL,
518c2ecf20Sopenharmony_ci	DIRECTIVE_FALSE,
528c2ecf20Sopenharmony_ci	DIRECTIVE_FROM,
538c2ecf20Sopenharmony_ci	DIRECTIVE_GeneralString,
548c2ecf20Sopenharmony_ci	DIRECTIVE_GeneralizedTime,
558c2ecf20Sopenharmony_ci	DIRECTIVE_GraphicString,
568c2ecf20Sopenharmony_ci	DIRECTIVE_IA5String,
578c2ecf20Sopenharmony_ci	DIRECTIVE_IDENTIFIER,
588c2ecf20Sopenharmony_ci	DIRECTIVE_IMPLICIT,
598c2ecf20Sopenharmony_ci	DIRECTIVE_IMPLIED,
608c2ecf20Sopenharmony_ci	DIRECTIVE_IMPORTS,
618c2ecf20Sopenharmony_ci	DIRECTIVE_INCLUDES,
628c2ecf20Sopenharmony_ci	DIRECTIVE_INSTANCE,
638c2ecf20Sopenharmony_ci	DIRECTIVE_INSTRUCTIONS,
648c2ecf20Sopenharmony_ci	DIRECTIVE_INTEGER,
658c2ecf20Sopenharmony_ci	DIRECTIVE_INTERSECTION,
668c2ecf20Sopenharmony_ci	DIRECTIVE_ISO646String,
678c2ecf20Sopenharmony_ci	DIRECTIVE_MAX,
688c2ecf20Sopenharmony_ci	DIRECTIVE_MIN,
698c2ecf20Sopenharmony_ci	DIRECTIVE_MINUS_INFINITY,
708c2ecf20Sopenharmony_ci	DIRECTIVE_NULL,
718c2ecf20Sopenharmony_ci	DIRECTIVE_NumericString,
728c2ecf20Sopenharmony_ci	DIRECTIVE_OBJECT,
738c2ecf20Sopenharmony_ci	DIRECTIVE_OCTET,
748c2ecf20Sopenharmony_ci	DIRECTIVE_OF,
758c2ecf20Sopenharmony_ci	DIRECTIVE_OPTIONAL,
768c2ecf20Sopenharmony_ci	DIRECTIVE_ObjectDescriptor,
778c2ecf20Sopenharmony_ci	DIRECTIVE_PATTERN,
788c2ecf20Sopenharmony_ci	DIRECTIVE_PDV,
798c2ecf20Sopenharmony_ci	DIRECTIVE_PLUS_INFINITY,
808c2ecf20Sopenharmony_ci	DIRECTIVE_PRESENT,
818c2ecf20Sopenharmony_ci	DIRECTIVE_PRIVATE,
828c2ecf20Sopenharmony_ci	DIRECTIVE_PrintableString,
838c2ecf20Sopenharmony_ci	DIRECTIVE_REAL,
848c2ecf20Sopenharmony_ci	DIRECTIVE_RELATIVE_OID,
858c2ecf20Sopenharmony_ci	DIRECTIVE_SEQUENCE,
868c2ecf20Sopenharmony_ci	DIRECTIVE_SET,
878c2ecf20Sopenharmony_ci	DIRECTIVE_SIZE,
888c2ecf20Sopenharmony_ci	DIRECTIVE_STRING,
898c2ecf20Sopenharmony_ci	DIRECTIVE_SYNTAX,
908c2ecf20Sopenharmony_ci	DIRECTIVE_T61String,
918c2ecf20Sopenharmony_ci	DIRECTIVE_TAGS,
928c2ecf20Sopenharmony_ci	DIRECTIVE_TRUE,
938c2ecf20Sopenharmony_ci	DIRECTIVE_TeletexString,
948c2ecf20Sopenharmony_ci	DIRECTIVE_UNION,
958c2ecf20Sopenharmony_ci	DIRECTIVE_UNIQUE,
968c2ecf20Sopenharmony_ci	DIRECTIVE_UNIVERSAL,
978c2ecf20Sopenharmony_ci	DIRECTIVE_UTCTime,
988c2ecf20Sopenharmony_ci	DIRECTIVE_UTF8String,
998c2ecf20Sopenharmony_ci	DIRECTIVE_UniversalString,
1008c2ecf20Sopenharmony_ci	DIRECTIVE_VideotexString,
1018c2ecf20Sopenharmony_ci	DIRECTIVE_VisibleString,
1028c2ecf20Sopenharmony_ci	DIRECTIVE_WITH,
1038c2ecf20Sopenharmony_ci	NR__DIRECTIVES,
1048c2ecf20Sopenharmony_ci	TOKEN_ASSIGNMENT = NR__DIRECTIVES,
1058c2ecf20Sopenharmony_ci	TOKEN_OPEN_CURLY,
1068c2ecf20Sopenharmony_ci	TOKEN_CLOSE_CURLY,
1078c2ecf20Sopenharmony_ci	TOKEN_OPEN_SQUARE,
1088c2ecf20Sopenharmony_ci	TOKEN_CLOSE_SQUARE,
1098c2ecf20Sopenharmony_ci	TOKEN_OPEN_ACTION,
1108c2ecf20Sopenharmony_ci	TOKEN_CLOSE_ACTION,
1118c2ecf20Sopenharmony_ci	TOKEN_COMMA,
1128c2ecf20Sopenharmony_ci	TOKEN_NUMBER,
1138c2ecf20Sopenharmony_ci	TOKEN_TYPE_NAME,
1148c2ecf20Sopenharmony_ci	TOKEN_ELEMENT_NAME,
1158c2ecf20Sopenharmony_ci	NR__TOKENS
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic const unsigned char token_to_tag[NR__TOKENS] = {
1198c2ecf20Sopenharmony_ci	/* EOC goes first */
1208c2ecf20Sopenharmony_ci	[DIRECTIVE_BOOLEAN]		= ASN1_BOOL,
1218c2ecf20Sopenharmony_ci	[DIRECTIVE_INTEGER]		= ASN1_INT,
1228c2ecf20Sopenharmony_ci	[DIRECTIVE_BIT]			= ASN1_BTS,
1238c2ecf20Sopenharmony_ci	[DIRECTIVE_OCTET]		= ASN1_OTS,
1248c2ecf20Sopenharmony_ci	[DIRECTIVE_NULL]		= ASN1_NULL,
1258c2ecf20Sopenharmony_ci	[DIRECTIVE_OBJECT]		= ASN1_OID,
1268c2ecf20Sopenharmony_ci	[DIRECTIVE_ObjectDescriptor]	= ASN1_ODE,
1278c2ecf20Sopenharmony_ci	[DIRECTIVE_EXTERNAL]		= ASN1_EXT,
1288c2ecf20Sopenharmony_ci	[DIRECTIVE_REAL]		= ASN1_REAL,
1298c2ecf20Sopenharmony_ci	[DIRECTIVE_ENUMERATED]		= ASN1_ENUM,
1308c2ecf20Sopenharmony_ci	[DIRECTIVE_EMBEDDED]		= 0,
1318c2ecf20Sopenharmony_ci	[DIRECTIVE_UTF8String]		= ASN1_UTF8STR,
1328c2ecf20Sopenharmony_ci	[DIRECTIVE_RELATIVE_OID]	= ASN1_RELOID,
1338c2ecf20Sopenharmony_ci	/* 14 */
1348c2ecf20Sopenharmony_ci	/* 15 */
1358c2ecf20Sopenharmony_ci	[DIRECTIVE_SEQUENCE]		= ASN1_SEQ,
1368c2ecf20Sopenharmony_ci	[DIRECTIVE_SET]			= ASN1_SET,
1378c2ecf20Sopenharmony_ci	[DIRECTIVE_NumericString]	= ASN1_NUMSTR,
1388c2ecf20Sopenharmony_ci	[DIRECTIVE_PrintableString]	= ASN1_PRNSTR,
1398c2ecf20Sopenharmony_ci	[DIRECTIVE_T61String]		= ASN1_TEXSTR,
1408c2ecf20Sopenharmony_ci	[DIRECTIVE_TeletexString]	= ASN1_TEXSTR,
1418c2ecf20Sopenharmony_ci	[DIRECTIVE_VideotexString]	= ASN1_VIDSTR,
1428c2ecf20Sopenharmony_ci	[DIRECTIVE_IA5String]		= ASN1_IA5STR,
1438c2ecf20Sopenharmony_ci	[DIRECTIVE_UTCTime]		= ASN1_UNITIM,
1448c2ecf20Sopenharmony_ci	[DIRECTIVE_GeneralizedTime]	= ASN1_GENTIM,
1458c2ecf20Sopenharmony_ci	[DIRECTIVE_GraphicString]	= ASN1_GRASTR,
1468c2ecf20Sopenharmony_ci	[DIRECTIVE_VisibleString]	= ASN1_VISSTR,
1478c2ecf20Sopenharmony_ci	[DIRECTIVE_GeneralString]	= ASN1_GENSTR,
1488c2ecf20Sopenharmony_ci	[DIRECTIVE_UniversalString]	= ASN1_UNITIM,
1498c2ecf20Sopenharmony_ci	[DIRECTIVE_CHARACTER]		= ASN1_CHRSTR,
1508c2ecf20Sopenharmony_ci	[DIRECTIVE_BMPString]		= ASN1_BMPSTR,
1518c2ecf20Sopenharmony_ci};
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic const char asn1_classes[4][5] = {
1548c2ecf20Sopenharmony_ci	[ASN1_UNIV]	= "UNIV",
1558c2ecf20Sopenharmony_ci	[ASN1_APPL]	= "APPL",
1568c2ecf20Sopenharmony_ci	[ASN1_CONT]	= "CONT",
1578c2ecf20Sopenharmony_ci	[ASN1_PRIV]	= "PRIV"
1588c2ecf20Sopenharmony_ci};
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic const char asn1_methods[2][5] = {
1618c2ecf20Sopenharmony_ci	[ASN1_UNIV]	= "PRIM",
1628c2ecf20Sopenharmony_ci	[ASN1_APPL]	= "CONS"
1638c2ecf20Sopenharmony_ci};
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic const char *const asn1_universal_tags[32] = {
1668c2ecf20Sopenharmony_ci	"EOC",
1678c2ecf20Sopenharmony_ci	"BOOL",
1688c2ecf20Sopenharmony_ci	"INT",
1698c2ecf20Sopenharmony_ci	"BTS",
1708c2ecf20Sopenharmony_ci	"OTS",
1718c2ecf20Sopenharmony_ci	"NULL",
1728c2ecf20Sopenharmony_ci	"OID",
1738c2ecf20Sopenharmony_ci	"ODE",
1748c2ecf20Sopenharmony_ci	"EXT",
1758c2ecf20Sopenharmony_ci	"REAL",
1768c2ecf20Sopenharmony_ci	"ENUM",
1778c2ecf20Sopenharmony_ci	"EPDV",
1788c2ecf20Sopenharmony_ci	"UTF8STR",
1798c2ecf20Sopenharmony_ci	"RELOID",
1808c2ecf20Sopenharmony_ci	NULL,		/* 14 */
1818c2ecf20Sopenharmony_ci	NULL,		/* 15 */
1828c2ecf20Sopenharmony_ci	"SEQ",
1838c2ecf20Sopenharmony_ci	"SET",
1848c2ecf20Sopenharmony_ci	"NUMSTR",
1858c2ecf20Sopenharmony_ci	"PRNSTR",
1868c2ecf20Sopenharmony_ci	"TEXSTR",
1878c2ecf20Sopenharmony_ci	"VIDSTR",
1888c2ecf20Sopenharmony_ci	"IA5STR",
1898c2ecf20Sopenharmony_ci	"UNITIM",
1908c2ecf20Sopenharmony_ci	"GENTIM",
1918c2ecf20Sopenharmony_ci	"GRASTR",
1928c2ecf20Sopenharmony_ci	"VISSTR",
1938c2ecf20Sopenharmony_ci	"GENSTR",
1948c2ecf20Sopenharmony_ci	"UNISTR",
1958c2ecf20Sopenharmony_ci	"CHRSTR",
1968c2ecf20Sopenharmony_ci	"BMPSTR",
1978c2ecf20Sopenharmony_ci	NULL		/* 31 */
1988c2ecf20Sopenharmony_ci};
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic const char *filename;
2018c2ecf20Sopenharmony_cistatic const char *grammar_name;
2028c2ecf20Sopenharmony_cistatic const char *outputname;
2038c2ecf20Sopenharmony_cistatic const char *headername;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic const char *const directives[NR__DIRECTIVES] = {
2068c2ecf20Sopenharmony_ci#define _(X) [DIRECTIVE_##X] = #X
2078c2ecf20Sopenharmony_ci	_(ABSENT),
2088c2ecf20Sopenharmony_ci	_(ALL),
2098c2ecf20Sopenharmony_ci	_(ANY),
2108c2ecf20Sopenharmony_ci	_(APPLICATION),
2118c2ecf20Sopenharmony_ci	_(AUTOMATIC),
2128c2ecf20Sopenharmony_ci	_(BEGIN),
2138c2ecf20Sopenharmony_ci	_(BIT),
2148c2ecf20Sopenharmony_ci	_(BMPString),
2158c2ecf20Sopenharmony_ci	_(BOOLEAN),
2168c2ecf20Sopenharmony_ci	_(BY),
2178c2ecf20Sopenharmony_ci	_(CHARACTER),
2188c2ecf20Sopenharmony_ci	_(CHOICE),
2198c2ecf20Sopenharmony_ci	_(CLASS),
2208c2ecf20Sopenharmony_ci	_(COMPONENT),
2218c2ecf20Sopenharmony_ci	_(COMPONENTS),
2228c2ecf20Sopenharmony_ci	_(CONSTRAINED),
2238c2ecf20Sopenharmony_ci	_(CONTAINING),
2248c2ecf20Sopenharmony_ci	_(DEFAULT),
2258c2ecf20Sopenharmony_ci	_(DEFINED),
2268c2ecf20Sopenharmony_ci	_(DEFINITIONS),
2278c2ecf20Sopenharmony_ci	_(EMBEDDED),
2288c2ecf20Sopenharmony_ci	_(ENCODED),
2298c2ecf20Sopenharmony_ci	[DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
2308c2ecf20Sopenharmony_ci	_(END),
2318c2ecf20Sopenharmony_ci	_(ENUMERATED),
2328c2ecf20Sopenharmony_ci	_(EXCEPT),
2338c2ecf20Sopenharmony_ci	_(EXPLICIT),
2348c2ecf20Sopenharmony_ci	_(EXPORTS),
2358c2ecf20Sopenharmony_ci	_(EXTENSIBILITY),
2368c2ecf20Sopenharmony_ci	_(EXTERNAL),
2378c2ecf20Sopenharmony_ci	_(FALSE),
2388c2ecf20Sopenharmony_ci	_(FROM),
2398c2ecf20Sopenharmony_ci	_(GeneralString),
2408c2ecf20Sopenharmony_ci	_(GeneralizedTime),
2418c2ecf20Sopenharmony_ci	_(GraphicString),
2428c2ecf20Sopenharmony_ci	_(IA5String),
2438c2ecf20Sopenharmony_ci	_(IDENTIFIER),
2448c2ecf20Sopenharmony_ci	_(IMPLICIT),
2458c2ecf20Sopenharmony_ci	_(IMPLIED),
2468c2ecf20Sopenharmony_ci	_(IMPORTS),
2478c2ecf20Sopenharmony_ci	_(INCLUDES),
2488c2ecf20Sopenharmony_ci	_(INSTANCE),
2498c2ecf20Sopenharmony_ci	_(INSTRUCTIONS),
2508c2ecf20Sopenharmony_ci	_(INTEGER),
2518c2ecf20Sopenharmony_ci	_(INTERSECTION),
2528c2ecf20Sopenharmony_ci	_(ISO646String),
2538c2ecf20Sopenharmony_ci	_(MAX),
2548c2ecf20Sopenharmony_ci	_(MIN),
2558c2ecf20Sopenharmony_ci	[DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
2568c2ecf20Sopenharmony_ci	[DIRECTIVE_NULL] = "NULL",
2578c2ecf20Sopenharmony_ci	_(NumericString),
2588c2ecf20Sopenharmony_ci	_(OBJECT),
2598c2ecf20Sopenharmony_ci	_(OCTET),
2608c2ecf20Sopenharmony_ci	_(OF),
2618c2ecf20Sopenharmony_ci	_(OPTIONAL),
2628c2ecf20Sopenharmony_ci	_(ObjectDescriptor),
2638c2ecf20Sopenharmony_ci	_(PATTERN),
2648c2ecf20Sopenharmony_ci	_(PDV),
2658c2ecf20Sopenharmony_ci	[DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
2668c2ecf20Sopenharmony_ci	_(PRESENT),
2678c2ecf20Sopenharmony_ci	_(PRIVATE),
2688c2ecf20Sopenharmony_ci	_(PrintableString),
2698c2ecf20Sopenharmony_ci	_(REAL),
2708c2ecf20Sopenharmony_ci	[DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
2718c2ecf20Sopenharmony_ci	_(SEQUENCE),
2728c2ecf20Sopenharmony_ci	_(SET),
2738c2ecf20Sopenharmony_ci	_(SIZE),
2748c2ecf20Sopenharmony_ci	_(STRING),
2758c2ecf20Sopenharmony_ci	_(SYNTAX),
2768c2ecf20Sopenharmony_ci	_(T61String),
2778c2ecf20Sopenharmony_ci	_(TAGS),
2788c2ecf20Sopenharmony_ci	_(TRUE),
2798c2ecf20Sopenharmony_ci	_(TeletexString),
2808c2ecf20Sopenharmony_ci	_(UNION),
2818c2ecf20Sopenharmony_ci	_(UNIQUE),
2828c2ecf20Sopenharmony_ci	_(UNIVERSAL),
2838c2ecf20Sopenharmony_ci	_(UTCTime),
2848c2ecf20Sopenharmony_ci	_(UTF8String),
2858c2ecf20Sopenharmony_ci	_(UniversalString),
2868c2ecf20Sopenharmony_ci	_(VideotexString),
2878c2ecf20Sopenharmony_ci	_(VisibleString),
2888c2ecf20Sopenharmony_ci	_(WITH)
2898c2ecf20Sopenharmony_ci};
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistruct action {
2928c2ecf20Sopenharmony_ci	struct action	*next;
2938c2ecf20Sopenharmony_ci	char		*name;
2948c2ecf20Sopenharmony_ci	unsigned char	index;
2958c2ecf20Sopenharmony_ci};
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic struct action *action_list;
2988c2ecf20Sopenharmony_cistatic unsigned nr_actions;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistruct token {
3018c2ecf20Sopenharmony_ci	unsigned short	line;
3028c2ecf20Sopenharmony_ci	enum token_type	token_type : 8;
3038c2ecf20Sopenharmony_ci	unsigned char	size;
3048c2ecf20Sopenharmony_ci	struct action	*action;
3058c2ecf20Sopenharmony_ci	char		*content;
3068c2ecf20Sopenharmony_ci	struct type	*type;
3078c2ecf20Sopenharmony_ci};
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic struct token *token_list;
3108c2ecf20Sopenharmony_cistatic unsigned nr_tokens;
3118c2ecf20Sopenharmony_cistatic bool verbose_opt;
3128c2ecf20Sopenharmony_cistatic bool debug_opt;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci#define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)
3158c2ecf20Sopenharmony_ci#define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic int directive_compare(const void *_key, const void *_pdir)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	const struct token *token = _key;
3208c2ecf20Sopenharmony_ci	const char *const *pdir = _pdir, *dir = *pdir;
3218c2ecf20Sopenharmony_ci	size_t dlen, clen;
3228c2ecf20Sopenharmony_ci	int val;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	dlen = strlen(dir);
3258c2ecf20Sopenharmony_ci	clen = (dlen < token->size) ? dlen : token->size;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	//debug("cmp(%s,%s) = ", token->content, dir);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	val = memcmp(token->content, dir, clen);
3308c2ecf20Sopenharmony_ci	if (val != 0) {
3318c2ecf20Sopenharmony_ci		//debug("%d [cmp]\n", val);
3328c2ecf20Sopenharmony_ci		return val;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (dlen == token->size) {
3368c2ecf20Sopenharmony_ci		//debug("0\n");
3378c2ecf20Sopenharmony_ci		return 0;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci	//debug("%d\n", (int)dlen - (int)token->size);
3408c2ecf20Sopenharmony_ci	return dlen - token->size; /* shorter -> negative */
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci/*
3448c2ecf20Sopenharmony_ci * Tokenise an ASN.1 grammar
3458c2ecf20Sopenharmony_ci */
3468c2ecf20Sopenharmony_cistatic void tokenise(char *buffer, char *end)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct token *tokens;
3498c2ecf20Sopenharmony_ci	char *line, *nl, *start, *p, *q;
3508c2ecf20Sopenharmony_ci	unsigned tix, lineno;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* Assume we're going to have half as many tokens as we have
3538c2ecf20Sopenharmony_ci	 * characters
3548c2ecf20Sopenharmony_ci	 */
3558c2ecf20Sopenharmony_ci	token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
3568c2ecf20Sopenharmony_ci	if (!tokens) {
3578c2ecf20Sopenharmony_ci		perror(NULL);
3588c2ecf20Sopenharmony_ci		exit(1);
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci	tix = 0;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	lineno = 0;
3638c2ecf20Sopenharmony_ci	while (buffer < end) {
3648c2ecf20Sopenharmony_ci		/* First of all, break out a line */
3658c2ecf20Sopenharmony_ci		lineno++;
3668c2ecf20Sopenharmony_ci		line = buffer;
3678c2ecf20Sopenharmony_ci		nl = memchr(line, '\n', end - buffer);
3688c2ecf20Sopenharmony_ci		if (!nl) {
3698c2ecf20Sopenharmony_ci			buffer = nl = end;
3708c2ecf20Sopenharmony_ci		} else {
3718c2ecf20Sopenharmony_ci			buffer = nl + 1;
3728c2ecf20Sopenharmony_ci			*nl = '\0';
3738c2ecf20Sopenharmony_ci		}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci		/* Remove "--" comments */
3768c2ecf20Sopenharmony_ci		p = line;
3778c2ecf20Sopenharmony_ci	next_comment:
3788c2ecf20Sopenharmony_ci		while ((p = memchr(p, '-', nl - p))) {
3798c2ecf20Sopenharmony_ci			if (p[1] == '-') {
3808c2ecf20Sopenharmony_ci				/* Found a comment; see if there's a terminator */
3818c2ecf20Sopenharmony_ci				q = p + 2;
3828c2ecf20Sopenharmony_ci				while ((q = memchr(q, '-', nl - q))) {
3838c2ecf20Sopenharmony_ci					if (q[1] == '-') {
3848c2ecf20Sopenharmony_ci						/* There is - excise the comment */
3858c2ecf20Sopenharmony_ci						q += 2;
3868c2ecf20Sopenharmony_ci						memmove(p, q, nl - q);
3878c2ecf20Sopenharmony_ci						goto next_comment;
3888c2ecf20Sopenharmony_ci					}
3898c2ecf20Sopenharmony_ci					q++;
3908c2ecf20Sopenharmony_ci				}
3918c2ecf20Sopenharmony_ci				*p = '\0';
3928c2ecf20Sopenharmony_ci				nl = p;
3938c2ecf20Sopenharmony_ci				break;
3948c2ecf20Sopenharmony_ci			} else {
3958c2ecf20Sopenharmony_ci				p++;
3968c2ecf20Sopenharmony_ci			}
3978c2ecf20Sopenharmony_ci		}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		p = line;
4008c2ecf20Sopenharmony_ci		while (p < nl) {
4018c2ecf20Sopenharmony_ci			/* Skip white space */
4028c2ecf20Sopenharmony_ci			while (p < nl && isspace(*p))
4038c2ecf20Sopenharmony_ci				*(p++) = 0;
4048c2ecf20Sopenharmony_ci			if (p >= nl)
4058c2ecf20Sopenharmony_ci				break;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci			tokens[tix].line = lineno;
4088c2ecf20Sopenharmony_ci			start = p;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci			/* Handle string tokens */
4118c2ecf20Sopenharmony_ci			if (isalpha(*p)) {
4128c2ecf20Sopenharmony_ci				const char **dir;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci				/* Can be a directive, type name or element
4158c2ecf20Sopenharmony_ci				 * name.  Find the end of the name.
4168c2ecf20Sopenharmony_ci				 */
4178c2ecf20Sopenharmony_ci				q = p + 1;
4188c2ecf20Sopenharmony_ci				while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
4198c2ecf20Sopenharmony_ci					q++;
4208c2ecf20Sopenharmony_ci				tokens[tix].size = q - p;
4218c2ecf20Sopenharmony_ci				p = q;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci				tokens[tix].content = malloc(tokens[tix].size + 1);
4248c2ecf20Sopenharmony_ci				if (!tokens[tix].content) {
4258c2ecf20Sopenharmony_ci					perror(NULL);
4268c2ecf20Sopenharmony_ci					exit(1);
4278c2ecf20Sopenharmony_ci				}
4288c2ecf20Sopenharmony_ci				memcpy(tokens[tix].content, start, tokens[tix].size);
4298c2ecf20Sopenharmony_ci				tokens[tix].content[tokens[tix].size] = 0;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci				/* If it begins with a lowercase letter then
4328c2ecf20Sopenharmony_ci				 * it's an element name
4338c2ecf20Sopenharmony_ci				 */
4348c2ecf20Sopenharmony_ci				if (islower(tokens[tix].content[0])) {
4358c2ecf20Sopenharmony_ci					tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
4368c2ecf20Sopenharmony_ci					continue;
4378c2ecf20Sopenharmony_ci				}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci				/* Otherwise we need to search the directive
4408c2ecf20Sopenharmony_ci				 * table
4418c2ecf20Sopenharmony_ci				 */
4428c2ecf20Sopenharmony_ci				dir = bsearch(&tokens[tix], directives,
4438c2ecf20Sopenharmony_ci					      sizeof(directives) / sizeof(directives[1]),
4448c2ecf20Sopenharmony_ci					      sizeof(directives[1]),
4458c2ecf20Sopenharmony_ci					      directive_compare);
4468c2ecf20Sopenharmony_ci				if (dir) {
4478c2ecf20Sopenharmony_ci					tokens[tix++].token_type = dir - directives;
4488c2ecf20Sopenharmony_ci					continue;
4498c2ecf20Sopenharmony_ci				}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci				tokens[tix++].token_type = TOKEN_TYPE_NAME;
4528c2ecf20Sopenharmony_ci				continue;
4538c2ecf20Sopenharmony_ci			}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci			/* Handle numbers */
4568c2ecf20Sopenharmony_ci			if (isdigit(*p)) {
4578c2ecf20Sopenharmony_ci				/* Find the end of the number */
4588c2ecf20Sopenharmony_ci				q = p + 1;
4598c2ecf20Sopenharmony_ci				while (q < nl && (isdigit(*q)))
4608c2ecf20Sopenharmony_ci					q++;
4618c2ecf20Sopenharmony_ci				tokens[tix].size = q - p;
4628c2ecf20Sopenharmony_ci				p = q;
4638c2ecf20Sopenharmony_ci				tokens[tix].content = malloc(tokens[tix].size + 1);
4648c2ecf20Sopenharmony_ci				if (!tokens[tix].content) {
4658c2ecf20Sopenharmony_ci					perror(NULL);
4668c2ecf20Sopenharmony_ci					exit(1);
4678c2ecf20Sopenharmony_ci				}
4688c2ecf20Sopenharmony_ci				memcpy(tokens[tix].content, start, tokens[tix].size);
4698c2ecf20Sopenharmony_ci				tokens[tix].content[tokens[tix].size] = 0;
4708c2ecf20Sopenharmony_ci				tokens[tix++].token_type = TOKEN_NUMBER;
4718c2ecf20Sopenharmony_ci				continue;
4728c2ecf20Sopenharmony_ci			}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci			if (nl - p >= 3) {
4758c2ecf20Sopenharmony_ci				if (memcmp(p, "::=", 3) == 0) {
4768c2ecf20Sopenharmony_ci					p += 3;
4778c2ecf20Sopenharmony_ci					tokens[tix].size = 3;
4788c2ecf20Sopenharmony_ci					tokens[tix].content = "::=";
4798c2ecf20Sopenharmony_ci					tokens[tix++].token_type = TOKEN_ASSIGNMENT;
4808c2ecf20Sopenharmony_ci					continue;
4818c2ecf20Sopenharmony_ci				}
4828c2ecf20Sopenharmony_ci			}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci			if (nl - p >= 2) {
4858c2ecf20Sopenharmony_ci				if (memcmp(p, "({", 2) == 0) {
4868c2ecf20Sopenharmony_ci					p += 2;
4878c2ecf20Sopenharmony_ci					tokens[tix].size = 2;
4888c2ecf20Sopenharmony_ci					tokens[tix].content = "({";
4898c2ecf20Sopenharmony_ci					tokens[tix++].token_type = TOKEN_OPEN_ACTION;
4908c2ecf20Sopenharmony_ci					continue;
4918c2ecf20Sopenharmony_ci				}
4928c2ecf20Sopenharmony_ci				if (memcmp(p, "})", 2) == 0) {
4938c2ecf20Sopenharmony_ci					p += 2;
4948c2ecf20Sopenharmony_ci					tokens[tix].size = 2;
4958c2ecf20Sopenharmony_ci					tokens[tix].content = "})";
4968c2ecf20Sopenharmony_ci					tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
4978c2ecf20Sopenharmony_ci					continue;
4988c2ecf20Sopenharmony_ci				}
4998c2ecf20Sopenharmony_ci			}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci			if (nl - p >= 1) {
5028c2ecf20Sopenharmony_ci				tokens[tix].size = 1;
5038c2ecf20Sopenharmony_ci				switch (*p) {
5048c2ecf20Sopenharmony_ci				case '{':
5058c2ecf20Sopenharmony_ci					p += 1;
5068c2ecf20Sopenharmony_ci					tokens[tix].content = "{";
5078c2ecf20Sopenharmony_ci					tokens[tix++].token_type = TOKEN_OPEN_CURLY;
5088c2ecf20Sopenharmony_ci					continue;
5098c2ecf20Sopenharmony_ci				case '}':
5108c2ecf20Sopenharmony_ci					p += 1;
5118c2ecf20Sopenharmony_ci					tokens[tix].content = "}";
5128c2ecf20Sopenharmony_ci					tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
5138c2ecf20Sopenharmony_ci					continue;
5148c2ecf20Sopenharmony_ci				case '[':
5158c2ecf20Sopenharmony_ci					p += 1;
5168c2ecf20Sopenharmony_ci					tokens[tix].content = "[";
5178c2ecf20Sopenharmony_ci					tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
5188c2ecf20Sopenharmony_ci					continue;
5198c2ecf20Sopenharmony_ci				case ']':
5208c2ecf20Sopenharmony_ci					p += 1;
5218c2ecf20Sopenharmony_ci					tokens[tix].content = "]";
5228c2ecf20Sopenharmony_ci					tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
5238c2ecf20Sopenharmony_ci					continue;
5248c2ecf20Sopenharmony_ci				case ',':
5258c2ecf20Sopenharmony_ci					p += 1;
5268c2ecf20Sopenharmony_ci					tokens[tix].content = ",";
5278c2ecf20Sopenharmony_ci					tokens[tix++].token_type = TOKEN_COMMA;
5288c2ecf20Sopenharmony_ci					continue;
5298c2ecf20Sopenharmony_ci				default:
5308c2ecf20Sopenharmony_ci					break;
5318c2ecf20Sopenharmony_ci				}
5328c2ecf20Sopenharmony_ci			}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci			fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
5358c2ecf20Sopenharmony_ci				filename, lineno, *p);
5368c2ecf20Sopenharmony_ci			exit(1);
5378c2ecf20Sopenharmony_ci		}
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	nr_tokens = tix;
5418c2ecf20Sopenharmony_ci	verbose("Extracted %u tokens\n", nr_tokens);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci#if 0
5448c2ecf20Sopenharmony_ci	{
5458c2ecf20Sopenharmony_ci		int n;
5468c2ecf20Sopenharmony_ci		for (n = 0; n < nr_tokens; n++)
5478c2ecf20Sopenharmony_ci			debug("Token %3u: '%s'\n", n, token_list[n].content);
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci#endif
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cistatic void build_type_list(void);
5538c2ecf20Sopenharmony_cistatic void parse(void);
5548c2ecf20Sopenharmony_cistatic void dump_elements(void);
5558c2ecf20Sopenharmony_cistatic void render(FILE *out, FILE *hdr);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci/*
5588c2ecf20Sopenharmony_ci *
5598c2ecf20Sopenharmony_ci */
5608c2ecf20Sopenharmony_ciint main(int argc, char **argv)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct stat st;
5638c2ecf20Sopenharmony_ci	ssize_t readlen;
5648c2ecf20Sopenharmony_ci	FILE *out, *hdr;
5658c2ecf20Sopenharmony_ci	char *buffer, *p;
5668c2ecf20Sopenharmony_ci	char *kbuild_verbose;
5678c2ecf20Sopenharmony_ci	int fd;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	kbuild_verbose = getenv("KBUILD_VERBOSE");
5708c2ecf20Sopenharmony_ci	if (kbuild_verbose)
5718c2ecf20Sopenharmony_ci		verbose_opt = atoi(kbuild_verbose);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	while (argc > 4) {
5748c2ecf20Sopenharmony_ci		if (strcmp(argv[1], "-v") == 0)
5758c2ecf20Sopenharmony_ci			verbose_opt = true;
5768c2ecf20Sopenharmony_ci		else if (strcmp(argv[1], "-d") == 0)
5778c2ecf20Sopenharmony_ci			debug_opt = true;
5788c2ecf20Sopenharmony_ci		else
5798c2ecf20Sopenharmony_ci			break;
5808c2ecf20Sopenharmony_ci		memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *));
5818c2ecf20Sopenharmony_ci		argc--;
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	if (argc != 4) {
5858c2ecf20Sopenharmony_ci		fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n",
5868c2ecf20Sopenharmony_ci			argv[0]);
5878c2ecf20Sopenharmony_ci		exit(2);
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	filename = argv[1];
5918c2ecf20Sopenharmony_ci	outputname = argv[2];
5928c2ecf20Sopenharmony_ci	headername = argv[3];
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	fd = open(filename, O_RDONLY);
5958c2ecf20Sopenharmony_ci	if (fd < 0) {
5968c2ecf20Sopenharmony_ci		perror(filename);
5978c2ecf20Sopenharmony_ci		exit(1);
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	if (fstat(fd, &st) < 0) {
6018c2ecf20Sopenharmony_ci		perror(filename);
6028c2ecf20Sopenharmony_ci		exit(1);
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	if (!(buffer = malloc(st.st_size + 1))) {
6068c2ecf20Sopenharmony_ci		perror(NULL);
6078c2ecf20Sopenharmony_ci		exit(1);
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	if ((readlen = read(fd, buffer, st.st_size)) < 0) {
6118c2ecf20Sopenharmony_ci		perror(filename);
6128c2ecf20Sopenharmony_ci		exit(1);
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	if (close(fd) < 0) {
6168c2ecf20Sopenharmony_ci		perror(filename);
6178c2ecf20Sopenharmony_ci		exit(1);
6188c2ecf20Sopenharmony_ci	}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	if (readlen != st.st_size) {
6218c2ecf20Sopenharmony_ci		fprintf(stderr, "%s: Short read\n", filename);
6228c2ecf20Sopenharmony_ci		exit(1);
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	p = strrchr(argv[1], '/');
6268c2ecf20Sopenharmony_ci	p = p ? p + 1 : argv[1];
6278c2ecf20Sopenharmony_ci	grammar_name = strdup(p);
6288c2ecf20Sopenharmony_ci	if (!grammar_name) {
6298c2ecf20Sopenharmony_ci		perror(NULL);
6308c2ecf20Sopenharmony_ci		exit(1);
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci	p = strchr(grammar_name, '.');
6338c2ecf20Sopenharmony_ci	if (p)
6348c2ecf20Sopenharmony_ci		*p = '\0';
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	buffer[readlen] = 0;
6378c2ecf20Sopenharmony_ci	tokenise(buffer, buffer + readlen);
6388c2ecf20Sopenharmony_ci	build_type_list();
6398c2ecf20Sopenharmony_ci	parse();
6408c2ecf20Sopenharmony_ci	dump_elements();
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	out = fopen(outputname, "w");
6438c2ecf20Sopenharmony_ci	if (!out) {
6448c2ecf20Sopenharmony_ci		perror(outputname);
6458c2ecf20Sopenharmony_ci		exit(1);
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	hdr = fopen(headername, "w");
6498c2ecf20Sopenharmony_ci	if (!hdr) {
6508c2ecf20Sopenharmony_ci		perror(headername);
6518c2ecf20Sopenharmony_ci		exit(1);
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	render(out, hdr);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (fclose(out) < 0) {
6578c2ecf20Sopenharmony_ci		perror(outputname);
6588c2ecf20Sopenharmony_ci		exit(1);
6598c2ecf20Sopenharmony_ci	}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (fclose(hdr) < 0) {
6628c2ecf20Sopenharmony_ci		perror(headername);
6638c2ecf20Sopenharmony_ci		exit(1);
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	return 0;
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_cienum compound {
6708c2ecf20Sopenharmony_ci	NOT_COMPOUND,
6718c2ecf20Sopenharmony_ci	SET,
6728c2ecf20Sopenharmony_ci	SET_OF,
6738c2ecf20Sopenharmony_ci	SEQUENCE,
6748c2ecf20Sopenharmony_ci	SEQUENCE_OF,
6758c2ecf20Sopenharmony_ci	CHOICE,
6768c2ecf20Sopenharmony_ci	ANY,
6778c2ecf20Sopenharmony_ci	TYPE_REF,
6788c2ecf20Sopenharmony_ci	TAG_OVERRIDE
6798c2ecf20Sopenharmony_ci};
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_cistruct element {
6828c2ecf20Sopenharmony_ci	struct type	*type_def;
6838c2ecf20Sopenharmony_ci	struct token	*name;
6848c2ecf20Sopenharmony_ci	struct token	*type;
6858c2ecf20Sopenharmony_ci	struct action	*action;
6868c2ecf20Sopenharmony_ci	struct element	*children;
6878c2ecf20Sopenharmony_ci	struct element	*next;
6888c2ecf20Sopenharmony_ci	struct element	*render_next;
6898c2ecf20Sopenharmony_ci	struct element	*list_next;
6908c2ecf20Sopenharmony_ci	uint8_t		n_elements;
6918c2ecf20Sopenharmony_ci	enum compound	compound : 8;
6928c2ecf20Sopenharmony_ci	enum asn1_class	class : 8;
6938c2ecf20Sopenharmony_ci	enum asn1_method method : 8;
6948c2ecf20Sopenharmony_ci	uint8_t		tag;
6958c2ecf20Sopenharmony_ci	unsigned	entry_index;
6968c2ecf20Sopenharmony_ci	unsigned	flags;
6978c2ecf20Sopenharmony_ci#define ELEMENT_IMPLICIT	0x0001
6988c2ecf20Sopenharmony_ci#define ELEMENT_EXPLICIT	0x0002
6998c2ecf20Sopenharmony_ci#define ELEMENT_TAG_SPECIFIED	0x0004
7008c2ecf20Sopenharmony_ci#define ELEMENT_RENDERED	0x0008
7018c2ecf20Sopenharmony_ci#define ELEMENT_SKIPPABLE	0x0010
7028c2ecf20Sopenharmony_ci#define ELEMENT_CONDITIONAL	0x0020
7038c2ecf20Sopenharmony_ci};
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_cistruct type {
7068c2ecf20Sopenharmony_ci	struct token	*name;
7078c2ecf20Sopenharmony_ci	struct token	*def;
7088c2ecf20Sopenharmony_ci	struct element	*element;
7098c2ecf20Sopenharmony_ci	unsigned	ref_count;
7108c2ecf20Sopenharmony_ci	unsigned	flags;
7118c2ecf20Sopenharmony_ci#define TYPE_STOP_MARKER	0x0001
7128c2ecf20Sopenharmony_ci#define TYPE_BEGIN		0x0002
7138c2ecf20Sopenharmony_ci};
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_cistatic struct type *type_list;
7168c2ecf20Sopenharmony_cistatic struct type **type_index;
7178c2ecf20Sopenharmony_cistatic unsigned nr_types;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_cistatic int type_index_compare(const void *_a, const void *_b)
7208c2ecf20Sopenharmony_ci{
7218c2ecf20Sopenharmony_ci	const struct type *const *a = _a, *const *b = _b;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	if ((*a)->name->size != (*b)->name->size)
7248c2ecf20Sopenharmony_ci		return (*a)->name->size - (*b)->name->size;
7258c2ecf20Sopenharmony_ci	else
7268c2ecf20Sopenharmony_ci		return memcmp((*a)->name->content, (*b)->name->content,
7278c2ecf20Sopenharmony_ci			      (*a)->name->size);
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_cistatic int type_finder(const void *_key, const void *_ti)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	const struct token *token = _key;
7338c2ecf20Sopenharmony_ci	const struct type *const *ti = _ti;
7348c2ecf20Sopenharmony_ci	const struct type *type = *ti;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	if (token->size != type->name->size)
7378c2ecf20Sopenharmony_ci		return token->size - type->name->size;
7388c2ecf20Sopenharmony_ci	else
7398c2ecf20Sopenharmony_ci		return memcmp(token->content, type->name->content,
7408c2ecf20Sopenharmony_ci			      token->size);
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci/*
7448c2ecf20Sopenharmony_ci * Build up a list of types and a sorted index to that list.
7458c2ecf20Sopenharmony_ci */
7468c2ecf20Sopenharmony_cistatic void build_type_list(void)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	struct type *types;
7498c2ecf20Sopenharmony_ci	unsigned nr, t, n;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	nr = 0;
7528c2ecf20Sopenharmony_ci	for (n = 0; n < nr_tokens - 1; n++)
7538c2ecf20Sopenharmony_ci		if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
7548c2ecf20Sopenharmony_ci		    token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
7558c2ecf20Sopenharmony_ci			nr++;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	if (nr == 0) {
7588c2ecf20Sopenharmony_ci		fprintf(stderr, "%s: No defined types\n", filename);
7598c2ecf20Sopenharmony_ci		exit(1);
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	nr_types = nr;
7638c2ecf20Sopenharmony_ci	types = type_list = calloc(nr + 1, sizeof(type_list[0]));
7648c2ecf20Sopenharmony_ci	if (!type_list) {
7658c2ecf20Sopenharmony_ci		perror(NULL);
7668c2ecf20Sopenharmony_ci		exit(1);
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci	type_index = calloc(nr, sizeof(type_index[0]));
7698c2ecf20Sopenharmony_ci	if (!type_index) {
7708c2ecf20Sopenharmony_ci		perror(NULL);
7718c2ecf20Sopenharmony_ci		exit(1);
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	t = 0;
7758c2ecf20Sopenharmony_ci	types[t].flags |= TYPE_BEGIN;
7768c2ecf20Sopenharmony_ci	for (n = 0; n < nr_tokens - 1; n++) {
7778c2ecf20Sopenharmony_ci		if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
7788c2ecf20Sopenharmony_ci		    token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
7798c2ecf20Sopenharmony_ci			types[t].name = &token_list[n];
7808c2ecf20Sopenharmony_ci			type_index[t] = &types[t];
7818c2ecf20Sopenharmony_ci			t++;
7828c2ecf20Sopenharmony_ci		}
7838c2ecf20Sopenharmony_ci	}
7848c2ecf20Sopenharmony_ci	types[t].name = &token_list[n + 1];
7858c2ecf20Sopenharmony_ci	types[t].flags |= TYPE_STOP_MARKER;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	verbose("Extracted %u types\n", nr_types);
7908c2ecf20Sopenharmony_ci#if 0
7918c2ecf20Sopenharmony_ci	for (n = 0; n < nr_types; n++) {
7928c2ecf20Sopenharmony_ci		struct type *type = type_index[n];
7938c2ecf20Sopenharmony_ci		debug("- %*.*s\n", type->name->content);
7948c2ecf20Sopenharmony_ci	}
7958c2ecf20Sopenharmony_ci#endif
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_cistatic struct element *parse_type(struct token **_cursor, struct token *stop,
7998c2ecf20Sopenharmony_ci				  struct token *name);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci/*
8028c2ecf20Sopenharmony_ci * Parse the token stream
8038c2ecf20Sopenharmony_ci */
8048c2ecf20Sopenharmony_cistatic void parse(void)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	struct token *cursor;
8078c2ecf20Sopenharmony_ci	struct type *type;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	/* Parse one type definition statement at a time */
8108c2ecf20Sopenharmony_ci	type = type_list;
8118c2ecf20Sopenharmony_ci	do {
8128c2ecf20Sopenharmony_ci		cursor = type->name;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci		if (cursor[0].token_type != TOKEN_TYPE_NAME ||
8158c2ecf20Sopenharmony_ci		    cursor[1].token_type != TOKEN_ASSIGNMENT)
8168c2ecf20Sopenharmony_ci			abort();
8178c2ecf20Sopenharmony_ci		cursor += 2;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		type->element = parse_type(&cursor, type[1].name, NULL);
8208c2ecf20Sopenharmony_ci		type->element->type_def = type;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci		if (cursor != type[1].name) {
8238c2ecf20Sopenharmony_ci			fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
8248c2ecf20Sopenharmony_ci				filename, cursor->line, cursor->content);
8258c2ecf20Sopenharmony_ci			exit(1);
8268c2ecf20Sopenharmony_ci		}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	} while (type++, !(type->flags & TYPE_STOP_MARKER));
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	verbose("Extracted %u actions\n", nr_actions);
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_cistatic struct element *element_list;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_cistatic struct element *alloc_elem(struct token *type)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	struct element *e = calloc(1, sizeof(*e));
8388c2ecf20Sopenharmony_ci	if (!e) {
8398c2ecf20Sopenharmony_ci		perror(NULL);
8408c2ecf20Sopenharmony_ci		exit(1);
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci	e->list_next = element_list;
8438c2ecf20Sopenharmony_ci	element_list = e;
8448c2ecf20Sopenharmony_ci	return e;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistatic struct element *parse_compound(struct token **_cursor, struct token *end,
8488c2ecf20Sopenharmony_ci				      int alternates);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci/*
8518c2ecf20Sopenharmony_ci * Parse one type definition statement
8528c2ecf20Sopenharmony_ci */
8538c2ecf20Sopenharmony_cistatic struct element *parse_type(struct token **_cursor, struct token *end,
8548c2ecf20Sopenharmony_ci				  struct token *name)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	struct element *top, *element;
8578c2ecf20Sopenharmony_ci	struct action *action, **ppaction;
8588c2ecf20Sopenharmony_ci	struct token *cursor = *_cursor;
8598c2ecf20Sopenharmony_ci	struct type **ref;
8608c2ecf20Sopenharmony_ci	char *p;
8618c2ecf20Sopenharmony_ci	int labelled = 0, implicit = 0;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	top = element = alloc_elem(cursor);
8648c2ecf20Sopenharmony_ci	element->class = ASN1_UNIV;
8658c2ecf20Sopenharmony_ci	element->method = ASN1_PRIM;
8668c2ecf20Sopenharmony_ci	element->tag = token_to_tag[cursor->token_type];
8678c2ecf20Sopenharmony_ci	element->name = name;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	/* Extract the tag value if one given */
8708c2ecf20Sopenharmony_ci	if (cursor->token_type == TOKEN_OPEN_SQUARE) {
8718c2ecf20Sopenharmony_ci		cursor++;
8728c2ecf20Sopenharmony_ci		if (cursor >= end)
8738c2ecf20Sopenharmony_ci			goto overrun_error;
8748c2ecf20Sopenharmony_ci		switch (cursor->token_type) {
8758c2ecf20Sopenharmony_ci		case DIRECTIVE_UNIVERSAL:
8768c2ecf20Sopenharmony_ci			element->class = ASN1_UNIV;
8778c2ecf20Sopenharmony_ci			cursor++;
8788c2ecf20Sopenharmony_ci			break;
8798c2ecf20Sopenharmony_ci		case DIRECTIVE_APPLICATION:
8808c2ecf20Sopenharmony_ci			element->class = ASN1_APPL;
8818c2ecf20Sopenharmony_ci			cursor++;
8828c2ecf20Sopenharmony_ci			break;
8838c2ecf20Sopenharmony_ci		case TOKEN_NUMBER:
8848c2ecf20Sopenharmony_ci			element->class = ASN1_CONT;
8858c2ecf20Sopenharmony_ci			break;
8868c2ecf20Sopenharmony_ci		case DIRECTIVE_PRIVATE:
8878c2ecf20Sopenharmony_ci			element->class = ASN1_PRIV;
8888c2ecf20Sopenharmony_ci			cursor++;
8898c2ecf20Sopenharmony_ci			break;
8908c2ecf20Sopenharmony_ci		default:
8918c2ecf20Sopenharmony_ci			fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
8928c2ecf20Sopenharmony_ci				filename, cursor->line, cursor->content);
8938c2ecf20Sopenharmony_ci			exit(1);
8948c2ecf20Sopenharmony_ci		}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci		if (cursor >= end)
8978c2ecf20Sopenharmony_ci			goto overrun_error;
8988c2ecf20Sopenharmony_ci		if (cursor->token_type != TOKEN_NUMBER) {
8998c2ecf20Sopenharmony_ci			fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
9008c2ecf20Sopenharmony_ci				filename, cursor->line, cursor->content);
9018c2ecf20Sopenharmony_ci			exit(1);
9028c2ecf20Sopenharmony_ci		}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci		element->tag &= ~0x1f;
9058c2ecf20Sopenharmony_ci		element->tag |= strtoul(cursor->content, &p, 10);
9068c2ecf20Sopenharmony_ci		element->flags |= ELEMENT_TAG_SPECIFIED;
9078c2ecf20Sopenharmony_ci		if (p - cursor->content != cursor->size)
9088c2ecf20Sopenharmony_ci			abort();
9098c2ecf20Sopenharmony_ci		cursor++;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci		if (cursor >= end)
9128c2ecf20Sopenharmony_ci			goto overrun_error;
9138c2ecf20Sopenharmony_ci		if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
9148c2ecf20Sopenharmony_ci			fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
9158c2ecf20Sopenharmony_ci				filename, cursor->line, cursor->content);
9168c2ecf20Sopenharmony_ci			exit(1);
9178c2ecf20Sopenharmony_ci		}
9188c2ecf20Sopenharmony_ci		cursor++;
9198c2ecf20Sopenharmony_ci		if (cursor >= end)
9208c2ecf20Sopenharmony_ci			goto overrun_error;
9218c2ecf20Sopenharmony_ci		labelled = 1;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	/* Handle implicit and explicit markers */
9258c2ecf20Sopenharmony_ci	if (cursor->token_type == DIRECTIVE_IMPLICIT) {
9268c2ecf20Sopenharmony_ci		element->flags |= ELEMENT_IMPLICIT;
9278c2ecf20Sopenharmony_ci		implicit = 1;
9288c2ecf20Sopenharmony_ci		cursor++;
9298c2ecf20Sopenharmony_ci		if (cursor >= end)
9308c2ecf20Sopenharmony_ci			goto overrun_error;
9318c2ecf20Sopenharmony_ci	} else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
9328c2ecf20Sopenharmony_ci		element->flags |= ELEMENT_EXPLICIT;
9338c2ecf20Sopenharmony_ci		cursor++;
9348c2ecf20Sopenharmony_ci		if (cursor >= end)
9358c2ecf20Sopenharmony_ci			goto overrun_error;
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	if (labelled) {
9398c2ecf20Sopenharmony_ci		if (!implicit)
9408c2ecf20Sopenharmony_ci			element->method |= ASN1_CONS;
9418c2ecf20Sopenharmony_ci		element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
9428c2ecf20Sopenharmony_ci		element->children = alloc_elem(cursor);
9438c2ecf20Sopenharmony_ci		element = element->children;
9448c2ecf20Sopenharmony_ci		element->class = ASN1_UNIV;
9458c2ecf20Sopenharmony_ci		element->method = ASN1_PRIM;
9468c2ecf20Sopenharmony_ci		element->tag = token_to_tag[cursor->token_type];
9478c2ecf20Sopenharmony_ci		element->name = name;
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	/* Extract the type we're expecting here */
9518c2ecf20Sopenharmony_ci	element->type = cursor;
9528c2ecf20Sopenharmony_ci	switch (cursor->token_type) {
9538c2ecf20Sopenharmony_ci	case DIRECTIVE_ANY:
9548c2ecf20Sopenharmony_ci		element->compound = ANY;
9558c2ecf20Sopenharmony_ci		cursor++;
9568c2ecf20Sopenharmony_ci		break;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	case DIRECTIVE_NULL:
9598c2ecf20Sopenharmony_ci	case DIRECTIVE_BOOLEAN:
9608c2ecf20Sopenharmony_ci	case DIRECTIVE_ENUMERATED:
9618c2ecf20Sopenharmony_ci	case DIRECTIVE_INTEGER:
9628c2ecf20Sopenharmony_ci		element->compound = NOT_COMPOUND;
9638c2ecf20Sopenharmony_ci		cursor++;
9648c2ecf20Sopenharmony_ci		break;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	case DIRECTIVE_EXTERNAL:
9678c2ecf20Sopenharmony_ci		element->method = ASN1_CONS;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	case DIRECTIVE_BMPString:
9708c2ecf20Sopenharmony_ci	case DIRECTIVE_GeneralString:
9718c2ecf20Sopenharmony_ci	case DIRECTIVE_GraphicString:
9728c2ecf20Sopenharmony_ci	case DIRECTIVE_IA5String:
9738c2ecf20Sopenharmony_ci	case DIRECTIVE_ISO646String:
9748c2ecf20Sopenharmony_ci	case DIRECTIVE_NumericString:
9758c2ecf20Sopenharmony_ci	case DIRECTIVE_PrintableString:
9768c2ecf20Sopenharmony_ci	case DIRECTIVE_T61String:
9778c2ecf20Sopenharmony_ci	case DIRECTIVE_TeletexString:
9788c2ecf20Sopenharmony_ci	case DIRECTIVE_UniversalString:
9798c2ecf20Sopenharmony_ci	case DIRECTIVE_UTF8String:
9808c2ecf20Sopenharmony_ci	case DIRECTIVE_VideotexString:
9818c2ecf20Sopenharmony_ci	case DIRECTIVE_VisibleString:
9828c2ecf20Sopenharmony_ci	case DIRECTIVE_ObjectDescriptor:
9838c2ecf20Sopenharmony_ci	case DIRECTIVE_GeneralizedTime:
9848c2ecf20Sopenharmony_ci	case DIRECTIVE_UTCTime:
9858c2ecf20Sopenharmony_ci		element->compound = NOT_COMPOUND;
9868c2ecf20Sopenharmony_ci		cursor++;
9878c2ecf20Sopenharmony_ci		break;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	case DIRECTIVE_BIT:
9908c2ecf20Sopenharmony_ci	case DIRECTIVE_OCTET:
9918c2ecf20Sopenharmony_ci		element->compound = NOT_COMPOUND;
9928c2ecf20Sopenharmony_ci		cursor++;
9938c2ecf20Sopenharmony_ci		if (cursor >= end)
9948c2ecf20Sopenharmony_ci			goto overrun_error;
9958c2ecf20Sopenharmony_ci		if (cursor->token_type != DIRECTIVE_STRING)
9968c2ecf20Sopenharmony_ci			goto parse_error;
9978c2ecf20Sopenharmony_ci		cursor++;
9988c2ecf20Sopenharmony_ci		break;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	case DIRECTIVE_OBJECT:
10018c2ecf20Sopenharmony_ci		element->compound = NOT_COMPOUND;
10028c2ecf20Sopenharmony_ci		cursor++;
10038c2ecf20Sopenharmony_ci		if (cursor >= end)
10048c2ecf20Sopenharmony_ci			goto overrun_error;
10058c2ecf20Sopenharmony_ci		if (cursor->token_type != DIRECTIVE_IDENTIFIER)
10068c2ecf20Sopenharmony_ci			goto parse_error;
10078c2ecf20Sopenharmony_ci		cursor++;
10088c2ecf20Sopenharmony_ci		break;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	case TOKEN_TYPE_NAME:
10118c2ecf20Sopenharmony_ci		element->compound = TYPE_REF;
10128c2ecf20Sopenharmony_ci		ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
10138c2ecf20Sopenharmony_ci			      type_finder);
10148c2ecf20Sopenharmony_ci		if (!ref) {
10158c2ecf20Sopenharmony_ci			fprintf(stderr, "%s:%d: Type '%s' undefined\n",
10168c2ecf20Sopenharmony_ci				filename, cursor->line, cursor->content);
10178c2ecf20Sopenharmony_ci			exit(1);
10188c2ecf20Sopenharmony_ci		}
10198c2ecf20Sopenharmony_ci		cursor->type = *ref;
10208c2ecf20Sopenharmony_ci		(*ref)->ref_count++;
10218c2ecf20Sopenharmony_ci		cursor++;
10228c2ecf20Sopenharmony_ci		break;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	case DIRECTIVE_CHOICE:
10258c2ecf20Sopenharmony_ci		element->compound = CHOICE;
10268c2ecf20Sopenharmony_ci		cursor++;
10278c2ecf20Sopenharmony_ci		element->children = parse_compound(&cursor, end, 1);
10288c2ecf20Sopenharmony_ci		break;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	case DIRECTIVE_SEQUENCE:
10318c2ecf20Sopenharmony_ci		element->compound = SEQUENCE;
10328c2ecf20Sopenharmony_ci		element->method = ASN1_CONS;
10338c2ecf20Sopenharmony_ci		cursor++;
10348c2ecf20Sopenharmony_ci		if (cursor >= end)
10358c2ecf20Sopenharmony_ci			goto overrun_error;
10368c2ecf20Sopenharmony_ci		if (cursor->token_type == DIRECTIVE_OF) {
10378c2ecf20Sopenharmony_ci			element->compound = SEQUENCE_OF;
10388c2ecf20Sopenharmony_ci			cursor++;
10398c2ecf20Sopenharmony_ci			if (cursor >= end)
10408c2ecf20Sopenharmony_ci				goto overrun_error;
10418c2ecf20Sopenharmony_ci			element->children = parse_type(&cursor, end, NULL);
10428c2ecf20Sopenharmony_ci		} else {
10438c2ecf20Sopenharmony_ci			element->children = parse_compound(&cursor, end, 0);
10448c2ecf20Sopenharmony_ci		}
10458c2ecf20Sopenharmony_ci		break;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	case DIRECTIVE_SET:
10488c2ecf20Sopenharmony_ci		element->compound = SET;
10498c2ecf20Sopenharmony_ci		element->method = ASN1_CONS;
10508c2ecf20Sopenharmony_ci		cursor++;
10518c2ecf20Sopenharmony_ci		if (cursor >= end)
10528c2ecf20Sopenharmony_ci			goto overrun_error;
10538c2ecf20Sopenharmony_ci		if (cursor->token_type == DIRECTIVE_OF) {
10548c2ecf20Sopenharmony_ci			element->compound = SET_OF;
10558c2ecf20Sopenharmony_ci			cursor++;
10568c2ecf20Sopenharmony_ci			if (cursor >= end)
10578c2ecf20Sopenharmony_ci				goto parse_error;
10588c2ecf20Sopenharmony_ci			element->children = parse_type(&cursor, end, NULL);
10598c2ecf20Sopenharmony_ci		} else {
10608c2ecf20Sopenharmony_ci			element->children = parse_compound(&cursor, end, 1);
10618c2ecf20Sopenharmony_ci		}
10628c2ecf20Sopenharmony_ci		break;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	default:
10658c2ecf20Sopenharmony_ci		fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
10668c2ecf20Sopenharmony_ci			filename, cursor->line, cursor->content);
10678c2ecf20Sopenharmony_ci		exit(1);
10688c2ecf20Sopenharmony_ci	}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	/* Handle elements that are optional */
10718c2ecf20Sopenharmony_ci	if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
10728c2ecf20Sopenharmony_ci			     cursor->token_type == DIRECTIVE_DEFAULT)
10738c2ecf20Sopenharmony_ci	    ) {
10748c2ecf20Sopenharmony_ci		cursor++;
10758c2ecf20Sopenharmony_ci		top->flags |= ELEMENT_SKIPPABLE;
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
10798c2ecf20Sopenharmony_ci		cursor++;
10808c2ecf20Sopenharmony_ci		if (cursor >= end)
10818c2ecf20Sopenharmony_ci			goto overrun_error;
10828c2ecf20Sopenharmony_ci		if (cursor->token_type != TOKEN_ELEMENT_NAME) {
10838c2ecf20Sopenharmony_ci			fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
10848c2ecf20Sopenharmony_ci				filename, cursor->line, cursor->content);
10858c2ecf20Sopenharmony_ci			exit(1);
10868c2ecf20Sopenharmony_ci		}
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci		action = malloc(sizeof(struct action));
10898c2ecf20Sopenharmony_ci		if (!action) {
10908c2ecf20Sopenharmony_ci			perror(NULL);
10918c2ecf20Sopenharmony_ci			exit(1);
10928c2ecf20Sopenharmony_ci		}
10938c2ecf20Sopenharmony_ci		action->index = 0;
10948c2ecf20Sopenharmony_ci		action->name = cursor->content;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci		for (ppaction = &action_list;
10978c2ecf20Sopenharmony_ci		     *ppaction;
10988c2ecf20Sopenharmony_ci		     ppaction = &(*ppaction)->next
10998c2ecf20Sopenharmony_ci		     ) {
11008c2ecf20Sopenharmony_ci			int cmp = strcmp(action->name, (*ppaction)->name);
11018c2ecf20Sopenharmony_ci			if (cmp == 0) {
11028c2ecf20Sopenharmony_ci				free(action);
11038c2ecf20Sopenharmony_ci				action = *ppaction;
11048c2ecf20Sopenharmony_ci				goto found;
11058c2ecf20Sopenharmony_ci			}
11068c2ecf20Sopenharmony_ci			if (cmp < 0) {
11078c2ecf20Sopenharmony_ci				action->next = *ppaction;
11088c2ecf20Sopenharmony_ci				*ppaction = action;
11098c2ecf20Sopenharmony_ci				nr_actions++;
11108c2ecf20Sopenharmony_ci				goto found;
11118c2ecf20Sopenharmony_ci			}
11128c2ecf20Sopenharmony_ci		}
11138c2ecf20Sopenharmony_ci		action->next = NULL;
11148c2ecf20Sopenharmony_ci		*ppaction = action;
11158c2ecf20Sopenharmony_ci		nr_actions++;
11168c2ecf20Sopenharmony_ci	found:
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci		element->action = action;
11198c2ecf20Sopenharmony_ci		cursor->action = action;
11208c2ecf20Sopenharmony_ci		cursor++;
11218c2ecf20Sopenharmony_ci		if (cursor >= end)
11228c2ecf20Sopenharmony_ci			goto overrun_error;
11238c2ecf20Sopenharmony_ci		if (cursor->token_type != TOKEN_CLOSE_ACTION) {
11248c2ecf20Sopenharmony_ci			fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
11258c2ecf20Sopenharmony_ci				filename, cursor->line, cursor->content);
11268c2ecf20Sopenharmony_ci			exit(1);
11278c2ecf20Sopenharmony_ci		}
11288c2ecf20Sopenharmony_ci		cursor++;
11298c2ecf20Sopenharmony_ci	}
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	*_cursor = cursor;
11328c2ecf20Sopenharmony_ci	return top;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ciparse_error:
11358c2ecf20Sopenharmony_ci	fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
11368c2ecf20Sopenharmony_ci		filename, cursor->line, cursor->content);
11378c2ecf20Sopenharmony_ci	exit(1);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_cioverrun_error:
11408c2ecf20Sopenharmony_ci	fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
11418c2ecf20Sopenharmony_ci	exit(1);
11428c2ecf20Sopenharmony_ci}
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci/*
11458c2ecf20Sopenharmony_ci * Parse a compound type list
11468c2ecf20Sopenharmony_ci */
11478c2ecf20Sopenharmony_cistatic struct element *parse_compound(struct token **_cursor, struct token *end,
11488c2ecf20Sopenharmony_ci				      int alternates)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	struct element *children, **child_p = &children, *element;
11518c2ecf20Sopenharmony_ci	struct token *cursor = *_cursor, *name;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	if (cursor->token_type != TOKEN_OPEN_CURLY) {
11548c2ecf20Sopenharmony_ci		fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
11558c2ecf20Sopenharmony_ci			filename, cursor->line, cursor->content);
11568c2ecf20Sopenharmony_ci		exit(1);
11578c2ecf20Sopenharmony_ci	}
11588c2ecf20Sopenharmony_ci	cursor++;
11598c2ecf20Sopenharmony_ci	if (cursor >= end)
11608c2ecf20Sopenharmony_ci		goto overrun_error;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	if (cursor->token_type == TOKEN_OPEN_CURLY) {
11638c2ecf20Sopenharmony_ci		fprintf(stderr, "%s:%d: Empty compound\n",
11648c2ecf20Sopenharmony_ci			filename, cursor->line);
11658c2ecf20Sopenharmony_ci		exit(1);
11668c2ecf20Sopenharmony_ci	}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	for (;;) {
11698c2ecf20Sopenharmony_ci		name = NULL;
11708c2ecf20Sopenharmony_ci		if (cursor->token_type == TOKEN_ELEMENT_NAME) {
11718c2ecf20Sopenharmony_ci			name = cursor;
11728c2ecf20Sopenharmony_ci			cursor++;
11738c2ecf20Sopenharmony_ci			if (cursor >= end)
11748c2ecf20Sopenharmony_ci				goto overrun_error;
11758c2ecf20Sopenharmony_ci		}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci		element = parse_type(&cursor, end, name);
11788c2ecf20Sopenharmony_ci		if (alternates)
11798c2ecf20Sopenharmony_ci			element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci		*child_p = element;
11828c2ecf20Sopenharmony_ci		child_p = &element->next;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci		if (cursor >= end)
11858c2ecf20Sopenharmony_ci			goto overrun_error;
11868c2ecf20Sopenharmony_ci		if (cursor->token_type != TOKEN_COMMA)
11878c2ecf20Sopenharmony_ci			break;
11888c2ecf20Sopenharmony_ci		cursor++;
11898c2ecf20Sopenharmony_ci		if (cursor >= end)
11908c2ecf20Sopenharmony_ci			goto overrun_error;
11918c2ecf20Sopenharmony_ci	}
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	children->flags &= ~ELEMENT_CONDITIONAL;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	if (cursor->token_type != TOKEN_CLOSE_CURLY) {
11968c2ecf20Sopenharmony_ci		fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
11978c2ecf20Sopenharmony_ci			filename, cursor->line, cursor->content);
11988c2ecf20Sopenharmony_ci		exit(1);
11998c2ecf20Sopenharmony_ci	}
12008c2ecf20Sopenharmony_ci	cursor++;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	*_cursor = cursor;
12038c2ecf20Sopenharmony_ci	return children;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_cioverrun_error:
12068c2ecf20Sopenharmony_ci	fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
12078c2ecf20Sopenharmony_ci	exit(1);
12088c2ecf20Sopenharmony_ci}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_cistatic void dump_element(const struct element *e, int level)
12118c2ecf20Sopenharmony_ci{
12128c2ecf20Sopenharmony_ci	const struct element *c;
12138c2ecf20Sopenharmony_ci	const struct type *t = e->type_def;
12148c2ecf20Sopenharmony_ci	const char *name = e->name ? e->name->content : ".";
12158c2ecf20Sopenharmony_ci	const char *tname = t && t->name ? t->name->content : ".";
12168c2ecf20Sopenharmony_ci	char tag[32];
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	if (e->class == 0 && e->method == 0 && e->tag == 0)
12198c2ecf20Sopenharmony_ci		strcpy(tag, "<...>");
12208c2ecf20Sopenharmony_ci	else if (e->class == ASN1_UNIV)
12218c2ecf20Sopenharmony_ci		sprintf(tag, "%s %s %s",
12228c2ecf20Sopenharmony_ci			asn1_classes[e->class],
12238c2ecf20Sopenharmony_ci			asn1_methods[e->method],
12248c2ecf20Sopenharmony_ci			asn1_universal_tags[e->tag]);
12258c2ecf20Sopenharmony_ci	else
12268c2ecf20Sopenharmony_ci		sprintf(tag, "%s %s %u",
12278c2ecf20Sopenharmony_ci			asn1_classes[e->class],
12288c2ecf20Sopenharmony_ci			asn1_methods[e->method],
12298c2ecf20Sopenharmony_ci			e->tag);
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
12328c2ecf20Sopenharmony_ci	       e->flags & ELEMENT_IMPLICIT ? 'I' : '-',
12338c2ecf20Sopenharmony_ci	       e->flags & ELEMENT_EXPLICIT ? 'E' : '-',
12348c2ecf20Sopenharmony_ci	       e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-',
12358c2ecf20Sopenharmony_ci	       e->flags & ELEMENT_SKIPPABLE ? 'S' : '-',
12368c2ecf20Sopenharmony_ci	       e->flags & ELEMENT_CONDITIONAL ? 'C' : '-',
12378c2ecf20Sopenharmony_ci	       "-tTqQcaro"[e->compound],
12388c2ecf20Sopenharmony_ci	       level, "",
12398c2ecf20Sopenharmony_ci	       tag,
12408c2ecf20Sopenharmony_ci	       tname,
12418c2ecf20Sopenharmony_ci	       name,
12428c2ecf20Sopenharmony_ci	       e->action ? e->action->name : "");
12438c2ecf20Sopenharmony_ci	if (e->compound == TYPE_REF)
12448c2ecf20Sopenharmony_ci		dump_element(e->type->type->element, level + 3);
12458c2ecf20Sopenharmony_ci	else
12468c2ecf20Sopenharmony_ci		for (c = e->children; c; c = c->next)
12478c2ecf20Sopenharmony_ci			dump_element(c, level + 3);
12488c2ecf20Sopenharmony_ci}
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_cistatic void dump_elements(void)
12518c2ecf20Sopenharmony_ci{
12528c2ecf20Sopenharmony_ci	if (debug_opt)
12538c2ecf20Sopenharmony_ci		dump_element(type_list[0].element, 0);
12548c2ecf20Sopenharmony_ci}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_cistatic void render_element(FILE *out, struct element *e, struct element *tag);
12578c2ecf20Sopenharmony_cistatic void render_out_of_line_list(FILE *out);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_cistatic int nr_entries;
12608c2ecf20Sopenharmony_cistatic int render_depth = 1;
12618c2ecf20Sopenharmony_cistatic struct element *render_list, **render_list_p = &render_list;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci__attribute__((format(printf, 2, 3)))
12648c2ecf20Sopenharmony_cistatic void render_opcode(FILE *out, const char *fmt, ...)
12658c2ecf20Sopenharmony_ci{
12668c2ecf20Sopenharmony_ci	va_list va;
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	if (out) {
12698c2ecf20Sopenharmony_ci		fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
12708c2ecf20Sopenharmony_ci		va_start(va, fmt);
12718c2ecf20Sopenharmony_ci		vfprintf(out, fmt, va);
12728c2ecf20Sopenharmony_ci		va_end(va);
12738c2ecf20Sopenharmony_ci	}
12748c2ecf20Sopenharmony_ci	nr_entries++;
12758c2ecf20Sopenharmony_ci}
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci__attribute__((format(printf, 2, 3)))
12788c2ecf20Sopenharmony_cistatic void render_more(FILE *out, const char *fmt, ...)
12798c2ecf20Sopenharmony_ci{
12808c2ecf20Sopenharmony_ci	va_list va;
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	if (out) {
12838c2ecf20Sopenharmony_ci		va_start(va, fmt);
12848c2ecf20Sopenharmony_ci		vfprintf(out, fmt, va);
12858c2ecf20Sopenharmony_ci		va_end(va);
12868c2ecf20Sopenharmony_ci	}
12878c2ecf20Sopenharmony_ci}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci/*
12908c2ecf20Sopenharmony_ci * Render the grammar into a state machine definition.
12918c2ecf20Sopenharmony_ci */
12928c2ecf20Sopenharmony_cistatic void render(FILE *out, FILE *hdr)
12938c2ecf20Sopenharmony_ci{
12948c2ecf20Sopenharmony_ci	struct element *e;
12958c2ecf20Sopenharmony_ci	struct action *action;
12968c2ecf20Sopenharmony_ci	struct type *root;
12978c2ecf20Sopenharmony_ci	int index;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	fprintf(hdr, "/*\n");
13008c2ecf20Sopenharmony_ci	fprintf(hdr, " * Automatically generated by asn1_compiler.  Do not edit\n");
13018c2ecf20Sopenharmony_ci	fprintf(hdr, " *\n");
13028c2ecf20Sopenharmony_ci	fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
13038c2ecf20Sopenharmony_ci	fprintf(hdr, " */\n");
13048c2ecf20Sopenharmony_ci	fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
13058c2ecf20Sopenharmony_ci	fprintf(hdr, "\n");
13068c2ecf20Sopenharmony_ci	fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
13078c2ecf20Sopenharmony_ci	if (ferror(hdr)) {
13088c2ecf20Sopenharmony_ci		perror(headername);
13098c2ecf20Sopenharmony_ci		exit(1);
13108c2ecf20Sopenharmony_ci	}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	fprintf(out, "/*\n");
13138c2ecf20Sopenharmony_ci	fprintf(out, " * Automatically generated by asn1_compiler.  Do not edit\n");
13148c2ecf20Sopenharmony_ci	fprintf(out, " *\n");
13158c2ecf20Sopenharmony_ci	fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
13168c2ecf20Sopenharmony_ci	fprintf(out, " */\n");
13178c2ecf20Sopenharmony_ci	fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
13188c2ecf20Sopenharmony_ci	fprintf(out, "#include \"%s.asn1.h\"\n", grammar_name);
13198c2ecf20Sopenharmony_ci	fprintf(out, "\n");
13208c2ecf20Sopenharmony_ci	if (ferror(out)) {
13218c2ecf20Sopenharmony_ci		perror(outputname);
13228c2ecf20Sopenharmony_ci		exit(1);
13238c2ecf20Sopenharmony_ci	}
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	/* Tabulate the action functions we might have to call */
13268c2ecf20Sopenharmony_ci	fprintf(hdr, "\n");
13278c2ecf20Sopenharmony_ci	index = 0;
13288c2ecf20Sopenharmony_ci	for (action = action_list; action; action = action->next) {
13298c2ecf20Sopenharmony_ci		action->index = index++;
13308c2ecf20Sopenharmony_ci		fprintf(hdr,
13318c2ecf20Sopenharmony_ci			"extern int %s(void *, size_t, unsigned char,"
13328c2ecf20Sopenharmony_ci			" const void *, size_t);\n",
13338c2ecf20Sopenharmony_ci			action->name);
13348c2ecf20Sopenharmony_ci	}
13358c2ecf20Sopenharmony_ci	fprintf(hdr, "\n");
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	fprintf(out, "enum %s_actions {\n", grammar_name);
13388c2ecf20Sopenharmony_ci	for (action = action_list; action; action = action->next)
13398c2ecf20Sopenharmony_ci		fprintf(out, "\tACT_%s = %u,\n",
13408c2ecf20Sopenharmony_ci			action->name, action->index);
13418c2ecf20Sopenharmony_ci	fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
13428c2ecf20Sopenharmony_ci	fprintf(out, "};\n");
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	fprintf(out, "\n");
13458c2ecf20Sopenharmony_ci	fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
13468c2ecf20Sopenharmony_ci		grammar_name, grammar_name);
13478c2ecf20Sopenharmony_ci	for (action = action_list; action; action = action->next)
13488c2ecf20Sopenharmony_ci		fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
13498c2ecf20Sopenharmony_ci	fprintf(out, "};\n");
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	if (ferror(out)) {
13528c2ecf20Sopenharmony_ci		perror(outputname);
13538c2ecf20Sopenharmony_ci		exit(1);
13548c2ecf20Sopenharmony_ci	}
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	/* We do two passes - the first one calculates all the offsets */
13578c2ecf20Sopenharmony_ci	verbose("Pass 1\n");
13588c2ecf20Sopenharmony_ci	nr_entries = 0;
13598c2ecf20Sopenharmony_ci	root = &type_list[0];
13608c2ecf20Sopenharmony_ci	render_element(NULL, root->element, NULL);
13618c2ecf20Sopenharmony_ci	render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
13628c2ecf20Sopenharmony_ci	render_out_of_line_list(NULL);
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	for (e = element_list; e; e = e->list_next)
13658c2ecf20Sopenharmony_ci		e->flags &= ~ELEMENT_RENDERED;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	/* And then we actually render */
13688c2ecf20Sopenharmony_ci	verbose("Pass 2\n");
13698c2ecf20Sopenharmony_ci	fprintf(out, "\n");
13708c2ecf20Sopenharmony_ci	fprintf(out, "static const unsigned char %s_machine[] = {\n",
13718c2ecf20Sopenharmony_ci		grammar_name);
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	nr_entries = 0;
13748c2ecf20Sopenharmony_ci	root = &type_list[0];
13758c2ecf20Sopenharmony_ci	render_element(out, root->element, NULL);
13768c2ecf20Sopenharmony_ci	render_opcode(out, "ASN1_OP_COMPLETE,\n");
13778c2ecf20Sopenharmony_ci	render_out_of_line_list(out);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	fprintf(out, "};\n");
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	fprintf(out, "\n");
13828c2ecf20Sopenharmony_ci	fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
13838c2ecf20Sopenharmony_ci	fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
13848c2ecf20Sopenharmony_ci	fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
13858c2ecf20Sopenharmony_ci	fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
13868c2ecf20Sopenharmony_ci	fprintf(out, "};\n");
13878c2ecf20Sopenharmony_ci}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci/*
13908c2ecf20Sopenharmony_ci * Render the out-of-line elements
13918c2ecf20Sopenharmony_ci */
13928c2ecf20Sopenharmony_cistatic void render_out_of_line_list(FILE *out)
13938c2ecf20Sopenharmony_ci{
13948c2ecf20Sopenharmony_ci	struct element *e, *ce;
13958c2ecf20Sopenharmony_ci	const char *act;
13968c2ecf20Sopenharmony_ci	int entry;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	while ((e = render_list)) {
13998c2ecf20Sopenharmony_ci		render_list = e->render_next;
14008c2ecf20Sopenharmony_ci		if (!render_list)
14018c2ecf20Sopenharmony_ci			render_list_p = &render_list;
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci		render_more(out, "\n");
14048c2ecf20Sopenharmony_ci		e->entry_index = entry = nr_entries;
14058c2ecf20Sopenharmony_ci		render_depth++;
14068c2ecf20Sopenharmony_ci		for (ce = e->children; ce; ce = ce->next)
14078c2ecf20Sopenharmony_ci			render_element(out, ce, NULL);
14088c2ecf20Sopenharmony_ci		render_depth--;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci		act = e->action ? "_ACT" : "";
14118c2ecf20Sopenharmony_ci		switch (e->compound) {
14128c2ecf20Sopenharmony_ci		case SEQUENCE:
14138c2ecf20Sopenharmony_ci			render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
14148c2ecf20Sopenharmony_ci			break;
14158c2ecf20Sopenharmony_ci		case SEQUENCE_OF:
14168c2ecf20Sopenharmony_ci			render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
14178c2ecf20Sopenharmony_ci			render_opcode(out, "_jump_target(%u),\n", entry);
14188c2ecf20Sopenharmony_ci			break;
14198c2ecf20Sopenharmony_ci		case SET:
14208c2ecf20Sopenharmony_ci			render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
14218c2ecf20Sopenharmony_ci			break;
14228c2ecf20Sopenharmony_ci		case SET_OF:
14238c2ecf20Sopenharmony_ci			render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
14248c2ecf20Sopenharmony_ci			render_opcode(out, "_jump_target(%u),\n", entry);
14258c2ecf20Sopenharmony_ci			break;
14268c2ecf20Sopenharmony_ci		default:
14278c2ecf20Sopenharmony_ci			break;
14288c2ecf20Sopenharmony_ci		}
14298c2ecf20Sopenharmony_ci		if (e->action)
14308c2ecf20Sopenharmony_ci			render_opcode(out, "_action(ACT_%s),\n",
14318c2ecf20Sopenharmony_ci				      e->action->name);
14328c2ecf20Sopenharmony_ci		render_opcode(out, "ASN1_OP_RETURN,\n");
14338c2ecf20Sopenharmony_ci	}
14348c2ecf20Sopenharmony_ci}
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci/*
14378c2ecf20Sopenharmony_ci * Render an element.
14388c2ecf20Sopenharmony_ci */
14398c2ecf20Sopenharmony_cistatic void render_element(FILE *out, struct element *e, struct element *tag)
14408c2ecf20Sopenharmony_ci{
14418c2ecf20Sopenharmony_ci	struct element *ec, *x;
14428c2ecf20Sopenharmony_ci	const char *cond, *act;
14438c2ecf20Sopenharmony_ci	int entry, skippable = 0, outofline = 0;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	if (e->flags & ELEMENT_SKIPPABLE ||
14468c2ecf20Sopenharmony_ci	    (tag && tag->flags & ELEMENT_SKIPPABLE))
14478c2ecf20Sopenharmony_ci		skippable = 1;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	if ((e->type_def && e->type_def->ref_count > 1) ||
14508c2ecf20Sopenharmony_ci	    skippable)
14518c2ecf20Sopenharmony_ci		outofline = 1;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	if (e->type_def && out) {
14548c2ecf20Sopenharmony_ci		render_more(out, "\t// %s\n", e->type_def->name->content);
14558c2ecf20Sopenharmony_ci	}
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	/* Render the operation */
14588c2ecf20Sopenharmony_ci	cond = (e->flags & ELEMENT_CONDITIONAL ||
14598c2ecf20Sopenharmony_ci		(tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
14608c2ecf20Sopenharmony_ci	act = e->action ? "_ACT" : "";
14618c2ecf20Sopenharmony_ci	switch (e->compound) {
14628c2ecf20Sopenharmony_ci	case ANY:
14638c2ecf20Sopenharmony_ci		render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
14648c2ecf20Sopenharmony_ci			      cond, act, skippable ? "_OR_SKIP" : "");
14658c2ecf20Sopenharmony_ci		if (e->name)
14668c2ecf20Sopenharmony_ci			render_more(out, "\t\t// %s", e->name->content);
14678c2ecf20Sopenharmony_ci		render_more(out, "\n");
14688c2ecf20Sopenharmony_ci		goto dont_render_tag;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	case TAG_OVERRIDE:
14718c2ecf20Sopenharmony_ci		render_element(out, e->children, e);
14728c2ecf20Sopenharmony_ci		return;
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci	case SEQUENCE:
14758c2ecf20Sopenharmony_ci	case SEQUENCE_OF:
14768c2ecf20Sopenharmony_ci	case SET:
14778c2ecf20Sopenharmony_ci	case SET_OF:
14788c2ecf20Sopenharmony_ci		render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
14798c2ecf20Sopenharmony_ci			      cond,
14808c2ecf20Sopenharmony_ci			      outofline ? "_JUMP" : "",
14818c2ecf20Sopenharmony_ci			      skippable ? "_OR_SKIP" : "");
14828c2ecf20Sopenharmony_ci		break;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	case CHOICE:
14858c2ecf20Sopenharmony_ci		goto dont_render_tag;
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	case TYPE_REF:
14888c2ecf20Sopenharmony_ci		if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
14898c2ecf20Sopenharmony_ci			goto dont_render_tag;
14908c2ecf20Sopenharmony_ci	default:
14918c2ecf20Sopenharmony_ci		render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
14928c2ecf20Sopenharmony_ci			      cond, act,
14938c2ecf20Sopenharmony_ci			      skippable ? "_OR_SKIP" : "");
14948c2ecf20Sopenharmony_ci		break;
14958c2ecf20Sopenharmony_ci	}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	x = tag ?: e;
14988c2ecf20Sopenharmony_ci	if (x->name)
14998c2ecf20Sopenharmony_ci		render_more(out, "\t\t// %s", x->name->content);
15008c2ecf20Sopenharmony_ci	render_more(out, "\n");
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	/* Render the tag */
15038c2ecf20Sopenharmony_ci	if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
15048c2ecf20Sopenharmony_ci		tag = e;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	if (tag->class == ASN1_UNIV &&
15078c2ecf20Sopenharmony_ci	    tag->tag != 14 &&
15088c2ecf20Sopenharmony_ci	    tag->tag != 15 &&
15098c2ecf20Sopenharmony_ci	    tag->tag != 31)
15108c2ecf20Sopenharmony_ci		render_opcode(out, "_tag(%s, %s, %s),\n",
15118c2ecf20Sopenharmony_ci			      asn1_classes[tag->class],
15128c2ecf20Sopenharmony_ci			      asn1_methods[tag->method | e->method],
15138c2ecf20Sopenharmony_ci			      asn1_universal_tags[tag->tag]);
15148c2ecf20Sopenharmony_ci	else
15158c2ecf20Sopenharmony_ci		render_opcode(out, "_tagn(%s, %s, %2u),\n",
15168c2ecf20Sopenharmony_ci			      asn1_classes[tag->class],
15178c2ecf20Sopenharmony_ci			      asn1_methods[tag->method | e->method],
15188c2ecf20Sopenharmony_ci			      tag->tag);
15198c2ecf20Sopenharmony_ci	tag = NULL;
15208c2ecf20Sopenharmony_cidont_render_tag:
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	/* Deal with compound types */
15238c2ecf20Sopenharmony_ci	switch (e->compound) {
15248c2ecf20Sopenharmony_ci	case TYPE_REF:
15258c2ecf20Sopenharmony_ci		render_element(out, e->type->type->element, tag);
15268c2ecf20Sopenharmony_ci		if (e->action)
15278c2ecf20Sopenharmony_ci			render_opcode(out, "ASN1_OP_%sACT,\n",
15288c2ecf20Sopenharmony_ci				      skippable ? "MAYBE_" : "");
15298c2ecf20Sopenharmony_ci		break;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	case SEQUENCE:
15328c2ecf20Sopenharmony_ci		if (outofline) {
15338c2ecf20Sopenharmony_ci			/* Render out-of-line for multiple use or
15348c2ecf20Sopenharmony_ci			 * skipability */
15358c2ecf20Sopenharmony_ci			render_opcode(out, "_jump_target(%u),", e->entry_index);
15368c2ecf20Sopenharmony_ci			if (e->type_def && e->type_def->name)
15378c2ecf20Sopenharmony_ci				render_more(out, "\t\t// --> %s",
15388c2ecf20Sopenharmony_ci					    e->type_def->name->content);
15398c2ecf20Sopenharmony_ci			render_more(out, "\n");
15408c2ecf20Sopenharmony_ci			if (!(e->flags & ELEMENT_RENDERED)) {
15418c2ecf20Sopenharmony_ci				e->flags |= ELEMENT_RENDERED;
15428c2ecf20Sopenharmony_ci				*render_list_p = e;
15438c2ecf20Sopenharmony_ci				render_list_p = &e->render_next;
15448c2ecf20Sopenharmony_ci			}
15458c2ecf20Sopenharmony_ci			return;
15468c2ecf20Sopenharmony_ci		} else {
15478c2ecf20Sopenharmony_ci			/* Render inline for single use */
15488c2ecf20Sopenharmony_ci			render_depth++;
15498c2ecf20Sopenharmony_ci			for (ec = e->children; ec; ec = ec->next)
15508c2ecf20Sopenharmony_ci				render_element(out, ec, NULL);
15518c2ecf20Sopenharmony_ci			render_depth--;
15528c2ecf20Sopenharmony_ci			render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
15538c2ecf20Sopenharmony_ci		}
15548c2ecf20Sopenharmony_ci		break;
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	case SEQUENCE_OF:
15578c2ecf20Sopenharmony_ci	case SET_OF:
15588c2ecf20Sopenharmony_ci		if (outofline) {
15598c2ecf20Sopenharmony_ci			/* Render out-of-line for multiple use or
15608c2ecf20Sopenharmony_ci			 * skipability */
15618c2ecf20Sopenharmony_ci			render_opcode(out, "_jump_target(%u),", e->entry_index);
15628c2ecf20Sopenharmony_ci			if (e->type_def && e->type_def->name)
15638c2ecf20Sopenharmony_ci				render_more(out, "\t\t// --> %s",
15648c2ecf20Sopenharmony_ci					    e->type_def->name->content);
15658c2ecf20Sopenharmony_ci			render_more(out, "\n");
15668c2ecf20Sopenharmony_ci			if (!(e->flags & ELEMENT_RENDERED)) {
15678c2ecf20Sopenharmony_ci				e->flags |= ELEMENT_RENDERED;
15688c2ecf20Sopenharmony_ci				*render_list_p = e;
15698c2ecf20Sopenharmony_ci				render_list_p = &e->render_next;
15708c2ecf20Sopenharmony_ci			}
15718c2ecf20Sopenharmony_ci			return;
15728c2ecf20Sopenharmony_ci		} else {
15738c2ecf20Sopenharmony_ci			/* Render inline for single use */
15748c2ecf20Sopenharmony_ci			entry = nr_entries;
15758c2ecf20Sopenharmony_ci			render_depth++;
15768c2ecf20Sopenharmony_ci			render_element(out, e->children, NULL);
15778c2ecf20Sopenharmony_ci			render_depth--;
15788c2ecf20Sopenharmony_ci			if (e->compound == SEQUENCE_OF)
15798c2ecf20Sopenharmony_ci				render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
15808c2ecf20Sopenharmony_ci			else
15818c2ecf20Sopenharmony_ci				render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
15828c2ecf20Sopenharmony_ci			render_opcode(out, "_jump_target(%u),\n", entry);
15838c2ecf20Sopenharmony_ci		}
15848c2ecf20Sopenharmony_ci		break;
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	case SET:
15878c2ecf20Sopenharmony_ci		/* I can't think of a nice way to do SET support without having
15888c2ecf20Sopenharmony_ci		 * a stack of bitmasks to make sure no element is repeated.
15898c2ecf20Sopenharmony_ci		 * The bitmask has also to be checked that no non-optional
15908c2ecf20Sopenharmony_ci		 * elements are left out whilst not preventing optional
15918c2ecf20Sopenharmony_ci		 * elements from being left out.
15928c2ecf20Sopenharmony_ci		 */
15938c2ecf20Sopenharmony_ci		fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
15948c2ecf20Sopenharmony_ci		exit(1);
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	case CHOICE:
15978c2ecf20Sopenharmony_ci		for (ec = e->children; ec; ec = ec->next)
15988c2ecf20Sopenharmony_ci			render_element(out, ec, ec);
15998c2ecf20Sopenharmony_ci		if (!skippable)
16008c2ecf20Sopenharmony_ci			render_opcode(out, "ASN1_OP_COND_FAIL,\n");
16018c2ecf20Sopenharmony_ci		if (e->action)
16028c2ecf20Sopenharmony_ci			render_opcode(out, "ASN1_OP_ACT,\n");
16038c2ecf20Sopenharmony_ci		break;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	default:
16068c2ecf20Sopenharmony_ci		break;
16078c2ecf20Sopenharmony_ci	}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	if (e->action)
16108c2ecf20Sopenharmony_ci		render_opcode(out, "_action(ACT_%s),\n", e->action->name);
16118c2ecf20Sopenharmony_ci}
1612