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 TTCN-3 compiler */
17 #include "../../common/memory.h"
18 #include "../../common/version_internal.h"
19 #include "../../common/path.h"
20 #include "../../common/userinfo.h"
26 #include "../../common/license.h"
32 #define COMMENT_PREFIX "// "
34 static unsigned int nof_updated_files
=0;
35 static unsigned int nof_uptodate_files
=0;
36 unsigned int nof_notupdated_files
=0;
38 static boolean
skip_over_lines(FILE *fp
, size_t nof_lines
)
41 while (i
< nof_lines
) {
54 static boolean
update_file(const char *file_name
, FILE *fp
, size_t skip_lines
)
56 boolean files_differ
= FALSE
;
58 FILE *target
= fopen(file_name
, "r");
59 if (target
== NULL
) files_differ
= TRUE
;
61 if (!files_differ
) files_differ
= skip_over_lines(target
, skip_lines
);
64 if (fseek(fp
, 0L, SEEK_SET
)) {
65 ERROR("Seek operation failed on a temporary file when trying to "
66 "update output file `%s': %s", file_name
, strerror(errno
));
68 files_differ
= skip_over_lines(fp
, skip_lines
);
72 /* compare the rest of the files */
74 char buf1
[BUFSIZE
], buf2
[BUFSIZE
];
75 int len1
= fread(buf1
, 1, BUFSIZE
, fp
);
76 int len2
= fread(buf2
, 1, BUFSIZE
, target
);
77 if ((len1
!= len2
) || memcmp(buf1
, buf2
, len1
)) {
80 } else if (len1
< BUFSIZE
) break;
84 if (target
!= NULL
) fclose(target
);
87 if (fseek(fp
, 0L, SEEK_SET
)) {
88 ERROR("Seek operation failed on a temporary file when trying to "
89 "update output file `%s': %s", file_name
, strerror(errno
));
91 target
= fopen(file_name
, "w");
93 ERROR("Cannot open output file `%s' for writing: %s", file_name
,
97 /* copy the contents of fp into target */
100 size_t len
= fread(buf
, 1, BUFSIZE
, fp
);
101 if (fwrite(buf
, 1, len
, target
) != len
) {
102 ERROR("Cannot write to output file `%s': %s", file_name
,
106 if (len
< BUFSIZE
) break;
114 FILE *open_output_file(const char *file_name
, boolean
*is_temporary
)
117 switch (get_path_status(file_name
)) {
119 if (force_overwrite
) *is_temporary
= FALSE
;
120 else *is_temporary
= TRUE
;
123 ERROR("Output file `%s' is a directory", file_name
);
127 *is_temporary
= FALSE
;
132 ERROR("Creation of a temporary file failed when trying to update "
133 "output file `%s': %s", file_name
, strerror(errno
));
137 fp
= fopen(file_name
, "w");
139 ERROR("Cannot open output file `%s' for writing: %s", file_name
,
147 void close_output_file(const char *file_name
, FILE *fp
,
148 boolean is_temporary
, size_t skip_lines
)
151 if (update_file(file_name
, fp
, skip_lines
)) {
152 NOTIFY("File `%s' was updated.", file_name
);
155 if (display_up_to_date
) {
156 NOTIFY("File `%s' was up-to-date.", file_name
);
158 DEBUG(1, "File `%s' was up-to-date.", file_name
);
160 nof_uptodate_files
++;
163 NOTIFY("File `%s' was generated.", file_name
);
169 void write_output(output_struct
*output
, const char *module_name
,
170 const char *module_dispname
, const char *filename_suffix
, boolean is_ttcn
,
171 boolean has_circular_import
, boolean is_module
)
173 char *header_name
, *source_name
, *user_info
;
175 boolean is_temporary
;
177 if (output_dir
!= NULL
) {
178 header_name
= mprintf("%s/%s%s.hh", output_dir
,
179 duplicate_underscores
? module_name
: module_dispname
,
181 source_name
= mprintf("%s/%s%s.cc", output_dir
,
182 duplicate_underscores
? module_name
: module_dispname
,
185 header_name
= mprintf("%s%s.hh",
186 duplicate_underscores
? module_name
: module_dispname
,
188 source_name
= mprintf("%s%s.cc",
189 duplicate_underscores
? module_name
: module_dispname
,
192 user_info
= get_user_info();
196 DEBUG(1, "Writing file `%s' ... ", header_name
);
198 fp
= open_output_file(header_name
, &is_temporary
);
200 fprintf(fp
, "// This C++ header file was generated by the %s compiler\n"
201 "// of the TTCN-3 Test Executor version " PRODUCT_NUMBER
"\n"
203 COPYRIGHT_STRING
"\n\n"
204 "// Do not edit this file unless you know what you are doing.\n\n"
207 is_ttcn
? "TTCN-3" : "ASN.1",
208 user_info
, module_name
, module_name
);
210 /* check if the generated code matches the runtime */
212 "#if%sdef TITAN_RUNTIME_2\n"
213 "#error Generated code does not match with used runtime.\\\n"
216 use_runtime_2
? "n" : "",
218 "Code was generated with -R option but -DTITAN_RUNTIME_2 was not used.":
219 "Code was generated without -R option but -DTITAN_RUNTIME_2 was used.");
221 /* #include directives must be the first in order to make GCC's
222 * precompiled headers working. */
223 if (output
->header
.includes
!= NULL
) {
224 fputs("\n/* Header file includes */\n\n", fp
);
225 fputs(output
->header
.includes
, fp
);
227 "#if TTCN3_VERSION != %d\n"
228 "#error Version mismatch detected.\\\n"
229 " Please check the version of the %s compiler and the "
232 TTCN3_VERSION
, is_ttcn
? "TTCN-3" : "ASN.1");
233 /* Check the platform matches */
234 #if defined SOLARIS || defined SOLARIS8
235 fputs("#if !defined SOLARIS && !defined SOLARIS8 \n",fp
);
236 fputs(" #error This file should be compiled on SOLARIS or SOLARIS8 \n",fp
);
237 fputs("#endif \n",fp
);
242 "#error This file should be compiled on %s\n"
243 "#endif\n", expected_platform
, expected_platform
);
249 if (!has_circular_import
)
250 fprintf(fp
, "\nnamespace %s {\n", module_name
);
252 if (output
->header
.class_decls
!= NULL
) {
253 if (has_circular_import
) {
254 fprintf(fp
, "\n#undef %s_HH\n"
255 "#endif\n", module_name
);
256 fprintf(fp
, "\nnamespace %s {\n", module_name
);
258 fputs("\n/* Forward declarations of classes */\n\n",fp
);
259 fputs(output
->header
.class_decls
, fp
);
260 if (has_circular_import
) {
261 fputs("\n} /* end of namespace */\n", fp
);
262 fprintf(fp
, "\n#ifndef %s_HH\n"
263 "#define %s_HH\n", module_name
, module_name
);
267 if (has_circular_import
)
268 fprintf(fp
, "\nnamespace %s {\n", module_name
);
270 if (output
->header
.typedefs
!= NULL
) {
271 fputs("\n/* Type definitions */\n\n", fp
);
272 fputs(output
->header
.typedefs
, fp
);
275 if (output
->header
.class_defs
!= NULL
) {
276 fputs("\n/* Class definitions */\n\n", fp
);
277 fputs(output
->header
.class_defs
, fp
);
280 if (output
->header
.function_prototypes
!= NULL
) {
281 fputs("\n/* Function prototypes */\n\n", fp
);
282 fputs(output
->header
.function_prototypes
, fp
);
285 if (output
->header
.global_vars
!= NULL
) {
286 fputs("\n/* Global variable declarations */\n\n", fp
);
287 fputs(output
->header
.global_vars
, fp
);
290 fputs("\n} /* end of namespace */\n", fp
);
292 if (output
->header
.testport_includes
!= NULL
) {
293 fputs("\n/* Test port header files */\n\n", fp
);
294 fputs(output
->header
.testport_includes
, fp
);
297 fputs("\n#endif\n", fp
);
299 close_output_file(header_name
, fp
, is_temporary
, 10);
303 DEBUG(1, "Writing file `%s' ... ", source_name
);
305 fp
= open_output_file(source_name
, &is_temporary
);
307 fprintf(fp
, "// This C++ source file was generated by the %s compiler\n"
308 "// of the TTCN-3 Test Executor version " PRODUCT_NUMBER
"\n"
310 COPYRIGHT_STRING
"\n\n"
311 "// Do not edit this file unless you know what you are doing.\n",
312 is_ttcn
? "TTCN-3" : "ASN.1", user_info
);
314 if (profiler_enabled
) {
315 output
->source
.includes
= mputstr(output
->source
.includes
, "#include \"Profiler.hh\"\n");
318 if (output
->source
.includes
!= NULL
) {
319 fputs("\n/* Including header files */\n\n", fp
);
320 fputs(output
->source
.includes
, fp
);
323 fprintf(fp
, "\nnamespace %s {\n", module_name
);
325 if (output
->source
.static_function_prototypes
!= NULL
) {
326 fputs("\n/* Prototypes of static functions */\n\n", fp
);
327 fputs(output
->source
.static_function_prototypes
, fp
);
330 if (output
->source
.static_conversion_function_prototypes
!= NULL
) {
331 fputs("\n/* Prototypes of static conversion functions */\n\n", fp
);
332 fputs(output
->source
.static_conversion_function_prototypes
, fp
);
335 if (output
->source
.string_literals
!= NULL
) {
336 fputs("\n/* Literal string constants */\n\n", fp
);
337 fputs(output
->source
.string_literals
, fp
);
340 if (output
->source
.class_defs
!= NULL
) {
341 fputs("\n/* Class definitions for internal use */\n\n", fp
);
342 fputs(output
->source
.class_defs
, fp
);
345 if (output
->source
.global_vars
!= NULL
) {
346 fputs("\n/* Global variable definitions */\n\n", fp
);
347 fputs(output
->source
.global_vars
, fp
);
350 if (output
->source
.methods
!= NULL
) {
351 fputs("\n/* Member functions of C++ classes */\n\n", fp
);
352 fputs(output
->source
.methods
, fp
);
355 if (output
->source
.function_bodies
!= NULL
) {
356 fputs("\n/* Bodies of functions, altsteps and testcases */\n\n", fp
);
357 fputs(output
->source
.function_bodies
, fp
);
360 if (output
->source
.static_function_bodies
!= NULL
) {
361 fputs("\n/* Bodies of static functions */\n\n", fp
);
362 fputs(output
->source
.static_function_bodies
, fp
);
365 if (output
->source
.static_conversion_function_bodies
!= NULL
) {
366 fputs("\n/* Bodies of static conversion functions */\n\n", fp
);
367 fputs(output
->source
.static_conversion_function_bodies
, fp
);
370 fputs("\n} /* end of namespace */\n", fp
);
372 close_output_file(source_name
, fp
, is_temporary
, 7);
379 void report_nof_updated_files(void)
381 DEBUG(1, "%u files updated, %u were up-to-date, %u excluded from code"
383 nof_updated_files
, nof_uptodate_files
, nof_notupdated_files
);
384 if(nof_updated_files
!=0)
385 NOTIFY("%u file%s updated.", nof_updated_files
,
386 nof_updated_files
> 1 ? "s were" : " was");
388 NOTIFY("None of the files needed update.");