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