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