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