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
17 * Szabo, Janos Zoltan – initial implementation
20 ******************************************************************************/
23 #include "../common/memory.h"
25 #include "Component.hh"
27 #include "Parameters.h"
28 #include "Param_Types.hh"
30 #include "Optional.hh"
32 #include "../common/dbgnew.hh"
34 COMPONENT::COMPONENT()
36 component_value
= UNBOUND_COMPREF
;
39 COMPONENT::COMPONENT(component other_value
)
41 component_value
= other_value
;
44 COMPONENT::COMPONENT(const COMPONENT
& other_value
)
45 : Base_Type(other_value
)
47 if (other_value
.component_value
== UNBOUND_COMPREF
)
48 TTCN_error("Copying an unbound component reference.");
49 component_value
= other_value
.component_value
;
52 COMPONENT
& COMPONENT::operator=(component other_value
)
54 component_value
= other_value
;
58 COMPONENT
& COMPONENT::operator=(const COMPONENT
& other_value
)
60 if (other_value
.component_value
== UNBOUND_COMPREF
)
61 TTCN_error("Assignment of an unbound component reference.");
62 component_value
= other_value
.component_value
;
66 boolean
COMPONENT::operator==(component other_value
) const
68 if (component_value
== UNBOUND_COMPREF
) TTCN_error("The left operand of "
69 "comparison is an unbound component reference.");
70 return component_value
== other_value
;
73 boolean
COMPONENT::operator==(const COMPONENT
& other_value
) const
75 if (component_value
== UNBOUND_COMPREF
) TTCN_error("The left operand of "
76 "comparison is an unbound component reference.");
77 if (other_value
.component_value
== UNBOUND_COMPREF
) TTCN_error("The right "
78 "operand of comparison is an unbound component reference.");
79 return component_value
== other_value
.component_value
;
82 COMPONENT::operator component() const
84 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Using the value of an "
85 "unbound component reference.");
86 return component_value
;
89 void COMPONENT::log() const
91 if (component_value
!= UNBOUND_COMPREF
)
92 log_component_reference(component_value
);
93 else TTCN_Logger::log_event_unbound();
96 alt_status
COMPONENT::done() const
98 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing done "
99 "operation on an unbound component reference.");
100 return TTCN_Runtime::component_done(component_value
);
103 alt_status
COMPONENT::killed() const
105 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing killed "
106 "operation on an unbound component reference.");
107 return TTCN_Runtime::component_killed(component_value
);
110 boolean
COMPONENT::running() const
112 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing running "
113 "operation on an unbound component reference.");
114 return TTCN_Runtime::component_running(component_value
);
117 boolean
COMPONENT::alive() const
119 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing alive "
120 "operation on an unbound component reference.");
121 return TTCN_Runtime::component_alive(component_value
);
124 void COMPONENT::stop() const
126 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing stop "
127 "operation on an unbound component reference.");
128 TTCN_Runtime::stop_component(component_value
);
131 void COMPONENT::kill() const
133 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing kill "
134 "operation on an unbound component reference.");
135 TTCN_Runtime::kill_component(component_value
);
138 void COMPONENT::set_param(Module_Param
& param
) {
139 param
.basic_check(Module_Param::BC_VALUE
, "component reference (integer or null) value");
140 Module_Param_Ptr mp
= ¶m
;
141 if (param
.get_type() == Module_Param::MP_Reference
) {
142 mp
= param
.get_referenced_param();
144 if (Ttcn_String_Parsing::happening()) {
145 // accept all component values in case it's a string2ttcn operation
146 switch (mp
->get_type()) {
147 case Module_Param::MP_Integer
:
148 component_value
= (component
)mp
->get_integer()->get_val();
150 case Module_Param::MP_Ttcn_Null
:
151 component_value
= NULL_COMPREF
;
153 case Module_Param::MP_Ttcn_mtc
:
154 component_value
= MTC_COMPREF
;
156 case Module_Param::MP_Ttcn_system
:
157 component_value
= SYSTEM_COMPREF
;
160 param
.type_error("component reference (integer or null) value");
164 // only accept the null value if it's a module parameter
165 if (Module_Param::MP_Ttcn_Null
!= mp
->get_type()) {
166 param
.error("Only the 'null' value is allowed for module parameters of type 'component'.");
168 component_value
= NULL_COMPREF
;
172 Module_Param
* COMPONENT::get_param(Module_Param_Name
& /* param_name */) const
175 return new Module_Param_Unbound();
177 return new Module_Param_Ttcn_Null();
180 void COMPONENT::encode_text(Text_Buf
& text_buf
) const
182 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Text encoder: Encoding "
183 "an unbound component reference.");
184 text_buf
.push_int((int)component_value
);
185 switch (component_value
) {
191 text_buf
.push_string(get_component_name(component_value
));
196 void COMPONENT::decode_text(Text_Buf
& text_buf
)
198 component_value
= (component
)text_buf
.pull_int().get_val();
199 switch (component_value
) {
205 char *component_name
= text_buf
.pull_string();
206 register_component_name(component_value
, component_name
);
207 delete [] component_name
;
212 boolean
operator==(component component_value
, const COMPONENT
& other_value
)
214 if (other_value
.component_value
== UNBOUND_COMPREF
) TTCN_error("The right "
215 "operand of comparison is an unbound component reference.");
216 return component_value
== other_value
.component_value
;
219 unsigned int COMPONENT::n_component_names
= 0;
220 struct COMPONENT::component_name_struct
{
221 component component_reference
;
222 char *component_name
;
223 } *COMPONENT::component_names
= NULL
;
225 void COMPONENT::register_component_name(component component_reference
,
226 const char *component_name
)
228 if (self
.component_value
== component_reference
) {
229 // the own name of the component will not be registered,
230 // but check whether we got the right string
231 const char *local_name
= TTCN_Runtime::get_component_name();
232 if (component_name
== NULL
|| component_name
[0] == '\0') {
233 if (local_name
!= NULL
) {
234 TTCN_error("Internal error: Trying to register the component "
235 "reference of this PTC without any name, but this "
236 "component has name %s.", local_name
);
239 if (local_name
== NULL
) {
240 TTCN_error("Internal error: Trying to register the component "
241 "reference of this PTC with name %s, but this component "
242 "does not have name.", component_name
);
243 } else if (strcmp(component_name
, local_name
)) {
244 TTCN_error("Internal error: Trying to register the component "
245 "reference of this PTC with name %s, but this component "
246 "has name %s.", component_name
, local_name
);
251 unsigned int min
= 0;
252 if (n_component_names
> 0) {
253 // perform a binary search to find the place for the component reference
254 unsigned int max
= n_component_names
- 1;
256 unsigned int mid
= min
+ (max
- min
) / 2;
257 if (component_names
[mid
].component_reference
< component_reference
)
259 else if (component_names
[mid
].component_reference
==
260 component_reference
) {
265 if (component_names
[min
].component_reference
== component_reference
) {
266 // the component reference is already registered
267 const char *stored_name
= component_names
[min
].component_name
;
268 if (component_name
== NULL
|| component_name
[0] == '\0') {
269 if (stored_name
!= NULL
) {
270 TTCN_error("Internal error: Trying to register component "
271 "reference %d without any name, but this component "
272 "reference is already registered with name %s.",
273 component_reference
, stored_name
);
276 if (stored_name
== NULL
) {
277 TTCN_error("Internal error: Trying to register component "
278 "reference %d with name %s, but this component "
279 "reference is already registered without name.",
280 component_reference
, component_name
);
281 } else if (strcmp(component_name
, stored_name
)) {
282 TTCN_error("Internal error: Trying to register component "
283 "reference %d with name %s, but this component "
284 "reference is already registered with a different "
285 "name (%s).", component_reference
, component_name
,
291 if (component_names
[min
].component_reference
< component_reference
)
293 // the component reference will be inserted before the index "min"
295 (component_name_struct
*)Realloc(component_names
,
296 (n_component_names
+ 1) * sizeof(*component_names
));
297 memmove(component_names
+ min
+ 1, component_names
+ min
,
298 (n_component_names
- min
) * sizeof(*component_names
));
301 // this is the first component reference to be registered
303 (component_name_struct
*)Malloc(sizeof(*component_names
));
305 component_names
[min
].component_reference
= component_reference
;
306 if (component_name
== NULL
|| component_name
[0] == '\0')
307 component_names
[min
].component_name
= NULL
;
308 else component_names
[min
].component_name
= mcopystr(component_name
);
312 const char *COMPONENT::get_component_name(component component_reference
)
314 if (self
.component_value
== component_reference
) {
315 // the own name of the PTC is not registered
316 return TTCN_Runtime::get_component_name();
317 } else if (n_component_names
> 0) {
318 unsigned int min
= 0, max
= n_component_names
- 1;
320 unsigned int mid
= min
+ (max
- min
) / 2;
321 if (component_names
[mid
].component_reference
< component_reference
)
323 else if (component_names
[mid
].component_reference
==
325 return component_names
[mid
].component_name
;
328 if (component_names
[min
].component_reference
!= component_reference
)
329 TTCN_error("Internal error: Trying to get the name of PTC with "
330 "component reference %d, but the name of the component "
331 "is not registered.", component_reference
);
332 return component_names
[min
].component_name
;
334 TTCN_error("Internal error: Trying to get the name of PTC with "
335 "component reference %d, but there are no component names "
336 "registered.", component_reference
);
341 void COMPONENT::clear_component_names()
343 for (unsigned int i
= 0; i
< n_component_names
; i
++)
344 Free(component_names
[i
].component_name
);
345 Free(component_names
);
346 n_component_names
= 0;
347 component_names
= NULL
;
350 void COMPONENT::log_component_reference(component component_reference
)
352 switch (component_reference
) {
354 TTCN_Logger::log_event_str("null");
357 TTCN_Logger::log_event_str("mtc");
360 TTCN_Logger::log_event_str("system");
363 const char *component_name
= get_component_name(component_reference
);
364 if (component_name
!= NULL
) TTCN_Logger::log_event("%s(%d)",
365 component_name
, component_reference
);
366 else TTCN_Logger::log_event("%d", component_reference
);
371 // get_component_string is suspiciously similar to log_component_reference.
372 // It would be trivially easy to implement log_... with get_...
373 // but it would involve a runtime penalty, because get_component_string
374 // returns a newly allocated string which must be freed, whereas log_...
375 // uses fixed strings. So the current implementation pays for speed with size.
376 // Perhaps log_component_reference will go away one day.
377 char *COMPONENT::get_component_string(component component_reference
)
379 switch (component_reference
) {
381 return mcopystr("null");
383 return mcopystr("mtc");
385 return mcopystr("system");
386 case CONTROL_COMPREF
:
387 return mcopystr("control");
389 const char *component_name
= get_component_name(component_reference
);
390 if (component_name
!= NULL
) return mprintf("%s(%d)",
391 component_name
, component_reference
);
392 else return mprintf("%d", component_reference
);
398 void COMPONENT_template::clean_up()
400 if (template_selection
== VALUE_LIST
401 ||template_selection
== COMPLEMENTED_LIST
)
402 delete [] value_list
.list_value
;
403 template_selection
= UNINITIALIZED_TEMPLATE
;
406 void COMPONENT_template::copy_template(const COMPONENT_template
& other_value
)
408 switch (other_value
.template_selection
) {
410 single_value
= other_value
.single_value
;
417 case COMPLEMENTED_LIST
:
418 value_list
.n_values
= other_value
.value_list
.n_values
;
419 value_list
.list_value
= new COMPONENT_template
[value_list
.n_values
];
420 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
421 value_list
.list_value
[i
].copy_template(
422 other_value
.value_list
.list_value
[i
]);
425 TTCN_error("Copying an uninitialized/unsupported component reference "
428 set_selection(other_value
);
431 COMPONENT_template::COMPONENT_template()
436 COMPONENT_template::COMPONENT_template(template_sel other_value
)
437 : Base_Template(other_value
)
439 check_single_selection(other_value
);
442 COMPONENT_template::COMPONENT_template(component other_value
)
443 : Base_Template(SPECIFIC_VALUE
)
445 single_value
= other_value
;
448 COMPONENT_template::COMPONENT_template(const COMPONENT
& other_value
)
449 : Base_Template(SPECIFIC_VALUE
)
451 if (other_value
.component_value
== UNBOUND_COMPREF
)
452 TTCN_error("Creating a template from an unbound component reference.");
453 single_value
= other_value
.component_value
;
456 COMPONENT_template::COMPONENT_template(const OPTIONAL
<COMPONENT
>& other_value
)
458 switch (other_value
.get_selection()) {
459 case OPTIONAL_PRESENT
:
460 set_selection(SPECIFIC_VALUE
);
461 single_value
= (component
)(const COMPONENT
&)other_value
;
464 set_selection(OMIT_VALUE
);
467 TTCN_error("Creating a component reference template from an unbound "
472 COMPONENT_template::COMPONENT_template(const COMPONENT_template
& other_value
)
475 copy_template(other_value
);
478 COMPONENT_template::~COMPONENT_template()
483 COMPONENT_template
& COMPONENT_template::operator=(template_sel other_value
)
485 check_single_selection(other_value
);
487 set_selection(other_value
);
491 COMPONENT_template
& COMPONENT_template::operator=(component other_value
)
494 set_selection(SPECIFIC_VALUE
);
495 single_value
= other_value
;
499 COMPONENT_template
& COMPONENT_template::operator=(const COMPONENT
& other_value
)
501 if (other_value
.component_value
== UNBOUND_COMPREF
)
502 TTCN_error("Assignment of an unbound component reference to a "
504 return *this = other_value
.component_value
;
507 COMPONENT_template
& COMPONENT_template::operator=
508 (const OPTIONAL
<COMPONENT
>& other_value
)
511 switch (other_value
.get_selection()) {
512 case OPTIONAL_PRESENT
:
513 set_selection(SPECIFIC_VALUE
);
514 single_value
= (component
)(const COMPONENT
&)other_value
;
517 set_selection(OMIT_VALUE
);
520 TTCN_error("Assignment of an unbound optional field to a component "
521 "reference template.");
526 COMPONENT_template
& COMPONENT_template::operator=
527 (const COMPONENT_template
& other_value
)
529 if (&other_value
!= this) {
531 copy_template(other_value
);
536 boolean
COMPONENT_template::match(component other_value
,
537 boolean
/* legacy */) const
539 switch (template_selection
) {
541 return single_value
== other_value
;
548 case COMPLEMENTED_LIST
:
549 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
550 if (value_list
.list_value
[i
].match(other_value
))
551 return template_selection
== VALUE_LIST
;
552 return template_selection
== COMPLEMENTED_LIST
;
554 TTCN_error("Matching an uninitialized/unsupported component reference "
560 boolean
COMPONENT_template::match(const COMPONENT
& other_value
,
561 boolean
/* legacy */) const
563 if (other_value
.component_value
== UNBOUND_COMPREF
)
564 TTCN_error("Matching an unbound component reference with a template.");
565 return match(other_value
.component_value
);
568 component
COMPONENT_template::valueof() const
570 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
571 TTCN_error("Performing a valueof or send operation on a non-specific "
572 "component reference template.");
576 void COMPONENT_template::set_type(template_sel template_type
,
577 unsigned int list_length
)
579 if (template_type
!= VALUE_LIST
&& template_type
!= COMPLEMENTED_LIST
)
580 TTCN_error("Setting an invalid list type for a component reference "
583 set_selection(template_type
);
584 value_list
.n_values
= list_length
;
585 value_list
.list_value
= new COMPONENT_template
[list_length
];
588 COMPONENT_template
& COMPONENT_template::list_item(unsigned int list_index
)
590 if (template_selection
!= VALUE_LIST
&&
591 template_selection
!= COMPLEMENTED_LIST
)
592 TTCN_error("Accessing a list element of a non-list component "
593 "reference template.");
594 if (list_index
>= value_list
.n_values
)
595 TTCN_error("Index overflow in a component reference value list "
597 return value_list
.list_value
[list_index
];
600 void COMPONENT_template::log() const
602 switch (template_selection
) {
604 switch (single_value
) {
606 TTCN_Logger::log_event_str("null");
609 TTCN_Logger::log_event_str("mtc");
612 TTCN_Logger::log_event_str("system");
615 TTCN_Logger::log_event("%d", single_value
);
619 case COMPLEMENTED_LIST
:
620 TTCN_Logger::log_event_str("complement ");
623 TTCN_Logger::log_char('(');
624 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++) {
625 if (i
> 0) TTCN_Logger::log_event_str(", ");
626 value_list
.list_value
[i
].log();
628 TTCN_Logger::log_char(')');
637 void COMPONENT_template::log_match(const COMPONENT
& match_value
,
638 boolean
/* legacy */) const
640 if (TTCN_Logger::VERBOSITY_COMPACT
== TTCN_Logger::get_matching_verbosity()
641 && TTCN_Logger::get_logmatch_buffer_len() != 0) {
642 TTCN_Logger::print_logmatch_buffer();
643 TTCN_Logger::log_event_str(" := ");
646 TTCN_Logger::log_event_str(" with ");
648 if (match(match_value
)) TTCN_Logger::log_event_str(" matched");
649 else TTCN_Logger::log_event_str(" unmatched");
652 void COMPONENT_template::set_param(Module_Param
& param
) {
653 param
.basic_check(Module_Param::BC_TEMPLATE
, "component reference (integer or null) template");
654 Module_Param_Ptr mp
= ¶m
;
655 if (param
.get_type() == Module_Param::MP_Reference
) {
656 mp
= param
.get_referenced_param();
658 switch (mp
->get_type()) {
659 case Module_Param::MP_Omit
:
662 case Module_Param::MP_Any
:
665 case Module_Param::MP_AnyOrNone
:
668 case Module_Param::MP_List_Template
:
669 case Module_Param::MP_ComplementList_Template
: {
670 COMPONENT_template temp
;
671 temp
.set_type(mp
->get_type() == Module_Param::MP_List_Template
?
672 VALUE_LIST
: COMPLEMENTED_LIST
, mp
->get_size());
673 for (size_t i
=0; i
<mp
->get_size(); i
++) {
674 temp
.list_item(i
).set_param(*mp
->get_elem(i
));
678 case Module_Param::MP_Integer
:
679 *this = (component
)mp
->get_integer()->get_val();
681 case Module_Param::MP_Ttcn_Null
:
682 *this = NULL_COMPREF
;
684 case Module_Param::MP_Ttcn_mtc
:
687 case Module_Param::MP_Ttcn_system
:
688 *this = SYSTEM_COMPREF
;
691 param
.type_error("component reference (integer or null) template");
693 is_ifpresent
= param
.get_ifpresent() || mp
->get_ifpresent();
696 Module_Param
* COMPONENT_template::get_param(Module_Param_Name
& param_name
) const
698 Module_Param
* mp
= NULL
;
699 switch (template_selection
) {
700 case UNINITIALIZED_TEMPLATE
:
701 mp
= new Module_Param_Unbound();
704 mp
= new Module_Param_Omit();
707 mp
= new Module_Param_Any();
710 mp
= new Module_Param_AnyOrNone();
713 switch (single_value
) {
715 mp
= new Module_Param_Ttcn_Null();
718 mp
= new Module_Param_Ttcn_mtc();
721 mp
= new Module_Param_Ttcn_system();
724 mp
= new Module_Param_Integer(new int_val_t(single_value
));
729 case COMPLEMENTED_LIST
: {
730 if (template_selection
== VALUE_LIST
) {
731 mp
= new Module_Param_List_Template();
734 mp
= new Module_Param_ComplementList_Template();
736 for (size_t i
= 0; i
< value_list
.n_values
; ++i
) {
737 mp
->add_elem(value_list
.list_value
[i
].get_param(param_name
));
749 void COMPONENT_template::encode_text(Text_Buf
& text_buf
) const
751 encode_text_base(text_buf
);
752 switch (template_selection
) {
758 text_buf
.push_int(single_value
);
760 case COMPLEMENTED_LIST
:
762 text_buf
.push_int(value_list
.n_values
);
763 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
764 value_list
.list_value
[i
].encode_text(text_buf
);
767 TTCN_error("Text encoder: Encoding an uninitialized/unsupported "
768 "component reference template.");
772 void COMPONENT_template::decode_text(Text_Buf
& text_buf
)
775 decode_text_base(text_buf
);
776 switch (template_selection
) {
782 single_value
= (component
)text_buf
.pull_int().get_val();
784 case COMPLEMENTED_LIST
:
786 value_list
.n_values
= text_buf
.pull_int().get_val();
787 value_list
.list_value
= new COMPONENT_template
[value_list
.n_values
];
788 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
789 value_list
.list_value
[i
].decode_text(text_buf
);
792 TTCN_error("Text decoder: An unknown/unsupported selection was "
793 "received for a component reference template.");
797 boolean
COMPONENT_template::is_present(boolean legacy
/* = FALSE */) const
799 if (template_selection
==UNINITIALIZED_TEMPLATE
) return FALSE
;
800 return !match_omit(legacy
);
803 boolean
COMPONENT_template::match_omit(boolean legacy
/* = FALSE */) const
805 if (is_ifpresent
) return TRUE
;
806 switch (template_selection
) {
811 case COMPLEMENTED_LIST
:
813 // legacy behavior: 'omit' can appear in the value/complement list
814 for (unsigned int i
=0; i
<value_list
.n_values
; i
++)
815 if (value_list
.list_value
[i
].match_omit())
816 return template_selection
==VALUE_LIST
;
817 return template_selection
==COMPLEMENTED_LIST
;
826 #ifndef TITAN_RUNTIME_2
827 void COMPONENT_template::check_restriction(template_res t_res
, const char* t_name
,
828 boolean legacy
/* = FALSE */) const
830 if (template_selection
==UNINITIALIZED_TEMPLATE
) return;
831 switch ((t_name
&&(t_res
==TR_VALUE
))?TR_OMIT
:t_res
) {
833 if (!is_ifpresent
&& template_selection
==SPECIFIC_VALUE
) return;
836 if (!is_ifpresent
&& (template_selection
==OMIT_VALUE
||
837 template_selection
==SPECIFIC_VALUE
)) return;
840 if (!match_omit(legacy
)) return;
845 TTCN_error("Restriction `%s' on template of type %s violated.",
846 get_res_name(t_res
), t_name
? t_name
: "component reference");
850 const COMPONENT_template
any_compref_value(ANY_VALUE
);
851 const COMPONENT_template
& any_compref
= any_compref_value
;