Merge pull request #51 from BenceJanosSzabo/master
[deliverable/titan.core.git] / compiler2 / ttcn3 / compiler.c
1 /******************************************************************************
2 * Copyright (c) 2000-2016 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 * Contributors:
9 * Baji, Laszlo
10 * Balasko, Jeno
11 * Baranyi, Botond
12 * Cserveni, Akos
13 * Delic, Adam
14 * Forstner, Matyas
15 * Kovacs, Ferenc
16 * Kremer, Peter
17 * Lovassy, Arpad
18 * Raduly, Csaba
19 * Szabados, Kristof
20 * Szabo, Janos Zoltan – initial implementation
21 * Zalanyi, Balazs Andor
22 * Pandi, Krisztian
23 *
24 ******************************************************************************/
25 /* Main program for the TTCN-3 compiler */
26
27 /* C declarations */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33
34 #include "../../common/memory.h"
35 #include "../../common/version_internal.h"
36 #include "../../common/path.h"
37 #include "../../common/userinfo.h"
38 #include "compiler.h"
39 #include "../main.hh"
40 #include "../error.h"
41 #include "profiler.h"
42
43 #ifdef LICENSE
44 #include "../../common/license.h"
45 #endif
46
47 #define BUFSIZE 1024
48
49 #undef COMMENT_PREFIX
50 #define COMMENT_PREFIX "// "
51
52 static unsigned int nof_updated_files=0;
53 static unsigned int nof_uptodate_files=0;
54 unsigned int nof_notupdated_files=0;
55
56 static boolean skip_over_lines(FILE *fp, size_t nof_lines)
57 {
58 size_t i = 0;
59 while (i < nof_lines) {
60 switch (getc(fp)) {
61 case EOF:
62 return TRUE;
63 case '\n':
64 i++;
65 default:
66 break;
67 }
68 }
69 return FALSE;
70 }
71
72 static boolean update_file(const char *file_name, FILE *fp, size_t skip_lines)
73 {
74 boolean files_differ = FALSE;
75
76 FILE *target = fopen(file_name, "r");
77 if (target == NULL) files_differ = TRUE;
78
79 if (!files_differ) files_differ = skip_over_lines(target, skip_lines);
80
81 if (!files_differ) {
82 if (fseek(fp, 0L, SEEK_SET)) {
83 ERROR("Seek operation failed on a temporary file when trying to "
84 "update output file `%s': %s", file_name, strerror(errno));
85 }
86 files_differ = skip_over_lines(fp, skip_lines);
87 }
88
89 if (!files_differ) {
90 /* compare the rest of the files */
91 for ( ; ; ) {
92 char buf1[BUFSIZE], buf2[BUFSIZE];
93 int len1 = fread(buf1, 1, BUFSIZE, fp);
94 int len2 = fread(buf2, 1, BUFSIZE, target);
95 if ((len1 != len2) || memcmp(buf1, buf2, len1)) {
96 files_differ = TRUE;
97 break;
98 } else if (len1 < BUFSIZE) break;
99 }
100 }
101
102 if (target != NULL) fclose(target);
103
104 if (files_differ) {
105 if (fseek(fp, 0L, SEEK_SET)) {
106 ERROR("Seek operation failed on a temporary file when trying to "
107 "update output file `%s': %s", file_name, strerror(errno));
108 }
109 target = fopen(file_name, "w");
110 if (target == NULL) {
111 ERROR("Cannot open output file `%s' for writing: %s", file_name,
112 strerror(errno));
113 exit(EXIT_FAILURE);
114 }
115 /* copy the contents of fp into target */
116 for ( ; ; ) {
117 char buf[BUFSIZE];
118 size_t len = fread(buf, 1, BUFSIZE, fp);
119 if (fwrite(buf, 1, len, target) != len) {
120 ERROR("Cannot write to output file `%s': %s", file_name,
121 strerror(errno));
122 exit(EXIT_FAILURE);
123 }
124 if (len < BUFSIZE) break;
125 }
126 fclose(target);
127 }
128
129 return files_differ;
130 }
131
132 FILE *open_output_file(const char *file_name, boolean *is_temporary)
133 {
134 FILE *fp;
135 switch (get_path_status(file_name)) {
136 case PS_FILE:
137 if (force_overwrite) *is_temporary = FALSE;
138 else *is_temporary = TRUE;
139 break;
140 case PS_DIRECTORY:
141 ERROR("Output file `%s' is a directory", file_name);
142 exit(EXIT_FAILURE);
143 break;
144 case PS_NONEXISTENT:
145 *is_temporary = FALSE;
146 }
147 if (*is_temporary) {
148 fp = tmpfile();
149 if (fp == NULL) {
150 ERROR("Creation of a temporary file failed when trying to update "
151 "output file `%s': %s", file_name, strerror(errno));
152 exit(EXIT_FAILURE);
153 }
154 } else {
155 fp = fopen(file_name, "w");
156 if (fp == NULL) {
157 ERROR("Cannot open output file `%s' for writing: %s", file_name,
158 strerror(errno));
159 exit(EXIT_FAILURE);
160 }
161 }
162 return fp;
163 }
164
165 void close_output_file(const char *file_name, FILE *fp,
166 boolean is_temporary, size_t skip_lines)
167 {
168 if (is_temporary) {
169 if (update_file(file_name, fp, skip_lines)) {
170 NOTIFY("File `%s' was updated.", file_name);
171 nof_updated_files++;
172 } else {
173 if (display_up_to_date) {
174 NOTIFY("File `%s' was up-to-date.", file_name);
175 } else {
176 DEBUG(1, "File `%s' was up-to-date.", file_name);
177 }
178 nof_uptodate_files++;
179 }
180 } else {
181 NOTIFY("File `%s' was generated.", file_name);
182 nof_updated_files++;
183 }
184 fclose(fp);
185 }
186
187 void write_output(output_struct *output, const char *module_name,
188 const char *module_dispname, const char *filename_suffix, boolean is_ttcn,
189 boolean has_circular_import, boolean is_module)
190 {
191 char *header_name, *source_name, *user_info;
192 FILE *fp;
193 boolean is_temporary;
194
195 if (output_dir != NULL) {
196 header_name = mprintf("%s/%s%s.hh", output_dir,
197 duplicate_underscores ? module_name : module_dispname,
198 filename_suffix);
199 source_name = mprintf("%s/%s%s.cc", output_dir,
200 duplicate_underscores ? module_name : module_dispname,
201 filename_suffix);
202 } else {
203 header_name = mprintf("%s%s.hh",
204 duplicate_underscores ? module_name : module_dispname,
205 filename_suffix);
206 source_name = mprintf("%s%s.cc",
207 duplicate_underscores ? module_name : module_dispname,
208 filename_suffix);
209 }
210 user_info = get_user_info();
211
212 if (is_module) {
213
214 DEBUG(1, "Writing file `%s' ... ", header_name);
215
216 fp = open_output_file(header_name, &is_temporary);
217
218 fprintf(fp, "// This C++ header file was generated by the %s compiler\n"
219 "// of the TTCN-3 Test Executor version " PRODUCT_NUMBER "\n"
220 "// for %s\n"
221 COPYRIGHT_STRING "\n\n"
222 "// Do not edit this file unless you know what you are doing.\n\n"
223 "#ifndef %s_HH\n"
224 "#define %s_HH\n",
225 is_ttcn ? "TTCN-3" : "ASN.1",
226 user_info, module_name, module_name);
227
228 /* check if the generated code matches the runtime */
229 fprintf(fp, "\n"
230 "#if%sdef TITAN_RUNTIME_2\n"
231 "#error Generated code does not match with used runtime.\\\n"
232 " %s\n"
233 "#endif\n",
234 use_runtime_2 ? "n" : "",
235 use_runtime_2 ?
236 "Code was generated with -R option but -DTITAN_RUNTIME_2 was not used.":
237 "Code was generated without -R option but -DTITAN_RUNTIME_2 was used.");
238
239 /* #include directives must be the first in order to make GCC's
240 * precompiled headers working. */
241 if (output->header.includes != NULL) {
242 fputs("\n/* Header file includes */\n\n", fp);
243 fputs(output->header.includes, fp);
244 fprintf(fp, "\n"
245 "#if TTCN3_VERSION != %d\n"
246 "#error Version mismatch detected.\\\n"
247 " Please check the version of the %s compiler and the "
248 "base library.\n"
249 "#endif\n",
250 TTCN3_VERSION, is_ttcn ? "TTCN-3" : "ASN.1");
251 /* Check the platform matches */
252 #if defined SOLARIS || defined SOLARIS8
253 fputs("#if !defined SOLARIS && !defined SOLARIS8 \n",fp);
254 fputs(" #error This file should be compiled on SOLARIS or SOLARIS8 \n",fp);
255 fputs("#endif \n",fp);
256
257 #else
258 fprintf(fp, "\n"
259 "#ifndef %s\n"
260 "#error This file should be compiled on %s\n"
261 "#endif\n", expected_platform, expected_platform);
262 #endif
263 }
264
265
266
267 if (!has_circular_import)
268 fprintf(fp, "\nnamespace %s {\n", module_name);
269
270 if (output->header.class_decls != NULL) {
271 if (has_circular_import) {
272 fprintf(fp, "\n#undef %s_HH\n"
273 "#endif\n", module_name);
274 fprintf(fp, "\nnamespace %s {\n", module_name);
275 }
276 fputs("\n/* Forward declarations of classes */\n\n",fp);
277 fputs(output->header.class_decls, fp);
278 if (has_circular_import) {
279 fputs("\n} /* end of namespace */\n", fp);
280 fprintf(fp, "\n#ifndef %s_HH\n"
281 "#define %s_HH\n", module_name, module_name);
282 }
283 }
284
285 if (has_circular_import)
286 fprintf(fp, "\nnamespace %s {\n", module_name);
287
288 if (output->header.typedefs != NULL) {
289 fputs("\n/* Type definitions */\n\n", fp);
290 fputs(output->header.typedefs, fp);
291 }
292
293 if (output->header.class_defs != NULL) {
294 fputs("\n/* Class definitions */\n\n", fp);
295 fputs(output->header.class_defs, fp);
296 }
297
298 if (output->header.function_prototypes != NULL) {
299 fputs("\n/* Function prototypes */\n\n", fp);
300 fputs(output->header.function_prototypes, fp);
301 }
302
303 if (output->header.global_vars != NULL) {
304 fputs("\n/* Global variable declarations */\n\n", fp);
305 fputs(output->header.global_vars, fp);
306 }
307
308 fputs("\n} /* end of namespace */\n", fp);
309
310 if (output->header.testport_includes != NULL) {
311 fputs("\n/* Test port header files */\n\n", fp);
312 fputs(output->header.testport_includes, fp);
313 }
314
315 fputs("\n#endif\n", fp);
316
317 close_output_file(header_name, fp, is_temporary, 10);
318
319 }
320
321 DEBUG(1, "Writing file `%s' ... ", source_name);
322
323 fp = open_output_file(source_name, &is_temporary);
324
325 fprintf(fp, "// This C++ source file was generated by the %s compiler\n"
326 "// of the TTCN-3 Test Executor version " PRODUCT_NUMBER "\n"
327 "// for %s\n"
328 COPYRIGHT_STRING "\n\n"
329 "// Do not edit this file unless you know what you are doing.\n",
330 is_ttcn ? "TTCN-3" : "ASN.1", user_info);
331
332 if (output->source.includes != NULL) {
333 fputs("\n/* Including header files */\n\n", fp);
334 fputs(output->source.includes, fp);
335 }
336
337 fprintf(fp, "\nnamespace %s {\n", module_name);
338
339 if (output->source.static_function_prototypes != NULL) {
340 fputs("\n/* Prototypes of static functions */\n\n", fp);
341 fputs(output->source.static_function_prototypes, fp);
342 }
343
344 if (output->source.static_conversion_function_prototypes != NULL) {
345 fputs("\n/* Prototypes of static conversion functions */\n\n", fp);
346 fputs(output->source.static_conversion_function_prototypes, fp);
347 }
348
349 if (output->source.string_literals != NULL) {
350 fputs("\n/* Literal string constants */\n\n", fp);
351 fputs(output->source.string_literals, fp);
352 }
353
354 if (output->source.class_defs != NULL) {
355 fputs("\n/* Class definitions for internal use */\n\n", fp);
356 fputs(output->source.class_defs, fp);
357 }
358
359 if (output->source.global_vars != NULL) {
360 fputs("\n/* Global variable definitions */\n\n", fp);
361 fputs(output->source.global_vars, fp);
362 }
363
364 if (output->source.methods != NULL) {
365 fputs("\n/* Member functions of C++ classes */\n\n", fp);
366 fputs(output->source.methods, fp);
367 }
368
369 if (output->source.function_bodies != NULL) {
370 fputs("\n/* Bodies of functions, altsteps and testcases */\n\n", fp);
371 fputs(output->source.function_bodies, fp);
372 }
373
374 if (output->source.static_function_bodies != NULL) {
375 fputs("\n/* Bodies of static functions */\n\n", fp);
376 fputs(output->source.static_function_bodies, fp);
377 }
378
379 if (output->source.static_conversion_function_bodies != NULL) {
380 fputs("\n/* Bodies of static conversion functions */\n\n", fp);
381 fputs(output->source.static_conversion_function_bodies, fp);
382 }
383
384 fputs("\n} /* end of namespace */\n", fp);
385
386 close_output_file(source_name, fp, is_temporary, 7);
387
388 Free(header_name);
389 Free(source_name);
390 Free(user_info);
391 }
392
393 void report_nof_updated_files(void)
394 {
395 DEBUG(1, "%u files updated, %u were up-to-date, %u excluded from code"
396 " generation.",
397 nof_updated_files, nof_uptodate_files, nof_notupdated_files);
398 if(nof_updated_files!=0)
399 NOTIFY("%u file%s updated.", nof_updated_files,
400 nof_updated_files > 1 ? "s were" : " was");
401 else
402 NOTIFY("None of the files needed update.");
403 }
This page took 0.03913 seconds and 5 git commands to generate.