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 | * | |
10 | * Balasko, Jeno | |
11 | * Baranyi, Botond | |
12 | * Beres, Szabolcs | |
13 | * Delic, Adam | |
14 | * Feher, Csaba | |
15 | * Kovacs, Ferenc | |
16 | * Raduly, Csaba | |
17 | * Szabados, Kristof | |
18 | * Szabo, Janos Zoltan – initial implementation | |
19 | * | |
20 | ******************************************************************************/ | |
970ed795 EL |
21 | #include <set> |
22 | #include <sstream> | |
23 | #include <string> | |
24 | ||
25 | #include "Module_list.hh" | |
26 | #include "Logger.hh" | |
27 | #include "Error.hh" | |
28 | #include "Textbuf.hh" | |
29 | #include "Types.h" | |
30 | #include "Param_Types.hh" | |
31 | #include "Basetype.hh" | |
32 | #include "Encdec.hh" | |
33 | ||
34 | #include "../common/ModuleVersion.hh" | |
35 | #ifdef USAGE_STATS | |
36 | #include "../common/usage_stats.hh" | |
37 | #endif | |
38 | ||
39 | #include "../common/dbgnew.hh" | |
40 | ||
41 | #include <stdio.h> | |
42 | #include <string.h> | |
43 | #include <limits.h> | |
44 | ||
45 | TTCN_Module *Module_List::list_head = NULL, *Module_List::list_tail = NULL; | |
46 | ||
47 | void fat_null() {} | |
48 | ||
49 | void Module_List::add_module(TTCN_Module *module_ptr) | |
50 | { | |
51 | if (module_ptr->list_next == NULL && module_ptr != list_tail) { | |
52 | TTCN_Module *list_iter = list_head; | |
53 | while (list_iter != NULL) { | |
54 | if (strcmp(list_iter->module_name, module_ptr->module_name) > 0) | |
55 | break; | |
56 | list_iter = list_iter->list_next; | |
57 | } | |
58 | if (list_iter != NULL) { | |
59 | // inserting before list_iter | |
60 | module_ptr->list_prev = list_iter->list_prev; | |
61 | if (list_iter->list_prev != NULL) | |
62 | list_iter->list_prev->list_next = module_ptr; | |
63 | list_iter->list_prev = module_ptr; | |
64 | } else { | |
65 | // inserting at the end of list | |
66 | module_ptr->list_prev = list_tail; | |
67 | if (list_tail != NULL) list_tail->list_next = module_ptr; | |
68 | list_tail = module_ptr; | |
69 | } | |
70 | module_ptr->list_next = list_iter; | |
71 | if (list_iter == list_head) list_head = module_ptr; | |
72 | } | |
73 | } | |
74 | ||
75 | void Module_List::remove_module(TTCN_Module *module_ptr) | |
76 | { | |
77 | if (module_ptr->list_prev == NULL) list_head = module_ptr->list_next; | |
78 | else module_ptr->list_prev->list_next = module_ptr->list_next; | |
79 | if (module_ptr->list_next == NULL) list_tail = module_ptr->list_prev; | |
80 | else module_ptr->list_next->list_prev = module_ptr->list_prev; | |
81 | ||
82 | module_ptr->list_prev = NULL; | |
83 | module_ptr->list_next = NULL; | |
84 | } | |
85 | ||
86 | TTCN_Module *Module_List::lookup_module(const char *module_name) | |
87 | { | |
88 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
89 | list_iter = list_iter->list_next) | |
90 | if (!strcmp(list_iter->module_name, module_name)) return list_iter; | |
91 | return NULL; | |
92 | } | |
93 | ||
94 | TTCN_Module *Module_List::single_control_part() | |
95 | { | |
96 | TTCN_Module *retval = 0; | |
97 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
98 | list_iter = list_iter->list_next) | |
99 | if (list_iter->control_func != 0) { | |
100 | if (retval != 0) return 0; // more than one control part => fail | |
101 | else retval = list_iter; | |
102 | } | |
103 | return retval; | |
104 | } | |
105 | ||
106 | ||
107 | void Module_List::pre_init_modules() | |
108 | { | |
109 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
110 | list_iter = list_iter->list_next) list_iter->pre_init_module(); | |
970ed795 EL |
111 | } |
112 | ||
113 | void Module_List::post_init_modules() | |
114 | { | |
115 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
116 | list_iter = list_iter->list_next) list_iter->post_init_called = FALSE; | |
117 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
118 | list_iter = list_iter->list_next) list_iter->post_init_module(); | |
119 | } | |
120 | ||
121 | void Module_List::start_function(const char *module_name, | |
122 | const char *function_name, Text_Buf& function_arguments) | |
123 | { | |
124 | TTCN_Module *module_ptr = lookup_module(module_name); | |
125 | if (module_ptr == NULL) { | |
126 | // the START message must be dropped here | |
127 | function_arguments.cut_message(); | |
128 | TTCN_error("Internal error: Module %s does not exist.", module_name); | |
129 | } else if (module_ptr->start_func == NULL) { | |
130 | // the START message must be dropped here | |
131 | function_arguments.cut_message(); | |
132 | TTCN_error("Internal error: Module %s does not have startable " | |
133 | "functions.", module_name); | |
134 | } else if (!module_ptr->start_func(function_name, function_arguments)) { | |
135 | // the START message must be dropped here | |
136 | function_arguments.cut_message(); | |
137 | TTCN_error("Internal error: Startable function %s does not exist in " | |
138 | "module %s.", function_name, module_name); | |
139 | } | |
140 | } | |
141 | ||
142 | void Module_List::initialize_component(const char *module_name, | |
143 | const char *component_type, boolean init_base_comps) | |
144 | { | |
145 | TTCN_Module *module_ptr = lookup_module(module_name); | |
146 | if (module_ptr == NULL) | |
147 | TTCN_error("Internal error: Module %s does not exist.", module_name); | |
148 | else if (module_ptr->initialize_component_func == NULL) | |
149 | TTCN_error("Internal error: Module %s does not have component types.", | |
150 | module_name); | |
151 | else if (!module_ptr->initialize_component_func(component_type, | |
152 | init_base_comps)) | |
153 | TTCN_error("Internal error: Component type %s does not exist in " | |
154 | "module %s.", component_type, module_name); | |
155 | } | |
156 | ||
157 | void Module_List::set_param(Module_Param& param) | |
158 | { | |
159 | // The first segment in the parameter name can either be the module name, | |
160 | // or the module parameter name - both must be checked | |
161 | const char* const first_name = param.get_id()->get_current_name(); | |
162 | const char* second_name = NULL; | |
163 | boolean param_found = FALSE; | |
164 | ||
165 | // Check if the first name segment is an existing module name | |
166 | TTCN_Module *module_ptr = lookup_module(first_name); | |
167 | if (module_ptr != NULL && module_ptr->set_param_func != NULL && param.get_id()->next_name()) { | |
168 | param_found = module_ptr->set_param_func(param); | |
169 | if (!param_found) { | |
170 | second_name = param.get_id()->get_current_name(); // for error messages | |
171 | } | |
172 | } | |
173 | ||
174 | // If not found, check if the first name segment was the module parameter name | |
175 | // (even if it matched a module name) | |
176 | if (!param_found) { | |
177 | param.get_id()->next_name(-1); // set the position back to the first segment | |
178 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
179 | list_iter = list_iter->list_next) { | |
180 | if (list_iter->set_param_func != NULL && | |
181 | list_iter->set_param_func(param)) { | |
182 | param_found = TRUE; | |
183 | } | |
184 | } | |
185 | } | |
186 | ||
187 | // Still not found -> error | |
188 | if (!param_found) { | |
189 | if (module_ptr == NULL) { | |
190 | param.error("Module parameter cannot be set, because module `%s' does not exist, " | |
191 | "and no parameter with name `%s' exists in any module.", | |
192 | first_name, first_name); | |
193 | } else if (module_ptr->set_param_func == NULL) { | |
194 | param.error("Module parameter cannot be set, because module `%s' does not have " | |
195 | "parameters, and no parameter with name `%s' exists in other modules.", | |
196 | first_name, first_name); | |
197 | } else { | |
198 | param.error("Module parameter cannot be set, because no parameter with name `%s' " | |
199 | "exists in module `%s', and no parameter with name `%s' exists in any module.", | |
200 | second_name, first_name, first_name); | |
201 | } | |
202 | } | |
203 | } | |
204 | ||
3abe9331 | 205 | Module_Param* Module_List::get_param(Module_Param_Name& param_name) |
206 | { | |
207 | // The first segment in the parameter name can either be the module name, | |
208 | // or the module parameter name - both must be checked | |
209 | const char* const first_name = param_name.get_current_name(); | |
210 | const char* second_name = NULL; | |
211 | Module_Param* param = NULL; | |
212 | ||
213 | // Check if the first name segment is an existing module name | |
214 | TTCN_Module *module_ptr = lookup_module(first_name); | |
215 | if (module_ptr != NULL && module_ptr->get_param_func != NULL && param_name.next_name()) { | |
216 | param = module_ptr->get_param_func(param_name); | |
217 | if (param == NULL) { | |
218 | second_name = param_name.get_current_name(); // for error messages | |
219 | } | |
220 | } | |
221 | ||
222 | // If not found, check if the first name segment was the module parameter name | |
223 | // (even if it matched a module name) | |
224 | if (param == NULL) { | |
225 | param_name.next_name(-1); // set the position back to the first segment | |
226 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
227 | list_iter = list_iter->list_next) { | |
228 | if (list_iter->get_param_func != NULL) { | |
229 | param = list_iter->get_param_func(param_name); | |
230 | if (param != NULL) { | |
231 | break; | |
232 | } | |
233 | } | |
234 | } | |
235 | } | |
236 | ||
237 | // Still not found -> error | |
238 | if (param == NULL) { | |
239 | if (module_ptr == NULL) { | |
240 | TTCN_error("Referenced module parameter cannot be found. Module `%s' does not exist, " | |
241 | "and no parameter with name `%s' exists in any module.", | |
242 | first_name, first_name); | |
243 | } else if (module_ptr->get_param_func == NULL) { | |
244 | TTCN_error("Referenced module parameter cannot be found. Module `%s' does not have " | |
245 | "parameters, and no parameter with name `%s' exists in other modules.", | |
246 | first_name, first_name); | |
247 | } else { | |
248 | TTCN_error("Referenced module parameter cannot be found. No parameter with name `%s' " | |
249 | "exists in module `%s', and no parameter with name `%s' exists in any module.", | |
250 | second_name, first_name, first_name); | |
251 | } | |
252 | } | |
253 | else if (param->get_type() == Module_Param::MP_Unbound) { | |
254 | delete param; | |
255 | TTCN_error("Referenced module parameter '%s' is unbound.", param_name.get_str()); | |
256 | } | |
257 | ||
258 | return param; | |
259 | } | |
260 | ||
970ed795 EL |
261 | void Module_List::log_param() |
262 | { | |
263 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
264 | list_iter = list_iter->list_next) { | |
265 | if (list_iter->log_param_func != NULL) { | |
266 | TTCN_Logger::begin_event(TTCN_Logger::EXECUTOR_CONFIGDATA); | |
267 | TTCN_Logger::log_event("Module %s has the following parameters: " | |
268 | "{ ", list_iter->module_name); | |
269 | list_iter->log_param_func(); | |
270 | TTCN_Logger::log_event_str(" }"); | |
271 | TTCN_Logger::end_event(); | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
276 | void Module_List::execute_control(const char *module_name) | |
277 | { | |
278 | TTCN_Module *module_ptr = lookup_module(module_name); | |
279 | if (module_ptr != NULL) { | |
280 | if (module_ptr->control_func != NULL) { | |
281 | try { | |
282 | module_ptr->control_func(); | |
283 | } catch (const TC_Error& tc_error) { | |
284 | TTCN_Logger::log(TTCN_Logger::ERROR_UNQUALIFIED, | |
285 | "Unrecoverable error in control part of module %s. Execution aborted.", | |
286 | module_name); | |
287 | } catch (const TC_End& tc_end) { | |
288 | TTCN_Logger::log(TTCN_Logger::FUNCTION_UNQUALIFIED, | |
289 | "Control part of module %s was stopped.", module_name); | |
290 | } | |
291 | } else TTCN_error("Module %s does not have control part.", module_name); | |
292 | } else TTCN_error("Module %s does not exist.", module_name); | |
293 | } | |
294 | ||
295 | void Module_List::execute_testcase(const char *module_name, | |
296 | const char *testcase_name) | |
297 | { | |
298 | TTCN_Module *module_ptr = lookup_module(module_name); | |
299 | if (module_ptr != NULL) module_ptr->execute_testcase(testcase_name); | |
300 | else TTCN_error("Module %s does not exist.", module_name); | |
301 | } | |
302 | ||
303 | void Module_List::execute_all_testcases(const char *module_name) | |
304 | { | |
305 | TTCN_Module *module_ptr = lookup_module(module_name); | |
306 | if (module_ptr != NULL) module_ptr->execute_all_testcases(); | |
307 | else TTCN_error("Module %s does not exist.", module_name); | |
308 | } | |
309 | ||
310 | void Module_List::print_version() | |
311 | { | |
312 | fputs( | |
313 | "Module name Language Compilation time MD5 checksum " | |
314 | " Version\n" | |
315 | "-------------------------------------------------------------------" | |
316 | "--------------------\n", stderr); | |
317 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
318 | list_iter = list_iter->list_next) list_iter->print_version(); | |
319 | fputs("-------------------------------------------------------------------" | |
320 | "--------------------\n", stderr); | |
321 | } | |
322 | ||
323 | void Module_List::send_versions() { | |
324 | #ifdef USAGE_STATS | |
325 | std::set<ModuleVersion> versions; | |
326 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
327 | list_iter = list_iter->list_next) { | |
328 | ModuleVersion* version = list_iter->get_version(); | |
329 | if (version->hasProductNumber()) { | |
330 | versions.insert(*version); | |
331 | } | |
332 | delete version; | |
333 | } | |
334 | ||
335 | std::stringstream stream; | |
336 | stream << "runtime"; | |
337 | for (std::set<ModuleVersion>::iterator it = versions.begin(); it != versions.end(); ++it) { | |
338 | if (it == versions.begin()) { | |
339 | stream << "&products=" << it->toString(); | |
340 | } else { | |
341 | stream << "," << it->toString(); | |
342 | } | |
343 | } | |
344 | ||
345 | HttpSender* sender = new HttpSender; | |
346 | UsageData::getInstance().sendDataThreaded(stream.str().c_str(), sender); | |
347 | #endif | |
348 | } | |
349 | ||
350 | ||
351 | void Module_List::list_testcases() | |
352 | { | |
353 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
354 | list_iter = list_iter->list_next) list_iter->list_testcases(); | |
355 | } | |
356 | ||
357 | void Module_List::push_version(Text_Buf& text_buf) | |
358 | { | |
359 | int n_modules = 0; | |
360 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
361 | list_iter = list_iter->list_next) n_modules++; | |
362 | text_buf.push_int(n_modules); | |
363 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
364 | list_iter = list_iter->list_next) { | |
365 | text_buf.push_string(list_iter->module_name); | |
366 | if (list_iter->md5_checksum != NULL) { | |
367 | text_buf.push_int(16); | |
368 | text_buf.push_raw(16, list_iter->md5_checksum); | |
369 | } else text_buf.push_int((RInt)0); | |
370 | } | |
371 | } | |
372 | ||
373 | void Module_List::encode_function(Text_Buf& text_buf, | |
374 | genericfunc_t function_address) | |
375 | { | |
376 | if (function_address == NULL) | |
377 | TTCN_error("Text encoder: Encoding an unbound function reference."); | |
378 | else if (function_address == fat_null) text_buf.push_string(""); | |
379 | else { | |
380 | const char *module_name, *function_name; | |
381 | if (lookup_function_by_address(function_address, module_name, | |
382 | function_name)) { | |
383 | text_buf.push_string(module_name); | |
384 | text_buf.push_string(function_name); | |
385 | } else TTCN_error("Text encoder: Encoding function reference %p, " | |
386 | "which does not point to a valid function.", | |
387 | (void*)(unsigned long)function_address); | |
388 | } | |
389 | } | |
390 | ||
391 | void Module_List::decode_function(Text_Buf& text_buf, | |
392 | genericfunc_t *function_addr_ptr) | |
393 | { | |
394 | char *module_name = text_buf.pull_string(); | |
395 | if (module_name[0] != '\0') { | |
396 | TTCN_Module* module_ptr = lookup_module(module_name); | |
397 | if (module_ptr == NULL) { | |
398 | try { | |
399 | TTCN_error("Text decoder: Module %s does not exist when trying " | |
400 | "to decode a function reference.", module_name); | |
401 | } catch (...) { | |
402 | // to prevent from memory leaks | |
403 | delete [] module_name; | |
404 | throw; | |
405 | } | |
406 | } | |
407 | char *function_name = text_buf.pull_string(); | |
408 | genericfunc_t function_address = | |
409 | module_ptr->get_function_address_by_name(function_name); | |
410 | if (function_address != NULL) *function_addr_ptr = function_address; | |
411 | else { | |
412 | try { | |
413 | TTCN_error("Text decoder: Reference to non-existent function " | |
414 | "%s.%s was received.", module_name, function_name); | |
415 | } catch (...) { | |
416 | // to prevent from memory leaks | |
417 | delete [] module_name; | |
418 | delete [] function_name; | |
419 | throw; | |
420 | } | |
421 | } | |
422 | delete [] function_name; | |
423 | } else *function_addr_ptr = fat_null; | |
424 | delete [] module_name; | |
425 | } | |
426 | ||
427 | void Module_List::log_function(genericfunc_t function_address) | |
428 | { | |
429 | if (function_address == NULL) TTCN_Logger::log_event_str("<unbound>"); | |
430 | else if (function_address == fat_null) TTCN_Logger::log_event_str("null"); | |
431 | else { | |
432 | const char *module_name, *function_name; | |
433 | if (lookup_function_by_address(function_address, module_name, | |
434 | function_name)) TTCN_Logger::log_event("refers(%s.%s)", | |
435 | module_name, function_name); | |
436 | else TTCN_Logger::log_event("<invalid function reference: %p>", | |
437 | (void*)(unsigned long)function_address); | |
438 | } | |
439 | } | |
440 | ||
441 | void Module_List::encode_altstep(Text_Buf& text_buf, | |
442 | genericfunc_t altstep_address) | |
443 | { | |
444 | if (altstep_address == NULL) | |
445 | TTCN_error("Text encoder: Encoding an unbound altstep reference."); | |
446 | else if (altstep_address == fat_null) text_buf.push_string(""); | |
447 | else { | |
448 | const char *module_name, *altstep_name; | |
449 | if (lookup_altstep_by_address(altstep_address, module_name, | |
450 | altstep_name)) { | |
451 | text_buf.push_string(module_name); | |
452 | text_buf.push_string(altstep_name); | |
453 | } else TTCN_error("Text encoder: Encoding altstep reference %p, " | |
454 | "which does not point to a valid altstep.", | |
455 | (void*)(unsigned long)altstep_address); | |
456 | } | |
457 | } | |
458 | ||
459 | void Module_List::decode_altstep(Text_Buf& text_buf, | |
460 | genericfunc_t *altstep_addr_ptr) | |
461 | { | |
462 | char *module_name = text_buf.pull_string(); | |
463 | if (module_name[0] != '\0') { | |
464 | TTCN_Module* module_ptr = lookup_module(module_name); | |
465 | if (module_ptr == NULL) { | |
466 | try { | |
467 | TTCN_error("Text decoder: Module %s does not exist when trying " | |
468 | "to decode an altstep reference.", module_name); | |
469 | } catch (...) { | |
470 | // to prevent from memory leaks | |
471 | delete [] module_name; | |
472 | throw; | |
473 | } | |
474 | } | |
475 | char *altstep_name = text_buf.pull_string(); | |
476 | genericfunc_t altstep_address = | |
477 | module_ptr->get_altstep_address_by_name(altstep_name); | |
478 | if (altstep_address != NULL) *altstep_addr_ptr = altstep_address; | |
479 | else { | |
480 | try { | |
481 | TTCN_error("Text decoder: Reference to non-existent altstep " | |
482 | "%s.%s was received.", module_name, altstep_name); | |
483 | } catch (...) { | |
484 | // to prevent from memory leaks | |
485 | delete [] module_name; | |
486 | delete [] altstep_name; | |
487 | throw; | |
488 | } | |
489 | } | |
490 | delete [] altstep_name; | |
491 | } else *altstep_addr_ptr = fat_null; | |
492 | delete [] module_name; | |
493 | } | |
494 | ||
495 | void Module_List::log_altstep(genericfunc_t altstep_address) | |
496 | { | |
497 | if (altstep_address == NULL) TTCN_Logger::log_event_str("<unbound>"); | |
498 | else if (altstep_address == fat_null) TTCN_Logger::log_event_str("null"); | |
499 | else { | |
500 | const char *module_name, *altstep_name; | |
501 | if (lookup_altstep_by_address(altstep_address, module_name, | |
502 | altstep_name)) TTCN_Logger::log_event("refers(%s.%s)", | |
503 | module_name, altstep_name); | |
504 | else TTCN_Logger::log_event("<invalid altstep reference: %p>", | |
505 | (void*)(unsigned long)altstep_address); | |
506 | } | |
507 | } | |
508 | ||
509 | // called by testcase_name::encode_text in the generated code | |
510 | void Module_List::encode_testcase(Text_Buf& text_buf, | |
511 | genericfunc_t testcase_address) | |
512 | { | |
513 | if (testcase_address == NULL) | |
514 | TTCN_error("Text encoder: Encoding an unbound testcase reference."); | |
515 | else if (testcase_address == fat_null) text_buf.push_string(""); | |
516 | else { | |
517 | const char *module_name, *testcase_name; | |
518 | if (lookup_testcase_by_address(testcase_address, module_name, | |
519 | testcase_name)) { | |
520 | text_buf.push_string(module_name); | |
521 | text_buf.push_string(testcase_name); | |
522 | } else TTCN_error("Text encoder: Encoding testcase reference %p, " | |
523 | "which does not point to a valid testcase.", | |
524 | (void*)(unsigned long)testcase_address); | |
525 | } | |
526 | } | |
527 | ||
528 | // called by testcase_name::decode_text in the generated code | |
529 | void Module_List::decode_testcase(Text_Buf& text_buf, | |
530 | genericfunc_t *testcase_addr_ptr) | |
531 | { | |
532 | char *module_name = text_buf.pull_string(); | |
533 | if (module_name[0] != '\0') { | |
534 | TTCN_Module* module_ptr = lookup_module(module_name); | |
535 | if (module_ptr == NULL) { | |
536 | try { | |
537 | TTCN_error("Text decoder: Module %s does not exist when trying " | |
538 | "to decode a testcase reference.", module_name); | |
539 | } catch (...) { | |
540 | // to prevent from memory leaks | |
541 | delete [] module_name; | |
542 | throw; | |
543 | } | |
544 | } | |
545 | char *testcase_name = text_buf.pull_string(); | |
546 | genericfunc_t testcase_address = | |
547 | module_ptr->get_testcase_address_by_name(testcase_name); | |
548 | if (testcase_address != NULL) *testcase_addr_ptr = testcase_address; | |
549 | else { | |
550 | try { | |
551 | TTCN_error("Text decoder: Reference to non-existent testcase " | |
552 | "%s.%s was received.", module_name, testcase_name); | |
553 | } catch (...) { | |
554 | // to prevent from memory leaks | |
555 | delete [] module_name; | |
556 | delete [] testcase_name; | |
557 | throw; | |
558 | } | |
559 | } | |
560 | delete [] testcase_name; | |
561 | } else *testcase_addr_ptr = fat_null; | |
562 | delete [] module_name; | |
563 | } | |
564 | ||
565 | void Module_List::log_testcase(genericfunc_t testcase_address) | |
566 | { | |
567 | if (testcase_address == NULL) TTCN_Logger::log_event_str("<unbound>"); | |
568 | else if (testcase_address == fat_null) TTCN_Logger::log_event_str("null"); | |
569 | else { | |
570 | const char *module_name, *testcase_name; | |
571 | if (lookup_testcase_by_address(testcase_address, module_name, | |
572 | testcase_name)) TTCN_Logger::log_event("refers(%s.%s)", | |
573 | module_name, testcase_name); | |
574 | else TTCN_Logger::log_event("<invalid testcase reference: %p>", | |
575 | (void*)(unsigned long)testcase_address); | |
576 | } | |
577 | } | |
578 | ||
579 | genericfunc_t Module_List::get_fat_null() | |
580 | { | |
581 | return fat_null; | |
582 | } | |
583 | ||
584 | genericfunc_t Module_List::lookup_start_by_function_address( | |
585 | genericfunc_t function_address) | |
586 | { | |
587 | if (function_address == NULL) TTCN_error("Performing a start test " | |
588 | "component operation with an unbound function reference."); | |
589 | else if (function_address == fat_null) TTCN_error("Start test component " | |
590 | "operation cannot be performed with a null function reference."); | |
591 | for (TTCN_Module* list_iter = list_head; list_iter != NULL; | |
592 | list_iter = list_iter->list_next) { | |
593 | genericfunc_t function_start = | |
594 | list_iter->get_function_start_by_address(function_address); | |
595 | if (function_start != NULL) return function_start; | |
596 | } | |
597 | TTCN_error("Function reference %p in start test component operation does " | |
598 | "not point to a valid function.", | |
599 | (void*)(unsigned long)function_address); | |
600 | // to avoid warnings | |
601 | return NULL; | |
602 | } | |
603 | ||
604 | genericfunc_t Module_List::lookup_standalone_address_by_altstep_address( | |
605 | genericfunc_t altstep_address) | |
606 | { | |
607 | if (altstep_address == NULL) TTCN_error("Performing an invoke operation " | |
608 | "on an unbound altstep reference."); | |
609 | else if (altstep_address == fat_null) TTCN_error("Invoke operation " | |
610 | "cannot be performed on a null altstep reference."); | |
611 | for (TTCN_Module* list_iter = list_head; list_iter != NULL; | |
612 | list_iter = list_iter->list_next) { | |
613 | genericfunc_t standalone_address, activate_address; | |
614 | if (list_iter->get_altstep_data_by_address(altstep_address, | |
615 | standalone_address, activate_address)) { | |
616 | if (standalone_address == NULL) | |
617 | TTCN_error("Internal error: Altstep reference %p cannot be " | |
618 | "instantiated as a stand-alone alt statement.", | |
619 | (void*)(unsigned long)altstep_address); | |
620 | return standalone_address; | |
621 | } | |
622 | } | |
623 | TTCN_error("Altstep reference %p in invoke operation does not point to a " | |
624 | "valid altstep.", (void*)(unsigned long)altstep_address); | |
625 | // to avoid warnings | |
626 | return NULL; | |
627 | } | |
628 | ||
629 | genericfunc_t Module_List::lookup_activate_address_by_altstep_address( | |
630 | genericfunc_t altstep_address) | |
631 | { | |
632 | if (altstep_address == NULL) TTCN_error("Performing an activate operation " | |
633 | "on an unbound altstep reference."); | |
634 | else if (altstep_address == fat_null) TTCN_error("Activate operation " | |
635 | "cannot be performed on a null altstep reference."); | |
636 | for (TTCN_Module* list_iter = list_head; list_iter != NULL; | |
637 | list_iter = list_iter->list_next) { | |
638 | genericfunc_t standalone_address, activate_address; | |
639 | if (list_iter->get_altstep_data_by_address(altstep_address, | |
640 | standalone_address, activate_address)) { | |
641 | if (activate_address == NULL) | |
642 | TTCN_error("Internal error: Altstep reference %p cannot be " | |
643 | "activated as a default.", | |
644 | (void*)(unsigned long)altstep_address); | |
645 | return activate_address; | |
646 | } | |
647 | } | |
648 | TTCN_error("Altstep reference %p in activate operation does not point to " | |
649 | "a valid altstep.", (void*)(unsigned long)altstep_address); | |
650 | // to avoid warnings | |
651 | return NULL; | |
652 | } | |
653 | ||
654 | boolean Module_List::lookup_function_by_address(genericfunc_t function_address, | |
655 | const char*& module_name, const char*& function_name) | |
656 | { | |
657 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
658 | list_iter = list_iter->list_next) { | |
659 | function_name = | |
660 | list_iter->get_function_name_by_address(function_address); | |
661 | if (function_name != NULL) { | |
662 | module_name = list_iter->module_name; | |
663 | return TRUE; | |
664 | } | |
665 | } | |
666 | return FALSE; | |
667 | } | |
668 | ||
669 | boolean Module_List::lookup_altstep_by_address(genericfunc_t altstep_address, | |
670 | const char*& module_name, const char*& altstep_name) | |
671 | { | |
672 | for (TTCN_Module *list_iter = list_head; list_iter != NULL; | |
673 | list_iter = list_iter->list_next) { | |
674 | altstep_name = list_iter->get_altstep_name_by_address(altstep_address); | |
675 | if (altstep_name != NULL) { | |
676 | module_name = list_iter->module_name; | |
677 | return TRUE; | |
678 | } | |
679 | } | |
680 | return FALSE; | |
681 | } | |
682 | ||
683 | boolean Module_List::lookup_testcase_by_address(genericfunc_t testcase_address, | |
684 | const char*& module_name, const char*& testcase_name) | |
685 | { | |
686 | for(TTCN_Module *list_iter = list_head; list_iter != NULL; | |
687 | list_iter = list_iter->list_next) { | |
688 | testcase_name = | |
689 | list_iter->get_testcase_name_by_address(testcase_address); | |
690 | if (testcase_name != NULL) { | |
691 | module_name = list_iter->module_name; | |
692 | return TRUE; | |
693 | } | |
694 | } | |
695 | return FALSE; | |
696 | } | |
697 | ||
698 | // ======================= TTCN_Module ======================= | |
699 | ||
700 | struct TTCN_Module::function_list_item { | |
701 | const char *function_name; | |
702 | genericfunc_t function_address; | |
703 | genericfunc_t start_address; | |
704 | function_list_item *next_function; | |
705 | }; | |
706 | ||
707 | struct TTCN_Module::altstep_list_item { | |
708 | const char *altstep_name; | |
709 | genericfunc_t altstep_address; //instance | |
710 | genericfunc_t activate_address; | |
711 | genericfunc_t standalone_address; | |
712 | altstep_list_item *next_altstep; | |
713 | }; | |
714 | ||
715 | struct TTCN_Module::testcase_list_item { | |
716 | const char *testcase_name; | |
717 | boolean is_pard; | |
718 | union { | |
719 | testcase_t testcase_function; | |
720 | genericfunc_t testcase_address; | |
721 | }; | |
722 | testcase_list_item *next_testcase; | |
723 | }; | |
724 | ||
725 | /** Constructor for TTCN modules */ | |
726 | TTCN_Module::TTCN_Module(const char *par_module_name, | |
727 | const char *par_compilation_date, | |
728 | const char *par_compilation_time, | |
729 | const unsigned char *par_md5_checksum, | |
730 | init_func_t par_pre_init_func, | |
731 | const char* par_product_number, | |
732 | unsigned int par_suffix, | |
733 | unsigned int par_release, | |
734 | unsigned int par_patch, | |
735 | unsigned int par_build, | |
736 | const char* par_extra, | |
737 | size_t par_num_namespace, | |
738 | const namespace_t *par_namespaces, | |
739 | init_func_t par_post_init_func, | |
740 | set_param_func_t par_set_param_func, | |
3abe9331 | 741 | get_param_func_t par_get_param_func, |
970ed795 EL |
742 | log_param_func_t par_log_param_func, |
743 | initialize_component_func_t par_initialize_component_func, | |
744 | start_func_t par_start_func, | |
745 | control_func_t par_control_func) | |
746 | : list_prev(NULL), list_next(NULL) | |
747 | , module_type(TTCN3_MODULE) | |
748 | , module_name(par_module_name) | |
749 | , compilation_date(par_compilation_date) | |
750 | , compilation_time(par_compilation_time) | |
751 | , md5_checksum(par_md5_checksum) | |
752 | , product_number(par_product_number) | |
753 | , suffix(par_suffix) | |
754 | , release(par_release) | |
755 | , patch(par_patch) | |
756 | , build(par_build) | |
757 | , extra(par_extra) | |
758 | , num_namespaces(par_num_namespace) | |
759 | , xer_namespaces(par_namespaces) | |
760 | , pre_init_func(par_pre_init_func) | |
761 | , post_init_func(par_post_init_func) | |
762 | , pre_init_called(FALSE) | |
763 | , post_init_called(FALSE) | |
764 | , set_param_func(par_set_param_func) | |
3abe9331 | 765 | , get_param_func(par_get_param_func) |
970ed795 EL |
766 | , log_param_func(par_log_param_func) |
767 | , initialize_component_func(par_initialize_component_func) | |
768 | , start_func(par_start_func) | |
769 | , control_func(par_control_func) | |
770 | , function_head(NULL) | |
771 | , function_tail(NULL) | |
772 | , altstep_head(NULL) | |
773 | , altstep_tail(NULL) | |
774 | , testcase_head(NULL) | |
775 | , testcase_tail(NULL) | |
776 | { | |
777 | Module_List::add_module(this); | |
778 | } | |
779 | ||
780 | /** Constructor for ASN.1 modules */ | |
781 | TTCN_Module::TTCN_Module(const char *par_module_name, | |
782 | const char *par_compilation_date, | |
783 | const char *par_compilation_time, | |
784 | const unsigned char par_md5_checksum[16], | |
785 | init_func_t par_init_func) | |
786 | : list_prev(NULL), list_next(NULL) | |
787 | , module_type(ASN1_MODULE) | |
788 | , module_name(par_module_name) | |
789 | , compilation_date(par_compilation_date) | |
790 | , compilation_time(par_compilation_time) | |
791 | , md5_checksum(par_md5_checksum) | |
792 | , product_number(NULL) | |
793 | , suffix(0) | |
794 | , release(UINT_MAX) | |
795 | , patch(UINT_MAX) | |
796 | , build(UINT_MAX) | |
797 | , extra(NULL) | |
798 | , num_namespaces(0) | |
799 | , xer_namespaces(NULL) // no EXER, no namespaces for ASN.1 | |
800 | , pre_init_func(par_init_func) | |
801 | , post_init_func(NULL) | |
802 | , pre_init_called(FALSE) | |
803 | , post_init_called(FALSE) | |
804 | , set_param_func(NULL) | |
3abe9331 | 805 | , get_param_func(NULL) |
970ed795 EL |
806 | , log_param_func(NULL) |
807 | , initialize_component_func(NULL) | |
808 | , start_func(NULL) | |
809 | , control_func(NULL) | |
810 | , function_head(NULL) | |
811 | , function_tail(NULL) | |
812 | , altstep_head(NULL) | |
813 | , altstep_tail(NULL) | |
814 | , testcase_head(NULL) | |
815 | , testcase_tail(NULL) | |
816 | { | |
817 | Module_List::add_module(this); | |
818 | } | |
819 | ||
820 | /** Constructor for C++ modules (?) */ | |
821 | TTCN_Module::TTCN_Module(const char *par_module_name, | |
822 | const char *par_compilation_date, | |
823 | const char *par_compilation_time, | |
824 | init_func_t par_init_func) | |
825 | : list_prev(NULL), list_next(NULL) | |
826 | , module_type(CPLUSPLUS_MODULE) | |
827 | , module_name(par_module_name ? par_module_name : "<unknown>") | |
828 | , compilation_date(par_compilation_date ? par_compilation_date : "<unknown>") | |
829 | , compilation_time(par_compilation_time ? par_compilation_time : "<unknown>") | |
830 | , md5_checksum(NULL) | |
831 | , product_number(NULL) | |
832 | , suffix(0) | |
833 | , release(UINT_MAX) | |
834 | , patch(UINT_MAX) | |
835 | , build(UINT_MAX) | |
836 | , extra(NULL) | |
837 | , num_namespaces(0) | |
838 | , xer_namespaces(NULL) | |
839 | , pre_init_func(par_init_func) | |
840 | , post_init_func(NULL) | |
841 | , pre_init_called(FALSE) | |
842 | , post_init_called(FALSE) | |
843 | , set_param_func(NULL) | |
844 | , log_param_func(NULL) | |
845 | , initialize_component_func(NULL) | |
846 | , start_func(NULL) | |
847 | , control_func(NULL) | |
848 | , function_head(NULL) | |
849 | , function_tail(NULL) | |
850 | , altstep_head(NULL) | |
851 | , altstep_tail(NULL) | |
852 | , testcase_head(NULL) | |
853 | , testcase_tail(NULL) | |
854 | { | |
855 | Module_List::add_module(this); | |
856 | } | |
857 | ||
858 | TTCN_Module::~TTCN_Module() | |
859 | { | |
860 | Module_List::remove_module(this); | |
861 | while (function_head != NULL) { | |
862 | function_list_item *tmp_ptr=function_head->next_function; | |
863 | delete function_head; | |
864 | function_head = tmp_ptr; | |
865 | } | |
866 | while (altstep_head != NULL) { | |
867 | altstep_list_item *tmp_ptr=altstep_head->next_altstep; | |
868 | delete altstep_head; | |
869 | altstep_head = tmp_ptr; | |
870 | } | |
871 | while (testcase_head != NULL) { | |
872 | testcase_list_item *tmp_ptr = testcase_head->next_testcase; | |
873 | delete testcase_head; | |
874 | testcase_head = tmp_ptr; | |
875 | } | |
876 | } | |
877 | ||
878 | void TTCN_Module::pre_init_module() | |
879 | { | |
880 | if (pre_init_called) return; | |
881 | pre_init_called = TRUE; | |
882 | if (pre_init_func == NULL) return; | |
883 | try { | |
884 | pre_init_func(); | |
885 | } catch (...) { | |
886 | TTCN_Logger::log(TTCN_Logger::ERROR_UNQUALIFIED, | |
887 | "An error occurred while initializing the constants of module %s.", | |
888 | module_name); | |
889 | throw; | |
890 | } | |
891 | } | |
892 | ||
893 | void TTCN_Module::post_init_module() | |
894 | { | |
895 | if (post_init_called) return; | |
896 | post_init_called = TRUE; | |
897 | TTCN_Logger::log_module_init(module_name); | |
898 | if (post_init_func != NULL) post_init_func(); | |
899 | TTCN_Logger::log_module_init(module_name, true); | |
900 | } | |
901 | ||
902 | void TTCN_Module::add_function(const char *function_name, | |
903 | genericfunc_t function_address, genericfunc_t start_address) | |
904 | { | |
905 | function_list_item *new_item = new function_list_item; | |
906 | new_item->function_name = function_name; | |
907 | new_item->function_address = function_address; | |
908 | new_item->start_address = start_address; | |
909 | new_item->next_function = NULL; | |
910 | if(function_head == NULL) function_head = new_item; | |
911 | else function_tail->next_function = new_item; | |
912 | function_tail = new_item; | |
913 | } | |
914 | ||
915 | void TTCN_Module::add_altstep(const char *altstep_name, | |
916 | genericfunc_t altstep_address, genericfunc_t activate_address, | |
917 | genericfunc_t standalone_address) | |
918 | { | |
919 | altstep_list_item *new_item = new altstep_list_item; | |
920 | new_item->altstep_name = altstep_name; | |
921 | new_item->altstep_address = altstep_address; | |
922 | new_item->activate_address = activate_address; | |
923 | new_item->standalone_address = standalone_address; | |
924 | new_item->next_altstep = NULL; | |
925 | if(altstep_head == NULL) altstep_head = new_item; | |
926 | else altstep_tail->next_altstep = new_item; | |
927 | altstep_tail = new_item; | |
928 | } | |
929 | ||
930 | void TTCN_Module::add_testcase_nonpard(const char *testcase_name, | |
931 | testcase_t testcase_function) | |
932 | { | |
933 | testcase_list_item *new_item = new testcase_list_item; | |
934 | new_item->testcase_name = testcase_name; | |
935 | new_item->is_pard = FALSE; | |
936 | new_item->testcase_function = testcase_function; | |
937 | new_item->next_testcase = NULL; | |
938 | if (testcase_head == NULL) testcase_head = new_item; | |
939 | else testcase_tail->next_testcase = new_item; | |
940 | testcase_tail = new_item; | |
941 | } | |
942 | ||
943 | void TTCN_Module::add_testcase_pard(const char *testcase_name, | |
944 | genericfunc_t testcase_address) | |
945 | { | |
946 | testcase_list_item *new_item = new testcase_list_item; | |
947 | new_item->testcase_name = testcase_name; | |
948 | new_item->is_pard = TRUE; | |
949 | new_item->testcase_address = testcase_address; | |
950 | new_item->next_testcase = NULL; | |
951 | if(testcase_head == NULL) testcase_head = new_item; | |
952 | else testcase_tail->next_testcase = new_item; | |
953 | testcase_tail = new_item; | |
954 | } | |
955 | ||
956 | void TTCN_Module::execute_testcase(const char *testcase_name) | |
957 | { | |
958 | for (testcase_list_item *list_iter = testcase_head; list_iter != NULL; | |
959 | list_iter = list_iter->next_testcase) { | |
960 | if (!strcmp(list_iter->testcase_name, testcase_name)) { | |
961 | if (list_iter->is_pard) { | |
962 | // Testcase has parameters. However, there might be a chance... | |
963 | // Move to the next one (if any) and check that it has the same name. | |
964 | list_iter = list_iter->next_testcase; | |
965 | if (list_iter == NULL | |
966 | || strcmp(list_iter->testcase_name, testcase_name)) { | |
967 | TTCN_error("Test case %s in module %s " | |
968 | "cannot be executed individually (without control part) " | |
969 | "because it has parameters.", testcase_name, module_name); | |
970 | continue; // not reached | |
971 | } | |
972 | // else it has the same name, fall through | |
973 | } | |
974 | ||
975 | list_iter->testcase_function(FALSE, 0.0); | |
976 | return; | |
977 | } | |
978 | } | |
979 | TTCN_error("Test case %s does not exist in module %s.", testcase_name, | |
980 | module_name); | |
981 | } | |
982 | ||
983 | void TTCN_Module::execute_all_testcases() | |
984 | { | |
985 | boolean found = FALSE; | |
986 | for (testcase_list_item *list_iter = testcase_head; list_iter != NULL; | |
987 | list_iter = list_iter->next_testcase) { | |
988 | if (!list_iter->is_pard) { | |
989 | list_iter->testcase_function(FALSE, 0.0); | |
990 | found = TRUE; | |
991 | } | |
992 | } | |
993 | if (!found) { | |
994 | if (testcase_head != NULL) TTCN_warning("Module %s does not contain " | |
995 | "non-parameterized test cases, which can be executed individually " | |
996 | "without control part.", module_name); | |
997 | else TTCN_warning("Module %s does not contain test cases.", | |
998 | module_name); | |
999 | } | |
1000 | } | |
1001 | ||
1002 | const char *TTCN_Module::get_function_name_by_address( | |
1003 | genericfunc_t function_address) | |
1004 | { | |
1005 | for (function_list_item *list_iter = function_head; list_iter != NULL; | |
1006 | list_iter = list_iter->next_function) | |
1007 | if (list_iter->function_address == function_address) | |
1008 | return list_iter->function_name; | |
1009 | return NULL; | |
1010 | } | |
1011 | ||
1012 | genericfunc_t TTCN_Module::get_function_address_by_name(const char *func_name) | |
1013 | { | |
1014 | for (function_list_item *list_iter = function_head; list_iter != NULL; | |
1015 | list_iter = list_iter->next_function) | |
1016 | if (!strcmp(list_iter->function_name, func_name)) | |
1017 | return list_iter->function_address; | |
1018 | return NULL; | |
1019 | } | |
1020 | ||
1021 | genericfunc_t TTCN_Module::get_function_start_by_address( | |
1022 | genericfunc_t function_address) | |
1023 | { | |
1024 | for (function_list_item *list_iter = function_head; list_iter != NULL; | |
1025 | list_iter = list_iter->next_function) { | |
1026 | if (list_iter->function_address == function_address) { | |
1027 | if (list_iter->start_address != NULL) | |
1028 | return list_iter->start_address; | |
1029 | else TTCN_error("Function %s.%s cannot be started on a parallel " | |
1030 | "test component.", module_name, list_iter->function_name); | |
1031 | } | |
1032 | } | |
1033 | return NULL; | |
1034 | } | |
1035 | ||
1036 | const char *TTCN_Module::get_altstep_name_by_address( | |
1037 | genericfunc_t altstep_address) | |
1038 | { | |
1039 | for(altstep_list_item *list_iter = altstep_head; list_iter != NULL; | |
1040 | list_iter = list_iter->next_altstep) { | |
1041 | if (list_iter->altstep_address == altstep_address) | |
1042 | return list_iter->altstep_name; | |
1043 | } | |
1044 | return NULL; | |
1045 | } | |
1046 | ||
1047 | genericfunc_t TTCN_Module::get_altstep_address_by_name(const char* altstep_name) | |
1048 | { | |
1049 | for(altstep_list_item *list_iter = altstep_head; list_iter != NULL; | |
1050 | list_iter = list_iter->next_altstep) { | |
1051 | if (!strcmp(list_iter->altstep_name, altstep_name)) | |
1052 | return list_iter->altstep_address; | |
1053 | } | |
1054 | return NULL; | |
1055 | } | |
1056 | ||
1057 | boolean TTCN_Module::get_altstep_data_by_address(genericfunc_t altstep_address, | |
1058 | genericfunc_t& standalone_address, genericfunc_t& activate_address) | |
1059 | { | |
1060 | for(altstep_list_item* list_iter = altstep_head; list_iter != NULL; | |
1061 | list_iter = list_iter->next_altstep) { | |
1062 | if (list_iter->altstep_address == altstep_address) { | |
1063 | standalone_address = list_iter->standalone_address; | |
1064 | activate_address = list_iter->activate_address; | |
1065 | return TRUE; | |
1066 | } | |
1067 | } | |
1068 | return FALSE; | |
1069 | } | |
1070 | ||
1071 | const char *TTCN_Module::get_testcase_name_by_address( | |
1072 | genericfunc_t testcase_address) | |
1073 | { | |
1074 | for(testcase_list_item *list_iter = testcase_head; list_iter != NULL; | |
1075 | list_iter = list_iter->next_testcase) { | |
1076 | if (list_iter->is_pard) { | |
1077 | if (list_iter->testcase_address == testcase_address) | |
1078 | return list_iter->testcase_name; | |
1079 | } else { | |
1080 | if ((genericfunc_t)list_iter->testcase_function == testcase_address) | |
1081 | return list_iter->testcase_name; | |
1082 | } | |
1083 | } | |
1084 | return NULL; | |
1085 | } | |
1086 | ||
1087 | genericfunc_t TTCN_Module::get_testcase_address_by_name(const char *testcase_name) | |
1088 | { | |
1089 | for (testcase_list_item *list_iter = testcase_head; list_iter != NULL; | |
1090 | list_iter = list_iter->next_testcase) { | |
1091 | if (!strcmp(list_iter->testcase_name, testcase_name)) { | |
1092 | if (!list_iter->is_pard) return list_iter->testcase_address; | |
1093 | else return (genericfunc_t)list_iter->testcase_function; | |
1094 | } | |
1095 | } | |
1096 | return NULL; | |
1097 | } | |
1098 | ||
1099 | ModuleVersion* TTCN_Module::get_version() const { | |
1100 | return new ModuleVersion(product_number, suffix, release, patch, build, extra); | |
1101 | } | |
1102 | ||
1103 | void TTCN_Module::print_version() | |
1104 | { | |
1105 | const char *type_str; | |
1106 | switch (module_type) { | |
1107 | case TTCN3_MODULE: | |
1108 | type_str = "TTCN-3"; | |
1109 | break; | |
1110 | case ASN1_MODULE: | |
1111 | type_str = "ASN.1"; | |
1112 | break; | |
1113 | case CPLUSPLUS_MODULE: | |
1114 | type_str = "C++"; | |
1115 | break; | |
1116 | default: | |
1117 | type_str = "???"; | |
1118 | break; | |
1119 | } | |
1120 | fprintf(stderr, "%-18s %-6s ", module_name, type_str); | |
1121 | if (compilation_date != NULL && compilation_time != NULL) { | |
1122 | fprintf(stderr, "%s %s", compilation_date, compilation_time); | |
1123 | } else { | |
1124 | fputs("<unknown> ", stderr); | |
1125 | } | |
1126 | if (md5_checksum != NULL) { | |
1127 | putc(' ', stderr); | |
1128 | for (int i = 0; i < 16; i++) fprintf(stderr, "%02x", md5_checksum[i]); | |
1129 | } | |
1130 | // else it's likely not a TTCN module, so no version info | |
1131 | ||
1132 | putc(' ', stderr); // separator for the version number | |
1133 | if (product_number != NULL) { | |
1134 | fprintf(stderr, "%s", product_number); | |
1135 | if (suffix > 0) { | |
1136 | fprintf(stderr, "/%d", suffix); | |
1137 | } | |
1138 | putc(' ', stderr); | |
1139 | } | |
1140 | // release can be between 0 and 999999 inclusive | |
1141 | // patch can go from 0 to 26 (English alphabet) - 6 (IOPQRW forbidden) | |
1142 | // build can be between 0 and 99 inclusive | |
1143 | if (release <= 999999 && patch <= ('Z'-'A'-6) && build <= 99) { | |
1144 | char *build_str = buildstr(build); | |
1145 | if (build_str == 0) TTCN_error("TTCN_Module::print_version()"); | |
1146 | if (extra != NULL ) { | |
1147 | build_str = mputprintf(build_str, "%s", extra); | |
1148 | } | |
1149 | fprintf(stderr, "R%u%c%-4s", release, eri(patch), build_str); | |
1150 | Free(build_str); | |
1151 | } | |
1152 | putc('\n', stderr); | |
1153 | } | |
1154 | ||
1155 | void TTCN_Module::list_testcases() | |
1156 | { | |
1157 | if (control_func != NULL) printf("%s.control\n", module_name); | |
1158 | for (testcase_list_item *list_iter = testcase_head; list_iter != NULL; | |
1159 | list_iter = list_iter->next_testcase) | |
1160 | if(!list_iter->is_pard) | |
1161 | printf("%s.%s\n", module_name, list_iter->testcase_name); | |
1162 | } | |
1163 | ||
1164 | const namespace_t *TTCN_Module::get_ns(size_t p_index) const | |
1165 | { | |
1166 | if (p_index == (size_t)-1) return NULL; | |
1167 | if (p_index >= num_namespaces) TTCN_error( | |
1168 | "Index overflow for namespaces, %lu instead of %lu", | |
1169 | (unsigned long)p_index, (unsigned long)num_namespaces); | |
1170 | ||
1171 | return xer_namespaces + p_index; | |
1172 | } | |
1173 | ||
1174 | const namespace_t *TTCN_Module::get_controlns() const | |
1175 | { | |
1176 | if (xer_namespaces==NULL) { | |
1177 | TTCN_error("No namespaces for module %s", module_name); | |
1178 | } | |
1179 | if (xer_namespaces[num_namespaces].px == NULL | |
1180 | ||xer_namespaces[num_namespaces].px[0] == '\0') { | |
1181 | TTCN_error("No control namespace for module %s", module_name); | |
1182 | } | |
1183 | return xer_namespaces+num_namespaces; | |
1184 | } | |
1185 | ||
1186 |