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