Sync with 5.3.0
[deliverable/titan.core.git] / compiler2 / main.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 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;
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 if (0 == strchr(file_name, '-' )) {
353 return TRUE;
354 }
355 return FALSE;
356 }
357
358 static void usage()
359 {
360 fprintf(stderr, "\n"
361 "usage: %s [-abcdfgijlLOpqrRsStuwxXyY] [-K file] [-z file] [-V verb_level]\n"
362 " [-o dir] [-U none|type] [-P modulename.top_level_pdu_name] [-Q number] ...\n"
363 " [-T] module.ttcn [-A] module.asn ...\n"
364 " or %s -v\n"
365 " or %s --ttcn2json [-jf] ... [-T] module.ttcn [-A] module.asn ... [- schema.json]\n"
366 "\n"
367 "OPTIONS:\n"
368 " -a: force XER in ASN.1 files\n"
369 " -b: disable BER encoder/decoder functions\n"
370 " -c: write out checksums in case of error\n"
371 " -d: treat default fields as omit\n"
372 " -f: force overwriting of output files\n"
373 " -g: emulate GCC error/warning message format\n"
374 " -i: use only line numbers in error/warning messages\n"
375 " -j: disable JSON encoder/decoder functions\n"
376 " -l: include source line info in C++ code\n"
377 " -L: add source line info for logging\n"
378 " -K file: enable selective code coverage\n"
379 " -o dir: output files will be placed into dir\n"
380 " -p: parse only (no semantic check or code generation)\n"
381 " -P pduname: define top-level pdu\n"
382 " -q: suppress all messages (quiet mode)\n"
383 " -Qn: quit after n errors\n"
384 " -r: disable RAW encoder/decoder functions\n"
385 " -R: use function test runtime (TITAN_RUNTIME_2)\n"
386 " -s: parse and semantic check only (no code generation)\n"
387 " -S: suppress context information\n"
388 " -t: generate Test Port skeleton\n"
389 " -u: duplicate underscores in file names\n"
390 " -U none|type: select code splitting mode for the generated C++ code\n"
391 " -V verb_level: set verbosity level bitmask (decimal)\n"
392 " -w: suppress warnings\n"
393 " -x: disable TEXT encoder/decoder functions\n"
394 " -X: disable XER encoder/decoder functions\n"
395 " -y: disable subtype checking\n"
396 " -Y: Enforces legacy behaviour of the \"out\" function parameters (see refguide)\n"
397 " -z file: enable profiling and code coverage for the TTCN-3 files in the argument\n"
398 " -T file: force interpretation of file as TTCN-3 module\n"
399 " -A file: force interpretation of file as ASN.1 module\n"
400 " -v: show version\n"
401 " --ttcn2json: generate JSON schema from input modules\n"
402 "JSON schema generator options:\n"
403 " -j: only include types with JSON encoding\n"
404 " -f: only generate references to types with JSON encoding/decoding functions\n", argv0, argv0, argv0);
405 }
406
407 #define SET_FLAG(x) if (x##flag) {\
408 ERROR("Flag -" #x " was specified more than once.");\
409 errflag = true;\
410 } else x##flag = true
411
412
413 extern int ttcn3_debug;
414 extern int asn1_yydebug;
415 extern int pattern_yydebug;
416 extern int pattern_unidebug;
417 extern int rawAST_debug;
418 extern int coding_attrib_debug;
419
420 int main(int argc, char *argv[])
421 {
422 argv0 = argv[0];
423 #ifndef NDEBUG
424 asn1_yydebug = !! getenv("DEBUG_ASN1");
425 ttcn3_debug = !! getenv("DEBUG_TTCN");
426 pattern_unidebug= pattern_yydebug = !! getenv("DEBUG_PATTERN");
427 rawAST_debug = !! getenv("DEBUG_RAW");
428 coding_attrib_debug = !!getenv("DEBUG_ATRIB") || getenv("DEBUG_ATTRIB");
429 #endif
430
431 #ifdef MEMORY_DEBUG
432 #if defined(__CYGWIN__) || defined(INTERIX)
433 //nothing to do
434 #else
435 debug_new_counter.set_program_name(argv0);
436 #endif
437 #endif
438
439 if (argc == 1) {
440 fputs("TTCN-3 and ASN.1 Compiler for the TTCN-3 Test Executor, version "
441 PRODUCT_NUMBER "\n", stderr);
442 usage();
443 return EXIT_FAILURE;
444 }
445
446 bool
447 Aflag = false, Lflag = false, Yflag = false,
448 Pflag = false, Tflag = false, Vflag = false, bflag = false,
449 cflag = false, fflag = false, iflag = false, lflag = false,
450 oflag = false, pflag = false, qflag = false, rflag = false, sflag = false,
451 tflag = false, uflag = false, vflag = false, wflag = false, xflag = false,
452 dflag = false, Xflag = false, Rflag = false, gflag = false, aflag = false,
453 s0flag = false, Cflag = false, yflag = false, Uflag = false, Qflag = false,
454 Sflag = false, Kflag = false, jflag = false, zflag = false, Fflag = false,
455 errflag = false, print_usage = false, ttcn2json = false;
456
457 CodeGenHelper cgh;
458
459 bool asn1_modules_present = false;
460 #ifdef LICENSE
461 bool ttcn3_modules_present = false;
462 #endif
463 size_t n_modules = 0;
464 module_struct *module_list = NULL;
465 char* json_schema_name = NULL;
466
467 if (0 == strcmp(argv[1], "--ttcn2json")) {
468 ttcn2json = true;
469 display_up_to_date = TRUE;
470 implicit_json_encoding = TRUE;
471 for (int i = 2; i < argc; ++i) {
472 // A dash (-) is used to separate the schema file name from the input files
473 if (0 == strcmp(argv[i], "-")) {
474 if (i == argc - 2) {
475 json_schema_name = mcopystr(argv[i + 1]);
476 } else {
477 ERROR("Expected JSON schema name (1 argument) after option `--ttcn2json' and `-'");
478 errflag = true;
479 }
480 break;
481 }
482 else if (0 == strcmp(argv[i], "-A")) {
483 ++i;
484 if (i == argc) {
485 ERROR("Option `-A' must be followed by an ASN.1 file name");
486 errflag = true;
487 break;
488 }
489 add_module(n_modules, module_list, argv[i], Module::MOD_ASN);
490 asn1_modules_present = true;
491 }
492 else if (0 == strcmp(argv[i], "-T")) {
493 ++i;
494 if (i == argc) {
495 ERROR("Option `-T' must be followed by a TTCN-3 file name");
496 errflag = true;
497 break;
498 }
499 add_module(n_modules, module_list, argv[i], Module::MOD_TTCN);
500 }
501 else if (0 == strcmp(argv[i], "-j")) {
502 implicit_json_encoding = FALSE;
503 }
504 else if (0 == strcmp(argv[i], "-f")) {
505 json_refs_for_all_types = FALSE;
506 }
507 else if (0 == strcmp(argv[i], "-fj") || 0 == strcmp(argv[i], "-jf")) {
508 implicit_json_encoding = FALSE;
509 json_refs_for_all_types = FALSE;
510 }
511 else if (argv[i][0] == '-') {
512 ERROR("Invalid option `%s' after option `--ttcn2json'", argv[i]);
513 print_usage = true;
514 errflag = true;
515 break;
516 }
517 else {
518 add_module(n_modules, module_list, argv[i], Module::MOD_UNKNOWN);
519 }
520 }
521
522 if (!errflag && 0 == n_modules) {
523 ERROR("No TTCN-3 or ASN.1 modules specified after option `--ttcn2json'");
524 errflag = true;
525 print_usage = true;
526 }
527
528 if (!errflag && NULL == json_schema_name) {
529 // Create the schema name using the first TTCN-3 or ASN.1 file's name
530 const module_struct& first = module_list[0];
531 if (0 == strncmp(first.file_name + strlen(first.file_name) - 4, ".asn", 4)) {
532 json_schema_name = mcopystrn(first.file_name, strlen(first.file_name) - 4);
533 json_schema_name = mputstrn(json_schema_name, ".json", 5);
534 }
535 else if (0 == strncmp(first.file_name + strlen(first.file_name) - 5, ".ttcn", 5)) {
536 json_schema_name = mcopystrn(first.file_name, strlen(first.file_name) - 5);
537 json_schema_name = mputstrn(json_schema_name, ".json", 5);
538 }
539 else {
540 json_schema_name = mprintf("%s.json", first.file_name);
541 }
542 }
543 }
544
545 if (!ttcn2json) {
546 for ( ; ; ) {
547 int c = getopt(argc, argv, "aA:C:K:LP:T:V:bcdfFgilo:YpqQ:rRs0StuU:vwxXjyz:-");
548 if (c == -1) break;
549 switch (c) {
550 case 'a':
551 SET_FLAG(a);
552 asn1_xer = TRUE;
553 break;
554 case 'A':
555 Aflag = true;
556 add_module(n_modules, module_list, optarg, Module::MOD_ASN);
557 asn1_modules_present = true;
558 break;
559 case 'C':
560 SET_FLAG(C);
561 expected_platform = optarg;
562 break;
563 case 'L':
564 SET_FLAG(L);
565 include_location_info = TRUE;
566 break;
567 case 'P':
568 Pflag = true;
569 nof_top_level_pdus++;
570 top_level_pdu=(const char**)
571 Realloc(top_level_pdu, nof_top_level_pdus*sizeof(*top_level_pdu));
572 top_level_pdu[nof_top_level_pdus-1] = optarg;
573 break;
574 case 'T':
575 Tflag = true;
576 add_module(n_modules, module_list, optarg, Module::MOD_TTCN);
577 #ifdef LICENSE
578 ttcn3_modules_present = true;
579 #endif
580 break;
581 case 'V':
582 SET_FLAG(V);
583 /* set verbosity level bitmask */
584 if (isdigit(optarg[0])) {
585 verb_level = atoi(optarg);
586 // don't bother with overflow
587 errno = 0;
588 } else {
589 ERROR("Option `-V' requires a decimal number as argument instead of "
590 "`%s'.", optarg);
591 errflag = true;
592 }
593 break;
594 case 'b':
595 SET_FLAG(b);
596 ber_disabled = TRUE;
597 break;
598 case 'c':
599 SET_FLAG(c);
600 break;
601 case 'd':
602 SET_FLAG(d);
603 default_as_optional = TRUE;
604 break;
605 case 'f':
606 SET_FLAG(f);
607 force_overwrite = TRUE;
608 break;
609 case 'g':
610 SET_FLAG(g);
611 gcc_compat = TRUE;
612 break;
613 case 'i':
614 SET_FLAG(i);
615 output_only_linenum = TRUE;
616 break;
617 case 'K':
618 SET_FLAG(K);
619 tcov_file_name = optarg;
620 break;
621 case 'l':
622 SET_FLAG(l);
623 include_line_info = TRUE;
624 break;
625 case 'o':
626 SET_FLAG(o);
627 output_dir = optarg;
628 break;
629 case 'Y':
630 SET_FLAG(Y);
631 enable_set_bound_out_param = TRUE;
632 break;
633 case 'p':
634 SET_FLAG(p);
635 parse_only = TRUE;
636 break;
637 case 'q':
638 SET_FLAG(q);
639 /* quiet; suppress all message */
640 verb_level = 0;
641 break;
642 case 'r':
643 SET_FLAG(r);
644 raw_disabled = TRUE;
645 break;
646 case 'R':
647 SET_FLAG(R);
648 use_runtime_2 = TRUE;
649 break;
650 case 's':
651 SET_FLAG(s);
652 semantic_check_only = TRUE;
653 break;
654 case 'S':
655 SET_FLAG(S);
656 suppress_context = TRUE;
657 break;
658 case '0':
659 SET_FLAG(s0);
660 attribute_validation_disabled = TRUE;
661 break;
662 case 't':
663 SET_FLAG(t);
664 generate_skeleton = TRUE;
665 break;
666 case 'u':
667 SET_FLAG(u);
668 duplicate_underscores = TRUE;
669 break;
670 case 'U':
671 SET_FLAG(U);
672 if (!cgh.set_split_mode(optarg)) {
673 ERROR("Wrong code splitting option: '%s'. Valid values are: 'none', "
674 "'type'.", optarg);
675 errflag = true;
676 }
677 break;
678 case 'v':
679 SET_FLAG(v);
680 break;
681 case 'w':
682 SET_FLAG(w);
683 /* suppress warnings and "not supported" messages */
684 verb_level &= ~(1|2);
685 break;
686 case 'x':
687 SET_FLAG(x);
688 text_disabled = TRUE;
689 break;
690 case 'X':
691 SET_FLAG(X);
692 xer_disabled = TRUE;
693 break;
694 case 'j':
695 SET_FLAG(j);
696 json_disabled = TRUE;
697 break;
698 case 'y':
699 SET_FLAG(y);
700 check_subtype = FALSE;
701 break;
702 case 'z':
703 SET_FLAG(z);
704 profiler_file_name = optarg;
705 break;
706 case 'F':
707 SET_FLAG(F);
708 force_gen_seof = TRUE;
709 break;
710
711 case 'Q': {
712 long max_errs;
713 SET_FLAG(Q);
714 printf("Q: %s\n", optarg);
715
716 errno = 0;
717 max_errs = strtol(optarg, (char**)NULL, 10);
718 if (errno != 0
719 || (long)(int)max_errs != max_errs) { // does not fit into int
720 ERROR("Invalid value %s: %s", optarg, strerror(errno));
721 errflag = true;
722 }
723 else if (max_errs < 0) {
724 ERROR("Negative value %s not allowed", optarg);
725 errflag = true;
726 }
727 else { // all good
728 if (max_errs == 0) max_errs = 1;
729 }
730
731 Error_Context::set_max_errors(max_errs);
732 break; }
733
734 case '-':
735 if (!strcmp(argv[optind], "--ttcn2json")) {
736 ERROR("Option `--ttcn2json' is only allowed as the first option");
737 } else {
738 ERROR("Invalid option: `%s'", argv[optind]);
739 }
740 // no break
741
742 default:
743 errflag = true;
744 print_usage = true;
745 break;
746 }
747 }
748
749 /* Checking incompatible options */
750 if (vflag) {
751 if (Aflag || Lflag || Pflag || Tflag || Vflag || Yflag ||
752 bflag || fflag || iflag || lflag || oflag || pflag || qflag ||
753 rflag || sflag || tflag || uflag || wflag || xflag || Xflag || Rflag ||
754 Uflag || yflag || Kflag || jflag || zflag || Fflag) {
755 errflag = true;
756 print_usage = true;
757 }
758 } else {
759 if (pflag) {
760 if (sflag) {
761 ERROR("Options `-p' and `-s' are incompatible with each other.");
762 // totally confusing: exit immediately
763 errflag = true;
764 }
765 }
766 if (Kflag && !Lflag) {
767 ERROR("Source line information `-L' is necessary for code coverage `-K'.");
768 errflag = true;
769 }
770 if (zflag && !Lflag) {
771 ERROR("Source line information `-L' is necessary for profiling `-z'.");
772 errflag = true;
773 }
774 if (iflag && gflag) {
775 WARNING("Option `-g' overrides `-i'.");
776 iflag = false; // -g gives more information
777 }
778 if (oflag && get_path_status(output_dir) != PS_DIRECTORY) {
779 ERROR("The argument of -o switch (`%s') must be a directory.",
780 output_dir);
781 errflag = true;
782 }
783 if (optind == argc && n_modules == 0) {
784 ERROR("No input TTCN-3 or ASN.1 module was given.");
785 errflag = true;
786 }
787 }
788 } // if (!ttcn2json)
789
790 if (errflag) {
791 if (print_usage) usage();
792 Free(json_schema_name);
793 return EXIT_FAILURE;
794 }
795
796 if (vflag) {
797 fputs("TTCN-3 and ASN.1 Compiler for the TTCN-3 Test Executor\n"
798 "Product number: " PRODUCT_NUMBER "\n"
799 "Build date: " __DATE__ " " __TIME__ "\n"
800 "Compiled with: " C_COMPILER_VERSION "\n\n"
801 COPYRIGHT_STRING "\n\n", stderr);
802 #ifdef LICENSE
803 print_license_info();
804 fputs("\nUsing ", stderr);
805 fputs(openssl_version_str(), stderr);
806 fputs("\n\n", stderr);
807 #endif
808 return EXIT_SUCCESS;
809 }
810
811 #ifdef LICENSE
812 init_openssl();
813 license_struct lstr;
814 load_license(&lstr);
815 int license_valid = verify_license(&lstr);
816 free_openssl();
817 if (!license_valid) {
818 free_license(&lstr);
819 exit(EXIT_FAILURE);
820 }
821 #endif
822
823 if (!ttcn2json) {
824 /* the position of '-' switch in argv list */
825 int dash_position = -1;
826
827 /* Add the remaining files until switch '-' to the module_list */
828 for(int i = optind; i < argc; i++) {
829 if (strcmp(argv[i], "-"))
830 add_module(n_modules, module_list, argv[i], Module::MOD_UNKNOWN);
831 else {
832 dash_position = i;
833 break;
834 }
835 }
836
837 if (dash_position == -1) {
838 /** if '-' was not present in the command line code should be generated for
839 * all modules */
840 for (size_t i = 0; i < n_modules; i++) module_list[i].need_codegen = true;
841 } else {
842 for (int i = dash_position + 1; i < argc; i++) {
843 char *absolute_path = canonize_input_file(argv[i]);
844 if (absolute_path == NULL) continue;
845 bool found = false;
846 for (size_t j = 0; j < n_modules; j++) {
847 module_struct *module = module_list + j;
848 if (!strcmp(module->absolute_path, absolute_path)) {
849 module->need_codegen = true;
850 found = true;
851 // do not stop: the same file may be present on the list twice
852 // (as both ASN.1 and TTCN-3 module)
853 }
854 }
855 Free(absolute_path);
856 if (!found) {
857 ERROR("File `%s' was not given before the `-' switch for selective "
858 "code generation.", argv[i]);
859 // go further (i.e. check all files after the `-')
860 }
861 }
862 }
863 } // if (!ttcn2json)
864
865 {
866 STOPWATCH("Determining module types");
867 // check the readability of all files and
868 // determine the type of unknown modules
869 for (size_t i = 0; i < n_modules; i++) {
870 module_struct *module = module_list + i;
871 FILE *fp = fopen(module->file_name, "r");
872 if (fp != NULL) {
873 if (module->module_type == Module::MOD_UNKNOWN) {
874 // try the ASN.1 and TTCN-3 preparsers
875 boolean asn1_module = is_asn1_module(module->file_name, fp, NULL);
876 boolean ttcn3_module = is_ttcn3_module(module->file_name, fp, NULL);
877 if (asn1_module) {
878 if (!is_valid_asn1_filename (module->file_name)) {
879 ERROR("The file name (without suffix) shall be identical to the module name.\n"
880 "If the name of the ASN.1 module contains a hyphen, the corresponding "
881 "file name shall contain an underscore character instead.");
882 }
883 if (ttcn3_module) {
884 ERROR("File `%s' looks so strange that it can contain both an "
885 "ASN.1 and a TTCN-3 module. Use the command-line switch `-A' or "
886 "`-T' to set its type.", module->file_name);
887 } else {
888 bool found = false;
889 for (size_t j = 0; j < n_modules; j++) {
890 module_struct *module2 = module_list + j;
891 if (module2->module_type == Module::MOD_ASN &&
892 !strcmp(module->absolute_path, module2->absolute_path)) {
893 found = true;
894 break;
895 }
896 }
897 if (found) {
898 ERROR("Input file `%s' was given more than once.",
899 module->file_name);
900 } else {
901 module->module_type = Module::MOD_ASN;
902 asn1_modules_present = true;
903 }
904 }
905 } else if (ttcn3_module) {
906 bool found = false;
907 for (size_t j = 0; j < n_modules; j++) {
908 module_struct *module2 = module_list + j;
909 if (module2->module_type == Module::MOD_TTCN &&
910 !strcmp(module->absolute_path, module2->absolute_path)) {
911 found = true;
912 break;
913 }
914 }
915 if (found) {
916 ERROR("Input file `%s' was given more than once.",
917 module->file_name);
918 } else {
919 module->module_type = Module::MOD_TTCN;
920 #ifdef LICENSE
921 ttcn3_modules_present = true;
922 #endif
923 }
924 } else {
925 ERROR("Cannot recognize file `%s' as an ASN.1 or TTCN-3 module. "
926 "Use the command-line switch `-A' or `-T' to set its type.",
927 module->file_name);
928 }
929 }
930 fclose(fp);
931 } else {
932 ERROR("Cannot open input file `%s' for reading: %s", module->file_name,
933 strerror(errno));
934 errno = 0;
935 // do not invoke the real parsers on that file
936 module->module_type = Module::MOD_UNKNOWN;
937 }
938 }
939 }
940
941 #if defined(MINGW)
942 if (!semantic_check_only) {
943 NOTIFY("On native win32 builds code generation is disabled.");
944 semantic_check_only = TRUE;
945 }
946 #endif
947 #ifdef LICENSE
948 /* Checking of required license features */
949 if (asn1_modules_present && !check_feature(&lstr, FEATURE_ASN1)) {
950 ERROR("The license key does not allow the parsing of "
951 "ASN.1 modules.");
952 return EXIT_FAILURE;
953 }
954 if (ttcn3_modules_present && !check_feature(&lstr, FEATURE_TTCN3)) {
955 ERROR("The license key does not allow the parsing of "
956 "TTCN-3 modules.");
957 return EXIT_FAILURE;
958 }
959 if (!parse_only && !semantic_check_only &&
960 !check_feature(&lstr, FEATURE_CODEGEN)) {
961 WARNING("The license key does not allow the generation of "
962 "C++ code.");
963 semantic_check_only = TRUE;
964 }
965 if (generate_skeleton && !check_feature(&lstr, FEATURE_TPGEN)) {
966 WARNING("The license key does not allow the generation of "
967 "Test Port skeletons.");
968 generate_skeleton = FALSE;
969 }
970 has_raw_feature = check_feature(&lstr, FEATURE_RAW);
971 has_ber_feature = check_feature(&lstr, FEATURE_BER);
972 has_per_feature = check_feature(&lstr, FEATURE_PER);
973 has_text_feature = check_feature(&lstr, FEATURE_TEXT);
974 has_xer_feature = check_feature(&lstr, FEATURE_XER);
975 free_license(&lstr);
976 #endif
977 if (Kflag && !check_file_list(tcov_file_name, module_list, n_modules, tcov_files)) {
978 ERROR("Error while processing `%s' provided for code coverage data "
979 "generation.", tcov_file_name);
980 return EXIT_FAILURE;
981 }
982 if (zflag) {
983 tcov_file_list *file_list_head = NULL;
984 if(!check_file_list(profiler_file_name, module_list, n_modules, file_list_head)) {
985 ERROR("Error while processing `%s' provided for profiling and code coverage.",
986 profiler_file_name);
987 return EXIT_FAILURE;
988 }
989 init_profiler_data(file_list_head);
990 }
991 {
992 STOPWATCH("Parsing modules");
993
994 // asn1_yydebug=1;
995 if (asn1_modules_present) asn1_init();
996 modules = new Common::Modules();
997
998 for (size_t i = 0; i < n_modules; i++) {
999 const module_struct *module = module_list + i;
1000 switch (module->module_type) {
1001 case Module::MOD_ASN:
1002 asn1_parse_file(module->file_name, module->need_codegen);
1003 break;
1004 case Module::MOD_TTCN:
1005 ttcn3_parse_file(module->file_name, module->need_codegen);
1006 break;
1007 default: // MOD_UNKNOWN ?
1008 break;
1009 }
1010 }
1011
1012 for (size_t i = 0; i < n_modules; i++) Free(module_list[i].absolute_path);
1013 Free(module_list);
1014 }
1015
1016 if (!parse_only && 0 == Error_Context::get_error_count()) {
1017 NOTIFY("Checking modules...");
1018 {
1019 STOPWATCH("Semantic check");
1020 modules->chk();
1021 }
1022 }
1023
1024 if (verb_level > 7) modules->dump();
1025
1026 int ret_val = EXIT_SUCCESS;
1027 unsigned int error_count = Error_Context::get_error_count();
1028 if (error_count > 0) ret_val = EXIT_FAILURE;
1029
1030 if (parse_only || semantic_check_only) {
1031 // print detailed statistics
1032 Error_Context::print_error_statistics();
1033 } else {
1034 if (error_count == 0) {
1035 #ifdef USAGE_STATS
1036 {
1037 // Ignore SIGPIPE signals
1038 struct sigaction sig_act;
1039 if (sigaction(SIGPIPE, NULL, &sig_act))
1040 ERROR("System call sigaction() failed when getting signal "
1041 "handling information for %s.", "SIGINT");
1042 sig_act.sa_handler = SIG_IGN;
1043 sig_act.sa_flags = 0;
1044 if (sigaction(SIGPIPE, &sig_act, NULL))
1045 ERROR("System call sigaction() failed when disabling signal "
1046 "%s.", "SIGINT");
1047 }
1048
1049 std::stringstream stream;
1050 stream << "compiler";
1051 std::set<ModuleVersion> versions = modules->getVersionsWithProductNumber();
1052 if (!versions.empty()) {
1053 stream << "&products=";
1054 for (std::set<ModuleVersion>::iterator it = versions.begin(); it != versions.end(); ++it) {
1055 if (it != versions.begin()) {
1056 stream << ",";
1057 }
1058 stream << it->toString();
1059 }
1060 }
1061
1062 HttpSender *sender = new HttpSender;
1063 UsageData::getInstance().sendDataThreaded(stream.str(), sender);
1064 #endif
1065 if (ttcn2json) {
1066 NOTIFY("Generating JSON schema...");
1067 STOPWATCH("Generating JSON schema");
1068 // the Ttcn2Json constructor starts the process
1069 Ttcn::Ttcn2Json t2j(modules, json_schema_name);
1070 } else {
1071 NOTIFY("Generating code...");
1072 STOPWATCH("Generating code");
1073 modules->generate_code(cgh);
1074 report_nof_updated_files();
1075 }
1076 } else {
1077 NOTIFY("Error%s found in the input module%s. Code will not be generated.",
1078 error_count > 1 ? "s" : "", n_modules > 1 ? "s" : "");
1079 if (cflag) {
1080 modules->write_checksums();
1081 }
1082 }
1083 }
1084
1085 if (Kflag) {
1086 while (tcov_files != NULL) {
1087 tcov_file_list *next_file = tcov_files->next;
1088 Free(tcov_files->file_name);
1089 Free(tcov_files);
1090 tcov_files = next_file;
1091 }
1092 tcov_files = NULL;
1093 }
1094 delete modules;
1095 Free(top_level_pdu);
1096 if (asn1_modules_present) asn1_free();
1097 Type::free_pools();
1098 Common::Node::chk_counter();
1099 Location::delete_source_file_names();
1100 Free(json_schema_name);
1101 if (zflag) {
1102 free_profiler_data();
1103 }
1104
1105 // dbgnew.hh already does it: check_mem_leak(argv[0]);
1106
1107 return ret_val;
1108 }
This page took 0.107021 seconds and 5 git commands to generate.