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