Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Simplified ASN.1 notation parser
0003  *
0004  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <stdarg.h>
0009 #include <stdio.h>
0010 #include <stdlib.h>
0011 #include <stdint.h>
0012 #include <stdbool.h>
0013 #include <string.h>
0014 #include <ctype.h>
0015 #include <unistd.h>
0016 #include <fcntl.h>
0017 #include <sys/stat.h>
0018 #include <linux/asn1_ber_bytecode.h>
0019 
0020 enum token_type {
0021     DIRECTIVE_ABSENT,
0022     DIRECTIVE_ALL,
0023     DIRECTIVE_ANY,
0024     DIRECTIVE_APPLICATION,
0025     DIRECTIVE_AUTOMATIC,
0026     DIRECTIVE_BEGIN,
0027     DIRECTIVE_BIT,
0028     DIRECTIVE_BMPString,
0029     DIRECTIVE_BOOLEAN,
0030     DIRECTIVE_BY,
0031     DIRECTIVE_CHARACTER,
0032     DIRECTIVE_CHOICE,
0033     DIRECTIVE_CLASS,
0034     DIRECTIVE_COMPONENT,
0035     DIRECTIVE_COMPONENTS,
0036     DIRECTIVE_CONSTRAINED,
0037     DIRECTIVE_CONTAINING,
0038     DIRECTIVE_DEFAULT,
0039     DIRECTIVE_DEFINED,
0040     DIRECTIVE_DEFINITIONS,
0041     DIRECTIVE_EMBEDDED,
0042     DIRECTIVE_ENCODED,
0043     DIRECTIVE_ENCODING_CONTROL,
0044     DIRECTIVE_END,
0045     DIRECTIVE_ENUMERATED,
0046     DIRECTIVE_EXCEPT,
0047     DIRECTIVE_EXPLICIT,
0048     DIRECTIVE_EXPORTS,
0049     DIRECTIVE_EXTENSIBILITY,
0050     DIRECTIVE_EXTERNAL,
0051     DIRECTIVE_FALSE,
0052     DIRECTIVE_FROM,
0053     DIRECTIVE_GeneralString,
0054     DIRECTIVE_GeneralizedTime,
0055     DIRECTIVE_GraphicString,
0056     DIRECTIVE_IA5String,
0057     DIRECTIVE_IDENTIFIER,
0058     DIRECTIVE_IMPLICIT,
0059     DIRECTIVE_IMPLIED,
0060     DIRECTIVE_IMPORTS,
0061     DIRECTIVE_INCLUDES,
0062     DIRECTIVE_INSTANCE,
0063     DIRECTIVE_INSTRUCTIONS,
0064     DIRECTIVE_INTEGER,
0065     DIRECTIVE_INTERSECTION,
0066     DIRECTIVE_ISO646String,
0067     DIRECTIVE_MAX,
0068     DIRECTIVE_MIN,
0069     DIRECTIVE_MINUS_INFINITY,
0070     DIRECTIVE_NULL,
0071     DIRECTIVE_NumericString,
0072     DIRECTIVE_OBJECT,
0073     DIRECTIVE_OCTET,
0074     DIRECTIVE_OF,
0075     DIRECTIVE_OPTIONAL,
0076     DIRECTIVE_ObjectDescriptor,
0077     DIRECTIVE_PATTERN,
0078     DIRECTIVE_PDV,
0079     DIRECTIVE_PLUS_INFINITY,
0080     DIRECTIVE_PRESENT,
0081     DIRECTIVE_PRIVATE,
0082     DIRECTIVE_PrintableString,
0083     DIRECTIVE_REAL,
0084     DIRECTIVE_RELATIVE_OID,
0085     DIRECTIVE_SEQUENCE,
0086     DIRECTIVE_SET,
0087     DIRECTIVE_SIZE,
0088     DIRECTIVE_STRING,
0089     DIRECTIVE_SYNTAX,
0090     DIRECTIVE_T61String,
0091     DIRECTIVE_TAGS,
0092     DIRECTIVE_TRUE,
0093     DIRECTIVE_TeletexString,
0094     DIRECTIVE_UNION,
0095     DIRECTIVE_UNIQUE,
0096     DIRECTIVE_UNIVERSAL,
0097     DIRECTIVE_UTCTime,
0098     DIRECTIVE_UTF8String,
0099     DIRECTIVE_UniversalString,
0100     DIRECTIVE_VideotexString,
0101     DIRECTIVE_VisibleString,
0102     DIRECTIVE_WITH,
0103     NR__DIRECTIVES,
0104     TOKEN_ASSIGNMENT = NR__DIRECTIVES,
0105     TOKEN_OPEN_CURLY,
0106     TOKEN_CLOSE_CURLY,
0107     TOKEN_OPEN_SQUARE,
0108     TOKEN_CLOSE_SQUARE,
0109     TOKEN_OPEN_ACTION,
0110     TOKEN_CLOSE_ACTION,
0111     TOKEN_COMMA,
0112     TOKEN_NUMBER,
0113     TOKEN_TYPE_NAME,
0114     TOKEN_ELEMENT_NAME,
0115     NR__TOKENS
0116 };
0117 
0118 static const unsigned char token_to_tag[NR__TOKENS] = {
0119     /* EOC goes first */
0120     [DIRECTIVE_BOOLEAN]     = ASN1_BOOL,
0121     [DIRECTIVE_INTEGER]     = ASN1_INT,
0122     [DIRECTIVE_BIT]         = ASN1_BTS,
0123     [DIRECTIVE_OCTET]       = ASN1_OTS,
0124     [DIRECTIVE_NULL]        = ASN1_NULL,
0125     [DIRECTIVE_OBJECT]      = ASN1_OID,
0126     [DIRECTIVE_ObjectDescriptor]    = ASN1_ODE,
0127     [DIRECTIVE_EXTERNAL]        = ASN1_EXT,
0128     [DIRECTIVE_REAL]        = ASN1_REAL,
0129     [DIRECTIVE_ENUMERATED]      = ASN1_ENUM,
0130     [DIRECTIVE_EMBEDDED]        = 0,
0131     [DIRECTIVE_UTF8String]      = ASN1_UTF8STR,
0132     [DIRECTIVE_RELATIVE_OID]    = ASN1_RELOID,
0133     /* 14 */
0134     /* 15 */
0135     [DIRECTIVE_SEQUENCE]        = ASN1_SEQ,
0136     [DIRECTIVE_SET]         = ASN1_SET,
0137     [DIRECTIVE_NumericString]   = ASN1_NUMSTR,
0138     [DIRECTIVE_PrintableString] = ASN1_PRNSTR,
0139     [DIRECTIVE_T61String]       = ASN1_TEXSTR,
0140     [DIRECTIVE_TeletexString]   = ASN1_TEXSTR,
0141     [DIRECTIVE_VideotexString]  = ASN1_VIDSTR,
0142     [DIRECTIVE_IA5String]       = ASN1_IA5STR,
0143     [DIRECTIVE_UTCTime]     = ASN1_UNITIM,
0144     [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM,
0145     [DIRECTIVE_GraphicString]   = ASN1_GRASTR,
0146     [DIRECTIVE_VisibleString]   = ASN1_VISSTR,
0147     [DIRECTIVE_GeneralString]   = ASN1_GENSTR,
0148     [DIRECTIVE_UniversalString] = ASN1_UNITIM,
0149     [DIRECTIVE_CHARACTER]       = ASN1_CHRSTR,
0150     [DIRECTIVE_BMPString]       = ASN1_BMPSTR,
0151 };
0152 
0153 static const char asn1_classes[4][5] = {
0154     [ASN1_UNIV] = "UNIV",
0155     [ASN1_APPL] = "APPL",
0156     [ASN1_CONT] = "CONT",
0157     [ASN1_PRIV] = "PRIV"
0158 };
0159 
0160 static const char asn1_methods[2][5] = {
0161     [ASN1_UNIV] = "PRIM",
0162     [ASN1_APPL] = "CONS"
0163 };
0164 
0165 static const char *const asn1_universal_tags[32] = {
0166     "EOC",
0167     "BOOL",
0168     "INT",
0169     "BTS",
0170     "OTS",
0171     "NULL",
0172     "OID",
0173     "ODE",
0174     "EXT",
0175     "REAL",
0176     "ENUM",
0177     "EPDV",
0178     "UTF8STR",
0179     "RELOID",
0180     NULL,       /* 14 */
0181     NULL,       /* 15 */
0182     "SEQ",
0183     "SET",
0184     "NUMSTR",
0185     "PRNSTR",
0186     "TEXSTR",
0187     "VIDSTR",
0188     "IA5STR",
0189     "UNITIM",
0190     "GENTIM",
0191     "GRASTR",
0192     "VISSTR",
0193     "GENSTR",
0194     "UNISTR",
0195     "CHRSTR",
0196     "BMPSTR",
0197     NULL        /* 31 */
0198 };
0199 
0200 static const char *filename;
0201 static const char *grammar_name;
0202 static const char *outputname;
0203 static const char *headername;
0204 
0205 static const char *const directives[NR__DIRECTIVES] = {
0206 #define _(X) [DIRECTIVE_##X] = #X
0207     _(ABSENT),
0208     _(ALL),
0209     _(ANY),
0210     _(APPLICATION),
0211     _(AUTOMATIC),
0212     _(BEGIN),
0213     _(BIT),
0214     _(BMPString),
0215     _(BOOLEAN),
0216     _(BY),
0217     _(CHARACTER),
0218     _(CHOICE),
0219     _(CLASS),
0220     _(COMPONENT),
0221     _(COMPONENTS),
0222     _(CONSTRAINED),
0223     _(CONTAINING),
0224     _(DEFAULT),
0225     _(DEFINED),
0226     _(DEFINITIONS),
0227     _(EMBEDDED),
0228     _(ENCODED),
0229     [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
0230     _(END),
0231     _(ENUMERATED),
0232     _(EXCEPT),
0233     _(EXPLICIT),
0234     _(EXPORTS),
0235     _(EXTENSIBILITY),
0236     _(EXTERNAL),
0237     _(FALSE),
0238     _(FROM),
0239     _(GeneralString),
0240     _(GeneralizedTime),
0241     _(GraphicString),
0242     _(IA5String),
0243     _(IDENTIFIER),
0244     _(IMPLICIT),
0245     _(IMPLIED),
0246     _(IMPORTS),
0247     _(INCLUDES),
0248     _(INSTANCE),
0249     _(INSTRUCTIONS),
0250     _(INTEGER),
0251     _(INTERSECTION),
0252     _(ISO646String),
0253     _(MAX),
0254     _(MIN),
0255     [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
0256     [DIRECTIVE_NULL] = "NULL",
0257     _(NumericString),
0258     _(OBJECT),
0259     _(OCTET),
0260     _(OF),
0261     _(OPTIONAL),
0262     _(ObjectDescriptor),
0263     _(PATTERN),
0264     _(PDV),
0265     [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
0266     _(PRESENT),
0267     _(PRIVATE),
0268     _(PrintableString),
0269     _(REAL),
0270     [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
0271     _(SEQUENCE),
0272     _(SET),
0273     _(SIZE),
0274     _(STRING),
0275     _(SYNTAX),
0276     _(T61String),
0277     _(TAGS),
0278     _(TRUE),
0279     _(TeletexString),
0280     _(UNION),
0281     _(UNIQUE),
0282     _(UNIVERSAL),
0283     _(UTCTime),
0284     _(UTF8String),
0285     _(UniversalString),
0286     _(VideotexString),
0287     _(VisibleString),
0288     _(WITH)
0289 };
0290 
0291 struct action {
0292     struct action   *next;
0293     char        *name;
0294     unsigned char   index;
0295 };
0296 
0297 static struct action *action_list;
0298 static unsigned nr_actions;
0299 
0300 struct token {
0301     unsigned short  line;
0302     enum token_type token_type : 8;
0303     unsigned char   size;
0304     struct action   *action;
0305     char        *content;
0306     struct type *type;
0307 };
0308 
0309 static struct token *token_list;
0310 static unsigned nr_tokens;
0311 static bool verbose_opt;
0312 static bool debug_opt;
0313 
0314 #define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)
0315 #define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)
0316 
0317 static int directive_compare(const void *_key, const void *_pdir)
0318 {
0319     const struct token *token = _key;
0320     const char *const *pdir = _pdir, *dir = *pdir;
0321     size_t dlen, clen;
0322     int val;
0323 
0324     dlen = strlen(dir);
0325     clen = (dlen < token->size) ? dlen : token->size;
0326 
0327     //debug("cmp(%s,%s) = ", token->content, dir);
0328 
0329     val = memcmp(token->content, dir, clen);
0330     if (val != 0) {
0331         //debug("%d [cmp]\n", val);
0332         return val;
0333     }
0334 
0335     if (dlen == token->size) {
0336         //debug("0\n");
0337         return 0;
0338     }
0339     //debug("%d\n", (int)dlen - (int)token->size);
0340     return dlen - token->size; /* shorter -> negative */
0341 }
0342 
0343 /*
0344  * Tokenise an ASN.1 grammar
0345  */
0346 static void tokenise(char *buffer, char *end)
0347 {
0348     struct token *tokens;
0349     char *line, *nl, *start, *p, *q;
0350     unsigned tix, lineno;
0351 
0352     /* Assume we're going to have half as many tokens as we have
0353      * characters
0354      */
0355     token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
0356     if (!tokens) {
0357         perror(NULL);
0358         exit(1);
0359     }
0360     tix = 0;
0361 
0362     lineno = 0;
0363     while (buffer < end) {
0364         /* First of all, break out a line */
0365         lineno++;
0366         line = buffer;
0367         nl = memchr(line, '\n', end - buffer);
0368         if (!nl) {
0369             buffer = nl = end;
0370         } else {
0371             buffer = nl + 1;
0372             *nl = '\0';
0373         }
0374 
0375         /* Remove "--" comments */
0376         p = line;
0377     next_comment:
0378         while ((p = memchr(p, '-', nl - p))) {
0379             if (p[1] == '-') {
0380                 /* Found a comment; see if there's a terminator */
0381                 q = p + 2;
0382                 while ((q = memchr(q, '-', nl - q))) {
0383                     if (q[1] == '-') {
0384                         /* There is - excise the comment */
0385                         q += 2;
0386                         memmove(p, q, nl - q);
0387                         goto next_comment;
0388                     }
0389                     q++;
0390                 }
0391                 *p = '\0';
0392                 nl = p;
0393                 break;
0394             } else {
0395                 p++;
0396             }
0397         }
0398 
0399         p = line;
0400         while (p < nl) {
0401             /* Skip white space */
0402             while (p < nl && isspace(*p))
0403                 *(p++) = 0;
0404             if (p >= nl)
0405                 break;
0406 
0407             tokens[tix].line = lineno;
0408             start = p;
0409 
0410             /* Handle string tokens */
0411             if (isalpha(*p)) {
0412                 const char **dir;
0413 
0414                 /* Can be a directive, type name or element
0415                  * name.  Find the end of the name.
0416                  */
0417                 q = p + 1;
0418                 while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
0419                     q++;
0420                 tokens[tix].size = q - p;
0421                 p = q;
0422 
0423                 tokens[tix].content = malloc(tokens[tix].size + 1);
0424                 if (!tokens[tix].content) {
0425                     perror(NULL);
0426                     exit(1);
0427                 }
0428                 memcpy(tokens[tix].content, start, tokens[tix].size);
0429                 tokens[tix].content[tokens[tix].size] = 0;
0430                 
0431                 /* If it begins with a lowercase letter then
0432                  * it's an element name
0433                  */
0434                 if (islower(tokens[tix].content[0])) {
0435                     tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
0436                     continue;
0437                 }
0438 
0439                 /* Otherwise we need to search the directive
0440                  * table
0441                  */
0442                 dir = bsearch(&tokens[tix], directives,
0443                           sizeof(directives) / sizeof(directives[1]),
0444                           sizeof(directives[1]),
0445                           directive_compare);
0446                 if (dir) {
0447                     tokens[tix++].token_type = dir - directives;
0448                     continue;
0449                 }
0450 
0451                 tokens[tix++].token_type = TOKEN_TYPE_NAME;
0452                 continue;
0453             }
0454 
0455             /* Handle numbers */
0456             if (isdigit(*p)) {
0457                 /* Find the end of the number */
0458                 q = p + 1;
0459                 while (q < nl && (isdigit(*q)))
0460                     q++;
0461                 tokens[tix].size = q - p;
0462                 p = q;
0463                 tokens[tix].content = malloc(tokens[tix].size + 1);
0464                 if (!tokens[tix].content) {
0465                     perror(NULL);
0466                     exit(1);
0467                 }
0468                 memcpy(tokens[tix].content, start, tokens[tix].size);
0469                 tokens[tix].content[tokens[tix].size] = 0;
0470                 tokens[tix++].token_type = TOKEN_NUMBER;
0471                 continue;
0472             }
0473 
0474             if (nl - p >= 3) {
0475                 if (memcmp(p, "::=", 3) == 0) {
0476                     p += 3;
0477                     tokens[tix].size = 3;
0478                     tokens[tix].content = "::=";
0479                     tokens[tix++].token_type = TOKEN_ASSIGNMENT;
0480                     continue;
0481                 }
0482             }
0483 
0484             if (nl - p >= 2) {
0485                 if (memcmp(p, "({", 2) == 0) {
0486                     p += 2;
0487                     tokens[tix].size = 2;
0488                     tokens[tix].content = "({";
0489                     tokens[tix++].token_type = TOKEN_OPEN_ACTION;
0490                     continue;
0491                 }
0492                 if (memcmp(p, "})", 2) == 0) {
0493                     p += 2;
0494                     tokens[tix].size = 2;
0495                     tokens[tix].content = "})";
0496                     tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
0497                     continue;
0498                 }
0499             }
0500 
0501             if (nl - p >= 1) {
0502                 tokens[tix].size = 1;
0503                 switch (*p) {
0504                 case '{':
0505                     p += 1;
0506                     tokens[tix].content = "{";
0507                     tokens[tix++].token_type = TOKEN_OPEN_CURLY;
0508                     continue;
0509                 case '}':
0510                     p += 1;
0511                     tokens[tix].content = "}";
0512                     tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
0513                     continue;
0514                 case '[':
0515                     p += 1;
0516                     tokens[tix].content = "[";
0517                     tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
0518                     continue;
0519                 case ']':
0520                     p += 1;
0521                     tokens[tix].content = "]";
0522                     tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
0523                     continue;
0524                 case ',':
0525                     p += 1;
0526                     tokens[tix].content = ",";
0527                     tokens[tix++].token_type = TOKEN_COMMA;
0528                     continue;
0529                 default:
0530                     break;
0531                 }
0532             }
0533 
0534             fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
0535                 filename, lineno, *p);
0536             exit(1);
0537         }
0538     }
0539 
0540     nr_tokens = tix;
0541     verbose("Extracted %u tokens\n", nr_tokens);
0542 
0543 #if 0
0544     {
0545         int n;
0546         for (n = 0; n < nr_tokens; n++)
0547             debug("Token %3u: '%s'\n", n, token_list[n].content);
0548     }
0549 #endif
0550 }
0551 
0552 static void build_type_list(void);
0553 static void parse(void);
0554 static void dump_elements(void);
0555 static void render(FILE *out, FILE *hdr);
0556 
0557 /*
0558  *
0559  */
0560 int main(int argc, char **argv)
0561 {
0562     struct stat st;
0563     ssize_t readlen;
0564     FILE *out, *hdr;
0565     char *buffer, *p;
0566     char *kbuild_verbose;
0567     int fd;
0568 
0569     kbuild_verbose = getenv("KBUILD_VERBOSE");
0570     if (kbuild_verbose)
0571         verbose_opt = atoi(kbuild_verbose);
0572 
0573     while (argc > 4) {
0574         if (strcmp(argv[1], "-v") == 0)
0575             verbose_opt = true;
0576         else if (strcmp(argv[1], "-d") == 0)
0577             debug_opt = true;
0578         else
0579             break;
0580         memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *));
0581         argc--;
0582     }
0583 
0584     if (argc != 4) {
0585         fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n",
0586             argv[0]);
0587         exit(2);
0588     }
0589 
0590     filename = argv[1];
0591     outputname = argv[2];
0592     headername = argv[3];
0593 
0594     fd = open(filename, O_RDONLY);
0595     if (fd < 0) {
0596         perror(filename);
0597         exit(1);
0598     }
0599 
0600     if (fstat(fd, &st) < 0) {
0601         perror(filename);
0602         exit(1);
0603     }
0604 
0605     if (!(buffer = malloc(st.st_size + 1))) {
0606         perror(NULL);
0607         exit(1);
0608     }
0609 
0610     if ((readlen = read(fd, buffer, st.st_size)) < 0) {
0611         perror(filename);
0612         exit(1);
0613     }
0614 
0615     if (close(fd) < 0) {
0616         perror(filename);
0617         exit(1);
0618     }
0619 
0620     if (readlen != st.st_size) {
0621         fprintf(stderr, "%s: Short read\n", filename);
0622         exit(1);
0623     }
0624 
0625     p = strrchr(argv[1], '/');
0626     p = p ? p + 1 : argv[1];
0627     grammar_name = strdup(p);
0628     if (!p) {
0629         perror(NULL);
0630         exit(1);
0631     }
0632     p = strchr(grammar_name, '.');
0633     if (p)
0634         *p = '\0';
0635 
0636     buffer[readlen] = 0;
0637     tokenise(buffer, buffer + readlen);
0638     build_type_list();
0639     parse();
0640     dump_elements();
0641 
0642     out = fopen(outputname, "w");
0643     if (!out) {
0644         perror(outputname);
0645         exit(1);
0646     }
0647 
0648     hdr = fopen(headername, "w");
0649     if (!hdr) {
0650         perror(headername);
0651         exit(1);
0652     }
0653 
0654     render(out, hdr);
0655 
0656     if (fclose(out) < 0) {
0657         perror(outputname);
0658         exit(1);
0659     }
0660 
0661     if (fclose(hdr) < 0) {
0662         perror(headername);
0663         exit(1);
0664     }
0665 
0666     return 0;
0667 }
0668 
0669 enum compound {
0670     NOT_COMPOUND,
0671     SET,
0672     SET_OF,
0673     SEQUENCE,
0674     SEQUENCE_OF,
0675     CHOICE,
0676     ANY,
0677     TYPE_REF,
0678     TAG_OVERRIDE
0679 };
0680 
0681 struct element {
0682     struct type *type_def;
0683     struct token    *name;
0684     struct token    *type;
0685     struct action   *action;
0686     struct element  *children;
0687     struct element  *next;
0688     struct element  *render_next;
0689     struct element  *list_next;
0690     uint8_t     n_elements;
0691     enum compound   compound : 8;
0692     enum asn1_class class : 8;
0693     enum asn1_method method : 8;
0694     uint8_t     tag;
0695     unsigned    entry_index;
0696     unsigned    flags;
0697 #define ELEMENT_IMPLICIT    0x0001
0698 #define ELEMENT_EXPLICIT    0x0002
0699 #define ELEMENT_TAG_SPECIFIED   0x0004
0700 #define ELEMENT_RENDERED    0x0008
0701 #define ELEMENT_SKIPPABLE   0x0010
0702 #define ELEMENT_CONDITIONAL 0x0020
0703 };
0704 
0705 struct type {
0706     struct token    *name;
0707     struct token    *def;
0708     struct element  *element;
0709     unsigned    ref_count;
0710     unsigned    flags;
0711 #define TYPE_STOP_MARKER    0x0001
0712 #define TYPE_BEGIN      0x0002
0713 };
0714 
0715 static struct type *type_list;
0716 static struct type **type_index;
0717 static unsigned nr_types;
0718 
0719 static int type_index_compare(const void *_a, const void *_b)
0720 {
0721     const struct type *const *a = _a, *const *b = _b;
0722 
0723     if ((*a)->name->size != (*b)->name->size)
0724         return (*a)->name->size - (*b)->name->size;
0725     else
0726         return memcmp((*a)->name->content, (*b)->name->content,
0727                   (*a)->name->size);
0728 }
0729 
0730 static int type_finder(const void *_key, const void *_ti)
0731 {
0732     const struct token *token = _key;
0733     const struct type *const *ti = _ti;
0734     const struct type *type = *ti;
0735 
0736     if (token->size != type->name->size)
0737         return token->size - type->name->size;
0738     else
0739         return memcmp(token->content, type->name->content,
0740                   token->size);
0741 }
0742 
0743 /*
0744  * Build up a list of types and a sorted index to that list.
0745  */
0746 static void build_type_list(void)
0747 {
0748     struct type *types;
0749     unsigned nr, t, n;
0750 
0751     nr = 0;
0752     for (n = 0; n < nr_tokens - 1; n++)
0753         if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
0754             token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
0755             nr++;
0756 
0757     if (nr == 0) {
0758         fprintf(stderr, "%s: No defined types\n", filename);
0759         exit(1);
0760     }
0761 
0762     nr_types = nr;
0763     types = type_list = calloc(nr + 1, sizeof(type_list[0]));
0764     if (!type_list) {
0765         perror(NULL);
0766         exit(1);
0767     }
0768     type_index = calloc(nr, sizeof(type_index[0]));
0769     if (!type_index) {
0770         perror(NULL);
0771         exit(1);
0772     }
0773 
0774     t = 0;
0775     types[t].flags |= TYPE_BEGIN;
0776     for (n = 0; n < nr_tokens - 1; n++) {
0777         if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
0778             token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
0779             types[t].name = &token_list[n];
0780             type_index[t] = &types[t];
0781             t++;
0782         }
0783     }
0784     types[t].name = &token_list[n + 1];
0785     types[t].flags |= TYPE_STOP_MARKER;
0786 
0787     qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
0788 
0789     verbose("Extracted %u types\n", nr_types);
0790 #if 0
0791     for (n = 0; n < nr_types; n++) {
0792         struct type *type = type_index[n];
0793         debug("- %*.*s\n", type->name->content);
0794     }
0795 #endif
0796 }
0797 
0798 static struct element *parse_type(struct token **_cursor, struct token *stop,
0799                   struct token *name);
0800 
0801 /*
0802  * Parse the token stream
0803  */
0804 static void parse(void)
0805 {
0806     struct token *cursor;
0807     struct type *type;
0808 
0809     /* Parse one type definition statement at a time */
0810     type = type_list;
0811     do {
0812         cursor = type->name;
0813 
0814         if (cursor[0].token_type != TOKEN_TYPE_NAME ||
0815             cursor[1].token_type != TOKEN_ASSIGNMENT)
0816             abort();
0817         cursor += 2;
0818 
0819         type->element = parse_type(&cursor, type[1].name, NULL);
0820         type->element->type_def = type;
0821 
0822         if (cursor != type[1].name) {
0823             fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
0824                 filename, cursor->line, cursor->content);
0825             exit(1);
0826         }
0827 
0828     } while (type++, !(type->flags & TYPE_STOP_MARKER));
0829 
0830     verbose("Extracted %u actions\n", nr_actions);
0831 }
0832 
0833 static struct element *element_list;
0834 
0835 static struct element *alloc_elem(struct token *type)
0836 {
0837     struct element *e = calloc(1, sizeof(*e));
0838     if (!e) {
0839         perror(NULL);
0840         exit(1);
0841     }
0842     e->list_next = element_list;
0843     element_list = e;
0844     return e;
0845 }
0846 
0847 static struct element *parse_compound(struct token **_cursor, struct token *end,
0848                       int alternates);
0849 
0850 /*
0851  * Parse one type definition statement
0852  */
0853 static struct element *parse_type(struct token **_cursor, struct token *end,
0854                   struct token *name)
0855 {
0856     struct element *top, *element;
0857     struct action *action, **ppaction;
0858     struct token *cursor = *_cursor;
0859     struct type **ref;
0860     char *p;
0861     int labelled = 0, implicit = 0;
0862 
0863     top = element = alloc_elem(cursor);
0864     element->class = ASN1_UNIV;
0865     element->method = ASN1_PRIM;
0866     element->tag = token_to_tag[cursor->token_type];
0867     element->name = name;
0868 
0869     /* Extract the tag value if one given */
0870     if (cursor->token_type == TOKEN_OPEN_SQUARE) {
0871         cursor++;
0872         if (cursor >= end)
0873             goto overrun_error;
0874         switch (cursor->token_type) {
0875         case DIRECTIVE_UNIVERSAL:
0876             element->class = ASN1_UNIV;
0877             cursor++;
0878             break;
0879         case DIRECTIVE_APPLICATION:
0880             element->class = ASN1_APPL;
0881             cursor++;
0882             break;
0883         case TOKEN_NUMBER:
0884             element->class = ASN1_CONT;
0885             break;
0886         case DIRECTIVE_PRIVATE:
0887             element->class = ASN1_PRIV;
0888             cursor++;
0889             break;
0890         default:
0891             fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
0892                 filename, cursor->line, cursor->content);
0893             exit(1);
0894         }
0895 
0896         if (cursor >= end)
0897             goto overrun_error;
0898         if (cursor->token_type != TOKEN_NUMBER) {
0899             fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
0900                 filename, cursor->line, cursor->content);
0901             exit(1);
0902         }
0903 
0904         element->tag &= ~0x1f;
0905         element->tag |= strtoul(cursor->content, &p, 10);
0906         element->flags |= ELEMENT_TAG_SPECIFIED;
0907         if (p - cursor->content != cursor->size)
0908             abort();
0909         cursor++;
0910 
0911         if (cursor >= end)
0912             goto overrun_error;
0913         if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
0914             fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
0915                 filename, cursor->line, cursor->content);
0916             exit(1);
0917         }
0918         cursor++;
0919         if (cursor >= end)
0920             goto overrun_error;
0921         labelled = 1;
0922     }
0923 
0924     /* Handle implicit and explicit markers */
0925     if (cursor->token_type == DIRECTIVE_IMPLICIT) {
0926         element->flags |= ELEMENT_IMPLICIT;
0927         implicit = 1;
0928         cursor++;
0929         if (cursor >= end)
0930             goto overrun_error;
0931     } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
0932         element->flags |= ELEMENT_EXPLICIT;
0933         cursor++;
0934         if (cursor >= end)
0935             goto overrun_error;
0936     }
0937 
0938     if (labelled) {
0939         if (!implicit)
0940             element->method |= ASN1_CONS;
0941         element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
0942         element->children = alloc_elem(cursor);
0943         element = element->children;
0944         element->class = ASN1_UNIV;
0945         element->method = ASN1_PRIM;
0946         element->tag = token_to_tag[cursor->token_type];
0947         element->name = name;
0948     }
0949 
0950     /* Extract the type we're expecting here */
0951     element->type = cursor;
0952     switch (cursor->token_type) {
0953     case DIRECTIVE_ANY:
0954         element->compound = ANY;
0955         cursor++;
0956         break;
0957 
0958     case DIRECTIVE_NULL:
0959     case DIRECTIVE_BOOLEAN:
0960     case DIRECTIVE_ENUMERATED:
0961     case DIRECTIVE_INTEGER:
0962         element->compound = NOT_COMPOUND;
0963         cursor++;
0964         break;
0965 
0966     case DIRECTIVE_EXTERNAL:
0967         element->method = ASN1_CONS;
0968 
0969     case DIRECTIVE_BMPString:
0970     case DIRECTIVE_GeneralString:
0971     case DIRECTIVE_GraphicString:
0972     case DIRECTIVE_IA5String:
0973     case DIRECTIVE_ISO646String:
0974     case DIRECTIVE_NumericString:
0975     case DIRECTIVE_PrintableString:
0976     case DIRECTIVE_T61String:
0977     case DIRECTIVE_TeletexString:
0978     case DIRECTIVE_UniversalString:
0979     case DIRECTIVE_UTF8String:
0980     case DIRECTIVE_VideotexString:
0981     case DIRECTIVE_VisibleString:
0982     case DIRECTIVE_ObjectDescriptor:
0983     case DIRECTIVE_GeneralizedTime:
0984     case DIRECTIVE_UTCTime:
0985         element->compound = NOT_COMPOUND;
0986         cursor++;
0987         break;
0988 
0989     case DIRECTIVE_BIT:
0990     case DIRECTIVE_OCTET:
0991         element->compound = NOT_COMPOUND;
0992         cursor++;
0993         if (cursor >= end)
0994             goto overrun_error;
0995         if (cursor->token_type != DIRECTIVE_STRING)
0996             goto parse_error;
0997         cursor++;
0998         break;
0999 
1000     case DIRECTIVE_OBJECT:
1001         element->compound = NOT_COMPOUND;
1002         cursor++;
1003         if (cursor >= end)
1004             goto overrun_error;
1005         if (cursor->token_type != DIRECTIVE_IDENTIFIER)
1006             goto parse_error;
1007         cursor++;
1008         break;
1009 
1010     case TOKEN_TYPE_NAME:
1011         element->compound = TYPE_REF;
1012         ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
1013                   type_finder);
1014         if (!ref) {
1015             fprintf(stderr, "%s:%d: Type '%s' undefined\n",
1016                 filename, cursor->line, cursor->content);
1017             exit(1);
1018         }
1019         cursor->type = *ref;
1020         (*ref)->ref_count++;
1021         cursor++;
1022         break;
1023 
1024     case DIRECTIVE_CHOICE:
1025         element->compound = CHOICE;
1026         cursor++;
1027         element->children = parse_compound(&cursor, end, 1);
1028         break;
1029 
1030     case DIRECTIVE_SEQUENCE:
1031         element->compound = SEQUENCE;
1032         element->method = ASN1_CONS;
1033         cursor++;
1034         if (cursor >= end)
1035             goto overrun_error;
1036         if (cursor->token_type == DIRECTIVE_OF) {
1037             element->compound = SEQUENCE_OF;
1038             cursor++;
1039             if (cursor >= end)
1040                 goto overrun_error;
1041             element->children = parse_type(&cursor, end, NULL);
1042         } else {
1043             element->children = parse_compound(&cursor, end, 0);
1044         }
1045         break;
1046 
1047     case DIRECTIVE_SET:
1048         element->compound = SET;
1049         element->method = ASN1_CONS;
1050         cursor++;
1051         if (cursor >= end)
1052             goto overrun_error;
1053         if (cursor->token_type == DIRECTIVE_OF) {
1054             element->compound = SET_OF;
1055             cursor++;
1056             if (cursor >= end)
1057                 goto parse_error;
1058             element->children = parse_type(&cursor, end, NULL);
1059         } else {
1060             element->children = parse_compound(&cursor, end, 1);
1061         }
1062         break;
1063 
1064     default:
1065         fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
1066             filename, cursor->line, cursor->content);
1067         exit(1);
1068     }
1069 
1070     /* Handle elements that are optional */
1071     if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1072                  cursor->token_type == DIRECTIVE_DEFAULT)
1073         ) {
1074         cursor++;
1075         top->flags |= ELEMENT_SKIPPABLE;
1076     }
1077 
1078     if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
1079         cursor++;
1080         if (cursor >= end)
1081             goto overrun_error;
1082         if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1083             fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
1084                 filename, cursor->line, cursor->content);
1085             exit(1);
1086         }
1087 
1088         action = malloc(sizeof(struct action));
1089         if (!action) {
1090             perror(NULL);
1091             exit(1);
1092         }
1093         action->index = 0;
1094         action->name = cursor->content;
1095 
1096         for (ppaction = &action_list;
1097              *ppaction;
1098              ppaction = &(*ppaction)->next
1099              ) {
1100             int cmp = strcmp(action->name, (*ppaction)->name);
1101             if (cmp == 0) {
1102                 free(action);
1103                 action = *ppaction;
1104                 goto found;
1105             }
1106             if (cmp < 0) {
1107                 action->next = *ppaction;
1108                 *ppaction = action;
1109                 nr_actions++;
1110                 goto found;
1111             }
1112         }
1113         action->next = NULL;
1114         *ppaction = action;
1115         nr_actions++;
1116     found:
1117 
1118         element->action = action;
1119         cursor->action = action;
1120         cursor++;
1121         if (cursor >= end)
1122             goto overrun_error;
1123         if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1124             fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
1125                 filename, cursor->line, cursor->content);
1126             exit(1);
1127         }
1128         cursor++;
1129     }
1130 
1131     *_cursor = cursor;
1132     return top;
1133 
1134 parse_error:
1135     fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
1136         filename, cursor->line, cursor->content);
1137     exit(1);
1138 
1139 overrun_error:
1140     fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1141     exit(1);
1142 }
1143 
1144 /*
1145  * Parse a compound type list
1146  */
1147 static struct element *parse_compound(struct token **_cursor, struct token *end,
1148                       int alternates)
1149 {
1150     struct element *children, **child_p = &children, *element;
1151     struct token *cursor = *_cursor, *name;
1152 
1153     if (cursor->token_type != TOKEN_OPEN_CURLY) {
1154         fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
1155             filename, cursor->line, cursor->content);
1156         exit(1);
1157     }
1158     cursor++;
1159     if (cursor >= end)
1160         goto overrun_error;
1161 
1162     if (cursor->token_type == TOKEN_OPEN_CURLY) {
1163         fprintf(stderr, "%s:%d: Empty compound\n",
1164             filename, cursor->line);
1165         exit(1);
1166     }
1167 
1168     for (;;) {
1169         name = NULL;
1170         if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1171             name = cursor;
1172             cursor++;
1173             if (cursor >= end)
1174                 goto overrun_error;
1175         }
1176 
1177         element = parse_type(&cursor, end, name);
1178         if (alternates)
1179             element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1180 
1181         *child_p = element;
1182         child_p = &element->next;
1183 
1184         if (cursor >= end)
1185             goto overrun_error;
1186         if (cursor->token_type != TOKEN_COMMA)
1187             break;
1188         cursor++;
1189         if (cursor >= end)
1190             goto overrun_error;
1191     }
1192 
1193     children->flags &= ~ELEMENT_CONDITIONAL;
1194 
1195     if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1196         fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
1197             filename, cursor->line, cursor->content);
1198         exit(1);
1199     }
1200     cursor++;
1201 
1202     *_cursor = cursor;
1203     return children;
1204 
1205 overrun_error:
1206     fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1207     exit(1);
1208 }
1209 
1210 static void dump_element(const struct element *e, int level)
1211 {
1212     const struct element *c;
1213     const struct type *t = e->type_def;
1214     const char *name = e->name ? e->name->content : ".";
1215     const char *tname = t && t->name ? t->name->content : ".";
1216     char tag[32];
1217 
1218     if (e->class == 0 && e->method == 0 && e->tag == 0)
1219         strcpy(tag, "<...>");
1220     else if (e->class == ASN1_UNIV)
1221         sprintf(tag, "%s %s %s",
1222             asn1_classes[e->class],
1223             asn1_methods[e->method],
1224             asn1_universal_tags[e->tag]);
1225     else
1226         sprintf(tag, "%s %s %u",
1227             asn1_classes[e->class],
1228             asn1_methods[e->method],
1229             e->tag);
1230 
1231     printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
1232            e->flags & ELEMENT_IMPLICIT ? 'I' : '-',
1233            e->flags & ELEMENT_EXPLICIT ? 'E' : '-',
1234            e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-',
1235            e->flags & ELEMENT_SKIPPABLE ? 'S' : '-',
1236            e->flags & ELEMENT_CONDITIONAL ? 'C' : '-',
1237            "-tTqQcaro"[e->compound],
1238            level, "",
1239            tag,
1240            tname,
1241            name,
1242            e->action ? e->action->name : "");
1243     if (e->compound == TYPE_REF)
1244         dump_element(e->type->type->element, level + 3);
1245     else
1246         for (c = e->children; c; c = c->next)
1247             dump_element(c, level + 3);
1248 }
1249 
1250 static void dump_elements(void)
1251 {
1252     if (debug_opt)
1253         dump_element(type_list[0].element, 0);
1254 }
1255 
1256 static void render_element(FILE *out, struct element *e, struct element *tag);
1257 static void render_out_of_line_list(FILE *out);
1258 
1259 static int nr_entries;
1260 static int render_depth = 1;
1261 static struct element *render_list, **render_list_p = &render_list;
1262 
1263 __attribute__((format(printf, 2, 3)))
1264 static void render_opcode(FILE *out, const char *fmt, ...)
1265 {
1266     va_list va;
1267 
1268     if (out) {
1269         fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1270         va_start(va, fmt);
1271         vfprintf(out, fmt, va);
1272         va_end(va);
1273     }
1274     nr_entries++;
1275 }
1276 
1277 __attribute__((format(printf, 2, 3)))
1278 static void render_more(FILE *out, const char *fmt, ...)
1279 {
1280     va_list va;
1281 
1282     if (out) {
1283         va_start(va, fmt);
1284         vfprintf(out, fmt, va);
1285         va_end(va);
1286     }
1287 }
1288 
1289 /*
1290  * Render the grammar into a state machine definition.
1291  */
1292 static void render(FILE *out, FILE *hdr)
1293 {
1294     struct element *e;
1295     struct action *action;
1296     struct type *root;
1297     int index;
1298 
1299     fprintf(hdr, "/*\n");
1300     fprintf(hdr, " * Automatically generated by asn1_compiler.  Do not edit\n");
1301     fprintf(hdr, " *\n");
1302     fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
1303     fprintf(hdr, " */\n");
1304     fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
1305     fprintf(hdr, "\n");
1306     fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
1307     if (ferror(hdr)) {
1308         perror(headername);
1309         exit(1);
1310     }
1311 
1312     fprintf(out, "/*\n");
1313     fprintf(out, " * Automatically generated by asn1_compiler.  Do not edit\n");
1314     fprintf(out, " *\n");
1315     fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
1316     fprintf(out, " */\n");
1317     fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
1318     fprintf(out, "#include \"%s.asn1.h\"\n", grammar_name);
1319     fprintf(out, "\n");
1320     if (ferror(out)) {
1321         perror(outputname);
1322         exit(1);
1323     }
1324 
1325     /* Tabulate the action functions we might have to call */
1326     fprintf(hdr, "\n");
1327     index = 0;
1328     for (action = action_list; action; action = action->next) {
1329         action->index = index++;
1330         fprintf(hdr,
1331             "extern int %s(void *, size_t, unsigned char,"
1332             " const void *, size_t);\n",
1333             action->name);
1334     }
1335     fprintf(hdr, "\n");
1336 
1337     fprintf(out, "enum %s_actions {\n", grammar_name);
1338     for (action = action_list; action; action = action->next)
1339         fprintf(out, "\tACT_%s = %u,\n",
1340             action->name, action->index);
1341     fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
1342     fprintf(out, "};\n");
1343 
1344     fprintf(out, "\n");
1345     fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1346         grammar_name, grammar_name);
1347     for (action = action_list; action; action = action->next)
1348         fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
1349     fprintf(out, "};\n");
1350 
1351     if (ferror(out)) {
1352         perror(outputname);
1353         exit(1);
1354     }
1355 
1356     /* We do two passes - the first one calculates all the offsets */
1357     verbose("Pass 1\n");
1358     nr_entries = 0;
1359     root = &type_list[0];
1360     render_element(NULL, root->element, NULL);
1361     render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
1362     render_out_of_line_list(NULL);
1363 
1364     for (e = element_list; e; e = e->list_next)
1365         e->flags &= ~ELEMENT_RENDERED;
1366 
1367     /* And then we actually render */
1368     verbose("Pass 2\n");
1369     fprintf(out, "\n");
1370     fprintf(out, "static const unsigned char %s_machine[] = {\n",
1371         grammar_name);
1372 
1373     nr_entries = 0;
1374     root = &type_list[0];
1375     render_element(out, root->element, NULL);
1376     render_opcode(out, "ASN1_OP_COMPLETE,\n");
1377     render_out_of_line_list(out);
1378 
1379     fprintf(out, "};\n");
1380 
1381     fprintf(out, "\n");
1382     fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
1383     fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
1384     fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
1385     fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
1386     fprintf(out, "};\n");
1387 }
1388 
1389 /*
1390  * Render the out-of-line elements
1391  */
1392 static void render_out_of_line_list(FILE *out)
1393 {
1394     struct element *e, *ce;
1395     const char *act;
1396     int entry;
1397 
1398     while ((e = render_list)) {
1399         render_list = e->render_next;
1400         if (!render_list)
1401             render_list_p = &render_list;
1402 
1403         render_more(out, "\n");
1404         e->entry_index = entry = nr_entries;
1405         render_depth++;
1406         for (ce = e->children; ce; ce = ce->next)
1407             render_element(out, ce, NULL);
1408         render_depth--;
1409 
1410         act = e->action ? "_ACT" : "";
1411         switch (e->compound) {
1412         case SEQUENCE:
1413             render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1414             break;
1415         case SEQUENCE_OF:
1416             render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1417             render_opcode(out, "_jump_target(%u),\n", entry);
1418             break;
1419         case SET:
1420             render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1421             break;
1422         case SET_OF:
1423             render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1424             render_opcode(out, "_jump_target(%u),\n", entry);
1425             break;
1426         default:
1427             break;
1428         }
1429         if (e->action)
1430             render_opcode(out, "_action(ACT_%s),\n",
1431                       e->action->name);
1432         render_opcode(out, "ASN1_OP_RETURN,\n");
1433     }
1434 }
1435 
1436 /*
1437  * Render an element.
1438  */
1439 static void render_element(FILE *out, struct element *e, struct element *tag)
1440 {
1441     struct element *ec, *x;
1442     const char *cond, *act;
1443     int entry, skippable = 0, outofline = 0;
1444 
1445     if (e->flags & ELEMENT_SKIPPABLE ||
1446         (tag && tag->flags & ELEMENT_SKIPPABLE))
1447         skippable = 1;
1448 
1449     if ((e->type_def && e->type_def->ref_count > 1) ||
1450         skippable)
1451         outofline = 1;
1452 
1453     if (e->type_def && out) {
1454         render_more(out, "\t// %s\n", e->type_def->name->content);
1455     }
1456 
1457     /* Render the operation */
1458     cond = (e->flags & ELEMENT_CONDITIONAL ||
1459         (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
1460     act = e->action ? "_ACT" : "";
1461     switch (e->compound) {
1462     case ANY:
1463         render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
1464                   cond, act, skippable ? "_OR_SKIP" : "");
1465         if (e->name)
1466             render_more(out, "\t\t// %s", e->name->content);
1467         render_more(out, "\n");
1468         goto dont_render_tag;
1469 
1470     case TAG_OVERRIDE:
1471         render_element(out, e->children, e);
1472         return;
1473 
1474     case SEQUENCE:
1475     case SEQUENCE_OF:
1476     case SET:
1477     case SET_OF:
1478         render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1479                   cond,
1480                   outofline ? "_JUMP" : "",
1481                   skippable ? "_OR_SKIP" : "");
1482         break;
1483 
1484     case CHOICE:
1485         goto dont_render_tag;
1486 
1487     case TYPE_REF:
1488         if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1489             goto dont_render_tag;
1490     default:
1491         render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1492                   cond, act,
1493                   skippable ? "_OR_SKIP" : "");
1494         break;
1495     }
1496 
1497     x = tag ?: e;
1498     if (x->name)
1499         render_more(out, "\t\t// %s", x->name->content);
1500     render_more(out, "\n");
1501 
1502     /* Render the tag */
1503     if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
1504         tag = e;
1505 
1506     if (tag->class == ASN1_UNIV &&
1507         tag->tag != 14 &&
1508         tag->tag != 15 &&
1509         tag->tag != 31)
1510         render_opcode(out, "_tag(%s, %s, %s),\n",
1511                   asn1_classes[tag->class],
1512                   asn1_methods[tag->method | e->method],
1513                   asn1_universal_tags[tag->tag]);
1514     else
1515         render_opcode(out, "_tagn(%s, %s, %2u),\n",
1516                   asn1_classes[tag->class],
1517                   asn1_methods[tag->method | e->method],
1518                   tag->tag);
1519     tag = NULL;
1520 dont_render_tag:
1521 
1522     /* Deal with compound types */
1523     switch (e->compound) {
1524     case TYPE_REF:
1525         render_element(out, e->type->type->element, tag);
1526         if (e->action)
1527             render_opcode(out, "ASN1_OP_%sACT,\n",
1528                       skippable ? "MAYBE_" : "");
1529         break;
1530 
1531     case SEQUENCE:
1532         if (outofline) {
1533             /* Render out-of-line for multiple use or
1534              * skipability */
1535             render_opcode(out, "_jump_target(%u),", e->entry_index);
1536             if (e->type_def && e->type_def->name)
1537                 render_more(out, "\t\t// --> %s",
1538                         e->type_def->name->content);
1539             render_more(out, "\n");
1540             if (!(e->flags & ELEMENT_RENDERED)) {
1541                 e->flags |= ELEMENT_RENDERED;
1542                 *render_list_p = e;
1543                 render_list_p = &e->render_next;
1544             }
1545             return;
1546         } else {
1547             /* Render inline for single use */
1548             render_depth++;
1549             for (ec = e->children; ec; ec = ec->next)
1550                 render_element(out, ec, NULL);
1551             render_depth--;
1552             render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1553         }
1554         break;
1555 
1556     case SEQUENCE_OF:
1557     case SET_OF:
1558         if (outofline) {
1559             /* Render out-of-line for multiple use or
1560              * skipability */
1561             render_opcode(out, "_jump_target(%u),", e->entry_index);
1562             if (e->type_def && e->type_def->name)
1563                 render_more(out, "\t\t// --> %s",
1564                         e->type_def->name->content);
1565             render_more(out, "\n");
1566             if (!(e->flags & ELEMENT_RENDERED)) {
1567                 e->flags |= ELEMENT_RENDERED;
1568                 *render_list_p = e;
1569                 render_list_p = &e->render_next;
1570             }
1571             return;
1572         } else {
1573             /* Render inline for single use */
1574             entry = nr_entries;
1575             render_depth++;
1576             render_element(out, e->children, NULL);
1577             render_depth--;
1578             if (e->compound == SEQUENCE_OF)
1579                 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1580             else
1581                 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1582             render_opcode(out, "_jump_target(%u),\n", entry);
1583         }
1584         break;
1585 
1586     case SET:
1587         /* I can't think of a nice way to do SET support without having
1588          * a stack of bitmasks to make sure no element is repeated.
1589          * The bitmask has also to be checked that no non-optional
1590          * elements are left out whilst not preventing optional
1591          * elements from being left out.
1592          */
1593         fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1594         exit(1);
1595 
1596     case CHOICE:
1597         for (ec = e->children; ec; ec = ec->next)
1598             render_element(out, ec, ec);
1599         if (!skippable)
1600             render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1601         if (e->action)
1602             render_opcode(out, "ASN1_OP_ACT,\n");
1603         break;
1604 
1605     default:
1606         break;
1607     }
1608 
1609     if (e->action)
1610         render_opcode(out, "_action(ACT_%s),\n", e->action->name);
1611 }