s4:torture: Adapt KDC canon test to Heimdal upstream changes
[samba.git] / source4 / heimdal / lib / asn1 / main.c
1 /*
2  * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "gen_locl.h"
35 #include <getarg.h>
36 #include "lex.h"
37
38 extern FILE *yyin;
39
40 static getarg_strings preserve;
41 static getarg_strings seq;
42 static getarg_strings decorate;
43
44 int
45 preserve_type(const char *p)
46 {
47     int i;
48     for (i = 0; i < preserve.num_strings; i++)
49         if (strcmp(preserve.strings[i], p) == 0)
50             return 1;
51     return 0;
52 }
53
54 int
55 seq_type(const char *p)
56 {
57     size_t i;
58
59     for (i = 0; i < seq.num_strings; i++)
60         if (strcmp(seq.strings[i], p) == 0)
61             return 1;
62     return 0;
63 }
64
65 int
66 decorate_type(const char *p, char **field_type, char **field_name, int *opt)
67 {
68     size_t plen = strlen(p);
69     size_t i;
70
71     *field_type = NULL;
72     *field_name = NULL;
73     *opt = 0;
74
75     for (i = 0; i < decorate.num_strings; i++) {
76         const char *r;
77         char *q;
78
79         if (strncmp(decorate.strings[i], p, plen) != 0)
80             continue;
81         if (decorate.strings[i][plen] != ':')
82             errx(1, "--decorate argument missing field type");
83
84         p = &decorate.strings[i][plen + 1];
85         if ((r = strchr(p, ':')) == NULL)
86             errx(1, "--decorate argument missing field name");
87         r++;
88         *field_type = estrdup(p);
89         *(strchr(*field_type, ':')) = '\0';
90         *field_name = estrdup(r);
91         if ((q = strchr(*field_name, '?'))) {
92             *q = '\0';
93             *opt = 1;
94         }
95         return 1;
96     }
97     return 0;
98 }
99
100 static const char *
101 my_basename(const char *fn)
102 {
103     const char *base, *p;
104
105     for (p = base = fn; *p; p++) {
106 #ifdef WIN32
107         if (*p == '/' || *p == '\\')
108             base = p + 1;
109 #else
110         if (*p == '/')
111             base = p + 1;
112 #endif
113     }
114     return base;
115 }
116
117 const char *fuzzer_string = "";
118 const char *enum_prefix;
119 const char *name;
120 int prefix_enum;
121 int fuzzer_flag;
122 int support_ber;
123 int template_flag;
124 int rfc1510_bitstring;
125 int one_code_file;
126 char *option_file;
127 int parse_units_flag = 1;
128 char *type_file_string = "krb5-types.h";
129 int original_order;
130 int version_flag;
131 int help_flag;
132 struct getargs args[] = {
133     { "fuzzer", 0, arg_flag, &fuzzer_flag, NULL, NULL },
134     { "template", 0, arg_flag, &template_flag, NULL, NULL },
135     { "prefix-enum", 0, arg_flag, &prefix_enum,
136         "prefix C enum labels for ENUMERATED types and INTEGER types with the "
137             "type's name", NULL },
138     { "enum-prefix", 0, arg_string, &enum_prefix,
139         "prefix for C enum labels for ENUMERATED types and INTEGER types with "
140             "enumerated values", "PREFIX" },
141     { "encode-rfc1510-bit-string", 0, arg_flag, &rfc1510_bitstring,
142         "Use RFC1510 incorrect BIT STRING handling for all BIT STRING types "
143             "in the module", NULL },
144     { "decode-dce-ber", 0, arg_flag, &support_ber,
145         "Allow DCE-style BER on decode", NULL },
146     { "support-ber", 0, arg_flag, &support_ber, "Allow BER on decode", NULL },
147     { "preserve-binary", 0, arg_strings, &preserve,
148         "Names of types for which to generate _save fields, saving original "
149             "encoding, in containing structures (useful for signature "
150             "verification)", "TYPE-NAME" },
151     { "sequence", 0, arg_strings, &seq,
152         "Generate add/remove functions for SEQUENCE OF types", "TYPE-NAME" },
153     { "decorate", 0, arg_strings, &decorate,
154         "Generate private field for SEQUENCE/SET type", "TYPE-NAME:FIELD_TYPE:field_name[?]" },
155     { "one-code-file", 0, arg_flag, &one_code_file, NULL, NULL },
156     { "gen-name", 0, arg_string, &name,
157         "Name of generated module", "NAME" },
158     { "option-file", 0, arg_string, &option_file,
159         "File with additional compiler CLI options", "FILE" },
160     { "original-order", 0, arg_flag, &original_order,
161         "Define C types and functions in the order in which they appear in "
162             "the ASN.1 module instead of topologically sorting types.  This "
163             "is useful for comparing output to earlier compiler versions.",
164         NULL },
165     { "parse-units", 0, arg_negative_flag, &parse_units_flag,
166         "Do not generate roken-style units", NULL },
167     { "type-file", 0, arg_string, &type_file_string,
168         "Name of a C header file to generate includes of for base types",
169         "C-HEADER-FILE" },
170     { "version", 0, arg_flag, &version_flag, NULL, NULL },
171     { "help", 0, arg_flag, &help_flag, NULL, NULL }
172 };
173 int num_args = sizeof(args) / sizeof(args[0]);
174
175 static void
176 usage(int code)
177 {
178     arg_printusage(args, num_args, NULL, "[asn1-file [name]]");
179     exit(code);
180 }
181
182 int error_flag;
183
184 int
185 main(int argc, char **argv)
186 {
187     int ret;
188     const char *file;
189     FILE *opt = NULL;
190     int optidx = 0;
191     char **arg = NULL;
192     size_t len = 0;
193     size_t sz = 0;
194     int i;
195
196     setprogname(argv[0]);
197     if (getarg(args, num_args, argc, argv, &optidx))
198         usage(1);
199     if (help_flag)
200         usage(0);
201     if (version_flag) {
202         print_version(NULL);
203         exit(0);
204     }
205     if (argc == optidx) {
206         /* Compile the module on stdin */
207         file = "stdin";
208         name = "stdin";
209         yyin = stdin;
210     } else {
211         /* Compile a named module */
212         file = argv[optidx];
213
214         /*
215          * If the .asn1 stem is not given, then assume it, and also assume
216          * --option-file was given if the .opt file exists
217          */
218         if (strchr(file, '.') == NULL) {
219             char *s = NULL;
220
221             if (asprintf(&s, "%s.opt", file) == -1 || s == NULL)
222                 err(1, "Out of memory");
223             if ((opt = fopen(s, "r")))
224                 option_file = s;
225             else
226                 free(s);
227             if (asprintf(&s, "%s.asn1", file) == -1 || s == NULL)
228                 err(1, "Out of memory");
229             file = s;
230         }
231         yyin = fopen (file, "r");
232         if (yyin == NULL)
233             err (1, "open %s", file);
234         if (argc == optidx + 1) {
235             char *p;
236
237             /* C module name substring not given; derive from file name */
238             name = my_basename(estrdup(file));
239             p = strrchr(name, '.');
240             if (p)
241                 *p = '\0';
242         } else
243             name = argv[optidx + 1];
244     }
245
246     /*
247      * Parse extra options file
248      */
249     if (option_file) {
250         char buf[1024];
251
252         if (opt == NULL &&
253             (opt = fopen(option_file, "r")) == NULL)
254             err(1, "Could not open given option file %s", option_file);
255
256         arg = calloc(2, sizeof(arg[0]));
257         if (arg == NULL) {
258             perror("calloc");
259             exit(1);
260         }
261         arg[0] = option_file;
262         arg[1] = NULL;
263         len = 1;
264         sz = 2;
265
266         while (fgets(buf, sizeof(buf), opt) != NULL) {
267             buf[strcspn(buf, "\n\r")] = '\0';
268
269             if (len + 1 >= sz) {
270                 arg = realloc(arg, (sz + (sz>>1) + 2) * sizeof(arg[0]));
271                 if (arg == NULL) {
272                     perror("malloc");
273                     exit(1);
274                 }
275                 sz += (sz>>1) + 2;
276             }
277             arg[len] = strdup(buf);
278             if (arg[len] == NULL) {
279                 perror("strdup");
280                 exit(1);
281             }
282             arg[len + 1] = NULL;
283             len++;
284         }
285         fclose(opt);
286
287         optidx = 0;
288         if(getarg(args, num_args, len, arg, &optidx))
289             usage(1);
290
291         if (len != optidx) {
292             fprintf(stderr, "extra args");
293             exit(1);
294         }
295     }
296
297     if (fuzzer_flag) {
298         if (!template_flag) {
299             printf("can't do fuzzer w/o --template");
300             exit(1);
301         }
302 #ifdef ASN1_FUZZER
303         fuzzer_string = "_fuzzer";
304 #endif
305     }
306
307
308     init_generate(file, name);
309
310     if (one_code_file)
311         generate_header_of_codefile(name);
312
313     initsym ();
314     ret = yyparse ();
315     if(ret != 0 || error_flag != 0)
316         exit(1);
317     if (!original_order)
318         generate_types();
319     close_generate ();
320     if (argc != optidx)
321         fclose(yyin);
322
323     if (one_code_file)
324         close_codefile();
325
326     if (arg) {
327         for (i = 1; i < len; i++)
328             free(arg[i]);
329         free(arg);
330     }
331
332     return 0;
333 }