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