2 * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
40 static getarg_strings preserve
;
41 static getarg_strings seq
;
42 static getarg_strings decorate
;
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
;
53 const char *sepa
= strchr(a
, sep
);
54 const char *sepb
= strchr(b
, sep
);
57 if (sepa
== NULL
) sepa
= a
+ strlen(a
);
58 if (sepb
== NULL
) sepb
= b
+ strlen(b
);
61 cmp
= strncmp(a
, b
, alen
> blen
? alen
: blen
);
67 return (uintptr_t)ap
- (uintptr_t)bp
; /* stable sort */
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
)
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;
93 if (strs
->num_strings
== 0)
96 if (sep
&& more
&& *more
> -1) {
97 /* If *more > -1 we're continuing an iteration */
100 if (prefix_check(strs
->strings
[*more
], p
, plen
, sep
, &cmp
))
106 while (left
<= right
) {
107 ssize_t mid
= left
+ (right
- left
) / 2;
112 while (prefix_check(strs
->strings
[mid
], p
, plen
, sep
, &cmp
) &&
114 prefix_check(strs
->strings
[mid
- 1], p
, plen
, sep
, &cmp2
))
117 cmp
= strcmp(p
, strs
->strings
[mid
]);
124 right
= mid
- 1; /* -1 if `p' is smaller than smallest in strs */
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
149 * The last element may contain `sep' chars if there are more fields in `s'
150 * than output locations in `fs[]'.
153 split_str(const char *s
, char sep
, char ***fs
)
157 fs
[0][0] = estrdup(s
);
158 for (i
= 1; fs
[i
]; i
++) {
161 if ((q
= strchr(fs
[i
-1][0], sep
)) == 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
)
184 deco
->first
= *more
== -1;
186 deco
->field_type
= NULL
;
187 if ((i
= bsearch_strings(&decorate
, p
, ':', more
)) == -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
;
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
, '?'))) {
214 if (strcmp(deco
->field_type
, "void*") == 0 ||
215 strcmp(deco
->field_type
, "void *") == 0) {
216 deco
->ext
= deco
->ptr
= deco
->void_star
= 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
)
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
;
236 my_basename(const char *fn
)
238 const char *base
, *p
;
240 for (p
= base
= fn
; *p
; p
++) {
242 if (*p
== '/' || *p
== '\\')
252 const char *fuzzer_string
= "";
253 const char *enum_prefix
;
259 int rfc1510_bitstring
;
262 int parse_units_flag
= 1;
263 char *type_file_string
= "krb5-types.h";
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.",
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",
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]);
314 dup2(STDERR_FILENO
, STDOUT_FILENO
);
316 dup2(STDOUT_FILENO
, STDERR_FILENO
);
317 arg_printusage(args
, num_args
, NULL
, "[asn1-file [name]]");
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");
330 main(int argc
, char **argv
)
341 setprogname(argv
[0]);
342 if (getarg(args
, num_args
, argc
, argv
, &optidx
))
350 if (argc
== optidx
) {
351 /* Compile the module on stdin */
356 /* Compile a named module */
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
) {
366 if (asprintf(&s
, "%s.opt", file
) == -1 || s
== NULL
)
367 err(1, "Out of memory");
368 if ((opt
= fopen(s
, "r")))
372 if (asprintf(&s
, "%s.asn1", file
) == -1 || s
== NULL
)
373 err(1, "Out of memory");
376 yyin
= fopen (file
, "r");
378 err (1, "open %s", file
);
379 if (argc
== optidx
+ 1) {
382 /* C module name substring not given; derive from file name */
383 name
= my_basename(estrdup(file
));
384 p
= strrchr(name
, '.');
388 name
= argv
[optidx
+ 1];
392 * Parse extra options file
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]));
406 arg
[0] = option_file
;
411 while (fgets(buf
, sizeof(buf
), opt
) != NULL
) {
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] == '#')
423 arg
= realloc(arg
, (sz
+ (sz
>>1) + 2) * sizeof(arg
[0]));
430 arg
[len
] = strdup(buf
);
431 if (arg
[len
] == NULL
) {
441 if(getarg(args
, num_args
, len
, arg
, &optidx
))
445 fprintf(stderr
, "extra args");
451 if (!template_flag
) {
452 printf("can't do fuzzer w/o --template");
456 fuzzer_string
= "_fuzzer";
460 if (preserve
.num_strings
)
461 mergesort_r(preserve
.strings
, preserve
.num_strings
,
462 sizeof(preserve
.strings
[0]), strcmp4mergesort_r
, "");
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
);
473 generate_header_of_codefile(name
);
477 if(ret
!= 0 || error_flag
!= 0)
489 for (i
= 1; i
< len
; i
++)