Newer
Older
/******************************************************************************
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
*
* >
* Baji, Laszlo
* Balasko, Jeno
* Baranyi, Botond
* Beres, Szabolcs
* Delic, Adam
* Forstner, Matyas
* Koppany, Csaba
* Kovacs, Ferenc
* Kremer, Peter
* Lovassy, Arpad
* Pandi, Krisztian
* Raduly, Csaba
* Szabados, Kristof
* Szabo, Bence Janos
* Szabo, Janos Zoltan – initial implementation
* Szalay, Akos
* Zalanyi, Balazs Andor
* Pandi, Krisztian
*
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#if defined SOLARIS || defined SOLARIS8
#endif
#include "../common/memory.h"
#include "../common/path.h"
#include "../common/version_internal.h"
#include "../common/userinfo.h"
#include "ttcn3/ttcn3_preparser.h"
#include "asn1/asn1_preparser.h"
#ifdef LICENSE
#include "../common/license.h"
#endif
#include "xpather.h"
static const char *program_name = NULL;
static unsigned int error_count = 0;
static boolean suppress_warnings = FALSE;
void free_string2_list(struct string2_list* act_elem);
void free_string_list(struct string_list* act_elem);
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
void ERROR(const char *fmt, ...)
{
va_list parameters;
fprintf(stderr, "%s: error: ", program_name);
va_start(parameters, fmt);
vfprintf(stderr, fmt, parameters);
va_end(parameters);
fprintf(stderr, "\n");
fflush(stderr);
error_count++;
}
void WARNING(const char *fmt, ...)
{
va_list parameters;
if (suppress_warnings) return;
fprintf(stderr, "%s: warning: ", program_name);
va_start(parameters, fmt);
vfprintf(stderr, fmt, parameters);
va_end(parameters);
putc('\n', stderr);
fflush(stderr);
}
void NOTIFY(const char *fmt, ...)
{
va_list parameters;
va_start(parameters, fmt);
vfprintf(stderr, fmt, parameters);
va_end(parameters);
putc('\n', stderr);
fflush(stderr);
}
void DEBUG(unsigned level, const char *fmt, ...)
{
va_list parameters;
fprintf(stderr, "%*s", 2 * level, "");
va_start(parameters, fmt);
vfprintf(stderr, fmt, parameters);
va_end(parameters);
putc('\n', stderr);
fflush(stderr);
}
void path_error(const char *fmt, ...)
{
va_list ap;
char *err_msg;
va_start(ap, fmt);
err_msg = mprintf_va_list(fmt, ap);
va_end(ap);
ERROR("%s", err_msg);
Free(err_msg);
}
#if defined SOLARIS || defined SOLARIS8
/** Automatic detection of Solaris version based on uname() system call.
* Distinguishing is needed because some socket functions use socklen_t
* (which is an alias for unsigned int) as length arguments on Solaris 8.
* On Solaris 2.6 the argument type is simply int and no socklen_t or other
* alias exists.
* Note: It was discovered later that Solaris 7 (which is used rarely within
* Ericsson) already uses socklen_t thus the SOLARIS8 platform identifier is a
* bit misleading. */
static const char *get_platform_string(void)
{
struct utsname name;
int major, minor;
if (uname(&name) < 0) {
WARNING("System call uname() failed: %s", strerror(errno));
errno = 0;
return "SOLARIS";
}
if (sscanf(name.release, "%d.%d", &major, &minor) == 2 && major == 5) {
if (minor <= 6) return "SOLARIS";
else return "SOLARIS8";
} else {
ERROR("Invalid OS release: %s", name.release);
return "SOLARIS";
}
}
#elif defined LINUX
#define get_platform_string() "LINUX"
#elif defined FREEBSD
#define get_platform_string() "FREEBSD"
#elif defined WIN32
#define get_platform_string() "WIN32"
#elif defined INTERIX
#define get_platform_string() "INTERIX"
#else
#error Platform was not set.
#endif
/** structure for describing TTCN-3 and ASN.1 modules */
struct module_struct {
char *dir_name; /* directory of the TTCN-3 or ASN.1 file, it is NULL if the
file is in the current working directory */
char *file_name; /* name of the TTCN-3 or ASN.1 file */
char *module_name; /* name of the TTCN-3 or ASN.1 module */
boolean is_regular; /* indicates whether the name of the source file follows
the default naming convention */
};
/** structure for describing test ports and other C/C++ modules */
struct user_struct {
char *dir_name; /* directory of the C/C++ source files, it is NULL if the
files are in the current working directory */
char *file_prefix; /* the common prefix of the header and source file */
char *header_name; /* name of the C/C++ header file, which has .hh or .h or .hpp
suffix, it is NULL if there is no header file */
char *source_name; /* name of the C/C++ source file, which has .cc or .c or .cpp
suffix, it is NULL if there is no source file */
boolean has_hh_suffix; /* indicates whether the header file is present and
has .hh or .hpp suffix */
boolean has_cc_suffix; /* indicates whether the source file is present and
has .cc or .cpp suffix */
};
/** structure for directories that pre-compiled files are taken from */
struct base_dir_struct {
const char *dir_name; /* name of the directory */
boolean has_modules; /* indicates whether there are TTCN-3/ASN.1 modules in
the directory (it is set to FALSE if dir_name
contains user C/C++ files only */
};
/** data structure that describes the information needed for the Makefile */
struct makefile_struct {
size_t nTTCN3Modules;
struct module_struct *TTCN3Modules;
boolean preprocess;
size_t nTTCN3PPModules;
struct module_struct *TTCN3PPModules;
boolean TTCN3ModulesRegular;
boolean BaseTTCN3ModulesRegular;
size_t nTTCN3IncludeFiles;
char **TTCN3IncludeFiles;
size_t nASN1Modules;
struct module_struct *ASN1Modules;
boolean ASN1ModulesRegular;
boolean BaseASN1ModulesRegular;
size_t nXSDModules;
struct module_struct *XSDModules;
// No XSDModulesRegular and BaseXSDModulesRegular: it would be always false
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
size_t nUserFiles;
struct user_struct *UserFiles;
boolean UserHeadersRegular;
boolean UserSourcesRegular;
boolean BaseUserHeadersRegular;
boolean BaseUserSourcesRegular;
size_t nOtherFiles;
char **OtherFiles;
boolean central_storage;
size_t nBaseDirs;
struct base_dir_struct *BaseDirs;
char *working_dir;
boolean gnu_make;
boolean single_mode;
char *output_file;
char *ets_name;
boolean force_overwrite;
boolean use_runtime_2;
boolean dynamic;
boolean gcc_dep;
char *code_splitting_mode;
boolean coverage;
char *tcov_file_name;
struct string_list* sub_project_dirs; /* not owned */
struct string_list* ttcn3_prep_includes; /* not owned */
struct string_list* ttcn3_prep_defines; /* not owned */
struct string_list* ttcn3_prep_undefines; /* not owned */
struct string_list* prep_includes; /* not owned */
struct string_list* prep_defines; /* not owned */
BenceJanosSzabo
committed
const char *codesplittpd;
boolean quietly;
boolean disablesubtypecheck;
const char *cxxcompiler;
const char *optlevel;
const char *optflags;
const char* linkerOptions;
boolean semanticcheckonly;
boolean disableattibutevalidation;
boolean disableber;
boolean disableraw;
boolean disabletext;
boolean disablexer;
boolean disablejson;
boolean disableoer;
boolean forcexerinasn;
boolean defaultasomit;
boolean gccmsgformat;
boolean linenumbersonlymsg;
boolean includesourceinfo;
boolean addsourcelineinfo;
boolean suppresswarnings;
boolean outparamboundness;
boolean ignore_untagged_on_top_union;
boolean enable_legacy_encoding;
Botond Baranyi
committed
boolean realtime_features;
boolean oop_features;
Botond Baranyi
committed
boolean charstring_compat;
struct string_list* solspeclibraries; /* not owned */
struct string_list* sol8speclibraries; /* not owned */
struct string_list* linuxspeclibraries; /* not owned */
struct string_list* freebsdspeclibraries; /* not owned */
struct string_list* win32speclibraries; /* not owned */
const char *ttcn3preprocessor;
struct string_list* linkerlibraries; /* not owned */
struct string_list* additionalObjects; /* not owned */
struct string_list* linkerlibsearchpath; /* not owned */
char* generatorCommandOutput; /* not owned */
struct string2_list* target_placement_list; /* not owned */
};
/** Initializes structure \a makefile with empty lists and default settings. */
static void init_makefile_struct(struct makefile_struct *makefile)
{
makefile->nTTCN3Modules = 0;
makefile->TTCN3Modules = NULL;
makefile->preprocess = FALSE;
makefile->nTTCN3PPModules = 0;
makefile->TTCN3PPModules = NULL;
makefile->TTCN3ModulesRegular = TRUE;
makefile->BaseTTCN3ModulesRegular = TRUE;
makefile->nTTCN3IncludeFiles = 0;
makefile->TTCN3IncludeFiles = NULL;
makefile->nASN1Modules = 0;
makefile->ASN1Modules = NULL;
makefile->ASN1ModulesRegular = TRUE;
makefile->BaseASN1ModulesRegular = TRUE;
makefile->nXSDModules = 0;
makefile->XSDModules = NULL;
makefile->nUserFiles = 0;
makefile->UserFiles = NULL;
makefile->UserHeadersRegular = TRUE;
makefile->UserSourcesRegular = TRUE;
makefile->BaseUserHeadersRegular = TRUE;
makefile->BaseUserSourcesRegular = TRUE;
makefile->nOtherFiles = 0;
makefile->OtherFiles = NULL;
makefile->central_storage = FALSE;
makefile->nBaseDirs = 0;
makefile->BaseDirs = NULL;
makefile->working_dir = get_working_dir();
makefile->gnu_make = FALSE;
makefile->single_mode = FALSE;
makefile->ets_name = NULL;
makefile->output_file = NULL;
makefile->force_overwrite = FALSE;
makefile->use_runtime_2 = FALSE;
makefile->dynamic = FALSE;
makefile->gcc_dep = FALSE;
makefile->code_splitting_mode = NULL;
makefile->coverage = FALSE;
makefile->tcov_file_name = NULL;
makefile->linkingStrategy = FALSE;
makefile->hierarchical = FALSE;
makefile->sub_project_dirs = NULL;
makefile->ttcn3_prep_includes = NULL;
makefile->prep_includes = NULL;
makefile->prep_defines = NULL;
makefile->outparamboundness = FALSE;
makefile->ignore_untagged_on_top_union = FALSE;
makefile->disable_predef_ext_folder = FALSE;
makefile->enable_legacy_encoding = FALSE;
makefile->disable_userinfo = FALSE;
Botond Baranyi
committed
makefile->realtime_features = FALSE;
makefile->oop_features = FALSE;
Botond Baranyi
committed
makefile->charstring_compat = FALSE;
makefile->solspeclibraries = NULL;
makefile->sol8speclibraries = NULL;
makefile->linuxspeclibraries = NULL;
makefile->freebsdspeclibraries = NULL;
makefile->win32speclibraries = NULL;
makefile->linkerlibraries = NULL;
makefile->additionalObjects = NULL;
makefile->linkerlibsearchpath = NULL;
makefile->generatorCommandOutput = NULL;
makefile->target_placement_list = NULL;
}
/** Deallocates all memory associated with structure \a makefile. */
static void free_makefile_struct(const struct makefile_struct *makefile)
{
size_t i;
for (i = 0; i < makefile->nTTCN3Modules; i++) {
Free(makefile->TTCN3Modules[i].dir_name);
Free(makefile->TTCN3Modules[i].file_name);
Free(makefile->TTCN3Modules[i].module_name);
}
Free(makefile->TTCN3Modules);
for (i = 0; i < makefile->nTTCN3PPModules; i++) {
Free(makefile->TTCN3PPModules[i].dir_name);
Free(makefile->TTCN3PPModules[i].file_name);
Free(makefile->TTCN3PPModules[i].module_name);
}
Free(makefile->TTCN3PPModules);
for (i = 0; i < makefile->nTTCN3IncludeFiles; i++)
Free(makefile->TTCN3IncludeFiles[i]);
Free(makefile->TTCN3IncludeFiles);
for (i = 0; i < makefile->nASN1Modules; i++) {
Free(makefile->ASN1Modules[i].dir_name);
Free(makefile->ASN1Modules[i].file_name);
Free(makefile->ASN1Modules[i].module_name);
}
Free(makefile->ASN1Modules);
for (i = 0; i < makefile->nXSDModules; i++) {
Free(makefile->XSDModules[i].dir_name);
Free(makefile->XSDModules[i].file_name);
Free(makefile->XSDModules[i].module_name);
}
Free(makefile->XSDModules);
for (i = 0; i < makefile->nUserFiles; i++) {
Free(makefile->UserFiles[i].dir_name);
Free(makefile->UserFiles[i].file_prefix);
Free(makefile->UserFiles[i].header_name);
Free(makefile->UserFiles[i].source_name);
}
Free(makefile->UserFiles);
for (i = 0; i < makefile->nOtherFiles; i++) Free(makefile->OtherFiles[i]);
Free(makefile->OtherFiles);
Free(makefile->BaseDirs);
Free(makefile->working_dir);
Free(makefile->ets_name);
Free(makefile->output_file);
Free(makefile->code_splitting_mode);
Free(makefile->tcov_file_name);
}
/** Displays the contents of structure \a makefile as debug messages. */
static void dump_makefile_struct(const struct makefile_struct *makefile,
unsigned level)
{
size_t i;
DEBUG(level, "Data used for Makefile generation:");
DEBUG(level + 1, "TTCN-3 project name: %s", makefile->project_name);
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
DEBUG(level + 1, "TTCN-3 modules: (%u pcs.)", makefile->nTTCN3Modules);
for (i = 0; i < makefile->nTTCN3Modules; i++) {
const struct module_struct *module = makefile->TTCN3Modules + i;
DEBUG(level + 2, "Module name: %s", module->module_name);
if (module->dir_name != NULL)
DEBUG(level + 3, "Directory: %s", module->dir_name);
DEBUG(level + 3, "File name: %s", module->file_name);
DEBUG(level + 3, "Follows the naming convention: %s",
module->is_regular ? "yes" : "no");
}
DEBUG(level + 1, "TTCN-3 preprocessing: %s",
makefile->preprocess ? "yes" : "no");
if (makefile->preprocess) {
DEBUG(level + 1, "TTCN-3 modules to be preprocessed: (%u pcs.)",
makefile->nTTCN3PPModules);
for (i = 0; i < makefile->nTTCN3PPModules; i++) {
const struct module_struct *module = makefile->TTCN3PPModules + i;
DEBUG(level + 2, "Module name: %s", module->module_name);
if (module->dir_name != NULL)
DEBUG(level + 3, "Directory: %s", module->dir_name);
DEBUG(level + 3, "File name: %s", module->file_name);
DEBUG(level + 3, "Follows the naming convention: %s",
module->is_regular ? "yes" : "no");
}
DEBUG(level + 1, "TTCN-3 include files: (%u pcs.)",
makefile->nTTCN3IncludeFiles);
for (i = 0; i < makefile->nTTCN3IncludeFiles; i++)
DEBUG(level + 2, "File name: %s", makefile->TTCN3IncludeFiles[i]);
}
DEBUG(level + 1, "All local TTCN-3 modules follow the naming convention: %s",
makefile->TTCN3ModulesRegular ? "yes" : "no");
if (makefile->central_storage) DEBUG(level + 1, "All TTCN-3 modules from other "
"directories follow the naming convention: %s",
makefile->BaseTTCN3ModulesRegular ? "yes" : "no");
DEBUG(level + 1, "ASN.1 modules: (%u pcs.)", makefile->nASN1Modules);
for (i = 0; i < makefile->nASN1Modules; i++) {
const struct module_struct *module = makefile->ASN1Modules + i;
DEBUG(level + 2, "Module name: %s", module->module_name);
if (module->dir_name != NULL)
DEBUG(level + 3, "Directory: %s", module->dir_name);
DEBUG(level + 3, "File name: %s", module->file_name);
DEBUG(level + 3, "Follows the naming convention: %s",
module->is_regular ? "yes" : "no");
}
DEBUG(level + 1, "All local ASN.1 modules follow the naming convention: %s",
makefile->ASN1ModulesRegular ? "yes" : "no");
if (makefile->central_storage) DEBUG(level + 1, "All ASN.1 modules from other "
"directories follow the naming convention: %s",
makefile->BaseASN1ModulesRegular ? "yes" : "no");
DEBUG(level + 1, "User C/C++ modules: (%u pcs.)", makefile->nUserFiles);
for (i = 0; i < makefile->nUserFiles; i++) {
const struct user_struct *user = makefile->UserFiles + i;
DEBUG(level + 2, "File prefix: %s", user->file_prefix);
if (user->dir_name != NULL)
DEBUG(level + 3, "Directory: %s", user->dir_name);
if (user->header_name != NULL) {
DEBUG(level + 3, "Header file: %s", user->header_name);
DEBUG(level + 3, "Header file has .hh or .hpp suffix: %s",
}
if (user->source_name != NULL) {
DEBUG(level + 3, "Source file: %s", user->source_name);
DEBUG(level + 3, "Source file has .cc or .cpp suffix: %s",
DEBUG(level + 3, "Object file: %s.o", user->file_prefix);
}
}
DEBUG(level + 1, "All local C/C++ header files follow the naming "
"convention: %s", makefile->UserHeadersRegular ? "yes" : "no");
DEBUG(level + 1, "All local C/C++ source files follow the naming "
"convention: %s", makefile->UserSourcesRegular ? "yes" : "no");
if (makefile->central_storage) {
DEBUG(level + 1, "All C/C++ header files from other directories follow the "
"naming convention: %s", makefile->BaseUserHeadersRegular ? "yes" : "no");
DEBUG(level + 1, "All C/C++ source files from other directories follow the "
"naming convention: %s", makefile->BaseUserSourcesRegular ? "yes" : "no");
}
DEBUG(level + 1, "Other files: (%u pcs.)", makefile->nOtherFiles);
for (i = 0; i < makefile->nOtherFiles; i++)
DEBUG(level + 2, "File name: %s", makefile->OtherFiles[i]);
DEBUG(level + 1, "Use pre-compiled files from central storage: %s",
makefile->central_storage ? "yes" : "no");
if (makefile->central_storage) {
DEBUG(level + 1, "Directories of pre-compiled files: (%u pcs.)",
makefile->nBaseDirs);
for (i = 0; i < makefile->nBaseDirs; i++) {
const struct base_dir_struct *base_dir = makefile->BaseDirs + i;
DEBUG(level + 2, "Directory: %s", base_dir->dir_name);
DEBUG(level + 3, "Has TTCN-3/ASN.1 modules: %s",
}
}
DEBUG(level + 1, "Working directory: %s",
makefile->working_dir != NULL ? makefile->working_dir : "<unknown>");
DEBUG(level + 1, "GNU make: %s", makefile->gnu_make ? "yes" : "no");
DEBUG(level + 1, "Execution mode: %s",
makefile->single_mode ? "single" : "parallel");
DEBUG(level + 1, "Name of executable: %s",
makefile->ets_name != NULL ? makefile->ets_name : "<unknown>");
DEBUG(level + 1, "Output file: %s",
makefile->output_file != NULL ? makefile->output_file : "<unknown>");
DEBUG(level + 1, "Force overwrite: %s",
makefile->force_overwrite ? "yes" : "no");
DEBUG(level + 1, "Use function test runtime: %s",
makefile->use_runtime_2 ? "yes" : "no");
DEBUG(level + 1, "Use dynamic linking: %s",
makefile->dynamic ? "yes" : "no");
DEBUG(level + 1, "Code splitting mode: %s",
makefile->code_splitting_mode != NULL ?
makefile->code_splitting_mode : "<unknown>");
DEBUG(level + 1, "Code coverage file: %s",
makefile->tcov_file_name != NULL ?
makefile->tcov_file_name : "<unknown>");
if (makefile->profiled_file_list) {
char* lists = mcopystr(makefile->profiled_file_list->str);
struct string_list* iter = makefile->profiled_file_list->next;
while(iter != NULL) {
lists = mputprintf(lists, " %s", iter->str);
iter = iter->next;
}
DEBUG(level + 1, "Profiled file list(s): %s", lists);
Free(lists);
}
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
#ifdef COVERAGE_BUILD
DEBUG(level + 1, "Enable coverage: %s", makefile->coverage ? "yes" : "no");
#endif
}
/** Returns the name of an existing file that is related to command line
* argument \a argument. Tries the given list of suffixes. NULL pointer is
* returned if no file was found. The returned string shall be deallocated
* by the caller. */
static char *get_file_name_for_argument(const char *argument)
{
static const char * const suffix_list[] = {
"", ".ttcnpp", ".ttcnin", ".ttcn", ".ttcn3", ".3mp", ".asn", ".asn1",
".cc", ".c", ".cpp", ".hh", ".h",".hpp", ".cfg", ".prj", NULL
};
const char * const *suffix_ptr;
for (suffix_ptr = suffix_list; *suffix_ptr != NULL; suffix_ptr++) {
char *file_name = mputstr(mcopystr(argument), *suffix_ptr);
if (get_path_status(file_name) == PS_FILE) return file_name;
Free(file_name);
}
return NULL;
}
/** Converts \a path_name to an absolute directory using \a working_dir.
* NULL pointer is returned if \a path_name does not contain a directory or
* the resulting absolute directory is identical to \a working_dir.
* The returned string shall be deallocated by the caller. */
static char *get_dir_name(const char *path_name, const char *working_dir)
{
char *dir_name = get_dir_from_path(path_name);
if (dir_name != NULL) {
char *absolute_dir = get_absolute_dir(dir_name, working_dir, TRUE);
Free(dir_name);
if (absolute_dir == NULL || working_dir == NULL) {
/* an error occurred */
Botond Baranyi
committed
Free(absolute_dir);
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
return NULL;
} else if (!strcmp(absolute_dir, working_dir)) {
/* the directory is identical to the working dir */
Free(absolute_dir);
return NULL;
} else return absolute_dir;
} else return NULL;
}
/** Returns whether \a dirname1 and \a dirname2 contain the same (canonized
* absolute) directories. NULL pointer is handled in a special way: it is
* identical only to itself. */
static boolean is_same_directory(const char *dirname1, const char *dirname2)
{
if (dirname1 == NULL) {
if (dirname2 == NULL) return TRUE;
else return FALSE;
} else {
if (dirname2 == NULL) return FALSE;
else if (strcmp(dirname1, dirname2)) return FALSE;
else return TRUE;
}
}
/** Returns whether the file \a filename1 in directory \a dirname1 is identical
* to file \a filename2 in directory \a dirname2. Only the directory names can
* be NULL. */
static boolean is_same_file(const char *dirname1, const char *filename1,
const char *dirname2, const char *filename2)
{
/* first examine the file names for efficiency reasons */
if (strcmp(filename1, filename2)) return FALSE;
else return is_same_directory(dirname1, dirname2);
}
/** Determines whether the TTCN-3 or ASN.1 module identifiers \a module1 and
* \a module2 are the same. Characters '-' and '_' in module names are not
* distinguished. */
static boolean is_same_module(const char *module1, const char *module2)
{
size_t i;
for (i = 0; ; i++) {
switch (module1[i]) {
case '\0':
if (module2[i] == '\0') return TRUE;
else return FALSE;
case '-':
case '_':
if (module2[i] != '-' && module2[i] != '_') return FALSE;
break;
default:
if (module1[i] != module2[i]) return FALSE;
break;
}
}
return FALSE; /* to avoid warnings */
}
/** Truncates the suffix (i.e. the last dot and the characters following it)
* from \a file_name and returns a copy of the prefix of \a file_name.
* If \a file_name does not have a suffix an exact copy of it is returned.
* The returned string shall be deallocated by the caller. */
static char *cut_suffix(const char *file_name)
{
char *ret_val;
size_t last_dot = (size_t)-1;
size_t i;
for (i = 0; file_name[i] != '\0'; i++)
if (file_name[i] == '.') last_dot = i;
ret_val = mcopystr(file_name);
if (last_dot != (size_t)-1) ret_val = mtruncstr(ret_val, last_dot);
return ret_val;
}
/** Determines the name of the preprocessed file from \a file_name.
* It is assumed that \a file_name has ttcnpp suffix.
* The returned string shall be deallocated by the caller. */
static char *get_preprocessed_file_name(const char *file_name)
{
char *ret_val = cut_suffix(file_name);
ret_val = mputstr(ret_val, ".ttcn");
return ret_val;
}
/** Check if any of the preprocessed ttcn file names with the preprocessed
* (TTCN-3) suffix is equal to any other file given in the \a makefile */
static void check_preprocessed_filename_collision(
struct makefile_struct *makefile)
{
size_t i;
if (makefile->nTTCN3PPModules == 0) {
WARNING("TTCN-3 preprocessing (option `-p') is enabled, but no TTCN-3 "
"files to be preprocessed were given for the Makefile.");
}
for (i = 0; i < makefile->nTTCN3PPModules; i++) {
const struct module_struct *pp_module = makefile->TTCN3PPModules + i;
/* name of the intermediate preprocessed file */
char *preprocessed_name = get_preprocessed_file_name(pp_module->file_name);
size_t j;
for (j = 0; j < makefile->nTTCN3Modules; j++) {
struct module_struct *module = makefile->TTCN3Modules + j;
if (is_same_file(pp_module->dir_name, preprocessed_name,
module->dir_name, module->file_name)) {
if (is_same_module(pp_module->module_name, module->module_name)) {
/* same file with the same module */
char *pp_pathname = compose_path_name(pp_module->dir_name,
pp_module->file_name);
char *m_pathname = compose_path_name(module->dir_name,
module->file_name);
WARNING("File `%s' containing TTCN-3 module `%s' is generated by "
"the preprocessor from `%s'. Removing the file from the list of "
"normal TTCN-3 modules.", m_pathname, module->module_name,
pp_pathname);
Free(pp_pathname);
Free(m_pathname);
Free(module->dir_name);
Free(module->file_name);
Free(module->module_name);
makefile->nTTCN3Modules--;
memmove(module, module + 1, (makefile->nTTCN3Modules - j) *
sizeof(*makefile->TTCN3Modules));
makefile->TTCN3Modules =
(struct module_struct*)Realloc(makefile->TTCN3Modules,
makefile->nTTCN3Modules * sizeof(*makefile->TTCN3Modules));
} else {
/* same file with different module */
char *pp_pathname = compose_path_name(pp_module->dir_name,
pp_module->file_name);
char *m_pathname = compose_path_name(module->dir_name,
module->file_name);
ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
"with file `%s' containing TTCN-3 module `%s'.", pp_pathname,
pp_module->module_name, m_pathname, module->module_name);
Free(pp_pathname);
Free(m_pathname);
}
} else if (is_same_module(pp_module->module_name, module->module_name)) {
/* different file with the same module */
char *pp_pathname = compose_path_name(pp_module->dir_name,
pp_module->file_name);
char *m_pathname = compose_path_name(module->dir_name,
module->file_name);
ERROR("Both files `%s' and `%s' contain TTCN-3 module `%s'.",
pp_pathname, m_pathname, pp_module->module_name);
Free(pp_pathname);
Free(m_pathname);
}
}
for (j = 0; j < makefile->nASN1Modules; j++) {
struct module_struct *module = makefile->ASN1Modules + j;
if (is_same_file(pp_module->dir_name, preprocessed_name,
module->dir_name, module->file_name)) {
char *pp_pathname = compose_path_name(pp_module->dir_name,
pp_module->file_name);
char *m_pathname = compose_path_name(module->dir_name,
module->file_name);
ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
"with file `%s' containing ASN.1 module `%s'.", pp_pathname,
pp_module->module_name, m_pathname, module->module_name);
Free(pp_pathname);
Free(m_pathname);
}
}
for (j = 0; j < makefile->nXSDModules; j++) {
struct module_struct *module = makefile->XSDModules + j;
if (module->dir_name == NULL || module->file_name == NULL) {
continue;
}
if (is_same_file(pp_module->dir_name, preprocessed_name,
module->dir_name, module->file_name)) {
char *pp_pathname = compose_path_name(pp_module->dir_name,
pp_module->file_name);
char *m_pathname = compose_path_name(module->dir_name,
module->file_name);
ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
"with file `%s' containing TTCN-3 module `%s'.", pp_pathname,
pp_module->module_name, m_pathname, module->module_name);
Free(pp_pathname);
Free(m_pathname);
}
}
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
for (j = 0; j < makefile->nOtherFiles; j++) {
char *dir_name = get_dir_name(makefile->OtherFiles[j],
makefile->working_dir);
char *file_name = get_file_from_path(makefile->OtherFiles[j]);
if (is_same_file(pp_module->dir_name, preprocessed_name, dir_name,
file_name)) {
char *pp_pathname = compose_path_name(pp_module->dir_name,
pp_module->file_name);
ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
"with other file `%s'.", pp_pathname, pp_module->module_name,
makefile->OtherFiles[j]);
Free(pp_pathname);
}
Free(dir_name);
Free(file_name);
}
Free(preprocessed_name);
}
}
/** Checks the name clash between existing module \a module and newly added
* module with parameters \a path_name, \a dir_name, \a file_name,
* \a module_name. Both the existing and the new module shall be of the same
* kind, parameter \a kind shall contain the respective string (either "ASN.1"
* or "TTCN-3"). If a clash is found the parameters of the new module except
* \a path_name are deallocated and TRUE is returned. Otherwise FALSE is
* returned. */
static boolean check_module_clash_same(const struct module_struct *module,
const char *kind, const char *path_name, char *dir_name, char *file_name,
char *module_name)
{
if (is_same_module(module_name, module->module_name)) {
if (is_same_file(dir_name, file_name,
module->dir_name, module->file_name)) {
/* the same file was given twice: just issue a warning */
WARNING("File `%s' was given more than once for the Makefile.",
path_name);
} else {
/* two different files contain the same module: this cannot be
* resolved as the generated C++ files will clash */
char *path_name1 = compose_path_name(module->dir_name,
module->file_name);
char *path_name2 = compose_path_name(dir_name, file_name);
ERROR("Both files `%s' and `%s' contain %s module `%s'.",
path_name1, path_name2, kind, module_name);
Free(path_name1);
Free(path_name2);
}
Free(file_name);
Free(dir_name);
Free(module_name);
return TRUE;
} else return FALSE;
}
/** Checks the name clash between existing module \a module and newly added
* module with parameters \a dir_name, \a file_name, \a module_name. The two
* modules shall be of different kinds (one is ASN.1, the other is TTCN-3).
* Parameters \a kind1 and \a kind2 shall contain the respective strings. If a
* clash is found the parameters of the new module are deallocated and TRUE is
* returned. Otherwise FALSE is returned. */
static boolean check_module_clash_different(const struct module_struct *module,
const char *kind1, char *dir_name, char *file_name, char *module_name,
const char *kind2)
{
if (is_same_module(module_name, module->module_name)) {
/* two different files contain the same module: this cannot be resolved
* as the generated C++ files will clash */
char *path_name1 = compose_path_name(module->dir_name, module->file_name);
char *path_name2 = compose_path_name(dir_name, file_name);
ERROR("File `%s' containing %s module `%s' and file `%s' containing "
"%s module `%s' cannot be used together in the same Makefile.",
path_name1, kind1, module->module_name, path_name2, kind2, module_name);
Free(path_name1);
Free(path_name2);
Free(file_name);
Free(dir_name);
Free(module_name);
return TRUE;
} else return FALSE;
}
/** Adds a TTCN-3 module to Makefile descriptor structure \a makefile.
* The name of the TTCN-3 source file is \a path_name, the module identifier
* is \a module_name. It is checked whether a file or module with the same name
* already exists in \a makefile and an appropriate warning or error is
* reported. */
static void add_ttcn3_module(struct makefile_struct *makefile,
const char *path_name, char *module_name)
{
struct module_struct *module;
char *dir_name = get_dir_name(path_name, makefile->working_dir);
char *file_name = get_file_from_path(path_name);
const char *suffix = get_suffix(file_name);
size_t i;
boolean is_preprocessed = FALSE;
if (suffix != NULL) {
if (!strcmp(suffix, "ttcnpp")) {
if (makefile->preprocess) is_preprocessed = TRUE;
else WARNING("The suffix of TTCN-3 file `%s' indicates that it should be "
"preprocessed, but TTCN-3 preprocessing is not enabled. The file "
"will be added to the list of normal TTCN-3 modules in the Makefile.",
path_name);
} else if (!strcmp(suffix, "ttcnin")) {
WARNING("The suffix of file `%s' indicates that it should be a "
"preprocessor include file, but it contains a TTCN-3 module named `%s'. "
"The file will be added to the list of normal TTCN-3 modules in the "
"Makefile.", path_name, module_name);
}
}
for (i = 0; i < makefile->nASN1Modules; i++) {
if (check_module_clash_different(makefile->ASN1Modules + i, "ASN.1",
dir_name, file_name, module_name, "TTCN-3")) return;
}
/* never entered if suffix is NULL */
if (is_preprocessed) {
char *file_prefix;
for (i = 0; i < makefile->nTTCN3PPModules; i++) {
if (check_module_clash_same(makefile->TTCN3PPModules + i, "TTCN-3",
path_name, dir_name, file_name, module_name)) return;
}
for (i = 0; i < makefile->nXSDModules; i++) {
if (check_module_clash_different(makefile->XSDModules + i, "TTCN-3",
dir_name, file_name, module_name, "TTCN-3")) return;
}
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
/* clashes with normal TTCN-3 modules will be checked (and maybe resolved)
* in \a check_preprocessed_filename_collision() */
/* add it to the list of TTCN-3 modules to be preprocessed */
makefile->TTCN3PPModules = (struct module_struct*)
Realloc(makefile->TTCN3PPModules,
(makefile->nTTCN3PPModules + 1) * sizeof(*makefile->TTCN3PPModules));
module = makefile->TTCN3PPModules + makefile->nTTCN3PPModules;
makefile->nTTCN3PPModules++;
module->dir_name = dir_name;
module->file_name = file_name;
module->module_name = module_name;
file_prefix = cut_suffix(file_name);
if (!strcmp(file_prefix, module_name)) module->is_regular = TRUE;
else module->is_regular = FALSE;
Free(file_prefix);
} else {
/* the file is not preprocessed */
for (i = 0; i < makefile->nTTCN3Modules; i++) {
if (check_module_clash_same(makefile->TTCN3Modules + i, "TTCN-3",
path_name, dir_name, file_name, module_name)) return;
}
/* clashes with preprocessed TTCN-3 modules will be checked (and maybe
* resolved) in \a check_preprocessed_filename_collision() */
/* add it to the list of normal TTCN-3 modules */
makefile->TTCN3Modules = (struct module_struct*)
Realloc(makefile->TTCN3Modules,
(makefile->nTTCN3Modules + 1) * sizeof(*makefile->TTCN3Modules));
module = makefile->TTCN3Modules + makefile->nTTCN3Modules;
makefile->nTTCN3Modules++;
module->dir_name = dir_name;
module->file_name = file_name;
module->module_name = module_name;
if (suffix != NULL && !strcmp(suffix, "ttcn")) {
char *file_prefix = cut_suffix(file_name);
if (!strcmp(file_prefix, module_name)) module->is_regular = TRUE;
else module->is_regular = FALSE;
Free(file_prefix);
} else {
module->is_regular = FALSE;
}
}
}
/** ASN.1 filename shall contain no hyphen */
static boolean is_valid_asn1_filename(const char* file_name)
{
if (0 == strchr(file_name, '-')) {
return TRUE;
}
return FALSE;
}
/** Adds an ASN.1 module to Makefile descriptor structure \a makefile.
* The name of the ASN.1 source file is \a path_name, the module identifier
* is \a module_name. It is checked whether a file or module with the same name
* already exists in \a makefile and an appropriate warning or error is
* reported. */
static void add_asn1_module(struct makefile_struct *makefile,
const char *path_name, char *module_name)
{
struct module_struct *module;
char *dir_name = get_dir_name(path_name, makefile->working_dir);
char *file_name = get_file_from_path(path_name);
const char *suffix = get_suffix(file_name);
size_t i;
for (i = 0; i < makefile->nASN1Modules; i++) {
if (check_module_clash_same(makefile->ASN1Modules + i, "ASN.1", path_name,
dir_name, file_name, module_name)) return;
}
for (i = 0; i < makefile->nTTCN3Modules; i++) {
if (check_module_clash_different(makefile->TTCN3Modules + i, "TTCN-3",
dir_name, file_name, module_name, "ASN.1")) return;
}
if (makefile->preprocess) {
for (i = 0; i < makefile->nTTCN3PPModules; i++) {
if (check_module_clash_different(makefile->TTCN3PPModules + i, "TTCN-3",
dir_name, file_name, module_name, "ASN.1")) return;
}
}
for (i = 0; i < makefile->nXSDModules; i++) {
if (check_module_clash_different(makefile->XSDModules + i, "TTCN-3",
dir_name, file_name, module_name, "ASN.1")) return;
}
makefile->ASN1Modules = (struct module_struct*)
Realloc(makefile->ASN1Modules,
(makefile->nASN1Modules + 1) * sizeof(*makefile->ASN1Modules));
module = makefile->ASN1Modules + makefile->nASN1Modules;
makefile->nASN1Modules++;
module->dir_name = dir_name;
module->file_name = file_name;
module->module_name = module_name;
if (suffix != NULL && !strcmp(suffix, "asn")) {
char *file_prefix = cut_suffix(file_name);
/* replace all '_' with '-' in file name prefix */
for (i = 0; file_prefix[i] != '\0'; i++)
if (file_prefix[i] == '_') file_prefix[i] = '-';
if (!strcmp(file_prefix, module_name)) module->is_regular = TRUE;
else module->is_regular = FALSE;
Free(file_prefix);
} else {
module->is_regular = FALSE;
}
}
/** Adds an XSD module to Makefile descriptor structure \a makefile.
* The name of the XSD source file is \a path_name, the module identifier
* is \a module_name. It is checked whether a file or module with the same name
* already exists in \a makefile and an appropriate warning or error is
* reported. */
static void add_xsd_module(struct makefile_struct *makefile,