blob: c097d556a7387aba144e8b2aff8b8b15bf378179 [file] [log] [blame]
Lev Walkin12984672004-09-24 21:00:15 +00001/*-
Lev Walkin46499872006-03-06 13:05:34 +00002 * Copyright (c) 2003, 2004, 2005, 2006
Lev Walkinc0d04912005-02-25 12:52:27 +00003 * Lev Walkin <vlm@lionet.info>. All rights reserved.
Lev Walkin12984672004-09-24 21:00:15 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id$
27 */
Lev Walkinf15320b2004-06-03 03:38:44 +000028/*
29 * This is the program that connects the libasn1* libraries together.
30 * It uses them in turn to parse, fix and then compile or print the ASN.1 tree.
31 */
Lev Walkinc0d04912005-02-25 12:52:27 +000032#include "sys-common.h"
Lev Walkinf15320b2004-06-03 03:38:44 +000033
34#include <asn1parser.h> /* Parse the ASN.1 file and build a tree */
35#include <asn1fix.h> /* Fix the ASN.1 tree */
36#include <asn1print.h> /* Print the ASN.1 tree */
37#include <asn1compiler.h> /* Compile the ASN.1 tree */
38
Lev Walkin79f54952004-08-13 16:58:19 +000039#include <asn1c_compat.h> /* Portable basename(3) and dirname(3) */
40
Lev Walkin46499872006-03-06 13:05:34 +000041#ifdef WIN32
42#include <io.h>
43#include <direct.h>
44#else
45#include <dirent.h>
46#endif
47
Lev Walkinc0d04912005-02-25 12:52:27 +000048#undef COPYRIGHT
49#define COPYRIGHT \
Lev Walkinfe1164b2006-03-02 02:09:07 +000050 "Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>\n"
Lev Walkinf15320b2004-06-03 03:38:44 +000051
Lev Walkinc0d04912005-02-25 12:52:27 +000052static void usage(const char *av0); /* Print the Usage screen and exit */
Lev Walkin46499872006-03-06 13:05:34 +000053static int importStandardModules(asn1p_t *asn, const char *skeletons_dir);
Lev Walkincbf218f2004-08-20 13:24:38 +000054
Lev Walkinf15320b2004-06-03 03:38:44 +000055int
56main(int ac, char **av) {
Lev Walkin7415bff2004-08-16 11:38:13 +000057 enum asn1p_flags asn1_parser_flags = A1P_NOFLAGS;
58 enum asn1f_flags asn1_fixer_flags = A1F_NOFLAGS;
Lev Walkincbf218f2004-08-20 13:24:38 +000059 enum asn1c_flags asn1_compiler_flags= A1C_NO_C99;
Lev Walkinab4bb292004-08-18 04:52:48 +000060 enum asn1print_flags asn1_printer_flags = APF_NOFLAGS;
Lev Walkinf15320b2004-06-03 03:38:44 +000061 int print_arg__print_out = 0; /* Don't compile, just print parsed */
62 int print_arg__fix_n_print = 0; /* Fix and print */
Lev Walkinf15320b2004-06-03 03:38:44 +000063 int warnings_as_errors = 0; /* Treat warnings as errors */
64 char *skeletons_dir = NULL; /* Directory with supplementary stuff */
65 asn1p_t *asn = 0; /* An ASN.1 parsed tree */
66 int ret; /* Return value from misc functions */
67 int ch; /* Command line character */
68 int i; /* Index in some loops */
69
70 /*
71 * Process command-line options.
72 */
Lev Walkin59b176e2005-11-26 11:25:14 +000073 while((ch = getopt(ac, av, "EFf:g:hLPp:RS:vW:X")) != -1)
Lev Walkinf15320b2004-06-03 03:38:44 +000074 switch(ch) {
75 case 'E':
76 print_arg__print_out = 1;
77 break;
78 case 'F':
79 print_arg__fix_n_print = 1;
80 break;
81 case 'f':
Lev Walkindd32b592004-09-06 08:07:29 +000082 if(strcmp(optarg, "all-defs-global") == 0) {
83 asn1_compiler_flags |= A1C_ALL_DEFS_GLOBAL;
84 } else if(strcmp(optarg, "bless-SIZE") == 0) {
85 asn1_fixer_flags |= A1F_EXTENDED_SizeConstraint;
Lev Walkin21d00002005-03-04 08:48:53 +000086 } else if(strcmp(optarg, "compound-names") == 0) {
87 asn1_compiler_flags |= A1C_COMPOUND_NAMES;
Lev Walkin72a0f5a2005-07-24 08:28:39 +000088 } else if(strcmp(optarg, "indirect-choice") == 0) {
89 asn1_compiler_flags |= A1C_INDIRECT_CHOICE;
Lev Walkin5555d532004-06-28 21:21:45 +000090 } else if(strncmp(optarg, "known-extern-type=", 18) == 0) {
91 char *known_type = optarg + 18;
92 ret = asn1f_make_known_external_type(known_type);
93 assert(ret == 0 || errno == EEXIST);
Lev Walkin46499872006-03-06 13:05:34 +000094 } else if(strcmp(optarg, "native-types") == 0) {
Lev Walkin99301892004-09-14 12:48:17 +000095 asn1_compiler_flags |= A1C_USE_NATIVE_TYPES;
Lev Walkin4e940a02004-09-26 13:13:13 +000096 } else if(strcmp(optarg, "no-constraints") == 0) {
97 asn1_compiler_flags |= A1C_NO_CONSTRAINTS;
Lev Walkinb9b8b952005-03-05 00:33:27 +000098 } else if(strcmp(optarg, "no-include-deps") == 0) {
99 asn1_compiler_flags |= A1C_NO_INCLUDE_DEPS;
Lev Walkindd32b592004-09-06 08:07:29 +0000100 } else if(strcmp(optarg, "unnamed-unions") == 0) {
101 asn1_compiler_flags |= A1C_UNNAMED_UNIONS;
Lev Walkina895afb2005-10-06 10:09:34 +0000102 } else if(strcmp(optarg, "skeletons-copy") == 0) {
103 asn1_compiler_flags |= A1C_SKELETONS_COPY;
Lev Walkinf15320b2004-06-03 03:38:44 +0000104 } else {
105 fprintf(stderr, "-f%s: Invalid argument\n", optarg);
106 exit(EX_USAGE);
107 }
108 break;
Lev Walkin59b176e2005-11-26 11:25:14 +0000109 case 'g':
110 if(strcmp(optarg, "en-PER") == 0) {
111 asn1_compiler_flags |= A1C_GEN_PER;
112 } else {
113 fprintf(stderr, "-g%s: Invalid argument\n", optarg);
114 exit(EX_USAGE);
115 }
116 break;
Lev Walkincbf218f2004-08-20 13:24:38 +0000117 case 'h':
118 usage(av[0]);
Lev Walkinf15320b2004-06-03 03:38:44 +0000119 case 'P':
120 asn1_compiler_flags |= A1C_PRINT_COMPILED;
Lev Walkincbf218f2004-08-20 13:24:38 +0000121 asn1_compiler_flags &= ~A1C_NO_C99;
Lev Walkinf15320b2004-06-03 03:38:44 +0000122 break;
Lev Walkinab4bb292004-08-18 04:52:48 +0000123 case 'p':
Lev Walkin59b176e2005-11-26 11:25:14 +0000124 if(strncmp(optarg, "du=", 3) == 0) {
125 char *pduname = optarg + 3;
126 if(strcmp(pduname, "auto")) {
127 fprintf(stderr, "-pdu=%s: expected -pdu=auto\n",
128 pduname);
129 exit(EX_USAGE);
130 }
131 asn1_compiler_flags |= A1C_PDU_AUTO;
132 } else if(strcmp(optarg, "rint-constraints") == 0) {
Lev Walkinab4bb292004-08-18 04:52:48 +0000133 asn1_printer_flags |= APF_DEBUG_CONSTRAINTS;
Lev Walkincbf218f2004-08-20 13:24:38 +0000134 } else if(strcmp(optarg, "rint-lines") == 0) {
135 asn1_printer_flags |= APF_LINE_COMMENTS;
Lev Walkinab4bb292004-08-18 04:52:48 +0000136 } else {
137 fprintf(stderr, "-p%s: Invalid argument\n", optarg);
138 exit(EX_USAGE);
139 }
140 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000141 case 'R':
142 asn1_compiler_flags |= A1C_OMIT_SUPPORT_CODE;
143 break;
144 case 'S':
145 skeletons_dir = optarg;
146 break;
Lev Walkincbf218f2004-08-20 13:24:38 +0000147 case 'v':
148 fprintf(stderr, "ASN.1 Compiler, v" VERSION "\n" COPYRIGHT);
149 exit(0);
150 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000151 case 'W':
152 if(strcmp(optarg, "error") == 0) {
153 warnings_as_errors = 1;
154 break;
155 } else if(strcmp(optarg, "debug-lexer") == 0) {
156 asn1_parser_flags |= A1P_LEXER_DEBUG;
157 break;
158 } else if(strcmp(optarg, "debug-fixer") == 0) {
159 asn1_fixer_flags |= A1F_DEBUG;
160 break;
161 } else if(strcmp(optarg, "debug-compiler") == 0) {
162 asn1_compiler_flags |= A1C_DEBUG;
163 break;
164 } else {
165 fprintf(stderr, "-W%s: Invalid argument\n", optarg);
166 exit(EX_USAGE);
167 }
168 break;
Lev Walkinf7484512004-10-13 09:13:56 +0000169 case 'X':
170 print_arg__print_out = 1; /* Implicit -E */
171 print_arg__fix_n_print = 1; /* Implicit -F */
172 asn1_printer_flags |= APF_PRINT_XML_DTD;
173 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000174 default:
175 usage(av[0]);
176 }
177
178 /*
179 * Validate the options combination.
180 */
181 if(!print_arg__print_out) {
182 if(print_arg__fix_n_print) {
183 fprintf(stderr, "Error: -F requires -E\n");
184 exit(EX_USAGE);
185 }
Lev Walkinab4bb292004-08-18 04:52:48 +0000186 if(asn1_printer_flags) {
187 fprintf(stderr, "Error: "
Lev Walkincbf218f2004-08-20 13:24:38 +0000188 "-print-... arguments require -E\n");
Lev Walkinab4bb292004-08-18 04:52:48 +0000189 exit(EX_USAGE);
190 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000191 }
192
193 /*
194 * Ensure that there are some input files present.
195 */
196 if(ac > optind) {
197 ac -= optind;
198 av += optind;
199 } else {
Lev Walkinbf430382005-11-05 12:28:16 +0000200 char *bin_name = a1c_basename(av[0]);
201 fprintf(stderr, "%s: No input files specified. "
202 "Try '%s -h' for more information\n",
203 bin_name, bin_name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000204 exit(1);
205 }
206
207 /*
Lev Walkin46499872006-03-06 13:05:34 +0000208 * Make sure the skeleton directory is out there.
209 */
210 if(skeletons_dir == NULL) {
211 struct stat sb;
212 skeletons_dir = DATADIR;
213 if((av[-optind][0] == '.' || av[-optind][1] == '/')
214 && stat(skeletons_dir, &sb)) {
215 /*
216 * The default skeletons directory does not exist,
217 * compute it from my file name:
218 * ./asn1c/asn1c -> ./skeletons
219 */
220 char *p;
221 size_t len;
222
223 p = a1c_dirname(av[-optind]);
224
225 len = strlen(p) + sizeof("/../skeletons");
226 skeletons_dir = malloc(len);
227 assert(skeletons_dir);
228 snprintf(skeletons_dir, len, "%s/../skeletons", p);
229 if(stat(skeletons_dir, &sb)) {
230 fprintf(stderr,
231 "WARNING: skeletons are neither in "
232 "\"%s\" nor in \"%s\"!\n",
233 DATADIR, skeletons_dir);
234 if(warnings_as_errors)
235 exit(EX_OSFILE);
236 }
237 }
238 }
239
240 /*
Lev Walkinf15320b2004-06-03 03:38:44 +0000241 * Iterate over input files and parse each.
242 * All syntax trees from all files will be bundled together.
243 */
244 for(i = 0; i < ac; i++) {
245 asn1p_t *new_asn;
246
247 new_asn = asn1p_parse_file(av[i], asn1_parser_flags);
248 if(new_asn == NULL) {
249 fprintf(stderr, "Cannot parse \"%s\"\n", av[i]);
250 exit(EX_DATAERR);
251 }
252
253 /*
254 * Bundle the parsed tree with existing one.
255 */
256 if(asn) {
257 asn1p_module_t *mod;
258 while((mod = TQ_REMOVE(&(new_asn->modules), mod_next)))
259 TQ_ADD(&(asn->modules), mod, mod_next);
260 asn1p_free(new_asn);
261 } else {
262 asn = new_asn;
263 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000264 }
265
Lev Walkin46499872006-03-06 13:05:34 +0000266 /* These are mostly notes for the human readers */
267 assert(asn);
268 assert(skeletons_dir);
269
Lev Walkinf15320b2004-06-03 03:38:44 +0000270 /*
Lev Walkin7415bff2004-08-16 11:38:13 +0000271 * Dump the parsed ASN.1 tree if -E specified and -F is NOT given.
Lev Walkinf15320b2004-06-03 03:38:44 +0000272 */
273 if(print_arg__print_out && !print_arg__fix_n_print) {
Lev Walkinab4bb292004-08-18 04:52:48 +0000274 if(asn1print(asn, asn1_printer_flags))
Lev Walkinf15320b2004-06-03 03:38:44 +0000275 exit(EX_SOFTWARE);
276 return 0;
277 }
278
Lev Walkin46499872006-03-06 13:05:34 +0000279 /*
280 * Read in the files from skeletons/standard-modules
281 */
282 if(importStandardModules(asn, skeletons_dir)) {
283 if(warnings_as_errors)
284 exit(EX_DATAERR);
285 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000286
287 /*
288 * Process the ASN.1 specification: perform semantic checks,
289 * expand references, etc, etc.
290 * This function will emit necessary warnings and error messages.
291 */
292 ret = asn1f_process(asn, asn1_fixer_flags,
293 NULL /* default fprintf(stderr) */);
294 switch(ret) {
295 case 1:
296 if(!warnings_as_errors)
297 /* Fall through */
298 case 0:
299 break; /* All clear */
300 case -1:
301 exit(EX_DATAERR); /* Fatal failure */
302 }
303
304 /*
305 * Dump the parsed ASN.1 tree if -E specified and -F is given.
306 */
307 if(print_arg__print_out && print_arg__fix_n_print) {
Lev Walkinab4bb292004-08-18 04:52:48 +0000308 if(asn1print(asn, asn1_printer_flags))
Lev Walkinf15320b2004-06-03 03:38:44 +0000309 exit(EX_SOFTWARE);
310 return 0;
311 }
312
313 /*
Lev Walkinf15320b2004-06-03 03:38:44 +0000314 * Compile the ASN.1 tree into a set of source files
315 * of another language.
316 */
Lev Walkin866cff12005-03-05 00:50:53 +0000317 if(asn1_compile(asn, skeletons_dir, asn1_compiler_flags,
318 ac + optind, av - optind)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000319 exit(EX_SOFTWARE);
320 }
321
Lev Walkincbad2512005-03-24 16:27:02 +0000322 return 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000323}
324
325/*
Lev Walkin46499872006-03-06 13:05:34 +0000326 * Parse and import *.asn1 from skeletons/standard-modules
327 */
328static int
329importStandardModules(asn1p_t *asn, const char *skeletons_dir) {
330 asn1p_t *new_asn;
331 asn1p_module_t *mod;
332 const char *filename;
333 char *target_dir;
334 int target_dir_len;
335 int len;
336#ifdef WIN32
337 intptr_t dir;
338 struct _finddata_t c_file;
339 char *pattern;
340#else
341 struct dirent *dp;
342 DIR *dir;
343#endif
344 int ret = 0;
345
346 /* Notes for the human reader */
347 assert(asn);
348 assert(skeletons_dir);
349
350 /*
351 * Figure out the standard-modules directory.
352 */
353 target_dir_len = strlen(skeletons_dir)
354 + sizeof("/standard-modules") - 1;
355 target_dir = malloc(target_dir_len + 1);
356 assert(target_dir);
357 snprintf(target_dir, target_dir_len + 1, "%s/standard-modules",
358 skeletons_dir);
359
360#ifdef WIN32
361 len = target_dir_len + sizeof("/*.asn1"));
362 pattern = malloc(len);
363 assert(pattern);
364 snprintf(pattern, len, "%s/*.asn1", target_dir);
365 dir = _findfirst(pattern, &c_file);
366 if(dir != -1L) {
367#else
368 dir = opendir(target_dir);
369 if(!dir) {
370#endif
371 fprintf(stderr,
372 "WARNING: Cannot find standard modules in %s\n",
373 target_dir);
374 return -1;
375 }
376
377#ifdef WIN32
378 do {
379 filename = c_file.name;
380#else
381 while((dp = readdir(dir))) {
382 char *fullname;
383 filename = dp->d_name;
384 len = strlen(filename);
385 if(len <= 5 || strcmp(filename + len - 5, ".asn1"))
386 continue;
387 len = target_dir_len + 1 + len + 1;
388 fullname = malloc(len);
389 if(!fullname) continue; /* Just skip it, no big deal */
390 snprintf(fullname, len, "%s/%s", target_dir, filename);
391 filename = fullname;
392#endif
393
394 new_asn = asn1p_parse_file(filename, A1P_NOFLAGS);
395 if(new_asn == NULL) {
396 fprintf(stderr, "WARNING: Cannot parse standard module \"%s\"\n", filename);
397 ret = -1;
398 continue;
399 }
400
401 /* Import these modules and mark them as "standard" */
402 while((mod = TQ_REMOVE(&(new_asn->modules), mod_next))) {
403 mod->_tags |= MT_STANDARD_MODULE;
404 TQ_ADD(&(asn->modules), mod, mod_next);
405 }
406 asn1p_free(new_asn);
407
408#ifdef WIN32
409 } while(_findnext(dir, &c_file) == 0);
410 _findclose(dir);
411#else
412 free(fullname);
413 } /* while(readdir()) */
414 closedir(dir);
415#endif
416
417 return ret;
418}
419
420/*
Lev Walkinf15320b2004-06-03 03:38:44 +0000421 * Print the usage screen and exit(EX_USAGE).
422 */
423static void
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000424usage(const char *av0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000425 fprintf(stderr,
Lev Walkincbf218f2004-08-20 13:24:38 +0000426"ASN.1 Compiler, v" VERSION "\n" COPYRIGHT
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000427"Usage: %s [options] file ...\n"
428"Options:\n"
Lev Walkincbf218f2004-08-20 13:24:38 +0000429" -E Run only the ASN.1 parser and print out the tree\n"
430" -F During -E operation, also perform tree fixing\n"
431"\n"
432" -P Concatenate and print the compiled text\n"
433" -R Restrict output (tables only, no support code)\n"
434" -S <dir> Directory with support (skeleton?) files\n"
435" (Default is \"%s\")\n"
Lev Walkinf7484512004-10-13 09:13:56 +0000436" -X Generate and print the XML DTD\n"
Lev Walkincbf218f2004-08-20 13:24:38 +0000437"\n"
438
Lev Walkincbf218f2004-08-20 13:24:38 +0000439" -Werror Treat warnings as errors; abort if any warning\n"
440" -Wdebug-lexer Enable verbose debugging output from lexer\n"
441" -Wdebug-fixer --//-- semantics processor\n"
442" -Wdebug-compiler --//-- compiler\n"
443"\n"
444
Lev Walkindd32b592004-09-06 08:07:29 +0000445" -fall-defs-global Don't make the asn1_DEF_'s of structure members \"static\"\n"
Lev Walkincbf218f2004-08-20 13:24:38 +0000446" -fbless-SIZE Allow SIZE() constraint for INTEGER etc (non-std.)\n"
Lev Walkin21d00002005-03-04 08:48:53 +0000447" -fcompound-names Disambiguate C's struct NAME's inside top-level types\n"
Lev Walkin72a0f5a2005-07-24 08:28:39 +0000448" -findirect-choice Compile members of CHOICE as indirect pointers\n"
Lev Walkin7c655122005-06-05 09:42:42 +0000449" -fknown-extern-type=<name> Pretend the specified type is known\n"
Lev Walkin87a18962005-02-25 11:49:54 +0000450" -fnative-types Use \"long\" instead of INTEGER_t whenever possible, etc.\n"
Lev Walkin4e940a02004-09-26 13:13:13 +0000451" -fno-constraints Do not generate constraint checking code\n"
Lev Walkinb9b8b952005-03-05 00:33:27 +0000452" -fno-include-deps Do not generate courtesy #includes for dependencies\n"
Lev Walkincbf218f2004-08-20 13:24:38 +0000453" -funnamed-unions Enable unnamed unions in structures\n"
Lev Walkina895afb2005-10-06 10:09:34 +0000454" -fskeletons-copy Force copying the support files\n"
Lev Walkin59b176e2005-11-26 11:25:14 +0000455"\n"
456
457" -gen-PER Generate PER support code\n"
458" -pdu=auto Generate PDU table (discover PDUs automatically)\n"
Lev Walkincbf218f2004-08-20 13:24:38 +0000459"\n"
460
461" -print-constraints Explain subtype constraints (debug)\n"
462" -print-lines Generate \"-- #line\" comments in -E output\n"
463
Lev Walkinab4bb292004-08-18 04:52:48 +0000464 ,
465 a1c_basename(av0), DATADIR
Lev Walkinf15320b2004-06-03 03:38:44 +0000466 );
467 exit(EX_USAGE);
468}
469