Sync with 5.2.0
[deliverable/titan.core.git] / compiler2 / ttcn3 / compiler.c
CommitLineData
970ed795
EL
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 */
9
10/* C declarations */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <errno.h>
16
17#include "../../common/memory.h"
18#include "../../common/version_internal.h"
19#include "../../common/path.h"
20#include "../../common/userinfo.h"
21#include "compiler.h"
22#include "../main.hh"
23#include "../error.h"
24
25#ifdef LICENSE
26#include "../../common/license.h"
27#endif
28
29#define BUFSIZE 1024
30
31#undef COMMENT_PREFIX
32#define COMMENT_PREFIX "// "
33
34static unsigned int nof_updated_files=0;
35static unsigned int nof_uptodate_files=0;
36unsigned int nof_notupdated_files=0;
37
38static boolean skip_over_lines(FILE *fp, size_t nof_lines)
39{
40 size_t i = 0;
41 while (i < nof_lines) {
42 switch (getc(fp)) {
43 case EOF:
44 return TRUE;
45 case '\n':
46 i++;
47 default:
48 break;
49 }
50 }
51 return FALSE;
52}
53
54static boolean update_file(const char *file_name, FILE *fp, size_t skip_lines)
55{
56 boolean files_differ = FALSE;
57
58 FILE *target = fopen(file_name, "r");
59 if (target == NULL) files_differ = TRUE;
60
61 if (!files_differ) files_differ = skip_over_lines(target, skip_lines);
62
63 if (!files_differ) {
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));
67 }
68 files_differ = skip_over_lines(fp, skip_lines);
69 }
70
71 if (!files_differ) {
72 /* compare the rest of the files */
73 for ( ; ; ) {
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)) {
78 files_differ = TRUE;
79 break;
80 } else if (len1 < BUFSIZE) break;
81 }
82 }
83
84 if (target != NULL) fclose(target);
85
86 if (files_differ) {
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));
90 }
91 target = fopen(file_name, "w");
92 if (target == NULL) {
93 ERROR("Cannot open output file `%s' for writing: %s", file_name,
94 strerror(errno));
95 exit(EXIT_FAILURE);
96 }
97 /* copy the contents of fp into target */
98 for ( ; ; ) {
99 char buf[BUFSIZE];
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,
103 strerror(errno));
104 exit(EXIT_FAILURE);
105 }
106 if (len < BUFSIZE) break;
107 }
108 fclose(target);
109 }
110
111 return files_differ;
112}
113
114FILE *open_output_file(const char *file_name, boolean *is_temporary)
115{
116 FILE *fp;
117 switch (get_path_status(file_name)) {
118 case PS_FILE:
119 if (force_overwrite) *is_temporary = FALSE;
120 else *is_temporary = TRUE;
121 break;
122 case PS_DIRECTORY:
123 ERROR("Output file `%s' is a directory", file_name);
124 exit(EXIT_FAILURE);
125 break;
126 case PS_NONEXISTENT:
127 *is_temporary = FALSE;
128 }
129 if (*is_temporary) {
130 fp = tmpfile();
131 if (fp == NULL) {
132 ERROR("Creation of a temporary file failed when trying to update "
133 "output file `%s': %s", file_name, strerror(errno));
134 exit(EXIT_FAILURE);
135 }
136 } else {
137 fp = fopen(file_name, "w");
138 if (fp == NULL) {
139 ERROR("Cannot open output file `%s' for writing: %s", file_name,
140 strerror(errno));
141 exit(EXIT_FAILURE);
142 }
143 }
144 return fp;
145}
146
147void close_output_file(const char *file_name, FILE *fp,
148 boolean is_temporary, size_t skip_lines)
149{
150 if (is_temporary) {
151 if (update_file(file_name, fp, skip_lines)) {
152 NOTIFY("File `%s' was updated.", file_name);
153 nof_updated_files++;
154 } else {
155 if (display_up_to_date) {
156 NOTIFY("File `%s' was up-to-date.", file_name);
157 } else {
158 DEBUG(1, "File `%s' was up-to-date.", file_name);
159 }
160 nof_uptodate_files++;
161 }
162 } else {
163 NOTIFY("File `%s' was generated.", file_name);
164 nof_updated_files++;
165 }
166 fclose(fp);
167}
168
169void 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)
172{
173 char *header_name, *source_name, *user_info;
174 FILE *fp;
175 boolean is_temporary;
176
177 if (output_dir != NULL) {
178 header_name = mprintf("%s/%s%s.hh", output_dir,
179 duplicate_underscores ? module_name : module_dispname,
180 filename_suffix);
181 source_name = mprintf("%s/%s%s.cc", output_dir,
182 duplicate_underscores ? module_name : module_dispname,
183 filename_suffix);
184 } else {
185 header_name = mprintf("%s%s.hh",
186 duplicate_underscores ? module_name : module_dispname,
187 filename_suffix);
188 source_name = mprintf("%s%s.cc",
189 duplicate_underscores ? module_name : module_dispname,
190 filename_suffix);
191 }
192 user_info = get_user_info();
193
194 if (is_module) {
195
196 DEBUG(1, "Writing file `%s' ... ", header_name);
197
198 fp = open_output_file(header_name, &is_temporary);
199
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"
202 "// for %s\n"
203 COPYRIGHT_STRING "\n\n"
204 "// Do not edit this file unless you know what you are doing.\n\n"
205 "#ifndef %s_HH\n"
206 "#define %s_HH\n",
207 is_ttcn ? "TTCN-3" : "ASN.1",
208 user_info, module_name, module_name);
209
210 /* check if the generated code matches the runtime */
211 fprintf(fp, "\n"
212 "#if%sdef TITAN_RUNTIME_2\n"
213 "#error Generated code does not match with used runtime.\\\n"
214 " %s\n"
215 "#endif\n",
216 use_runtime_2 ? "n" : "",
217 use_runtime_2 ?
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.");
220
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);
226 fprintf(fp, "\n"
227 "#if TTCN3_VERSION != %d\n"
228 "#error Version mismatch detected.\\\n"
229 " Please check the version of the %s compiler and the "
230 "base library.\n"
231 "#endif\n",
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);
238
239#else
240 fprintf(fp, "\n"
241 "#ifndef %s\n"
242 "#error This file should be compiled on %s\n"
243 "#endif\n", expected_platform, expected_platform);
244#endif
245 }
246
247
248
249 if (!has_circular_import)
250 fprintf(fp, "\nnamespace %s {\n", module_name);
251
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);
257 }
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);
264 }
265 }
266
267 if (has_circular_import)
268 fprintf(fp, "\nnamespace %s {\n", module_name);
269
270 if (output->header.typedefs != NULL) {
271 fputs("\n/* Type definitions */\n\n", fp);
272 fputs(output->header.typedefs, fp);
273 }
274
275 if (output->header.class_defs != NULL) {
276 fputs("\n/* Class definitions */\n\n", fp);
277 fputs(output->header.class_defs, fp);
278 }
279
280 if (output->header.function_prototypes != NULL) {
281 fputs("\n/* Function prototypes */\n\n", fp);
282 fputs(output->header.function_prototypes, fp);
283 }
284
285 if (output->header.global_vars != NULL) {
286 fputs("\n/* Global variable declarations */\n\n", fp);
287 fputs(output->header.global_vars, fp);
288 }
289
290 fputs("\n} /* end of namespace */\n", fp);
291
292 if (output->header.testport_includes != NULL) {
293 fputs("\n/* Test port header files */\n\n", fp);
294 fputs(output->header.testport_includes, fp);
295 }
296
297 fputs("\n#endif\n", fp);
298
299 close_output_file(header_name, fp, is_temporary, 10);
300
301 }
302
303 DEBUG(1, "Writing file `%s' ... ", source_name);
304
305 fp = open_output_file(source_name, &is_temporary);
306
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"
309 "// for %s\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);
af710487 313
314 if (profiler_enabled) {
315 output->source.includes = mputstr(output->source.includes, "#include \"Profiler.hh\"\n");
316 }
970ed795
EL
317
318 if (output->source.includes != NULL) {
319 fputs("\n/* Including header files */\n\n", fp);
320 fputs(output->source.includes, fp);
321 }
322
323 fprintf(fp, "\nnamespace %s {\n", module_name);
324
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);
328 }
329
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);
333 }
334
335 if (output->source.string_literals != NULL) {
336 fputs("\n/* Literal string constants */\n\n", fp);
337 fputs(output->source.string_literals, fp);
338 }
339
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);
343 }
344
345 if (output->source.global_vars != NULL) {
346 fputs("\n/* Global variable definitions */\n\n", fp);
347 fputs(output->source.global_vars, fp);
348 }
349
350 if (output->source.methods != NULL) {
351 fputs("\n/* Member functions of C++ classes */\n\n", fp);
352 fputs(output->source.methods, fp);
353 }
354
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);
358 }
359
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);
363 }
364
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);
368 }
369
370 fputs("\n} /* end of namespace */\n", fp);
371
372 close_output_file(source_name, fp, is_temporary, 7);
373
374 Free(header_name);
375 Free(source_name);
376 Free(user_info);
377}
378
379void report_nof_updated_files(void)
380{
381 DEBUG(1, "%u files updated, %u were up-to-date, %u excluded from code"
382 " generation.",
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");
387 else
388 NOTIFY("None of the files needed update.");
389}
This page took 0.039897 seconds and 5 git commands to generate.