Commit | Line | Data |
---|---|---|
d44e3c4f | 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 | * Balasko, Jeno | |
10 | * Baranyi, Botond | |
11 | * Raduly, Csaba | |
14e21cff | 12 | * Szabo, Bence Janos |
d44e3c4f | 13 | * Zalanyi, Balazs Andor |
14 | * | |
15 | ******************************************************************************/ | |
970ed795 EL |
16 | #include "CodeGenHelper.hh" |
17 | #include "Code.hh" | |
18 | #include "error.h" | |
19 | #include "main.hh" | |
20 | #include <cstdio> | |
21 | #include <cstring> | |
faf9c345 | 22 | #include <stdlib.h> |
970ed795 EL |
23 | |
24 | namespace Common { | |
14e21cff | 25 | |
970ed795 EL |
26 | CodeGenHelper* CodeGenHelper::instance = 0; |
27 | ||
28 | CodeGenHelper::generated_output_t::generated_output_t() : | |
29 | is_module(false), | |
30 | is_ttcn(true), | |
31 | has_circular_import(false) | |
32 | { | |
33 | Code::init_output(&os); | |
34 | } | |
35 | ||
36 | CodeGenHelper::generated_output_t::~generated_output_t() { | |
37 | Code::free_output(&os); | |
38 | } | |
39 | ||
40 | // from Type.cc | |
41 | const char* const CodeGenHelper::typetypemap[] = { | |
42 | "", /**< undefined */ | |
43 | "", /**< erroneous (e.g. nonexistent reference) */ | |
44 | "", /**< null (ASN.1) */ | |
45 | "", /**< boolean */ | |
46 | "", /**< integer */ | |
47 | "", /**< integer / ASN */ | |
48 | "", /**< real/float */ | |
49 | "", /**< enumerated / ASN */ | |
50 | "", /**< enumerated / TTCN */ | |
51 | "", /**< bitstring */ | |
52 | "", /**< bitstring */ | |
53 | "", /**< hexstring (TTCN-3) */ | |
54 | "", /**< octetstring */ | |
55 | "", /**< charstring (TTCN-3) */ | |
56 | "", /**< universal charstring (TTCN-3) */ | |
57 | "", /**< UTF8String (ASN.1) */ | |
58 | "", /**< NumericString (ASN.1) */ | |
59 | "", /**< PrintableString (ASN.1) */ | |
60 | "", /**< TeletexString (ASN.1) */ | |
61 | "", /**< VideotexString (ASN.1) */ | |
62 | "", /**< IA5String (ASN.1) */ | |
63 | "", /**< GraphicString (ASN.1) */ | |
64 | "", /**< VisibleString (ASN.1) */ | |
65 | "", /**< GeneralString (ASN.1) */ | |
66 | "", /**< UniversalString (ASN.1) */ | |
67 | "", /**< BMPString (ASN.1) */ | |
68 | "", /**< UnrestrictedCharacterString (ASN.1) */ | |
69 | "", /**< UTCTime (ASN.1) */ | |
70 | "", /**< GeneralizedTime (ASN.1) */ | |
71 | "", /** Object descriptor, a kind of string (ASN.1) */ | |
72 | "", /**< object identifier */ | |
73 | "", /**< relative OID (ASN.1) */ | |
74 | "_union", /**< choice /ASN, uses u.secho */ | |
75 | "_union", /**< union /TTCN, uses u.secho */ | |
76 | "_seqof", /**< sequence (record) of */ | |
77 | "_setof", /**< set of */ | |
78 | "_seq", /**< sequence /ASN, uses u.secho */ | |
79 | "_seq", /**< record /TTCN, uses u.secho */ | |
80 | "_set", /**< set /ASN, uses u.secho */ | |
81 | "_set", /**< set /TTCN, uses u.secho */ | |
82 | "", /**< ObjectClassFieldType (ASN.1) */ | |
83 | "", /**< open type (ASN.1) */ | |
84 | "", /**< ANY (deprecated ASN.1) */ | |
85 | "", /**< %EXTERNAL (ASN.1) */ | |
86 | "", /**< EMBEDDED PDV (ASN.1) */ | |
87 | "", /**< referenced */ | |
88 | "", /**< special referenced (by pointer, not by name) */ | |
89 | "", /**< selection type (ASN.1) */ | |
90 | "", /**< verdict type (TTCN-3) */ | |
91 | "", /**< port type (TTCN-3) */ | |
92 | "", /**< component type (TTCN-3) */ | |
93 | "", /**< address type (TTCN-3) */ | |
94 | "", /**< default type (TTCN-3) */ | |
95 | "", /**< array (TTCN-3), uses u.array */ | |
96 | "", /**< signature (TTCN-3) */ | |
97 | "", /**< function reference (TTCN-3) */ | |
98 | "", /**< altstep reference (TTCN-3) */ | |
99 | "", /**< testcase reference (TTCN-3) */ | |
100 | "", /**< anytype (TTCN-3) */ | |
101 | 0 | |
102 | }; | |
103 | ||
104 | CodeGenHelper::CodeGenHelper() : | |
14e21cff | 105 | split_mode(SPLIT_NONE), |
106 | slice_num(1) | |
970ed795 EL |
107 | { |
108 | if (instance != 0) | |
109 | FATAL_ERROR("Attempted to create a second code generator."); | |
110 | instance = this; | |
111 | } | |
112 | ||
113 | CodeGenHelper& CodeGenHelper::GetInstance() { | |
114 | if (instance == 0) | |
115 | FATAL_ERROR("Trying to access to the already destroyed code generator."); | |
116 | return *instance; | |
117 | } | |
118 | ||
119 | void CodeGenHelper::set_split_mode(split_type st) { | |
120 | split_mode = st; | |
14e21cff | 121 | |
122 | if (split_mode == SPLIT_TO_SLICES) { | |
123 | split_to_slices = true; | |
124 | } else { | |
125 | split_to_slices = false; | |
126 | } | |
970ed795 EL |
127 | } |
128 | ||
129 | bool CodeGenHelper::set_split_mode(const char* type) { | |
14e21cff | 130 | int n; |
131 | if (strcmp(type, "none") == 0) { | |
970ed795 | 132 | split_mode = SPLIT_NONE; |
14e21cff | 133 | split_to_slices = false; |
134 | } else if (strcmp(type, "type") == 0) { | |
970ed795 | 135 | split_mode = SPLIT_BY_KIND; |
14e21cff | 136 | split_to_slices = false; |
137 | } else if ((n = atoi(type))) { | |
138 | size_t length = strlen(type); | |
139 | for (int i=0;i<length; i++) { | |
140 | if (!isdigit(type[i])) { | |
141 | ERROR("The number argument of -U must be a valid number."); | |
142 | break; | |
143 | } | |
144 | } | |
145 | split_mode = SPLIT_TO_SLICES; | |
146 | if (n < 1 || n > 999999) { | |
147 | ERROR("The number argument of -U must be between 1 and 999999."); | |
148 | return false; | |
149 | } | |
150 | slice_num = n; | |
151 | split_to_slices = slice_num > 1; // slice_num == 1 has no effect | |
152 | } else | |
970ed795 EL |
153 | return false; |
154 | return true; | |
155 | } | |
156 | ||
157 | CodeGenHelper::split_type CodeGenHelper::get_split_mode() const { | |
158 | return split_mode; | |
159 | } | |
160 | ||
161 | void CodeGenHelper::add_module(const string& name, const string& dispname, | |
162 | bool is_ttcn, bool has_circular_import) { | |
163 | generated_output_t* go = new generated_output_t; | |
164 | go->filename.clear(); | |
165 | go->modulename = name; | |
166 | go->module_dispname = dispname; | |
167 | go->is_module = true; | |
168 | go->is_ttcn = is_ttcn; | |
169 | go->has_circular_import = has_circular_import; | |
170 | generated_code.add(dispname, go); | |
171 | module_names_t* mod_names = new module_names_t; | |
172 | mod_names->name = name; | |
173 | mod_names->dispname = dispname; | |
174 | modules.add(mod_names); | |
175 | } | |
176 | ||
177 | output_struct* CodeGenHelper::get_outputstruct(const string& name) { | |
178 | return &generated_code[name]->os; | |
179 | } | |
180 | ||
181 | void CodeGenHelper::set_current_module(const string& name) { | |
182 | current_module = name; | |
183 | } | |
184 | ||
14e21cff | 185 | void CodeGenHelper::update_intervals(output_struct* const output) { |
186 | if(instance->split_mode != SPLIT_TO_SLICES) return; | |
187 | ||
188 | size_t tmp; | |
189 | ||
190 | // 1. check if some characters are added to the charstring | |
191 | // 2. increment size variable | |
192 | // 3. if size is bigger than the array's size, then double the array size | |
193 | // 4. store new end position | |
194 | ||
195 | // class_defs are not counted as they will be in the header | |
196 | tmp = mstrlen(output->source.function_bodies); | |
197 | if (output->intervals.function_bodies[output->intervals.function_bodies_size] < tmp) { | |
198 | output->intervals.function_bodies_size++; | |
199 | if (output->intervals.function_bodies_size > output->intervals.function_bodies_max_size) { | |
200 | output->intervals.function_bodies_max_size *= 2; | |
201 | output->intervals.function_bodies = (size_t*)Realloc(output->intervals.function_bodies, output->intervals.function_bodies_max_size * sizeof(size_t)); | |
202 | } | |
203 | output->intervals.function_bodies[output->intervals.function_bodies_size] = tmp; | |
204 | } | |
205 | tmp = mstrlen(output->source.methods); | |
206 | if (output->intervals.methods[output->intervals.methods_size] < tmp) { | |
207 | output->intervals.methods_size++; | |
208 | if (output->intervals.methods_size > output->intervals.methods_max_size) { | |
209 | output->intervals.methods_max_size *= 2; | |
210 | output->intervals.methods = (size_t*)Realloc(output->intervals.methods, output->intervals.methods_max_size * sizeof(size_t)); | |
211 | } | |
212 | output->intervals.methods[output->intervals.methods_size] = tmp; | |
213 | } | |
214 | tmp = mstrlen(output->source.static_conversion_function_bodies); | |
215 | if (output->intervals.static_conversion_function_bodies[output->intervals.static_conversion_function_bodies_size] < tmp) { | |
216 | output->intervals.static_conversion_function_bodies_size++; | |
217 | if (output->intervals.static_conversion_function_bodies_size > output->intervals.static_conversion_function_bodies_max_size) { | |
218 | output->intervals.static_conversion_function_bodies_max_size *= 2; | |
219 | output->intervals.static_conversion_function_bodies = (size_t*)Realloc(output->intervals.static_conversion_function_bodies, output->intervals.static_conversion_function_bodies_max_size * sizeof(size_t)); | |
220 | } | |
221 | output->intervals.static_conversion_function_bodies[output->intervals.static_conversion_function_bodies_size] = tmp; | |
222 | } | |
223 | tmp = mstrlen(output->source.static_function_bodies); | |
224 | if (output->intervals.static_function_bodies[output->intervals.static_function_bodies_size] < tmp) { | |
225 | output->intervals.static_function_bodies_size++; | |
226 | if (output->intervals.static_function_bodies_size > output->intervals.static_function_bodies_max_size) { | |
227 | output->intervals.static_function_bodies_max_size *= 2; | |
228 | output->intervals.static_function_bodies = (size_t*)Realloc(output->intervals.static_function_bodies, output->intervals.static_function_bodies_max_size * sizeof(size_t)); | |
229 | } | |
230 | output->intervals.static_function_bodies[output->intervals.static_function_bodies_size] = tmp; | |
231 | } | |
232 | } | |
233 | //Advised to call update_intervals before this | |
234 | size_t CodeGenHelper::size_of_sources(output_struct * const output) { | |
235 | size_t size = 0; | |
236 | // Calculate global var and string literals size | |
237 | output->intervals.pre_things_size = mstrlen(output->source.global_vars) + mstrlen(output->source.string_literals); | |
238 | ||
239 | // Class_defs, static_conversion_function_prototypes, static_function_prototypes are in the header, | |
240 | // and includes are not counted | |
241 | size = output->intervals.pre_things_size + | |
242 | output->intervals.function_bodies[output->intervals.function_bodies_size] + | |
243 | output->intervals.methods[output->intervals.methods_size] + | |
244 | output->intervals.static_conversion_function_bodies[output->intervals.static_conversion_function_bodies_size] + | |
245 | output->intervals.static_function_bodies[output->intervals.static_function_bodies_size]; | |
246 | return size; | |
247 | } | |
248 | ||
249 | size_t CodeGenHelper::get_next_chunk_pos(const output_struct * const from, output_struct * const to, const size_t base_pos, const size_t chunk_size) { | |
250 | size_t pos = 0; // Holds the position from the beginning | |
251 | ||
252 | pos += from->intervals.pre_things_size; | |
253 | ||
254 | if (pos > base_pos) { | |
255 | to->source.global_vars = mputstr(to->source.global_vars, from->source.global_vars); | |
256 | to->source.string_literals = mputstr(to->source.string_literals, from->source.string_literals); | |
257 | } | |
258 | ||
259 | get_chunk_from_poslist(from->source.methods, to->source.methods, from->intervals.methods, from->intervals.methods_size, base_pos, chunk_size, pos); | |
260 | get_chunk_from_poslist(from->source.function_bodies, to->source.function_bodies, from->intervals.function_bodies, from->intervals.function_bodies_size, base_pos, chunk_size, pos); | |
261 | get_chunk_from_poslist(from->source.static_function_bodies, to->source.static_function_bodies, from->intervals.static_function_bodies, from->intervals.static_function_bodies_size, base_pos, chunk_size, pos); | |
262 | get_chunk_from_poslist(from->source.static_conversion_function_bodies, to->source.static_conversion_function_bodies, from->intervals.static_conversion_function_bodies, from->intervals.static_conversion_function_bodies_size, base_pos, chunk_size, pos); | |
263 | ||
264 | return pos; | |
265 | } | |
266 | //if from null return. | |
267 | void CodeGenHelper::get_chunk_from_poslist(const char* from, char *& to, const size_t interval_array[], const size_t interval_array_size, const size_t base_pos, const size_t chunk_size, size_t& pos) { | |
268 | if (from == NULL) return; | |
269 | // If we have enough to form a chunk | |
270 | ||
271 | // pos is unsigned so it can't be negative | |
272 | if (pos > base_pos && pos - base_pos >= chunk_size) return; | |
273 | ||
274 | size_t tmp = pos; | |
275 | ||
276 | pos += interval_array[interval_array_size]; | |
277 | ||
278 | if (pos > base_pos) { // If we haven't finished with this interval_array | |
279 | if (pos - base_pos >= chunk_size) { // It is a good chunk, but make it more precise because it may be too big | |
280 | int ind = 0; | |
281 | for (int i = 0; i <= interval_array_size; i++) { | |
282 | if (tmp + interval_array[i] <= base_pos) { // Find the pos where we left off | |
283 | ind = i; | |
284 | } else if (tmp + interval_array[i] - base_pos >= chunk_size) { | |
285 | // Found the first optimal position that is a good chunk | |
286 | to = mputstrn(to, from + interval_array[ind], interval_array[i] - interval_array[ind]); | |
287 | pos = tmp + interval_array[i]; | |
288 | return; | |
289 | } | |
290 | } | |
291 | } else { // We can't form a new chunk from the remaining characters | |
292 | int ind = 0; | |
293 | for (int i = 0; i <= interval_array_size; i++) { | |
294 | if (tmp + interval_array[i] <= base_pos) { | |
295 | ind = i; | |
296 | } else { | |
297 | break; | |
298 | } | |
299 | } | |
300 | // Put the remaining characters | |
301 | to = mputstrn(to, from + interval_array[ind], interval_array[interval_array_size] - interval_array[ind]); | |
302 | pos = tmp + interval_array[interval_array_size]; | |
303 | } | |
304 | } | |
305 | } | |
306 | ||
970ed795 EL |
307 | output_struct* CodeGenHelper::get_outputstruct(Ttcn::Definition* def) { |
308 | string key = get_key(*def); | |
309 | const string& new_name = current_module + key; | |
310 | if (!generated_code.has_key(new_name)) { | |
311 | generated_output_t* go = new generated_output_t; | |
312 | go->filename = key; | |
313 | go->modulename = generated_code[current_module]->modulename; | |
314 | go->module_dispname = generated_code[current_module]->module_dispname; | |
315 | generated_code.add(new_name, go); | |
316 | go->os.source.includes = mprintf("\n#include \"%s.hh\"\n" | |
317 | , current_module.c_str()); | |
318 | } | |
319 | return &generated_code[new_name]->os; | |
320 | } | |
321 | ||
322 | output_struct* CodeGenHelper::get_outputstruct(Type* type) { | |
323 | string key = get_key(*type); | |
324 | const string& new_name = current_module + key; | |
325 | if (!generated_code.has_key(new_name)) { | |
326 | generated_output_t* go = new generated_output_t; | |
327 | go->filename = key; | |
328 | go->modulename = generated_code[current_module]->modulename; | |
329 | go->module_dispname = generated_code[current_module]->module_dispname; | |
330 | generated_code.add(new_name, go); | |
331 | go->os.source.includes = mprintf("\n#include \"%s.hh\"\n" | |
332 | , current_module.c_str()); | |
333 | } | |
334 | return &generated_code[new_name]->os; | |
335 | } | |
336 | ||
337 | output_struct* CodeGenHelper::get_current_outputstruct() { | |
338 | return &generated_code[current_module]->os; | |
339 | } | |
340 | ||
341 | void CodeGenHelper::transfer_value(char* &dst, char* &src) { | |
342 | dst = mputstr(dst, src); | |
343 | Free(src); | |
344 | src = 0; | |
345 | } | |
346 | ||
347 | void CodeGenHelper::finalize_generation(Type* type) { | |
348 | string key = get_key(*type); | |
349 | if (key.empty()) return; | |
350 | ||
351 | output_struct& dst = *get_current_outputstruct(); | |
352 | output_struct& src = *get_outputstruct(current_module + key); | |
353 | // key is not empty so these can never be the same | |
354 | ||
355 | transfer_value(dst.header.includes, src.header.includes); | |
356 | transfer_value(dst.header.class_decls, src.header.class_decls); | |
357 | transfer_value(dst.header.typedefs, src.header.typedefs); | |
358 | transfer_value(dst.header.class_defs, src.header.class_defs); | |
359 | transfer_value(dst.header.function_prototypes, src.header.function_prototypes); | |
360 | transfer_value(dst.header.global_vars, src.header.global_vars); | |
361 | transfer_value(dst.header.testport_includes, src.header.testport_includes); | |
362 | ||
363 | transfer_value(dst.source.global_vars, src.source.global_vars); | |
364 | ||
365 | transfer_value(dst.functions.pre_init, src.functions.pre_init); | |
366 | transfer_value(dst.functions.post_init, src.functions.post_init); | |
367 | ||
368 | transfer_value(dst.functions.set_param, src.functions.set_param); | |
3abe9331 | 369 | transfer_value(dst.functions.get_param, src.functions.get_param); |
970ed795 EL |
370 | transfer_value(dst.functions.log_param, src.functions.log_param); |
371 | transfer_value(dst.functions.init_comp, src.functions.init_comp); | |
372 | transfer_value(dst.functions.start, src.functions.start); | |
373 | transfer_value(dst.functions.control, src.functions.control); | |
374 | } | |
375 | ||
376 | string CodeGenHelper::get_key(Ttcn::Definition& def) const { | |
377 | string retval; | |
378 | switch (split_mode) { | |
379 | case SPLIT_NONE: | |
380 | // returns the current module | |
381 | break; | |
382 | case SPLIT_BY_KIND: | |
383 | break; | |
384 | case SPLIT_BY_NAME: | |
385 | retval += "_" + def.get_id().get_name(); | |
386 | break; | |
387 | case SPLIT_BY_HEURISTICS: | |
388 | break; | |
14e21cff | 389 | case SPLIT_TO_SLICES: |
390 | break; | |
970ed795 EL |
391 | } |
392 | return retval; | |
393 | } | |
394 | ||
395 | string CodeGenHelper::get_key(Type& type) const { | |
396 | string retval; | |
397 | switch (split_mode) { | |
398 | case SPLIT_NONE: | |
399 | break; | |
400 | case SPLIT_BY_KIND: { | |
401 | Type::typetype_t tt = type.get_typetype(); | |
402 | switch(tt) { | |
403 | case Type::T_CHOICE_A: | |
404 | case Type::T_CHOICE_T: | |
405 | case Type::T_SEQOF: | |
406 | case Type::T_SETOF: | |
407 | case Type::T_SEQ_A: | |
408 | case Type::T_SEQ_T: | |
409 | case Type::T_SET_A: | |
410 | case Type::T_SET_T: | |
411 | retval += typetypemap[(int)tt]; | |
412 | break; | |
413 | default: | |
414 | // put it into the module (no suffix) | |
415 | break; | |
416 | } | |
417 | break; } | |
418 | case SPLIT_BY_NAME: | |
419 | break; | |
420 | case SPLIT_BY_HEURISTICS: | |
421 | break; | |
14e21cff | 422 | case SPLIT_TO_SLICES: |
423 | break; | |
970ed795 EL |
424 | } |
425 | return retval; | |
426 | } | |
427 | ||
428 | void CodeGenHelper::write_output() { | |
429 | size_t i, j; | |
430 | if (split_mode == SPLIT_BY_KIND) { | |
431 | // Create empty files to have a fix set of files to compile | |
432 | string fname; | |
433 | for (j = 0; j < modules.size(); j++) { | |
434 | for (i = 0; typetypemap[i]; i++) { | |
435 | fname = modules[j]->dispname + typetypemap[i]; | |
436 | if (!generated_code.has_key(fname)) { | |
437 | generated_output_t* go = new generated_output_t; | |
438 | go->filename = typetypemap[i]; | |
439 | go->modulename = modules[j]->name; | |
440 | go->module_dispname = modules[j]->dispname; | |
441 | go->os.source.includes = mcopystr( | |
14e21cff | 442 | "\n//This file is intentionally empty." |
970ed795 EL |
443 | "\n#include <version.h>\n"); |
444 | generated_code.add(fname, go); | |
445 | } | |
446 | } | |
447 | } | |
14e21cff | 448 | } else if (split_mode == SPLIT_TO_SLICES && slice_num > 0) { |
449 | // The strategy is the following: | |
450 | // Goal: Get files with equal size | |
451 | // Get the longest file's length and divide it by slice_num (chunk_size) | |
452 | // We split every file to chunk_size sized chunks | |
453 | size_t max = 0; | |
454 | // Calculate maximum character length | |
455 | for (j = 0; j < generated_code.size(); j++) { | |
456 | update_intervals(&generated_code.get_nth_elem(j)->os); | |
457 | size_t num_of_chars = size_of_sources(&generated_code.get_nth_elem(j)->os); | |
458 | if (max < num_of_chars) { | |
459 | max = num_of_chars; | |
460 | } | |
461 | } | |
462 | // Calculate ideal chunk size | |
463 | size_t chunk_size = max / slice_num; | |
464 | string fname; | |
465 | for (j = 0; j < modules.size(); j++) { | |
466 | generated_output_t *output = generated_code[modules[j]->dispname]; | |
467 | ||
468 | // Just to be sure that everything is in the right place | |
469 | update_intervals(&output->os); | |
470 | ||
471 | // Move static function prototypes to header (no longer static) | |
472 | output->os.header.function_prototypes = mputstr(output->os.header.function_prototypes, output->os.source.static_function_prototypes); | |
473 | Free(output->os.source.static_function_prototypes); | |
474 | output->os.source.static_function_prototypes = NULL; | |
475 | ||
476 | output->os.header.function_prototypes = mputstr(output->os.header.function_prototypes, output->os.source.static_conversion_function_prototypes); | |
477 | Free(output->os.source.static_conversion_function_prototypes); | |
478 | output->os.source.static_conversion_function_prototypes = NULL; | |
479 | ||
480 | // Move internal class definitions to the header | |
481 | output->os.header.class_defs = mputstr(output->os.header.class_defs, output->os.source.class_defs); | |
482 | Free(output->os.source.class_defs); | |
483 | output->os.source.class_defs = NULL; | |
484 | ||
485 | update_intervals(&output->os); | |
486 | size_t num_of_chars = size_of_sources(&output->os); | |
487 | char buffer[13]= ""; // Max is 999999 should be enough (checked in main.cc) | 6 digit + 2 underscore + part | |
488 | // If we need to split | |
489 | if (num_of_chars >= chunk_size) { | |
490 | size_t base_pos = 0; | |
491 | for (unsigned int i = 0; i < slice_num; i++) { | |
492 | if (i == 0) { // The first slice has the module's name | |
493 | fname = output->module_dispname; | |
494 | } else { | |
495 | sprintf(buffer, "_part_%d", (int)i); | |
496 | fname = output->module_dispname + "_" + buffer; | |
497 | } | |
498 | if (i == 0 || !generated_code.has_key(fname)) { | |
499 | generated_output_t* go = new generated_output_t; | |
500 | go->filename = buffer; | |
501 | go->modulename = output->modulename; | |
502 | go->module_dispname = output->module_dispname; | |
503 | size_t act_pos = get_next_chunk_pos(&output->os, &go->os, base_pos, chunk_size); | |
504 | // True if the file is not empty | |
505 | if (act_pos > base_pos) { | |
506 | go->os.source.includes = mputstr(go->os.source.includes, output->os.source.includes); | |
507 | } else { | |
508 | go->os.source.includes = mcopystr( | |
509 | "\n//This file is intentionally empty." | |
510 | "\n#include <version.h>\n"); | |
511 | } | |
512 | // First slice: copy header and other properties and replace the original output struct | |
513 | if (i == 0) { | |
514 | go->has_circular_import = output->has_circular_import; | |
515 | go->is_module = output->is_module; | |
516 | go->is_ttcn = output->is_ttcn; | |
517 | go->os.header.class_decls = mputstr(go->os.header.class_decls, output->os.header.class_decls); | |
518 | go->os.header.class_defs = mputstr(go->os.header.class_defs, output->os.header.class_defs); | |
519 | go->os.header.function_prototypes = mputstr(go->os.header.function_prototypes, output->os.header.function_prototypes); | |
520 | go->os.header.global_vars = mputstr(go->os.header.global_vars, output->os.header.global_vars); | |
521 | go->os.header.includes = mputstr(go->os.header.includes, output->os.header.includes); | |
522 | go->os.header.testport_includes = mputstr(go->os.header.testport_includes, output->os.header.testport_includes); | |
523 | go->os.header.typedefs = mputstr(go->os.header.typedefs, output->os.header.typedefs); | |
524 | generated_code[modules[j]->dispname] = go; | |
525 | } else { | |
526 | generated_code.add(fname, go); | |
527 | } | |
528 | base_pos = act_pos; | |
529 | } else { | |
530 | // TODO: error handling: there is a module which has the same name as the | |
531 | // numbered splitted file. splitting by type does not have this error | |
532 | // handling so don't we | |
533 | } | |
534 | } | |
535 | // Extra safety. If something is missing after the splitting, put the remaining | |
536 | // things to the last file. (Should never happen) | |
537 | if (base_pos < num_of_chars) { | |
538 | get_next_chunk_pos(&output->os, &generated_code[fname]->os, base_pos, num_of_chars); | |
539 | } | |
540 | delete output; | |
541 | } else { | |
542 | // Create empty files. | |
543 | for (i = 1; i < slice_num; i++) { | |
544 | sprintf(buffer, "_part_%d", (int)i); | |
545 | fname = output->module_dispname + "_" + buffer; | |
546 | if (!generated_code.has_key(fname)) { | |
547 | generated_output_t* go = new generated_output_t; | |
548 | go->filename = buffer; | |
549 | go->modulename = modules[j]->name; | |
550 | go->module_dispname = modules[j]->dispname; | |
551 | go->os.source.includes = mcopystr( | |
552 | "\n//This file is intentionally empty." | |
553 | "\n#include <version.h>\n"); | |
554 | generated_code.add(fname, go); | |
555 | } | |
556 | } | |
557 | } | |
558 | } | |
970ed795 EL |
559 | } |
560 | generated_output_t* go; | |
561 | for (i = 0; i < generated_code.size(); i++) { | |
562 | go = generated_code.get_nth_elem(i); | |
563 | ::write_output(&go->os, go->modulename.c_str(), go->module_dispname.c_str(), | |
564 | go->filename.c_str(), go->is_ttcn, go->has_circular_import, go->is_module); | |
565 | } | |
566 | } | |
567 | ||
568 | CodeGenHelper::~CodeGenHelper() { | |
569 | size_t i; | |
570 | for (i = 0; i < generated_code.size(); i++) | |
571 | delete generated_code.get_nth_elem(i); | |
572 | generated_code.clear(); | |
573 | for (i = 0; i < modules.size(); i++) | |
574 | delete modules[i]; | |
575 | modules.clear(); | |
576 | instance = 0; | |
577 | } | |
578 | ||
579 | } |