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