Sync with 5.4.2
[deliverable/titan.core.git] / compiler2 / main.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 /* Main program for the merged compiler */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <vector>
17 #include <sstream>
18 #if defined SOLARIS || defined SOLARIS8
19 # include <sys/utsname.h>
20 #endif
21
22 #ifdef USAGE_STATS
23 #include "../common/usage_stats.hh"
24 #include <signal.h>
25 #endif
26
27 #include "../common/dbgnew.hh"
28 #include "../common/path.h"
29 #include "../common/version_internal.h"
30 #include "../common/userinfo.h"
31 #include "datatypes.h"
32 #include "main.hh"
33
34 #include "asn1/asn1_preparser.h"
35 #include "asn1/asn1.hh"
36 #include "ttcn3/ttcn3_preparser.h"
37 #include "ttcn3/compiler.h"
38
39 #include "AST.hh"
40 #include "asn1/AST_asn1.hh"
41 #include "ttcn3/AST_ttcn3.hh"
42
43 #include "CodeGenHelper.hh"
44 #include "Stopwatch.hh"
45
46 #include "ttcn3/Ttcn2Json.hh"
47
48 #include "ttcn3/profiler.h"
49
50 #ifdef LICENSE
51 #include "../common/license.h"
52 #endif
53
54 using namespace Common;
55
56 const char *output_dir = NULL;
57 const char *tcov_file_name = NULL;
58 const char *profiler_file_name = NULL;
59 tcov_file_list *tcov_files = NULL;
60 expstring_t effective_module_lines = NULL;
61 expstring_t effective_module_functions = NULL;
62
63 size_t nof_top_level_pdus = 0;
64 const char **top_level_pdu = NULL;
65
66 boolean generate_skeleton = FALSE, force_overwrite = FALSE,
67 include_line_info = FALSE, include_location_info = FALSE,
68 duplicate_underscores = FALSE, parse_only = FALSE,
69 semantic_check_only = FALSE, output_only_linenum = FALSE,
70 default_as_optional = FALSE, enable_set_bound_out_param = FALSE,
71 use_runtime_2 = FALSE, gcc_compat = FALSE, asn1_xer = FALSE,
72 check_subtype = TRUE, suppress_context = FALSE, display_up_to_date = FALSE,
73 implicit_json_encoding = FALSE, json_refs_for_all_types = TRUE,
74 force_gen_seof = FALSE, omit_in_value_list = FALSE;
75
76 // Default code splitting mode is set to 'no splitting'.
77 CodeGenHelper::split_type code_splitting_mode = CodeGenHelper::SPLIT_NONE;
78
79 #if defined SOLARIS || defined SOLARIS8
80 /** Automatic detection of Solaris version based on uname() system call.
81 * Distinguishing is needed because some socket functions use socklen_t
82 * (which is an alias for unsigned int) as length arguments on Solaris 8.
83 * On Solaris 2.6 the argument type is simply int and no socklen_t or other
84 * alias exists.
85 * Note: It was discovered later that Solaris 7 (which is used rarely within
86 * Ericsson) already uses socklen_t thus the SOLARIS8 platform identifier is a
87 * bit misleading. */
88 static const char *get_platform_string(void)
89 {
90 struct utsname name;
91 int major, minor;
92 if (uname(&name) < 0) {
93 WARNING("System call uname() failed: %s", strerror(errno));
94 errno = 0;
95 return "SOLARIS";
96 }
97 if (sscanf(name.release, "%d.%d", &major, &minor) == 2 && major == 5) {
98 if (minor <= 6) return "SOLARIS";
99 else return "SOLARIS8";
100 } else {
101 ERROR("Invalid OS release: %s", name.release);
102 return "SOLARIS";
103 }
104 }
105 #elif defined LINUX
106 #define get_platform_string() "LINUX"
107 #elif defined FREEBSD
108 #define get_platform_string() "FREEBSD"
109 #elif defined WIN32
110 #define get_platform_string() "WIN32"
111 #elif defined INTERIX
112 #define get_platform_string() "INTERIX"
113 #else
114 #error Platform was not set.
115 #endif
116
117
118 const char *expected_platform = get_platform_string();
119
120 /// "The" AST.
121 Modules *modules = NULL;
122
123 // Features can be disabled in the license or by commandline switches
124 static bool raw_disabled = false, ber_disabled = false, per_disabled = false,
125 text_disabled = false, xer_disabled = false, json_disabled = false;
126 static bool attribute_validation_disabled = FALSE;
127 #ifdef LICENSE
128 static bool has_raw_feature = false, has_ber_feature = false,
129 has_per_feature = false, has_text_feature = false, has_xer_feature = false;
130 #endif
131
132 boolean enable_raw()
133 {
134 if (raw_disabled) return FALSE;
135 #ifdef LICENSE
136 if (!has_raw_feature) {
137 WARNING("The license key does not allow the generation of "
138 "RAW encoder/decoder functions.");
139 raw_disabled = true;
140 return FALSE;
141 }
142 #endif
143 return TRUE;
144 }
145
146 boolean enable_ber()
147 {
148 if (ber_disabled) return FALSE;
149 #ifdef LICENSE
150 if (!has_ber_feature) {
151 WARNING("The license key does not allow the generation of "
152 "BER encoder/decoder functions.");
153 ber_disabled = true;
154 return FALSE;
155 }
156 #endif
157 return TRUE;
158 }
159
160 boolean enable_per()
161 {
162 if (per_disabled) return FALSE;
163 #ifdef LICENSE
164 if (!has_per_feature) {
165 WARNING("The license key does not allow the generation of "
166 "PER encoder/decoder functions.");
167 per_disabled = true;
168 return FALSE;
169 }
170 #endif
171 return TRUE;
172 }
173
174 boolean enable_text()
175 {
176 if (text_disabled) return FALSE;
177 #ifdef LICENSE
178 if (!has_text_feature) {
179 WARNING("The license key does not allow the generation of "
180 "TEXT encoder/decoder functions.");
181 text_disabled = true;
182 return FALSE;
183 }
184 #endif
185 return TRUE;
186 }
187
188 boolean enable_xer()
189 {
190 if (xer_disabled) return FALSE;
191 #ifdef LICENSE
192 if (!has_xer_feature) {
193 WARNING("The license key does not allow the generation of "
194 "XER encoder/decoder functions.");
195 xer_disabled = true;
196 return FALSE;
197 }
198 #endif
199 return TRUE;
200 }
201
202 boolean enable_json()
203 {
204 return !json_disabled;
205 }
206
207 boolean disable_attribute_validation()
208 {
209 if (attribute_validation_disabled) return TRUE;
210
211 return FALSE;
212 }
213
214 char *canonize_input_file(const char *path_name)
215 {
216 switch (get_path_status(path_name)) {
217 case PS_NONEXISTENT:
218 ERROR("Input file `%s' does not exist.", path_name);
219 return NULL;
220 case PS_DIRECTORY:
221 ERROR("Argument `%s' is a directory.", path_name);
222 return NULL;
223 default:
224 break;
225 }
226 char *dir_name = get_dir_from_path(path_name);
227 char *abs_dir = get_absolute_dir(dir_name, NULL);
228 Free(dir_name);
229 char *file_name = get_file_from_path(path_name);
230 char *ret_val = compose_path_name(abs_dir, file_name);
231 Free(abs_dir);
232 Free(file_name);
233 return ret_val;
234 }
235
236 struct module_struct {
237 const char *file_name;
238 char *absolute_path;
239 Module::moduletype_t module_type;
240 bool need_codegen; /**< Code is generated for a module if
241 - the module appears on the command line after the dash, or
242 - there is no dash (code is generated for all modules) */
243 };
244
245 static void add_module(size_t& n_modules, module_struct*& module_list,
246 const char *file_name, Module::moduletype_t module_type)
247 {
248 char *absolute_path = canonize_input_file(file_name);
249 if (absolute_path == NULL) return;
250 for (size_t i = 0; i < n_modules; i++) {
251 const module_struct *module = module_list + i;
252 if (module->module_type == module_type &&
253 !strcmp(module->absolute_path, absolute_path)) {
254 ERROR("Input file `%s' was given more than once.", file_name);
255 Free(absolute_path);
256 return;
257 }
258 }
259 module_list = (module_struct*)
260 Realloc(module_list, (n_modules + 1) * sizeof(module_struct));
261 module_struct *module = module_list + n_modules;
262 module->file_name = file_name;
263 module->absolute_path = absolute_path;
264 module->module_type = module_type;
265 module->need_codegen = false;
266 n_modules++;
267 }
268
269 const char *get_tcov_file_name(const char *file_name)
270 {
271 tcov_file_list *tcov_file = tcov_files;
272 expstring_t file_name_pp = mputprintf(NULL, "%spp", file_name);
273 while (tcov_file != NULL) {
274 // This name can be a `.ttcnpp' too.
275 const char *real_file_name = static_cast<const char *>(tcov_file->file_name);
276 if (!strcmp(file_name, real_file_name) ||
277 !strcmp(static_cast<const char *>(file_name_pp), real_file_name)) {
278 Free(file_name_pp);
279 return real_file_name;
280 }
281 tcov_file = tcov_file->next;
282 }
283 Free(file_name_pp);
284 return NULL;
285 }
286
287 boolean in_tcov_files(const char *file_name)
288 {
289 return get_tcov_file_name(file_name) ? TRUE : FALSE;
290 }
291
292 static bool check_file_list(const char *file_name, module_struct *module_list,
293 size_t n_modules, tcov_file_list *&file_list_head)
294 {
295 FILE *fp = fopen(file_name, "r");
296 if (fp == NULL) {
297 ERROR("File `%s' does not exist.", file_name);
298 return false;
299 }
300 #ifndef PATH_MAX
301 #define PATH_MAX 1024
302 #endif
303 char line[PATH_MAX];
304 bool unlisted_files = false;
305 while (fgets(line, sizeof(line), fp) != NULL) {
306 // Remove trailing '\n'.
307 size_t line_len = strlen(line) - 1;
308 if (line[line_len] == '\n')
309 line[line_len] = 0;
310 // Handle `.ttcnpp' files in input file.
311 if (line_len > 1) {
312 char last = line[line_len - 1];
313 char before_last = line[line_len - 2];
314 if (last == 'p' && before_last == 'p')
315 line_len -= 2;
316 }
317 if (line_len < 1)
318 continue;
319 size_t i = 0;
320 for (; i < n_modules; ++i) {
321 const module_struct *module = module_list + i;
322 if (!strncmp(module->file_name, line, line_len)) {
323 tcov_file_list *next_file = (tcov_file_list*)Malloc(sizeof(tcov_file_list));
324 next_file->next = file_list_head;
325 // We'll need the `.ttcnpp' file name.
326 next_file->file_name = mcopystr(line);
327 file_list_head = next_file;
328 break;
329 }
330 }
331 if (i == n_modules) {
332 ERROR("File `%s' was listed in `%s', but not in the command line.",
333 line, file_name);
334 unlisted_files = true;
335 }
336 }
337 fclose(fp);
338 if (unlisted_files) {
339 while (file_list_head != NULL) {
340 tcov_file_list *next_file = file_list_head->next;
341 Free(file_list_head->file_name);
342 Free(file_list_head);
343 file_list_head = next_file;
344 }
345 file_list_head = NULL;
346 }
347 return !unlisted_files;
348 }
349
350 static boolean is_valid_asn1_filename(const char* file_name)
351 {
352 // only check the actual file name, not the whole path
353 const char* file_name_start = strrchr(file_name, '/');
354 if (0 == strchr(file_name_start != NULL ? file_name_start : file_name, '-' )) {
355 return TRUE;
356 }
357 return FALSE;
358 }
359
360 static void usage()
361 {
362 fprintf(stderr, "\n"
363 "usage: %s [-abcdfgijlLOpqrRsStuwxXyY] [-K file] [-z file] [-V verb_level]\n"
364 " [-o dir] [-U none|type] [-P modulename.top_level_pdu_name] [-Q number] ...\n"
365 " [-T] module.ttcn [-A] module.asn ...\n"
366 " or %s -v\n"
367 " or %s --ttcn2json [-jf] ... [-T] module.ttcn [-A] module.asn ... [- schema.json]\n"
368 "\n"
369 "OPTIONS:\n"
370 " -a: force XER in ASN.1 files\n"
371 " -b: disable BER encoder/decoder functions\n"
372 " -c: write out checksums in case of error\n"
373 " -d: treat default fields as omit\n"
374 " -f: force overwriting of output files\n"
375 " -g: emulate GCC error/warning message format\n"
376 " -i: use only line numbers in error/warning messages\n"
377 " -j: disable JSON encoder/decoder functions\n"
378 " -K file: enable selective code coverage\n"
379 " -l: include source line info in C++ code\n"
380 " -L: add source line info for logging\n"
381 " -M: allow 'omit' in template value lists (legacy behavior)\n"
382 " -o dir: output files will be placed into dir\n"
383 " -p: parse only (no semantic check or code generation)\n"
384 " -P pduname: define top-level pdu\n"
385 " -q: suppress all messages (quiet mode)\n"
386 " -Qn: quit after n errors\n"
387 " -r: disable RAW encoder/decoder functions\n"
388 " -R: use function test runtime (TITAN_RUNTIME_2)\n"
389 " -s: parse and semantic check only (no code generation)\n"
390 " -S: suppress context information\n"
391 " -t: generate Test Port skeleton\n"
392 " -u: duplicate underscores in file names\n"
393 " -U none|type: select code splitting mode for the generated C++ code\n"
394 " -V verb_level: set verbosity level bitmask (decimal)\n"
395 " -w: suppress warnings\n"
396 " -x: disable TEXT encoder/decoder functions\n"
397 " -X: disable XER encoder/decoder functions\n"
398 " -y: disable subtype checking\n"
399 " -Y: enforce legacy behaviour for \"out\" function parameters (see refguide)\n"
400 " -z file: enable profiling and code coverage for the TTCN-3 files in the argument\n"
401 " -T file: force interpretation of file as TTCN-3 module\n"
402 " -A file: force interpretation of file as ASN.1 module\n"
403 " -v: show version\n"
404 " --ttcn2json: generate JSON schema from input modules\n"
405 "JSON schema generator options:\n"
406 " -j: only include types with JSON encoding\n"
407 " -f: only generate references to types with JSON encoding/decoding functions\n", argv0, argv0, argv0);
408 }
409
410 #define SET_FLAG(x) if (x##flag) {\
411 ERROR("Flag -" #x " was specified more than once.");\
412 errflag = true;\
413 } else x##flag = true
414
415
416 extern int ttcn3_debug;
417 extern int asn1_yydebug;
418 extern int pattern_yydebug;
419 extern int pattern_unidebug;
420 extern int rawAST_debug;
421 extern int coding_attrib_debug;
422
423 int main(int argc, char *argv[])
424 {
425 argv0 = argv[0];
426 #ifndef NDEBUG
427 asn1_yydebug = !! getenv("DEBUG_ASN1");
428 ttcn3_debug = !! getenv("DEBUG_TTCN");
429 pattern_unidebug= pattern_yydebug = !! getenv("DEBUG_PATTERN");
430 rawAST_debug = !! getenv("DEBUG_RAW");
431 coding_attrib_debug = !!getenv("DEBUG_ATRIB") || getenv("DEBUG_ATTRIB");
432 #endif
433
434 #ifdef MEMORY_DEBUG
435 #if defined(__CYGWIN__) || defined(INTERIX)
436 //nothing to do
437 #else
438 debug_new_counter.set_program_name(argv0);
439 #endif
440 #endif
441
442 if (argc == 1) {
443 fputs("TTCN-3 and ASN.1 Compiler for the TTCN-3 Test Executor, version "
444 PRODUCT_NUMBER "\n", stderr);
445 usage();
446 return EXIT_FAILURE;
447 }
448
449 bool
450 Aflag = false, Lflag = false, Yflag = false,
451 Pflag = false, Tflag = false, Vflag = false, bflag = false,
452 cflag = false, fflag = false, iflag = false, lflag = false,
453 oflag = false, pflag = false, qflag = false, rflag = false, sflag = false,
454 tflag = false, uflag = false, vflag = false, wflag = false, xflag = false,
455 dflag = false, Xflag = false, Rflag = false, gflag = false, aflag = false,
456 s0flag = false, Cflag = false, yflag = false, Uflag = false, Qflag = false,
457 Sflag = false, Kflag = false, jflag = false, zflag = false, Fflag = false,
458 Mflag = false, errflag = false, print_usage = false, ttcn2json = false;
459
460 CodeGenHelper cgh;
461
462 bool asn1_modules_present = false;
463 #ifdef LICENSE
464 bool ttcn3_modules_present = false;
465 #endif
466 size_t n_modules = 0;
467 module_struct *module_list = NULL;
468 char* json_schema_name = NULL;
469
470 if (0 == strcmp(argv[1], "--ttcn2json")) {
471 ttcn2json = true;
472 display_up_to_date = TRUE;
473 implicit_json_encoding = TRUE;
474 for (int i = 2; i < argc; ++i) {
475 // A dash (-) is used to separate the schema file name from the input files
476 if (0 == strcmp(argv[i], "-")) {
477 if (i == argc - 2) {
478 json_schema_name = mcopystr(argv[i + 1]);
479 } else {
480 ERROR("Expected JSON schema name (1 argument) after option `--ttcn2json' and `-'");
481 errflag = true;
482 }
483 break;
484 }
485 else if (0 == strcmp(argv[i], "-A")) {
486 ++i;
487 if (i == argc) {
488 ERROR("Option `-A' must be followed by an ASN.1 file name");
489 errflag = true;
490 break;
491 }
492 add_module(n_modules, module_list, argv[i], Module::MOD_ASN);
493 asn1_modules_present = true;
494 }
495 else if (0 == strcmp(argv[i], "-T")) {
496 ++i;
497 if (i == argc) {
498 ERROR("Option `-T' must be followed by a TTCN-3 file name");
499 errflag = true;
500 break;
501 }
502 add_module(n_modules, module_list, argv[i], Module::MOD_TTCN);
503 }
504 else if (0 == strcmp(argv[i], "-j")) {
505 implicit_json_encoding = FALSE;
506 }
507 else if (0 == strcmp(argv[i], "-f")) {
508 json_refs_for_all_types = FALSE;
509 }
510 else if (0 == strcmp(argv[i], "-fj") || 0 == strcmp(argv[i], "-jf")) {
511 implicit_json_encoding = FALSE;
512 json_refs_for_all_types = FALSE;
513 }
514 else if (argv[i][0] == '-') {
515 ERROR("Invalid option `%s' after option `--ttcn2json'", argv[i]);
516 print_usage = true;
517 errflag = true;
518 break;
519 }
520 else {
521 add_module(n_modules, module_list, argv[i], Module::MOD_UNKNOWN);
522 }
523 }
524
525 if (!errflag && 0 == n_modules) {
526 ERROR("No TTCN-3 or ASN.1 modules specified after option `--ttcn2json'");
527 errflag = true;
528 print_usage = true;
529 }
530
531 if (!errflag && NULL == json_schema_name) {
532 // Create the schema name using the first TTCN-3 or ASN.1 file's name
533 const module_struct& first = module_list[0];
534 if (0 == strncmp(first.file_name + strlen(first.file_name) - 4, ".asn", 4)) {
535 json_schema_name = mcopystrn(first.file_name, strlen(first.file_name) - 4);
536 json_schema_name = mputstrn(json_schema_name, ".json", 5);
537 }
538 else if (0 == strncmp(first.file_name + strlen(first.file_name) - 5, ".ttcn", 5)) {
539 json_schema_name = mcopystrn(first.file_name, strlen(first.file_name) - 5);
540 json_schema_name = mputstrn(json_schema_name, ".json", 5);
541 }
542 else {
543 json_schema_name = mprintf("%s.json", first.file_name);
544 }
545 }
546 }
547
548 if (!ttcn2json) {
549 for ( ; ; ) {
550 int c = getopt(argc, argv, "aA:C:K:LP:T:V:bcdfFgilMo:YpqQ:rRs0StuU:vwxXjyz:-");
551 if (c == -1) break;
552 switch (c) {
553 case 'a':
554 SET_FLAG(a);
555 asn1_xer = TRUE;
556 break;
557 case 'A':
558 Aflag = true;
559 add_module(n_modules, module_list, optarg, Module::MOD_ASN);
560 asn1_modules_present = true;
561 break;
562 case 'C':
563 SET_FLAG(C);
564 expected_platform = optarg;
565 break;
566 case 'L':
567 SET_FLAG(L);
568 include_location_info = TRUE;
569 break;
570 case 'P':
571 Pflag = true;
572 nof_top_level_pdus++;
573 top_level_pdu=(const char**)
574 Realloc(top_level_pdu, nof_top_level_pdus*sizeof(*top_level_pdu));
575 top_level_pdu[nof_top_level_pdus-1] = optarg;
576 break;
577 case 'T':
578 Tflag = true;
579 add_module(n_modules, module_list, optarg, Module::MOD_TTCN);
580 #ifdef LICENSE
581 ttcn3_modules_present = true;
582 #endif
583 break;
584 case 'V':
585 SET_FLAG(V);
586 /* set verbosity level bitmask */
587 if (isdigit(optarg[0])) {
588 verb_level = atoi(optarg);
589 // don't bother with overflow
590 errno = 0;
591 } else {
592 ERROR("Option `-V' requires a decimal number as argument instead of "
593 "`%s'.", optarg);
594 errflag = true;
595 }
596 break;
597 case 'b':
598 SET_FLAG(b);
599 ber_disabled = TRUE;
600 break;
601 case 'c':
602 SET_FLAG(c);
603 break;
604 case 'd':
605 SET_FLAG(d);
606 default_as_optional = TRUE;
607 break;
608 case 'f':
609 SET_FLAG(f);
610 force_overwrite = TRUE;
611 break;
612 case 'g':
613 SET_FLAG(g);
614 gcc_compat = TRUE;
615 break;
616 case 'i':
617 SET_FLAG(i);
618 output_only_linenum = TRUE;
619 break;
620 case 'K':
621 SET_FLAG(K);
622 tcov_file_name = optarg;
623 break;
624 case 'l':
625 SET_FLAG(l);
626 include_line_info = TRUE;
627 break;
628 case 'o':
629 SET_FLAG(o);
630 output_dir = optarg;
631 break;
632 case 'Y':
633 SET_FLAG(Y);
634 enable_set_bound_out_param = TRUE;
635 break;
636 case 'p':
637 SET_FLAG(p);
638 parse_only = TRUE;
639 break;
640 case 'q':
641 SET_FLAG(q);
642 /* quiet; suppress all message */
643 verb_level = 0;
644 break;
645 case 'r':
646 SET_FLAG(r);
647 raw_disabled = TRUE;
648 break;
649 case 'R':
650 SET_FLAG(R);
651 use_runtime_2 = TRUE;
652 break;
653 case 's':
654 SET_FLAG(s);
655 semantic_check_only = TRUE;
656 break;
657 case 'S':
658 SET_FLAG(S);
659 suppress_context = TRUE;
660 break;
661 case '0':
662 SET_FLAG(s0);
663 attribute_validation_disabled = TRUE;
664 break;
665 case 't':
666 SET_FLAG(t);
667 generate_skeleton = TRUE;
668 break;
669 case 'u':
670 SET_FLAG(u);
671 duplicate_underscores = TRUE;
672 break;
673 case 'U':
674 SET_FLAG(U);
675 if (!cgh.set_split_mode(optarg)) {
676 ERROR("Wrong code splitting option: '%s'. Valid values are: 'none', "
677 "'type'.", optarg);
678 errflag = true;
679 }
680 break;
681 case 'v':
682 SET_FLAG(v);
683 break;
684 case 'w':
685 SET_FLAG(w);
686 /* suppress warnings and "not supported" messages */
687 verb_level &= ~(1|2);
688 break;
689 case 'x':
690 SET_FLAG(x);
691 text_disabled = TRUE;
692 break;
693 case 'X':
694 SET_FLAG(X);
695 xer_disabled = TRUE;
696 break;
697 case 'j':
698 SET_FLAG(j);
699 json_disabled = TRUE;
700 break;
701 case 'y':
702 SET_FLAG(y);
703 check_subtype = FALSE;
704 break;
705 case 'z':
706 SET_FLAG(z);
707 profiler_file_name = optarg;
708 break;
709 case 'F':
710 SET_FLAG(F);
711 force_gen_seof = TRUE;
712 break;
713 case 'M':
714 SET_FLAG(M);
715 omit_in_value_list = TRUE;
716 break;
717
718 case 'Q': {
719 long max_errs;
720 SET_FLAG(Q);
721 printf("Q: %s\n", optarg);
722
723 errno = 0;
724 max_errs = strtol(optarg, (char**)NULL, 10);
725 if (errno != 0
726 || (long)(int)max_errs != max_errs) { // does not fit into int
727 ERROR("Invalid value %s: %s", optarg, strerror(errno));
728 errflag = true;
729 }
730 else if (max_errs < 0) {
731 ERROR("Negative value %s not allowed", optarg);
732 errflag = true;
733 }
734 else { // all good
735 if (max_errs == 0) max_errs = 1;
736 }
737
738 Error_Context::set_max_errors(max_errs);
739 break; }
740
741 case '-':
742 if (!strcmp(argv[optind], "--ttcn2json")) {
743 ERROR("Option `--ttcn2json' is only allowed as the first option");
744 } else {
745 ERROR("Invalid option: `%s'", argv[optind]);
746 }
747 // no break
748
749 default:
750 errflag = true;
751 print_usage = true;
752 break;
753 }
754 }
755
756 /* Checking incompatible options */
757 if (vflag) {
758 if (Aflag || Lflag || Pflag || Tflag || Vflag || Yflag ||
759 bflag || fflag || iflag || lflag || oflag || pflag || qflag ||
760 rflag || sflag || tflag || uflag || wflag || xflag || Xflag || Rflag ||
761 Uflag || yflag || Kflag || jflag || zflag || Fflag || Mflag) {
762 errflag = true;
763 print_usage = true;
764 }
765 } else {
766 if (pflag) {
767 if (sflag) {
768 ERROR("Options `-p' and `-s' are incompatible with each other.");
769 // totally confusing: exit immediately
770 errflag = true;
771 }
772 }
773 if (Kflag && !Lflag) {
774 ERROR("Source line information `-L' is necessary for code coverage `-K'.");
775 errflag = true;
776 }
777 if (zflag && !Lflag) {
778 ERROR("Source line information `-L' is necessary for profiling `-z'.");
779 errflag = true;
780 }
781 if (iflag && gflag) {
782 WARNING("Option `-g' overrides `-i'.");
783 iflag = false; // -g gives more information
784 }
785 if (oflag && get_path_status(output_dir) != PS_DIRECTORY) {
786 ERROR("The argument of -o switch (`%s') must be a directory.",
787 output_dir);
788 errflag = true;
789 }
790 if (optind == argc && n_modules == 0) {
791 ERROR("No input TTCN-3 or ASN.1 module was given.");
792 errflag = true;
793 }
794 }
795 } // if (!ttcn2json)
796
797 if (errflag) {
798 if (print_usage) usage();
799 Free(json_schema_name);
800 return EXIT_FAILURE;
801 }
802
803 if (vflag) {
804 fputs("TTCN-3 and ASN.1 Compiler for the TTCN-3 Test Executor\n"
805 "Product number: " PRODUCT_NUMBER "\n"
806 "Build date: " __DATE__ " " __TIME__ "\n"
807 "Compiled with: " C_COMPILER_VERSION "\n\n"
808 COPYRIGHT_STRING "\n\n", stderr);
809 #ifdef LICENSE
810 print_license_info();
811 fputs("\nUsing ", stderr);
812 fputs(openssl_version_str(), stderr);
813 fputs("\n\n", stderr);
814 #endif
815 return EXIT_SUCCESS;
816 }
817
818 #ifdef LICENSE
819 init_openssl();
820 license_struct lstr;
821 load_license(&lstr);
822 int license_valid = verify_license(&lstr);
823 free_openssl();
824 if (!license_valid) {
825 free_license(&lstr);
826 exit(EXIT_FAILURE);
827 }
828 #endif
829
830 if (!ttcn2json) {
831 /* the position of '-' switch in argv list */
832 int dash_position = -1;
833
834 /* Add the remaining files until switch '-' to the module_list */
835 for(int i = optind; i < argc; i++) {
836 if (strcmp(argv[i], "-"))
837 add_module(n_modules, module_list, argv[i], Module::MOD_UNKNOWN);
838 else {
839 dash_position = i;
840 break;
841 }
842 }
843
844 if (dash_position == -1) {
845 /** if '-' was not present in the command line code should be generated for
846 * all modules */
847 for (size_t i = 0; i < n_modules; i++) module_list[i].need_codegen = true;
848 } else {
849 for (int i = dash_position + 1; i < argc; i++) {
850 char *absolute_path = canonize_input_file(argv[i]);
851 if (absolute_path == NULL) continue;
852 bool found = false;
853 for (size_t j = 0; j < n_modules; j++) {
854 module_struct *module = module_list + j;
855 if (!strcmp(module->absolute_path, absolute_path)) {
856 module->need_codegen = true;
857 found = true;
858 // do not stop: the same file may be present on the list twice
859 // (as both ASN.1 and TTCN-3 module)
860 }
861 }
862 Free(absolute_path);
863 if (!found) {
864 ERROR("File `%s' was not given before the `-' switch for selective "
865 "code generation.", argv[i]);
866 // go further (i.e. check all files after the `-')
867 }
868 }
869 }
870 } // if (!ttcn2json)
871
872 {
873 STOPWATCH("Determining module types");
874 // check the readability of all files and
875 // determine the type of unknown modules
876 for (size_t i = 0; i < n_modules; i++) {
877 module_struct *module = module_list + i;
878 FILE *fp = fopen(module->file_name, "r");
879 if (fp != NULL) {
880 if (module->module_type == Module::MOD_UNKNOWN) {
881 // try the ASN.1 and TTCN-3 preparsers
882 boolean asn1_module = is_asn1_module(module->file_name, fp, NULL);
883 boolean ttcn3_module = is_ttcn3_module(module->file_name, fp, NULL);
884 if (asn1_module) {
885 if (!is_valid_asn1_filename (module->file_name)) {
886 ERROR("The file name (without suffix) shall be identical to the module name.\n"
887 "If the name of the ASN.1 module contains a hyphen, the corresponding "
888 "file name shall contain an underscore character instead.");
889 }
890 if (ttcn3_module) {
891 ERROR("File `%s' looks so strange that it can contain both an "
892 "ASN.1 and a TTCN-3 module. Use the command-line switch `-A' or "
893 "`-T' to set its type.", module->file_name);
894 } else {
895 bool found = false;
896 for (size_t j = 0; j < n_modules; j++) {
897 module_struct *module2 = module_list + j;
898 if (module2->module_type == Module::MOD_ASN &&
899 !strcmp(module->absolute_path, module2->absolute_path)) {
900 found = true;
901 break;
902 }
903 }
904 if (found) {
905 ERROR("Input file `%s' was given more than once.",
906 module->file_name);
907 } else {
908 module->module_type = Module::MOD_ASN;
909 asn1_modules_present = true;
910 }
911 }
912 } else if (ttcn3_module) {
913 bool found = false;
914 for (size_t j = 0; j < n_modules; j++) {
915 module_struct *module2 = module_list + j;
916 if (module2->module_type == Module::MOD_TTCN &&
917 !strcmp(module->absolute_path, module2->absolute_path)) {
918 found = true;
919 break;
920 }
921 }
922 if (found) {
923 ERROR("Input file `%s' was given more than once.",
924 module->file_name);
925 } else {
926 module->module_type = Module::MOD_TTCN;
927 #ifdef LICENSE
928 ttcn3_modules_present = true;
929 #endif
930 }
931 } else {
932 ERROR("Cannot recognize file `%s' as an ASN.1 or TTCN-3 module. "
933 "Use the command-line switch `-A' or `-T' to set its type.",
934 module->file_name);
935 }
936 }
937 fclose(fp);
938 } else {
939 ERROR("Cannot open input file `%s' for reading: %s", module->file_name,
940 strerror(errno));
941 errno = 0;
942 // do not invoke the real parsers on that file
943 module->module_type = Module::MOD_UNKNOWN;
944 }
945 }
946 }
947
948 #if defined(MINGW)
949 if (!semantic_check_only) {
950 NOTIFY("On native win32 builds code generation is disabled.");
951 semantic_check_only = TRUE;
952 }
953 #endif
954 #ifdef LICENSE
955 /* Checking of required license features */
956 if (asn1_modules_present && !check_feature(&lstr, FEATURE_ASN1)) {
957 ERROR("The license key does not allow the parsing of "
958 "ASN.1 modules.");
959 return EXIT_FAILURE;
960 }
961 if (ttcn3_modules_present && !check_feature(&lstr, FEATURE_TTCN3)) {
962 ERROR("The license key does not allow the parsing of "
963 "TTCN-3 modules.");
964 return EXIT_FAILURE;
965 }
966 if (!parse_only && !semantic_check_only &&
967 !check_feature(&lstr, FEATURE_CODEGEN)) {
968 WARNING("The license key does not allow the generation of "
969 "C++ code.");
970 semantic_check_only = TRUE;
971 }
972 if (generate_skeleton && !check_feature(&lstr, FEATURE_TPGEN)) {
973 WARNING("The license key does not allow the generation of "
974 "Test Port skeletons.");
975 generate_skeleton = FALSE;
976 }
977 has_raw_feature = check_feature(&lstr, FEATURE_RAW);
978 has_ber_feature = check_feature(&lstr, FEATURE_BER);
979 has_per_feature = check_feature(&lstr, FEATURE_PER);
980 has_text_feature = check_feature(&lstr, FEATURE_TEXT);
981 has_xer_feature = check_feature(&lstr, FEATURE_XER);
982 free_license(&lstr);
983 #endif
984 if (Kflag && !check_file_list(tcov_file_name, module_list, n_modules, tcov_files)) {
985 ERROR("Error while processing `%s' provided for code coverage data "
986 "generation.", tcov_file_name);
987 return EXIT_FAILURE;
988 }
989 if (zflag) {
990 tcov_file_list *file_list_head = NULL;
991 if(!check_file_list(profiler_file_name, module_list, n_modules, file_list_head)) {
992 ERROR("Error while processing `%s' provided for profiling and code coverage.",
993 profiler_file_name);
994 return EXIT_FAILURE;
995 }
996 init_profiler_data(file_list_head);
997 }
998 {
999 STOPWATCH("Parsing modules");
1000
1001 // asn1_yydebug=1;
1002 if (asn1_modules_present) asn1_init();
1003 modules = new Common::Modules();
1004
1005 for (size_t i = 0; i < n_modules; i++) {
1006 const module_struct *module = module_list + i;
1007 switch (module->module_type) {
1008 case Module::MOD_ASN:
1009 asn1_parse_file(module->file_name, module->need_codegen);
1010 break;
1011 case Module::MOD_TTCN:
1012 ttcn3_parse_file(module->file_name, module->need_codegen);
1013 break;
1014 default: // MOD_UNKNOWN ?
1015 break;
1016 }
1017 }
1018
1019 for (size_t i = 0; i < n_modules; i++) Free(module_list[i].absolute_path);
1020 Free(module_list);
1021 }
1022
1023 if (!parse_only && 0 == Error_Context::get_error_count()) {
1024 NOTIFY("Checking modules...");
1025 {
1026 STOPWATCH("Semantic check");
1027 modules->chk();
1028 }
1029 }
1030
1031 if (verb_level > 7) modules->dump();
1032
1033 int ret_val = EXIT_SUCCESS;
1034 unsigned int error_count = Error_Context::get_error_count();
1035 if (error_count > 0) ret_val = EXIT_FAILURE;
1036
1037 if (parse_only || semantic_check_only) {
1038 // print detailed statistics
1039 Error_Context::print_error_statistics();
1040 } else {
1041 if (error_count == 0) {
1042 #ifdef USAGE_STATS
1043 {
1044 // Ignore SIGPIPE signals
1045 struct sigaction sig_act;
1046 if (sigaction(SIGPIPE, NULL, &sig_act))
1047 ERROR("System call sigaction() failed when getting signal "
1048 "handling information for %s.", "SIGINT");
1049 sig_act.sa_handler = SIG_IGN;
1050 sig_act.sa_flags = 0;
1051 if (sigaction(SIGPIPE, &sig_act, NULL))
1052 ERROR("System call sigaction() failed when disabling signal "
1053 "%s.", "SIGINT");
1054 }
1055
1056 std::stringstream stream;
1057 stream << "compiler";
1058 std::set<ModuleVersion> versions = modules->getVersionsWithProductNumber();
1059 if (!versions.empty()) {
1060 stream << "&products=";
1061 for (std::set<ModuleVersion>::iterator it = versions.begin(); it != versions.end(); ++it) {
1062 if (it != versions.begin()) {
1063 stream << ",";
1064 }
1065 stream << it->toString();
1066 }
1067 }
1068
1069 HttpSender *sender = new HttpSender;
1070 UsageData::getInstance().sendDataThreaded(stream.str(), sender);
1071 #endif
1072 if (ttcn2json) {
1073 NOTIFY("Generating JSON schema...");
1074 STOPWATCH("Generating JSON schema");
1075 // the Ttcn2Json constructor starts the process
1076 Ttcn::Ttcn2Json t2j(modules, json_schema_name);
1077 } else {
1078 NOTIFY("Generating code...");
1079 STOPWATCH("Generating code");
1080 modules->generate_code(cgh);
1081 report_nof_updated_files();
1082 }
1083 } else {
1084 NOTIFY("Error%s found in the input module%s. Code will not be generated.",
1085 error_count > 1 ? "s" : "", n_modules > 1 ? "s" : "");
1086 if (cflag) {
1087 modules->write_checksums();
1088 }
1089 }
1090 }
1091
1092 if (Kflag) {
1093 while (tcov_files != NULL) {
1094 tcov_file_list *next_file = tcov_files->next;
1095 Free(tcov_files->file_name);
1096 Free(tcov_files);
1097 tcov_files = next_file;
1098 }
1099 tcov_files = NULL;
1100 }
1101 delete modules;
1102 Free(top_level_pdu);
1103 if (asn1_modules_present) asn1_free();
1104 Type::free_pools();
1105 Common::Node::chk_counter();
1106 Location::delete_source_file_names();
1107 Free(json_schema_name);
1108 if (zflag) {
1109 free_profiler_data();
1110 }
1111
1112 // dbgnew.hh already does it: check_mem_leak(argv[0]);
1113
1114 return ret_val;
1115 }
This page took 0.054147 seconds and 5 git commands to generate.