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