1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
10 #include "../common/memory.h"
12 #include "Component.hh"
14 #include "Parameters.h"
15 #include "Param_Types.hh"
17 #include "Optional.hh"
19 #include "../common/dbgnew.hh"
21 COMPONENT::COMPONENT()
23 component_value
= UNBOUND_COMPREF
;
26 COMPONENT::COMPONENT(component other_value
)
28 component_value
= other_value
;
31 COMPONENT::COMPONENT(const COMPONENT
& other_value
)
32 : Base_Type(other_value
)
34 if (other_value
.component_value
== UNBOUND_COMPREF
)
35 TTCN_error("Copying an unbound component reference.");
36 component_value
= other_value
.component_value
;
39 COMPONENT
& COMPONENT::operator=(component other_value
)
41 component_value
= other_value
;
45 COMPONENT
& COMPONENT::operator=(const COMPONENT
& other_value
)
47 if (other_value
.component_value
== UNBOUND_COMPREF
)
48 TTCN_error("Assignment of an unbound component reference.");
49 component_value
= other_value
.component_value
;
53 boolean
COMPONENT::operator==(component other_value
) const
55 if (component_value
== UNBOUND_COMPREF
) TTCN_error("The left operand of "
56 "comparison is an unbound component reference.");
57 return component_value
== other_value
;
60 boolean
COMPONENT::operator==(const COMPONENT
& other_value
) const
62 if (component_value
== UNBOUND_COMPREF
) TTCN_error("The left operand of "
63 "comparison is an unbound component reference.");
64 if (other_value
.component_value
== UNBOUND_COMPREF
) TTCN_error("The right "
65 "operand of comparison is an unbound component reference.");
66 return component_value
== other_value
.component_value
;
69 COMPONENT::operator component() const
71 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Using the value of an "
72 "unbound component reference.");
73 return component_value
;
76 void COMPONENT::log() const
78 if (component_value
!= UNBOUND_COMPREF
)
79 log_component_reference(component_value
);
80 else TTCN_Logger::log_event_unbound();
83 alt_status
COMPONENT::done() const
85 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing done "
86 "operation on an unbound component reference.");
87 return TTCN_Runtime::component_done(component_value
);
90 alt_status
COMPONENT::killed() const
92 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing killed "
93 "operation on an unbound component reference.");
94 return TTCN_Runtime::component_killed(component_value
);
97 boolean
COMPONENT::running() const
99 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing running "
100 "operation on an unbound component reference.");
101 return TTCN_Runtime::component_running(component_value
);
104 boolean
COMPONENT::alive() const
106 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing alive "
107 "operation on an unbound component reference.");
108 return TTCN_Runtime::component_alive(component_value
);
111 void COMPONENT::stop() const
113 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing stop "
114 "operation on an unbound component reference.");
115 TTCN_Runtime::stop_component(component_value
);
118 void COMPONENT::kill() const
120 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Performing kill "
121 "operation on an unbound component reference.");
122 TTCN_Runtime::kill_component(component_value
);
125 void COMPONENT::set_param(Module_Param
& param
) {
126 param
.basic_check(Module_Param::BC_VALUE
, "component reference (integer or null) value");
127 Module_Param_Ptr mp
= ¶m
;
128 if (param
.get_type() == Module_Param::MP_Reference
) {
129 mp
= param
.get_referenced_param();
131 if (Ttcn_String_Parsing::happening()) {
132 // accept all component values in case it's a string2ttcn operation
133 switch (mp
->get_type()) {
134 case Module_Param::MP_Integer
:
135 component_value
= (component
)mp
->get_integer()->get_val();
137 case Module_Param::MP_Ttcn_Null
:
138 component_value
= NULL_COMPREF
;
140 case Module_Param::MP_Ttcn_mtc
:
141 component_value
= MTC_COMPREF
;
143 case Module_Param::MP_Ttcn_system
:
144 component_value
= SYSTEM_COMPREF
;
147 param
.type_error("component reference (integer or null) value");
151 // only accept the null value if it's a module parameter
152 if (Module_Param::MP_Ttcn_Null
!= mp
->get_type()) {
153 param
.error("Only the 'null' value is allowed for module parameters of type 'component'.");
155 component_value
= NULL_COMPREF
;
159 Module_Param
* COMPONENT::get_param(Module_Param_Name
& /* param_name */) const
162 return new Module_Param_Unbound();
164 return new Module_Param_Ttcn_Null();
167 void COMPONENT::encode_text(Text_Buf
& text_buf
) const
169 if (component_value
== UNBOUND_COMPREF
) TTCN_error("Text encoder: Encoding "
170 "an unbound component reference.");
171 text_buf
.push_int((int)component_value
);
172 switch (component_value
) {
178 text_buf
.push_string(get_component_name(component_value
));
183 void COMPONENT::decode_text(Text_Buf
& text_buf
)
185 component_value
= (component
)text_buf
.pull_int().get_val();
186 switch (component_value
) {
192 char *component_name
= text_buf
.pull_string();
193 register_component_name(component_value
, component_name
);
194 delete [] component_name
;
199 boolean
operator==(component component_value
, const COMPONENT
& other_value
)
201 if (other_value
.component_value
== UNBOUND_COMPREF
) TTCN_error("The right "
202 "operand of comparison is an unbound component reference.");
203 return component_value
== other_value
.component_value
;
206 unsigned int COMPONENT::n_component_names
= 0;
207 struct COMPONENT::component_name_struct
{
208 component component_reference
;
209 char *component_name
;
210 } *COMPONENT::component_names
= NULL
;
212 void COMPONENT::register_component_name(component component_reference
,
213 const char *component_name
)
215 if (self
.component_value
== component_reference
) {
216 // the own name of the component will not be registered,
217 // but check whether we got the right string
218 const char *local_name
= TTCN_Runtime::get_component_name();
219 if (component_name
== NULL
|| component_name
[0] == '\0') {
220 if (local_name
!= NULL
) {
221 TTCN_error("Internal error: Trying to register the component "
222 "reference of this PTC without any name, but this "
223 "component has name %s.", local_name
);
226 if (local_name
== NULL
) {
227 TTCN_error("Internal error: Trying to register the component "
228 "reference of this PTC with name %s, but this component "
229 "does not have name.", component_name
);
230 } else if (strcmp(component_name
, local_name
)) {
231 TTCN_error("Internal error: Trying to register the component "
232 "reference of this PTC with name %s, but this component "
233 "has name %s.", component_name
, local_name
);
238 unsigned int min
= 0;
239 if (n_component_names
> 0) {
240 // perform a binary search to find the place for the component reference
241 unsigned int max
= n_component_names
- 1;
243 unsigned int mid
= min
+ (max
- min
) / 2;
244 if (component_names
[mid
].component_reference
< component_reference
)
246 else if (component_names
[mid
].component_reference
==
247 component_reference
) {
252 if (component_names
[min
].component_reference
== component_reference
) {
253 // the component reference is already registered
254 const char *stored_name
= component_names
[min
].component_name
;
255 if (component_name
== NULL
|| component_name
[0] == '\0') {
256 if (stored_name
!= NULL
) {
257 TTCN_error("Internal error: Trying to register component "
258 "reference %d without any name, but this component "
259 "reference is already registered with name %s.",
260 component_reference
, stored_name
);
263 if (stored_name
== NULL
) {
264 TTCN_error("Internal error: Trying to register component "
265 "reference %d with name %s, but this component "
266 "reference is already registered without name.",
267 component_reference
, component_name
);
268 } else if (strcmp(component_name
, stored_name
)) {
269 TTCN_error("Internal error: Trying to register component "
270 "reference %d with name %s, but this component "
271 "reference is already registered with a different "
272 "name (%s).", component_reference
, component_name
,
278 if (component_names
[min
].component_reference
< component_reference
)
280 // the component reference will be inserted before the index "min"
282 (component_name_struct
*)Realloc(component_names
,
283 (n_component_names
+ 1) * sizeof(*component_names
));
284 memmove(component_names
+ min
+ 1, component_names
+ min
,
285 (n_component_names
- min
) * sizeof(*component_names
));
288 // this is the first component reference to be registered
290 (component_name_struct
*)Malloc(sizeof(*component_names
));
292 component_names
[min
].component_reference
= component_reference
;
293 if (component_name
== NULL
|| component_name
[0] == '\0')
294 component_names
[min
].component_name
= NULL
;
295 else component_names
[min
].component_name
= mcopystr(component_name
);
299 const char *COMPONENT::get_component_name(component component_reference
)
301 if (self
.component_value
== component_reference
) {
302 // the own name of the PTC is not registered
303 return TTCN_Runtime::get_component_name();
304 } else if (n_component_names
> 0) {
305 unsigned int min
= 0, max
= n_component_names
- 1;
307 unsigned int mid
= min
+ (max
- min
) / 2;
308 if (component_names
[mid
].component_reference
< component_reference
)
310 else if (component_names
[mid
].component_reference
==
312 return component_names
[mid
].component_name
;
315 if (component_names
[min
].component_reference
!= component_reference
)
316 TTCN_error("Internal error: Trying to get the name of PTC with "
317 "component reference %d, but the name of the component "
318 "is not registered.", component_reference
);
319 return component_names
[min
].component_name
;
321 TTCN_error("Internal error: Trying to get the name of PTC with "
322 "component reference %d, but there are no component names "
323 "registered.", component_reference
);
328 void COMPONENT::clear_component_names()
330 for (unsigned int i
= 0; i
< n_component_names
; i
++)
331 Free(component_names
[i
].component_name
);
332 Free(component_names
);
333 n_component_names
= 0;
334 component_names
= NULL
;
337 void COMPONENT::log_component_reference(component component_reference
)
339 switch (component_reference
) {
341 TTCN_Logger::log_event_str("null");
344 TTCN_Logger::log_event_str("mtc");
347 TTCN_Logger::log_event_str("system");
350 const char *component_name
= get_component_name(component_reference
);
351 if (component_name
!= NULL
) TTCN_Logger::log_event("%s(%d)",
352 component_name
, component_reference
);
353 else TTCN_Logger::log_event("%d", component_reference
);
358 // get_component_string is suspiciously similar to log_component_reference.
359 // It would be trivially easy to implement log_... with get_...
360 // but it would involve a runtime penalty, because get_component_string
361 // returns a newly allocated string which must be freed, whereas log_...
362 // uses fixed strings. So the current implementation pays for speed with size.
363 // Perhaps log_component_reference will go away one day.
364 char *COMPONENT::get_component_string(component component_reference
)
366 switch (component_reference
) {
368 return mcopystr("null");
370 return mcopystr("mtc");
372 return mcopystr("system");
373 case CONTROL_COMPREF
:
374 return mcopystr("control");
376 const char *component_name
= get_component_name(component_reference
);
377 if (component_name
!= NULL
) return mprintf("%s(%d)",
378 component_name
, component_reference
);
379 else return mprintf("%d", component_reference
);
385 void COMPONENT_template::clean_up()
387 if (template_selection
== VALUE_LIST
388 ||template_selection
== COMPLEMENTED_LIST
)
389 delete [] value_list
.list_value
;
390 template_selection
= UNINITIALIZED_TEMPLATE
;
393 void COMPONENT_template::copy_template(const COMPONENT_template
& other_value
)
395 switch (other_value
.template_selection
) {
397 single_value
= other_value
.single_value
;
404 case COMPLEMENTED_LIST
:
405 value_list
.n_values
= other_value
.value_list
.n_values
;
406 value_list
.list_value
= new COMPONENT_template
[value_list
.n_values
];
407 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
408 value_list
.list_value
[i
].copy_template(
409 other_value
.value_list
.list_value
[i
]);
412 TTCN_error("Copying an uninitialized/unsupported component reference "
415 set_selection(other_value
);
418 COMPONENT_template::COMPONENT_template()
423 COMPONENT_template::COMPONENT_template(template_sel other_value
)
424 : Base_Template(other_value
)
426 check_single_selection(other_value
);
429 COMPONENT_template::COMPONENT_template(component other_value
)
430 : Base_Template(SPECIFIC_VALUE
)
432 single_value
= other_value
;
435 COMPONENT_template::COMPONENT_template(const COMPONENT
& other_value
)
436 : Base_Template(SPECIFIC_VALUE
)
438 if (other_value
.component_value
== UNBOUND_COMPREF
)
439 TTCN_error("Creating a template from an unbound component reference.");
440 single_value
= other_value
.component_value
;
443 COMPONENT_template::COMPONENT_template(const OPTIONAL
<COMPONENT
>& other_value
)
445 switch (other_value
.get_selection()) {
446 case OPTIONAL_PRESENT
:
447 set_selection(SPECIFIC_VALUE
);
448 single_value
= (component
)(const COMPONENT
&)other_value
;
451 set_selection(OMIT_VALUE
);
454 TTCN_error("Creating a component reference template from an unbound "
459 COMPONENT_template::COMPONENT_template(const COMPONENT_template
& other_value
)
462 copy_template(other_value
);
465 COMPONENT_template::~COMPONENT_template()
470 COMPONENT_template
& COMPONENT_template::operator=(template_sel other_value
)
472 check_single_selection(other_value
);
474 set_selection(other_value
);
478 COMPONENT_template
& COMPONENT_template::operator=(component other_value
)
481 set_selection(SPECIFIC_VALUE
);
482 single_value
= other_value
;
486 COMPONENT_template
& COMPONENT_template::operator=(const COMPONENT
& other_value
)
488 if (other_value
.component_value
== UNBOUND_COMPREF
)
489 TTCN_error("Assignment of an unbound component reference to a "
491 return *this = other_value
.component_value
;
494 COMPONENT_template
& COMPONENT_template::operator=
495 (const OPTIONAL
<COMPONENT
>& other_value
)
498 switch (other_value
.get_selection()) {
499 case OPTIONAL_PRESENT
:
500 set_selection(SPECIFIC_VALUE
);
501 single_value
= (component
)(const COMPONENT
&)other_value
;
504 set_selection(OMIT_VALUE
);
507 TTCN_error("Assignment of an unbound optional field to a component "
508 "reference template.");
513 COMPONENT_template
& COMPONENT_template::operator=
514 (const COMPONENT_template
& other_value
)
516 if (&other_value
!= this) {
518 copy_template(other_value
);
523 boolean
COMPONENT_template::match(component other_value
,
524 boolean
/* legacy */) const
526 switch (template_selection
) {
528 return single_value
== other_value
;
535 case COMPLEMENTED_LIST
:
536 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
537 if (value_list
.list_value
[i
].match(other_value
))
538 return template_selection
== VALUE_LIST
;
539 return template_selection
== COMPLEMENTED_LIST
;
541 TTCN_error("Matching an uninitialized/unsupported component reference "
547 boolean
COMPONENT_template::match(const COMPONENT
& other_value
,
548 boolean
/* legacy */) const
550 if (other_value
.component_value
== UNBOUND_COMPREF
)
551 TTCN_error("Matching an unbound component reference with a template.");
552 return match(other_value
.component_value
);
555 component
COMPONENT_template::valueof() const
557 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
558 TTCN_error("Performing a valueof or send operation on a non-specific "
559 "component reference template.");
563 void COMPONENT_template::set_type(template_sel template_type
,
564 unsigned int list_length
)
566 if (template_type
!= VALUE_LIST
&& template_type
!= COMPLEMENTED_LIST
)
567 TTCN_error("Setting an invalid list type for a component reference "
570 set_selection(template_type
);
571 value_list
.n_values
= list_length
;
572 value_list
.list_value
= new COMPONENT_template
[list_length
];
575 COMPONENT_template
& COMPONENT_template::list_item(unsigned int list_index
)
577 if (template_selection
!= VALUE_LIST
&&
578 template_selection
!= COMPLEMENTED_LIST
)
579 TTCN_error("Accessing a list element of a non-list component "
580 "reference template.");
581 if (list_index
>= value_list
.n_values
)
582 TTCN_error("Index overflow in a component reference value list "
584 return value_list
.list_value
[list_index
];
587 void COMPONENT_template::log() const
589 switch (template_selection
) {
591 switch (single_value
) {
593 TTCN_Logger::log_event_str("null");
596 TTCN_Logger::log_event_str("mtc");
599 TTCN_Logger::log_event_str("system");
602 TTCN_Logger::log_event("%d", single_value
);
606 case COMPLEMENTED_LIST
:
607 TTCN_Logger::log_event_str("complement ");
610 TTCN_Logger::log_char('(');
611 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++) {
612 if (i
> 0) TTCN_Logger::log_event_str(", ");
613 value_list
.list_value
[i
].log();
615 TTCN_Logger::log_char(')');
624 void COMPONENT_template::log_match(const COMPONENT
& match_value
,
625 boolean
/* legacy */) const
627 if (TTCN_Logger::VERBOSITY_COMPACT
== TTCN_Logger::get_matching_verbosity()
628 && TTCN_Logger::get_logmatch_buffer_len() != 0) {
629 TTCN_Logger::print_logmatch_buffer();
630 TTCN_Logger::log_event_str(" := ");
633 TTCN_Logger::log_event_str(" with ");
635 if (match(match_value
)) TTCN_Logger::log_event_str(" matched");
636 else TTCN_Logger::log_event_str(" unmatched");
639 void COMPONENT_template::set_param(Module_Param
& param
) {
640 param
.basic_check(Module_Param::BC_TEMPLATE
, "component reference (integer or null) template");
641 Module_Param_Ptr mp
= ¶m
;
642 if (param
.get_type() == Module_Param::MP_Reference
) {
643 mp
= param
.get_referenced_param();
645 switch (mp
->get_type()) {
646 case Module_Param::MP_Omit
:
649 case Module_Param::MP_Any
:
652 case Module_Param::MP_AnyOrNone
:
655 case Module_Param::MP_List_Template
:
656 case Module_Param::MP_ComplementList_Template
: {
657 COMPONENT_template temp
;
658 temp
.set_type(mp
->get_type() == Module_Param::MP_List_Template
?
659 VALUE_LIST
: COMPLEMENTED_LIST
, mp
->get_size());
660 for (size_t i
=0; i
<mp
->get_size(); i
++) {
661 temp
.list_item(i
).set_param(*mp
->get_elem(i
));
665 case Module_Param::MP_Integer
:
666 *this = (component
)mp
->get_integer()->get_val();
668 case Module_Param::MP_Ttcn_Null
:
669 *this = NULL_COMPREF
;
671 case Module_Param::MP_Ttcn_mtc
:
674 case Module_Param::MP_Ttcn_system
:
675 *this = SYSTEM_COMPREF
;
678 param
.type_error("component reference (integer or null) template");
680 is_ifpresent
= param
.get_ifpresent() || mp
->get_ifpresent();
683 Module_Param
* COMPONENT_template::get_param(Module_Param_Name
& param_name
) const
685 Module_Param
* mp
= NULL
;
686 switch (template_selection
) {
687 case UNINITIALIZED_TEMPLATE
:
688 mp
= new Module_Param_Unbound();
691 mp
= new Module_Param_Omit();
694 mp
= new Module_Param_Any();
697 mp
= new Module_Param_AnyOrNone();
700 switch (single_value
) {
702 mp
= new Module_Param_Ttcn_Null();
705 mp
= new Module_Param_Ttcn_mtc();
708 mp
= new Module_Param_Ttcn_system();
711 mp
= new Module_Param_Integer(new int_val_t(single_value
));
716 case COMPLEMENTED_LIST
: {
717 if (template_selection
== VALUE_LIST
) {
718 mp
= new Module_Param_List_Template();
721 mp
= new Module_Param_ComplementList_Template();
723 for (size_t i
= 0; i
< value_list
.n_values
; ++i
) {
724 mp
->add_elem(value_list
.list_value
[i
].get_param(param_name
));
736 void COMPONENT_template::encode_text(Text_Buf
& text_buf
) const
738 encode_text_base(text_buf
);
739 switch (template_selection
) {
745 text_buf
.push_int(single_value
);
747 case COMPLEMENTED_LIST
:
749 text_buf
.push_int(value_list
.n_values
);
750 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
751 value_list
.list_value
[i
].encode_text(text_buf
);
754 TTCN_error("Text encoder: Encoding an uninitialized/unsupported "
755 "component reference template.");
759 void COMPONENT_template::decode_text(Text_Buf
& text_buf
)
762 decode_text_base(text_buf
);
763 switch (template_selection
) {
769 single_value
= (component
)text_buf
.pull_int().get_val();
771 case COMPLEMENTED_LIST
:
773 value_list
.n_values
= text_buf
.pull_int().get_val();
774 value_list
.list_value
= new COMPONENT_template
[value_list
.n_values
];
775 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
776 value_list
.list_value
[i
].decode_text(text_buf
);
779 TTCN_error("Text decoder: An unknown/unsupported selection was "
780 "received for a component reference template.");
784 boolean
COMPONENT_template::is_present(boolean legacy
/* = FALSE */) const
786 if (template_selection
==UNINITIALIZED_TEMPLATE
) return FALSE
;
787 return !match_omit(legacy
);
790 boolean
COMPONENT_template::match_omit(boolean legacy
/* = FALSE */) const
792 if (is_ifpresent
) return TRUE
;
793 switch (template_selection
) {
798 case COMPLEMENTED_LIST
:
800 // legacy behavior: 'omit' can appear in the value/complement list
801 for (unsigned int i
=0; i
<value_list
.n_values
; i
++)
802 if (value_list
.list_value
[i
].match_omit())
803 return template_selection
==VALUE_LIST
;
804 return template_selection
==COMPLEMENTED_LIST
;
813 #ifndef TITAN_RUNTIME_2
814 void COMPONENT_template::check_restriction(template_res t_res
, const char* t_name
,
815 boolean legacy
/* = FALSE */) const
817 if (template_selection
==UNINITIALIZED_TEMPLATE
) return;
818 switch ((t_name
&&(t_res
==TR_VALUE
))?TR_OMIT
:t_res
) {
820 if (!is_ifpresent
&& template_selection
==SPECIFIC_VALUE
) return;
823 if (!is_ifpresent
&& (template_selection
==OMIT_VALUE
||
824 template_selection
==SPECIFIC_VALUE
)) return;
827 if (!match_omit(legacy
)) return;
832 TTCN_error("Restriction `%s' on template of type %s violated.",
833 get_res_name(t_res
), t_name
? t_name
: "component reference");
837 const COMPONENT_template
any_compref_value(ANY_VALUE
);
838 const COMPONENT_template
& any_compref
= any_compref_value
;