roken: qsort provide ANSI C prototype for swapfunc()
[heimdal.git] / lib / asn1 / main.c
blobbabcc009c29fb639898387366ee4bb2b6d7e60ef
1 /*
2 * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "gen_locl.h"
35 #include <getarg.h>
36 #include "lex.h"
38 extern FILE *yyin;
40 static getarg_strings preserve;
41 static getarg_strings seq;
42 static getarg_strings decorate;
44 static int
45 strcmp4mergesort_r(const void *ap, const void *bp, void *d)
47 const char *a = *(const char **)ap;
48 const char *b = *(const char **)bp;
49 char sep = *(const char *)d;
50 int cmp;
52 if (sep) {
53 const char *sepa = strchr(a, sep);
54 const char *sepb = strchr(b, sep);
55 size_t alen, blen;
57 if (sepa == NULL) sepa = a + strlen(a);
58 if (sepb == NULL) sepb = b + strlen(b);
59 alen = sepa - a;
60 blen = sepb - b;
61 cmp = strncmp(a, b, alen > blen ? alen : blen);
62 if (cmp == 0)
63 cmp = alen - blen;
64 } else
65 cmp = strcmp(a, b);
66 if (cmp == 0)
67 return (uintptr_t)ap - (uintptr_t)bp; /* stable sort */
68 return cmp;
71 static int
72 prefix_check(const char *s, const char *p, size_t plen, char sep, int *cmp)
74 if ((*cmp = strncmp(p, s, plen)) == 0 && s[plen] == sep)
75 return 1;
76 if (*cmp == 0)
77 *cmp = 1;
78 return 0;
81 static ssize_t
82 bsearch_strings(struct getarg_strings *strs, const char *p,
83 char sep, ssize_t *more)
85 ssize_t right = (ssize_t)strs->num_strings - 1;
86 ssize_t left = 0;
87 ssize_t plen = 0;
88 int cmp;
90 if (sep)
91 plen = strlen(p);
93 if (strs->num_strings == 0)
94 return -1;
96 if (sep && more && *more > -1) {
97 /* If *more > -1 we're continuing an iteration */
98 if (*more > right)
99 return -1;
100 if (prefix_check(strs->strings[*more], p, plen, sep, &cmp))
101 return (*more)++;
102 (*more)++;
103 return -1;
106 while (left <= right) {
107 ssize_t mid = left + (right - left) / 2;
109 if (sep) {
110 int cmp2;
112 while (prefix_check(strs->strings[mid], p, plen, sep, &cmp) &&
113 mid > 0 &&
114 prefix_check(strs->strings[mid - 1], p, plen, sep, &cmp2))
115 mid--;
116 } else
117 cmp = strcmp(p, strs->strings[mid]);
118 if (cmp == 0) {
119 if (more)
120 *more = mid + 1;
121 return mid;
123 if (cmp < 0)
124 right = mid - 1; /* -1 if `p' is smaller than smallest in strs */
125 else
126 left = mid + 1;
128 return -1;
132 preserve_type(const char *p)
134 return bsearch_strings(&preserve, p, '\0', 0) > -1;
138 seq_type(const char *p)
140 return bsearch_strings(&seq, p, '\0', 0) > -1;
144 * Split `s' on `sep' and fill fs[] with pointers to the substrings.
146 * Only the first substring is to be freed -- the rest share the same
147 * allocation.
149 * The last element may contain `sep' chars if there are more fields in `s'
150 * than output locations in `fs[]'.
152 static void
153 split_str(const char *s, char sep, char ***fs)
155 size_t i;
157 fs[0][0] = estrdup(s);
158 for (i = 1; fs[i]; i++) {
159 char *q;
161 if ((q = strchr(fs[i-1][0], sep)) == NULL)
162 break;
163 *(q++) = '\0';
164 fs[i][0] = q;
166 for (; fs[i]; i++)
167 fs[i][0] = NULL;
171 * If `p' is "decorated" with a not-to-be-encoded-or-decoded field,
172 * output the field's typename and fieldname, whether it's optional, whether
173 * it's an ASN.1 type or an "external" type, and if external the names of
174 * functions to copy and free values of that type.
177 decorate_type(const char *p, struct decoration *deco, ssize_t *more)
179 ssize_t i;
180 char **s[7];
181 char *junk = NULL;
182 char *cp;
184 deco->first = *more == -1;
185 deco->decorated = 0;
186 deco->field_type = NULL;
187 if ((i = bsearch_strings(&decorate, p, ':', more)) == -1)
188 return 0;
190 deco->decorated = 1;
191 deco->opt = deco->ext = deco->ptr = 0;
192 deco->void_star = deco->struct_star = 0;
193 deco->field_name = deco->copy_function_name = deco->free_function_name =
194 deco->header_name = NULL;
196 s[0] = &deco->field_type;
197 s[1] = &deco->field_name;
198 s[2] = &deco->copy_function_name;
199 s[3] = &deco->free_function_name;
200 s[4] = &deco->header_name;
201 s[5] = &junk;
202 s[6] = NULL;
203 split_str(decorate.strings[i] + strlen(p) + 1, ':', s);
205 if (junk || deco->field_type[0] == '\0' || !deco->field_name ||
206 deco->field_name[0] == '\0' || deco->field_name[0] == '?') {
207 errx(1, "Invalidate type decoration specification: --decorate=\"%s\"",
208 decorate.strings[i]);
210 if ((cp = strchr(deco->field_name, '?'))) {
211 deco->opt = 1;
212 *cp = '\0';
214 if (strcmp(deco->field_type, "void*") == 0 ||
215 strcmp(deco->field_type, "void *") == 0) {
216 deco->ext = deco->ptr = deco->void_star = 1;
217 deco->opt = 1;
218 deco->header_name = NULL;
219 } else if (strncmp(deco->field_type, "struct ", sizeof("struct ") - 1) == 0 &&
220 deco->field_type[strlen(deco->field_type) - 1] == '*')
221 deco->ptr = deco->struct_star = 1;
222 if (deco->ptr || deco->copy_function_name)
223 deco->ext = 1;
224 if (deco->ext && deco->copy_function_name && !deco->copy_function_name[0])
225 deco->copy_function_name = NULL;
226 if (deco->ext && deco->free_function_name && !deco->free_function_name[0])
227 deco->free_function_name = NULL;
228 if (deco->header_name && !deco->header_name[0])
229 deco->header_name = NULL;
230 if (deco->ptr)
231 deco->opt = 0;
232 return 1;
235 static const char *
236 my_basename(const char *fn)
238 const char *base, *p;
240 for (p = base = fn; *p; p++) {
241 #ifdef WIN32
242 if (*p == '/' || *p == '\\')
243 base = p + 1;
244 #else
245 if (*p == '/')
246 base = p + 1;
247 #endif
249 return base;
252 const char *fuzzer_string = "";
253 const char *enum_prefix;
254 const char *name;
255 int prefix_enum;
256 int fuzzer_flag;
257 int support_ber;
258 int template_flag;
259 int rfc1510_bitstring;
260 int one_code_file;
261 char *option_file;
262 int parse_units_flag = 1;
263 char *type_file_string = "krb5-types.h";
264 int original_order;
265 int version_flag;
266 int help_flag;
267 struct getargs args[] = {
268 { "fuzzer", 0, arg_flag, &fuzzer_flag, NULL, NULL },
269 { "template", 0, arg_flag, &template_flag, NULL, NULL },
270 { "prefix-enum", 0, arg_flag, &prefix_enum,
271 "prefix C enum labels for ENUMERATED types and INTEGER types with the "
272 "type's name", NULL },
273 { "enum-prefix", 0, arg_string, &enum_prefix,
274 "prefix for C enum labels for ENUMERATED types and INTEGER types with "
275 "enumerated values", "PREFIX" },
276 { "encode-rfc1510-bit-string", 0, arg_flag, &rfc1510_bitstring,
277 "Use RFC1510 incorrect BIT STRING handling for all BIT STRING types "
278 "in the module", NULL },
279 { "decode-dce-ber", 0, arg_flag, &support_ber,
280 "Allow DCE-style BER on decode", NULL },
281 { "support-ber", 0, arg_flag, &support_ber, "Allow BER on decode", NULL },
282 { "preserve-binary", 0, arg_strings, &preserve,
283 "Names of types for which to generate _save fields, saving original "
284 "encoding, in containing structures (useful for signature "
285 "verification)", "TYPE" },
286 { "sequence", 0, arg_strings, &seq,
287 "Generate add/remove functions for SEQUENCE OF types", "TYPE" },
288 { "decorate", 0, arg_strings, &decorate,
289 "Generate private field for SEQUENCE/SET type", "DECORATION" },
290 { "one-code-file", 0, arg_flag, &one_code_file, NULL, NULL },
291 { "gen-name", 0, arg_string, &name,
292 "Name of generated module", "NAME" },
293 { "option-file", 0, arg_string, &option_file,
294 "File with additional compiler CLI options", "FILE" },
295 { "original-order", 0, arg_flag, &original_order,
296 "Define C types and functions in the order in which they appear in "
297 "the ASN.1 module instead of topologically sorting types. This "
298 "is useful for comparing output to earlier compiler versions.",
299 NULL },
300 { "parse-units", 0, arg_negative_flag, &parse_units_flag,
301 "Do not generate roken-style units", NULL },
302 { "type-file", 0, arg_string, &type_file_string,
303 "Name of a C header file to generate includes of for base types",
304 "FILE" },
305 { "version", 0, arg_flag, &version_flag, NULL, NULL },
306 { "help", 0, arg_flag, &help_flag, NULL, NULL }
308 int num_args = sizeof(args) / sizeof(args[0]);
310 static void
311 usage(int code)
313 if (code)
314 dup2(STDERR_FILENO, STDOUT_FILENO);
315 else
316 dup2(STDOUT_FILENO, STDERR_FILENO);
317 arg_printusage(args, num_args, NULL, "[asn1-file [name]]");
318 fprintf(stderr,
319 "\nA DECORATION is one of:\n\n"
320 "\tTYPE:FTYPE:fname[?]\n"
321 "\tTYPE:FTYPE:fname[?]:[copy_function]:[free_function]:header\n"
322 "\tTYPE:void:fname:::\n"
323 "\nSee the manual page.\n");
324 exit(code);
327 int error_flag;
330 main(int argc, char **argv)
332 int ret;
333 const char *file;
334 FILE *opt = NULL;
335 int optidx = 0;
336 char **arg = NULL;
337 size_t len = 0;
338 size_t sz = 0;
339 int i;
341 setprogname(argv[0]);
342 if (getarg(args, num_args, argc, argv, &optidx))
343 usage(1);
344 if (help_flag)
345 usage(0);
346 if (version_flag) {
347 print_version(NULL);
348 exit(0);
350 if (argc == optidx) {
351 /* Compile the module on stdin */
352 file = "stdin";
353 name = "stdin";
354 yyin = stdin;
355 } else {
356 /* Compile a named module */
357 file = argv[optidx];
360 * If the .asn1 stem is not given, then assume it, and also assume
361 * --option-file was given if the .opt file exists
363 if (strchr(file, '.') == NULL) {
364 char *s = NULL;
366 if (asprintf(&s, "%s.opt", file) == -1 || s == NULL)
367 err(1, "Out of memory");
368 if ((opt = fopen(s, "r")))
369 option_file = s;
370 else
371 free(s);
372 if (asprintf(&s, "%s.asn1", file) == -1 || s == NULL)
373 err(1, "Out of memory");
374 file = s;
376 yyin = fopen (file, "r");
377 if (yyin == NULL)
378 err (1, "open %s", file);
379 if (argc == optidx + 1) {
380 char *p;
382 /* C module name substring not given; derive from file name */
383 name = my_basename(estrdup(file));
384 p = strrchr(name, '.');
385 if (p)
386 *p = '\0';
387 } else
388 name = argv[optidx + 1];
392 * Parse extra options file
394 if (option_file) {
395 char buf[1024];
397 if (opt == NULL &&
398 (opt = fopen(option_file, "r")) == NULL)
399 err(1, "Could not open given option file %s", option_file);
401 arg = calloc(2, sizeof(arg[0]));
402 if (arg == NULL) {
403 perror("calloc");
404 exit(1);
406 arg[0] = option_file;
407 arg[1] = NULL;
408 len = 1;
409 sz = 2;
411 while (fgets(buf, sizeof(buf), opt) != NULL) {
412 size_t buflen, ws;
414 buf[strcspn(buf, "\n\r")] = '\0';
416 buflen = strlen(buf);
417 if ((ws = strspn(buf, " \t")))
418 memmove(buf, buf + ws, buflen - ws);
419 if (buf[0] == '\0' || buf[0] == '#')
420 continue;
422 if (len + 1 >= sz) {
423 arg = realloc(arg, (sz + (sz>>1) + 2) * sizeof(arg[0]));
424 if (arg == NULL) {
425 perror("malloc");
426 exit(1);
428 sz += (sz>>1) + 2;
430 arg[len] = strdup(buf);
431 if (arg[len] == NULL) {
432 perror("strdup");
433 exit(1);
435 arg[len + 1] = NULL;
436 len++;
438 fclose(opt);
440 optidx = 0;
441 if(getarg(args, num_args, len, arg, &optidx))
442 usage(1);
444 if (len != optidx) {
445 fprintf(stderr, "extra args");
446 exit(1);
450 if (fuzzer_flag) {
451 if (!template_flag) {
452 printf("can't do fuzzer w/o --template");
453 exit(1);
455 #ifdef ASN1_FUZZER
456 fuzzer_string = "_fuzzer";
457 #endif
460 if (preserve.num_strings)
461 mergesort_r(preserve.strings, preserve.num_strings,
462 sizeof(preserve.strings[0]), strcmp4mergesort_r, "");
463 if (seq.num_strings)
464 mergesort_r(seq.strings, seq.num_strings, sizeof(seq.strings[0]),
465 strcmp4mergesort_r, "");
466 if (decorate.num_strings)
467 mergesort_r(decorate.strings, decorate.num_strings,
468 sizeof(decorate.strings[0]), strcmp4mergesort_r, ":");
470 init_generate(file, name);
472 if (one_code_file)
473 generate_header_of_codefile(name);
475 initsym ();
476 ret = yyparse ();
477 if(ret != 0 || error_flag != 0)
478 exit(1);
479 if (!original_order)
480 generate_types();
481 if (argc != optidx)
482 fclose(yyin);
484 if (one_code_file)
485 close_codefile();
486 close_generate();
488 if (arg) {
489 for (i = 1; i < len; i++)
490 free(arg[i]);
491 free(arg);
494 return 0;