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