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