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