From a38c6d4c92d78d84a8c44543ee3a890e50432e35 Mon Sep 17 00:00:00 2001 From: erititan Date: Fri, 22 May 2015 10:58:38 +0200 Subject: [PATCH] Sync with 5.3.0 --- common/version.h | 4 +- compiler2/AST.cc | 47 +- compiler2/Setting.cc | 31 +- compiler2/Type.cc | 81 +- compiler2/Type.hh | 6 +- compiler2/Type_codegen.cc | 63 +- compiler2/Value.cc | 26 +- compiler2/Value.hh | 6 +- compiler2/compiler.1 | 7 + compiler2/datatypes.h | 2 + compiler2/main.cc | 66 +- compiler2/main.hh | 3 +- compiler2/record.c | 39 +- compiler2/record_of.c | 387 ++-- compiler2/subtype.cc | 3 + compiler2/ttcn3/AST_ttcn3.cc | 2046 +++++++++-------- compiler2/ttcn3/Makefile | 2 +- compiler2/ttcn3/Statement.cc | 56 +- compiler2/ttcn3/Statement.hh | 9 +- compiler2/ttcn3/TtcnTemplate.cc | 37 +- compiler2/ttcn3/compiler.c | 5 +- compiler2/ttcn3/compiler.l | 1 + compiler2/ttcn3/compiler.y | 41 +- compiler2/ttcn3/profiler.c | 126 + compiler2/ttcn3/profiler.h | 74 + core/ASN_CharacterString.cc | 26 +- core/ASN_EmbeddedPDV.cc | 26 +- core/ASN_External.cc | 8 +- core/Array.hh | 36 +- core/Basetype.cc | 64 +- core/Basetype.hh | 14 +- core/Component.cc | 38 +- core/Float.cc | 65 +- core/Float.hh | 4 + core/Makefile | 24 +- core/Module_list.cc | 2 - core/Optional.hh | 32 +- core/Parallel_main.cc | 18 +- core/PreGenRecordOf.ttcn | 83 + core/Profiler.cc | 1549 ++++++++++--- core/Profiler.hh | 133 +- core/RAW.cc | 4 +- core/RefdIndex.hh | 55 + core/Runtime.cc | 5 + core/Single_main.cc | 20 +- core/Snapshot.cc | 1 + core/TEXT.cc | 3 + core/TEXT.hh | 1 + core/TTCN3.hh | 3 + core/Template.hh | 13 +- core/Universal_charstring.cc | 241 +- core/Universal_charstring.hh | 4 + core/XER.hh | 26 +- core/config_process.l | 191 +- core/config_process.y | 64 +- core2/Basetype2.cc | 73 +- etc/xsd/TXD.xsd | 174 -- .../BER_EncDec/BER_EncDec_TD.fast_script | 6 +- .../Config_Parser/Logging_1_TD.script | 6 +- .../Config_Parser/OrderedInclude.script | 4 +- .../PreprocessingCfgFiles_TD.script | 6 +- .../RAW_EncDec/RAW_EncDec_TD.fast_script | 4 +- .../Semantic_Analyser/ASN_SA_1_TD.script | 6 +- .../ASN_SA_asn1adhoc_TD.script | 6 +- .../Semantic_Analyser/TTCN3_SA_10_TD.script | 6 +- .../Semantic_Analyser/TTCN3_SA_11_TD.script | 6 +- .../TTCN3_SA_12_TD.script_not_running | 4 +- .../Semantic_Analyser/TTCN3_SA_13_TD.script | 4 +- .../Semantic_Analyser/TTCN3_SA_1_TD.script | 6 +- .../Semantic_Analyser/TTCN3_SA_3_TD.script | 8 +- .../Semantic_Analyser/TTCN3_SA_4_TD.script | 4 +- .../Semantic_Analyser/TTCN3_SA_5_TD.script | 6 +- .../Semantic_Analyser/TTCN3_SA_6_TD.script | 12 +- .../Semantic_Analyser/TTCN3_SA_7_TD.script | 4 +- .../Semantic_Analyser/TTCN3_SA_9_TD.script | 13 +- .../TTCN3_SA_ttcn3adhoc_TD.script | 142 +- .../Text_EncDec/TEXT_1_TD.fast_script | 4 +- function_test/Tools/SAtester | 9 +- function_test/XER_EncDec/XER_EncDec_TD.script | 18 +- .../doc/TTCN3_Executor_TestReport.doc | Bin 1091072 -> 1106432 bytes help/Makefile | 10 +- help/info/on.html | 2 +- help/info/operators.html | 4 +- help/info/optional.html | 2 +- help/info/procedure.html | 2 +- help/info/profiler.html | 134 ++ help/info/public.html | 2 +- help/info/running.html | 28 +- help/info/start.html | 14 +- help/info/stop.html | 22 +- help/titan_index.html | 17 +- help/titan_main.html | 4 +- loggerplugins/JUnitLogger2/JUnitLogger2.cc | 346 +++ loggerplugins/JUnitLogger2/JUnitLogger2.hh | 119 + loggerplugins/JUnitLogger2/Makefile | 96 + loggerplugins/Makefile | 2 +- loggerplugins/TSTLogger/TSTLogger.cc | 1 + mctr2/cli/config_read.l | 63 +- mctr2/cli/config_read.y | 44 +- mctr2/mctr/MainController.cc | 2 + mctr2/mctr/ttcn3_start | 5 +- regression_test/Makefile | 2 +- .../XML/EXER-whitepaper/EmbedValues.ttcnpp | 96 +- regression_test/XML/TTCNandXML/Makefile | 2 +- regression_test/XML/XER/checkit.pl | 1 + .../all_from/all_from_subtype.ttcn | 191 ++ .../all_from/all_from_with_functions.ttcn | 44 +- regression_test/all_from/types.ttcn | 44 + regression_test/boolOper/TboolOper.ttcn | 55 + .../assignment/assignment.cfg | 4 +- .../assignment/assignment.ttcn | 16 +- regression_test/compileonly/Makefile | 2 +- .../compileonly/selectCase/Makefile | 41 + .../compileonly/selectCase/selectCase.ttcn | 76 + regression_test/negativeTest/Makefile | 2 +- regression_test/profiler/Makefile | 82 + regression_test/profiler/PIPEasp_PT.cc | 738 ++++++ regression_test/profiler/PIPEasp_PT.hh | 106 + .../profiler/PIPEasp_PortType.ttcn | 46 + .../profiler/PIPEasp_Templates.ttcn | 93 + regression_test/profiler/PIPEasp_Types.ttcn | 180 ++ regression_test/profiler/Shell.ttcn | 244 ++ regression_test/profiler/Testcases.ttcn | 74 + regression_test/profiler/data_e.json | 226 ++ regression_test/profiler/empty_e.stats | 5 + regression_test/profiler/prof1.cfg | 22 + regression_test/profiler/prof1.ttcn | 30 + regression_test/profiler/prof1_e.stats | 84 + regression_test/profiler/prof2.cfg | 20 + regression_test/profiler/prof2.ttcn | 36 + regression_test/profiler/prof3.cfg | 22 + regression_test/profiler/prof3.ttcn | 35 + regression_test/profiler/prof_files.txt | 3 + regression_test/recofOper/Makefile | 2 +- regression_test/recofOper/TrecofCompat.ttcn | 262 +++ regression_test/recofOper/TrecofParamRef.ttcn | 28 + regression_test/recofOper/config.cfg | 1 + regression_test/recofOper/config_rt2.cfg | 1 + regression_test/testcase_defparam/Makefile | 2 +- .../ucharstrOper/cstr_content.ttcn | 36 + .../doc/Titan_Executor_API_User_Guide.doc | Bin 64512 -> 64512 bytes usrguide/PRI.doc | Bin 83456 -> 84480 bytes usrguide/apiguide.doc | Bin 564224 -> 555520 bytes usrguide/installationguide.doc | Bin 118272 -> 118272 bytes usrguide/referenceguide.doc | Bin 1541120 -> 1615360 bytes usrguide/releasenotes.doc | Bin 572416 -> 581120 bytes usrguide/userguide.doc | Bin 849408 -> 847872 bytes 147 files changed, 8087 insertions(+), 2238 deletions(-) create mode 100644 compiler2/ttcn3/profiler.c create mode 100644 compiler2/ttcn3/profiler.h create mode 100644 core/PreGenRecordOf.ttcn create mode 100644 core/RefdIndex.hh delete mode 100644 etc/xsd/TXD.xsd create mode 100644 help/info/profiler.html create mode 100644 loggerplugins/JUnitLogger2/JUnitLogger2.cc create mode 100644 loggerplugins/JUnitLogger2/JUnitLogger2.hh create mode 100644 loggerplugins/JUnitLogger2/Makefile create mode 100644 regression_test/all_from/all_from_subtype.ttcn create mode 100644 regression_test/compileonly/selectCase/Makefile create mode 100644 regression_test/compileonly/selectCase/selectCase.ttcn create mode 100755 regression_test/profiler/Makefile create mode 100644 regression_test/profiler/PIPEasp_PT.cc create mode 100644 regression_test/profiler/PIPEasp_PT.hh create mode 100644 regression_test/profiler/PIPEasp_PortType.ttcn create mode 100644 regression_test/profiler/PIPEasp_Templates.ttcn create mode 100644 regression_test/profiler/PIPEasp_Types.ttcn create mode 100644 regression_test/profiler/Shell.ttcn create mode 100644 regression_test/profiler/Testcases.ttcn create mode 100644 regression_test/profiler/data_e.json create mode 100644 regression_test/profiler/empty_e.stats create mode 100644 regression_test/profiler/prof1.cfg create mode 100644 regression_test/profiler/prof1.ttcn create mode 100644 regression_test/profiler/prof1_e.stats create mode 100644 regression_test/profiler/prof2.cfg create mode 100644 regression_test/profiler/prof2.ttcn create mode 100644 regression_test/profiler/prof3.cfg create mode 100644 regression_test/profiler/prof3.ttcn create mode 100644 regression_test/profiler/prof_files.txt create mode 100644 regression_test/recofOper/TrecofCompat.ttcn diff --git a/common/version.h b/common/version.h index a72a783..5ee2842 100644 --- a/common/version.h +++ b/common/version.h @@ -10,7 +10,7 @@ /* Version numbers */ #define TTCN3_MAJOR 5 -#define TTCN3_MINOR 2 +#define TTCN3_MINOR 3 #define TTCN3_PATCHLEVEL 0 //#define TTCN3_BUILDNUMBER 0 @@ -22,7 +22,7 @@ * TTCN3_VERSION = TTCN3_MAJOR * 1000000 + TTCN3_MINOR * 10000 + * TTCN3_PATCHLEVEL * 100 + TTCN3_BUILDNUMBER */ -#define TTCN3_VERSION 50200 +#define TTCN3_VERSION 50300 /* A monotonically increasing version number. * An official release is deemed to have the highest possible build number (99) diff --git a/compiler2/AST.cc b/compiler2/AST.cc index 4cfcad2..202d282 100644 --- a/compiler2/AST.cc +++ b/compiler2/AST.cc @@ -23,6 +23,7 @@ #include "../common/version.h" #include "CodeGenHelper.hh" #include +#include "ttcn3/profiler.h" reffer::reffer(const char*) {} @@ -774,7 +775,9 @@ namespace Common { } // pre_init function bool has_pre_init = false; - if (output->functions.pre_init) { + bool profiled = MOD_TTCN == get_moduletype() && is_file_profiled(get_filename()); + // always generate pre_init_module if the file is profiled + if (output->functions.pre_init || profiled) { output->source.static_function_prototypes = mputstr(output->source.static_function_prototypes, "static void pre_init_module();\n"); @@ -800,11 +803,11 @@ namespace Common { mputprintf(effective_module_functions, "%s\"%s\"", (effective_module_functions ? ", " : ""), get_modid().get_dispname().c_str()); } - if (profiler_enabled && MOD_TTCN == get_moduletype()) { + if (profiled) { output->source.static_function_bodies = mputprintf(output->source.static_function_bodies, + "%s::init_ttcn3_profiler();\n" "TTCN3_Stack_Depth stack_depth;\n" - "ttcn3_prof.enter_function(\"%s\", 0, \"%s\");\n", - get_filename(), get_modid().get_dispname().c_str()); + "ttcn3_prof.execute_line(\"%s\", 0);\n", get_modid().get_name().c_str(), get_filename()); } } output->source.static_function_bodies = @@ -843,11 +846,10 @@ namespace Common { mputprintf(effective_module_functions, "%s\"%s\"", (effective_module_functions ? ", " : ""), get_modid().get_dispname().c_str()); } - if (profiler_enabled && MOD_TTCN == get_moduletype()) { + if (MOD_TTCN == get_moduletype() && is_file_profiled(get_filename())) { output->source.static_function_bodies = mputprintf(output->source.static_function_bodies, "TTCN3_Stack_Depth stack_depth;\n" - "ttcn3_prof.enter_function(\"%s\", 0, \"%s\");\n", - get_filename(), get_modid().get_dispname().c_str()); + "ttcn3_prof.execute_line(\"%s\", 0);\n", get_filename()); } } output->source.static_function_bodies = @@ -1482,13 +1484,38 @@ namespace Common { // language specific parts (definitions, imports, etc.) //generate_code_internal(&target); <- needed to pass cgh generate_code_internal(cgh); + + output_struct* output = cgh.get_current_outputstruct(); // string literals - generate_literals(cgh.get_current_outputstruct()); + generate_literals(output); // module level entry points - generate_functions(cgh.get_current_outputstruct()); + generate_functions(output); // type conversion functions for type compatibility - generate_conversion_functions(cgh.get_current_outputstruct()); + generate_conversion_functions(output); + + /* generate the initializer function for the TTCN-3 profiler + * (this is done at the end of the code generation, to make sure all code + * lines have been added to the profiler database) */ + if (is_file_profiled(get_filename())) { + output->source.global_vars = mputstr(output->source.global_vars, + "\n/* Initializing TTCN-3 profiler */\n" + "void init_ttcn3_profiler()\n" + "{\n"); + char* function_name = 0; + int line_no = -1; + while(get_profiler_code_line(get_filename(), &function_name, &line_no)) { + output->source.global_vars = mputprintf(output->source.global_vars, + " ttcn3_prof.create_line(ttcn3_prof.get_element(\"%s\"), %d);\n", + get_filename(), line_no); + if (0 != function_name) { + output->source.global_vars = mputprintf(output->source.global_vars, + " ttcn3_prof.create_function(ttcn3_prof.get_element(\"%s\"), %d, \"%s\");\n", + get_filename(), line_no, function_name); + } + } + output->source.global_vars = mputstr(output->source.global_vars, "}\n\n"); + } } void Module::dump(unsigned level) const diff --git a/compiler2/Setting.cc b/compiler2/Setting.cc index 1dae00b..47e5a73 100644 --- a/compiler2/Setting.cc +++ b/compiler2/Setting.cc @@ -18,6 +18,7 @@ #include "Value.hh" #include "Int.hh" #include "main.hh" +#include "ttcn3/profiler.h" namespace Common { @@ -232,11 +233,20 @@ namespace Common { mputprintf(effective_module_functions, "%s\"%s\"", (effective_module_functions ? ", " : ""), entityname); } - if (profiler_enabled) { + if (is_file_profiled(filename)) { + // .ttcnpp -> .ttcn + size_t file_name_len = strlen(filename); + if ('p' == filename[file_name_len - 1] && 'p' == filename[file_name_len - 2]) { + file_name_len -= 2; + } + char* file_name2 = mcopystrn(filename, file_name_len); str = mputprintf(str, "TTCN3_Stack_Depth stack_depth;\n" - "ttcn3_prof.enter_function(\"%s\", %d, \"%s\");\n", - filename, yyloc.first_line, entityname); + "ttcn3_prof.enter_function(\"%s\", %d);\n", file_name2, yyloc.first_line); + insert_profiler_code_line(file_name2, + (0 == strcmp(entitytype, "CONTROLPART") ? "control" : entityname), + yyloc.first_line); + Free(file_name2); } } return str; @@ -248,11 +258,20 @@ namespace Common { if (include_location_info && !transparency) { str = mputprintf(str, "current_location.update_lineno(%d);\n", yyloc.first_line); - if (profiler_enabled) { + const char* file_name = get_filename(); + if (is_file_profiled(file_name)) { + // .ttcnpp -> .ttcn + size_t file_name_len = strlen(file_name); + if ('p' == file_name[file_name_len - 1] && 'p' == file_name[file_name_len - 2]) { + file_name_len -= 2; + } + char* file_name2 = mcopystrn(file_name, file_name_len); str = mputprintf(str, "ttcn3_prof.execute_line(\"%s\", %d);\n", - get_filename(), yyloc.first_line); + file_name2, yyloc.first_line); + insert_profiler_code_line(file_name2, NULL, yyloc.first_line); + Free(file_name2); } - if (tcov_file_name && in_tcov_files(get_filename())) { + if (tcov_file_name && in_tcov_files(file_name)) { effective_module_lines = mputprintf(effective_module_lines, "%s%d", (effective_module_lines ? ", " : ""), yyloc.first_line); diff --git a/compiler2/Type.cc b/compiler2/Type.cc index 2a9683d..fd06d5d 100644 --- a/compiler2/Type.cc +++ b/compiler2/Type.cc @@ -149,7 +149,7 @@ namespace Common { } } - Type *Type::get_stream_type(MessageEncodingType_t encoding_type) + Type *Type::get_stream_type(MessageEncodingType_t encoding_type, int stream_variant) { switch (encoding_type) { case CT_BER: @@ -159,7 +159,11 @@ namespace Common { case CT_JSON: return get_pooltype(T_OSTR); case CT_TEXT: - return get_pooltype(T_CSTR); + if(stream_variant==0){ + return get_pooltype(T_CSTR); + } else { + return get_pooltype(T_OSTR); + } default: FATAL_ERROR("Type::get_stream_type()"); return 0; @@ -3529,6 +3533,20 @@ namespace Common { { if (typetype != T_SEQOF) FATAL_ERROR("Type::is_compatible_record_of()"); if (this == p_type) return true; + else if (T_SEQOF == p_type->get_type_refd_last()->typetype && + is_pregenerated() && p_type->is_pregenerated() && + get_ofType()->get_type_refd_last()->typetype == + p_type->get_ofType()->get_type_refd_last()->typetype && + (use_runtime_2 || get_optimize_attribute() == p_type->get_optimize_attribute())) { + // Pre-generated record-ofs of the same element type are compatible with + // each other (in RT1 optimized record-ofs are not compatible with non-optimized ones) + if (!is_subtype_length_compatible(p_type)) { + p_info->set_is_erroneous(this, p_type, string("Incompatible " + "record of/SEQUENCE OF subtypes")); + return false; + } + return true; + } else if (!use_runtime_2 || !p_info || (p_info && p_info->is_strict())) return false; switch (p_type->typetype) { @@ -3878,6 +3896,20 @@ namespace Common { { if (typetype != T_SETOF) FATAL_ERROR("Type::is_compatible_set_of()"); if (this == p_type) return true; + else if (T_SETOF == p_type->get_type_refd_last()->typetype && + is_pregenerated() && p_type->is_pregenerated() && + get_ofType()->get_type_refd_last()->typetype == + p_type->get_ofType()->get_type_refd_last()->typetype && + (use_runtime_2 || get_optimize_attribute() == p_type->get_optimize_attribute())) { + // Pre-generated set-ofs of the same element type are compatible with + // each other (in RT1 optimized set-ofs are not compatible with non-optimized ones) + if (!is_subtype_length_compatible(p_type)) { + p_info->set_is_erroneous(this, p_type, string("Incompatible " + "set of/SET OF subtypes")); + return false; + } + return true; + } else if (!use_runtime_2 || !p_info || (p_info && p_info->is_strict())) return false; Type *of_type = get_ofType(); @@ -5523,6 +5555,7 @@ end_ext: case T_INT: case T_OSTR: case T_CSTR: + case T_USTR: // TTCN3 universal charstring // these basic types support TEXT encoding by default return true; default: @@ -6833,6 +6866,50 @@ end_ext: } return dispname; } + + bool Type::is_pregenerated() + { + // records/sets of base types are already pre-generated, only a type alias will be generated + // exception: record of universal charstring with the XER coding instruction "anyElement" + if (!force_gen_seof && (T_SEQOF == get_type_refd_last()->typetype || + T_SETOF == get_type_refd_last()->typetype) && + (NULL == xerattrib || /* check for "anyElement" at the record of type */ + NamespaceRestriction::UNUSED == xerattrib->anyElement_.type_) && + (NULL == u.seof.ofType->xerattrib || /* check for "anyElement" at the element type */ + NamespaceRestriction::UNUSED == u.seof.ofType->xerattrib->anyElement_.type_)) { + switch(u.seof.ofType->get_type_refd_last()->typetype) { + case T_BOOL: + case T_INT: + case T_INT_A: + case T_REAL: + case T_BSTR: + case T_BSTR_A: + case T_HSTR: + case T_OSTR: + case T_CSTR: + case T_NUMERICSTRING: + case T_PRINTABLESTRING: + case T_IA5STRING: + case T_VISIBLESTRING: + case T_UNRESTRICTEDSTRING: + case T_UTCTIME: + case T_GENERALIZEDTIME: + case T_USTR: + case T_UTF8STRING: + case T_TELETEXSTRING: + case T_VIDEOTEXSTRING: + case T_GRAPHICSTRING: + case T_GENERALSTRING: + case T_UNIVERSALSTRING: + case T_BMPSTRING: + case T_OBJECTDESCRIPTOR: + return true; + default: + return false; + } + } + return false; + } } // namespace Common diff --git a/compiler2/Type.hh b/compiler2/Type.hh index 55737c9..29f8595 100644 --- a/compiler2/Type.hh +++ b/compiler2/Type.hh @@ -244,7 +244,7 @@ namespace Common { static const char *get_encoding_name(MessageEncodingType_t encoding_type); /** Returns a pool type that represents the encoded stream of the given * \a encoding_type. */ - static Type *get_stream_type(MessageEncodingType_t encoding_type); + static Type *get_stream_type(MessageEncodingType_t encoding_type, int stream_variant=0); enum truth { No, Maybe, Yes @@ -1017,6 +1017,10 @@ namespace Common { otherwise returns false. **/ bool ispresent_anyvalue_embedded_field(Type* t, Ttcn::FieldOrArrayRefs *subrefs, size_t begin_index); + + /** Returns true if the C++ class for this type has already been pre-generated + * or false if it still needs to be generated */ + bool is_pregenerated(); public: /** Generates type specific call for the reference used in isbound call * into argument \a expr. Argument \a subrefs holds the reference path diff --git a/compiler2/Type_codegen.cc b/compiler2/Type_codegen.cc index b6baffb..5be67c2 100644 --- a/compiler2/Type_codegen.cc +++ b/compiler2/Type_codegen.cc @@ -382,6 +382,16 @@ void Type::generate_code_typedescriptor(output_struct *target) "NULL, "); } } + + if (T_SEQOF == get_type_refd_last()->typetype || + T_SETOF == get_type_refd_last()->typetype) { + target->source.global_vars=mputprintf(target->source.global_vars, + "&%s_descr_, ", get_type_refd_last()->u.seof.ofType->get_genname_typedescriptor(my_scope).c_str()); + } + else { + target->source.global_vars = mputstr(target->source.global_vars, + "NULL, "); + } target->source.global_vars=mputprintf(target->source.global_vars, "TTCN_Typedescriptor_t::%s };\n" @@ -483,6 +493,7 @@ void Type::generate_code_xerdescriptor(output_struct* target) any_except=0, nof_ns_uris=0; const char* dfe_str = 0; char** ns_uris = 0; + char* oftype_descr_name = 0; if (xerattrib) { change_name(last_s, xerattrib->name_); @@ -572,6 +583,12 @@ void Type::generate_code_xerdescriptor(output_struct* target) size_t last_len = 2 + last_s.size(); // 2 for > \n size_t bxer_len = 2 + bxer_name.size(); // 2 for > \n + if ((T_SEQOF == last->typetype || T_SETOF == last->typetype) && + T_ANYTYPE != last->u.seof.ofType->get_type_refd_last()->typetype) { + // anytypes don't have XER descriptors + oftype_descr_name = mprintf("&%s_xer_", last->u.seof.ofType->get_genname_typedescriptor(my_scope).c_str()); + } + // Generate a separate variable for the namespace URIs, if there are any char* ns_uris_var = 0; if (ns_uris && nof_ns_uris) { @@ -591,7 +608,7 @@ void Type::generate_code_xerdescriptor(output_struct* target) target->source.global_vars = mputprintf(target->source.global_vars, "const XERdescriptor_t %s_xer_ = { {\"%s>\\n\", \"%s>\\n\"}," " {%lu, %lu}, %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s, WHITESPACE_%s, %c%s, " - "&%s, %ld, %u, %s };\n", + "&%s, %ld, %u, %s, %s };\n", gennameown_str, bxer_name.c_str(), last_s.c_str(), // names (unsigned long)bxer_len, (unsigned long)last_len, // lengths @@ -618,10 +635,12 @@ void Type::generate_code_xerdescriptor(output_struct* target) "module_object", ns_index, nof_ns_uris, - (ns_uris_var ? ns_uris_var : "NULL") + (ns_uris_var ? ns_uris_var : "NULL"), + (oftype_descr_name ? oftype_descr_name : "NULL") ); Free(ns_uris_var); + Free(oftype_descr_name); } void Type::generate_code_rawdescriptor(output_struct *target) @@ -1471,6 +1490,7 @@ void Type::generate_code_Se(output_struct *target) cur.dispname = id.get_ttcnname().c_str(); cur.isOptional = cf->get_is_optional(); cur.isDefault = cf->has_default(); + cur.optimizedMemAlloc = cur.of_type && (type->get_optimize_attribute() == "memalloc"); if (cur.isDefault) { Value *defval = cf->get_defval(); const_def cdef; @@ -1810,6 +1830,41 @@ bool Type::is_untagged() const { return xerattrib && xerattrib->untagged_; } void Type::generate_code_SeOf(output_struct *target) { + const Type *oftypelast = u.seof.ofType->get_type_refd_last(); + const string& oftypename = u.seof.ofType->get_genname_value(my_scope); + boolean optimized_memalloc = !use_runtime_2 && get_optimize_attribute() == "memalloc"; + + if (is_pregenerated()) { + switch(oftypelast->typetype) { + case T_USTR: + case T_UTF8STRING: + case T_TELETEXSTRING: + case T_VIDEOTEXSTRING: + case T_GRAPHICSTRING: + case T_GENERALSTRING: + case T_UNIVERSALSTRING: + case T_BMPSTRING: + case T_OBJECTDESCRIPTOR: + target->header.typedefs = mputprintf(target->header.typedefs, + "typedef PreGenRecordOf::PREGEN__%s__OF__UNIVERSAL__CHARSTRING%s %s;\n" + "typedef PreGenRecordOf::PREGEN__%s__OF__UNIVERSAL__CHARSTRING%s_template %s_template;\n", + (typetype == T_SEQOF) ? "RECORD" : "SET", + optimized_memalloc ? "__OPTIMIZED" : "", get_genname_own().c_str(), + (typetype == T_SEQOF) ? "RECORD" : "SET", + optimized_memalloc ? "__OPTIMIZED" : "", get_genname_own().c_str()); + return; + default: + target->header.typedefs = mputprintf(target->header.typedefs, + "typedef PreGenRecordOf::PREGEN__%s__OF__%s%s %s;\n" + "typedef PreGenRecordOf::PREGEN__%s__OF__%s%s_template %s_template;\n", + (typetype == T_SEQOF) ? "RECORD" : "SET", oftypename.c_str(), + optimized_memalloc ? "__OPTIMIZED" : "", get_genname_own().c_str(), + (typetype == T_SEQOF) ? "RECORD" : "SET", oftypename.c_str(), + optimized_memalloc ? "__OPTIMIZED" : "", get_genname_own().c_str()); + return; + } + } + stringpool pool; struct_of_def sofdef; memset(&sofdef, 0, sizeof(sofdef)); @@ -1826,10 +1881,8 @@ void Type::generate_code_SeOf(output_struct *target) } // If a record of UTF8String, we need to prepare for ANY-ATTRIBUTES and // ANY-ELEMENT - const Type *oftypelast = u.seof.ofType->get_type_refd_last(); sofdef.xerAnyAttrElem = oftypelast->typetype == T_USTR || oftypelast->typetype == T_UTF8STRING; - const string& oftypename = u.seof.ofType->get_genname_value(my_scope); sofdef.type = oftypename.c_str(); sofdef.has_opentypes = get_has_opentypes(); const string& oftypedescrname = @@ -1895,7 +1948,7 @@ void Type::generate_code_SeOf(output_struct *target) sofdef.hasRaw=true; } else sofdef.hasRaw=false; - if (!use_runtime_2 && get_optimize_attribute()=="memalloc") { + if (optimized_memalloc) { defRecordOfClassMemAllocOptimized(&sofdef, target); } else { defRecordOfClass(&sofdef, target); diff --git a/compiler2/Value.cc b/compiler2/Value.cc index a1c1c8a..7fb2f0b 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -143,6 +143,7 @@ namespace Common { case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: + case OPTYPE_PROF_RUNNING: break; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: @@ -446,6 +447,7 @@ namespace Common { case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: + case OPTYPE_PROF_RUNNING: break; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: @@ -809,6 +811,7 @@ namespace Common { case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: + case OPTYPE_PROF_RUNNING: break; default: FATAL_ERROR("Value::Value()"); @@ -1388,6 +1391,7 @@ namespace Common { case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: + case OPTYPE_PROF_RUNNING: break; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: @@ -1567,6 +1571,7 @@ namespace Common { case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: + case OPTYPE_PROF_RUNNING: break; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: @@ -1876,6 +1881,7 @@ namespace Common { case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: + case OPTYPE_PROF_RUNNING: break; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: @@ -2765,6 +2771,7 @@ namespace Common { case OPTYPE_ISCHOSEN_T: case OPTYPE_ISVALUE: case OPTYPE_ISBOUND: + case OPTYPE_PROF_RUNNING: return Type::T_BOOL; case OPTYPE_GETVERDICT: return Type::T_VERDICT; @@ -3448,6 +3455,8 @@ namespace Common { return "log2str()"; case OPTYPE_TTCN2STRING: return "ttcn2string()"; + case OPTYPE_PROF_RUNNING: + return "@profiler.running"; default: FATAL_ERROR("Value::get_opname()"); } // switch @@ -6038,6 +6047,7 @@ error: switch (u.expr.v_optype) { case OPTYPE_COMP_NULL: case OPTYPE_TESTCASENAME: + case OPTYPE_PROF_RUNNING: break; case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: @@ -6998,6 +7008,7 @@ error: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: + case OPTYPE_PROF_RUNNING: case OPTYPE_RNDWITHVAL: // v1 case OPTYPE_COMP_RUNNING: // v1 case OPTYPE_COMP_ALIVE: @@ -8294,6 +8305,7 @@ error: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: + case OPTYPE_PROF_RUNNING: case OPTYPE_RNDWITHVAL: // v1 case OPTYPE_MATCH: // v1 t2 case OPTYPE_UNDEF_RUNNING: // v1 @@ -9797,6 +9809,7 @@ error: case OPTYPE_COMP_ALIVE_ALL: // - case OPTYPE_TMR_RUNNING_ANY: // - case OPTYPE_GETVERDICT: // - + case OPTYPE_PROF_RUNNING: // - break; // nothing to do case OPTYPE_MATCH: // v1 t2 @@ -10496,6 +10509,8 @@ error: } ret_val += ')'; return ret_val; } + case OPTYPE_PROF_RUNNING: + return string("@profiler.running"); default: return string(""); } // switch u.expr.v_optype @@ -11771,6 +11786,9 @@ error: } expr->expr = mputstr(expr->expr, ")"); } break; + case OPTYPE_PROF_RUNNING: + expr->expr = mputstr(expr->expr, "ttcn3_prof.is_running()"); + break; default: FATAL_ERROR("Value::generate_code_expr_expr()"); } @@ -12857,6 +12875,7 @@ error: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: + case OPTYPE_PROF_RUNNING: return true; case OPTYPE_ENCODE: case OPTYPE_DECODE: @@ -13178,13 +13197,16 @@ error: if (t_subrefs) { // the evaluation of the reference does not have side effects // (i.e. false shall be returned) only if all sub-references point to - // mandatory fields of record/set types + // mandatory fields of record/set types, and neither sub-reference points + // to a field of a union type Type *t_type = t_ass->get_Type(); for (size_t i = 0; i < t_subrefs->get_nof_refs(); i++) { Ttcn::FieldOrArrayRef *t_fieldref = t_subrefs->get_ref(i); if (t_fieldref->get_type() == Ttcn::FieldOrArrayRef::FIELD_REF) { CompField *t_cf = t_type->get_comp_byName(*t_fieldref->get_id()); - if (t_cf->get_is_optional()) return true; + if (Type::T_CHOICE_T == t_type->get_type_refd_last()->get_typetype() || + Type::T_CHOICE_A == t_type->get_type_refd_last()->get_typetype() || + t_cf->get_is_optional()) return true; t_type = t_cf->get_type(); } else return true; } diff --git a/compiler2/Value.hh b/compiler2/Value.hh index cfd3f79..61d324c 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -238,7 +238,8 @@ namespace Common { OPTYPE_EXECUTE, // r1 [v2] OPTYPE_EXECUTE_REFD, // v1 t_list2 [v3] - OPTYPE_LOG2STR, // logagrs 98 + OPTYPE_LOG2STR, // logagrs + OPTYPE_PROF_RUNNING, // - 99 NUMBER_OF_OPTYPES // must be last }; @@ -369,7 +370,8 @@ namespace Common { Value(valuetype_t p_vt, Value *p_v, Ttcn::ParsedActualParameters *p_t_list); /** Constructor used by V_EXPR "-": RND, TESTCASENAME, COMP_NULL, COMP_MTC, * COMP_SYSTEM, COMP_SELF, COMP_RUNNING_ANY, COMP_RUNNING_ALL, - * COMP_ALIVE_ALL, COMP_ALIVE_ANY, TMR_RUNNING_ANY, GETVERDICT */ + * COMP_ALIVE_ALL, COMP_ALIVE_ANY, TMR_RUNNING_ANY, GETVERDICT, + * PROF_RUNNING */ Value(operationtype_t p_optype); /** Constructor used by V_EXPR "v1" */ Value(operationtype_t p_optype, Value *p_v1); diff --git a/compiler2/compiler.1 b/compiler2/compiler.1 index a3416e4..2df9a34 100644 --- a/compiler2/compiler.1 +++ b/compiler2/compiler.1 @@ -8,6 +8,8 @@ compiler \- TTCN-3 and ASN.1 to C++ translator .IR " verb_level" " \|]" .RB "[\| " \-K .IR " file" " \|]" +.RB "[\| " \-z +.IR " file" " \|]" .RB "[\| " \-o .IR " dir" " \|]" .RB "[\| " \-P @@ -294,6 +296,11 @@ checking .B \-Y Enforces legacy behaviour of the "out" function parameters (see refguide). .TP +.BI \-z " file" +Enables profiling and code coverage in the selected TTCN-3 files. The +.I file +argument contains a list of TTCN-3 files separated by new lines. Each TTCN-3 file must be among the compiler's TTCN-3 file arguments. +.TP .B \- The single dash character as command line argument controls the .I selective code generation diff --git a/compiler2/datatypes.h b/compiler2/datatypes.h index a24cf63..a49fe4b 100644 --- a/compiler2/datatypes.h +++ b/compiler2/datatypes.h @@ -70,6 +70,8 @@ typedef struct { boolean jsonOmitAsNull; const char* jsonAlias; const char* jsonDefaultValue; + /** true if the field is a record-of or set-of with optimized memory allocation */ + boolean optimizedMemAlloc; } struct_field; /** Structure (record, set, union, anytype) descriptor for code generation */ diff --git a/compiler2/main.cc b/compiler2/main.cc index fd58f1a..7a0d19b 100644 --- a/compiler2/main.cc +++ b/compiler2/main.cc @@ -45,6 +45,8 @@ #include "ttcn3/Ttcn2Json.hh" +#include "ttcn3/profiler.h" + #ifdef LICENSE #include "../common/license.h" #endif @@ -53,6 +55,7 @@ using namespace Common; const char *output_dir = NULL; const char *tcov_file_name = NULL; +const char *profiler_file_name = NULL; tcov_file_list *tcov_files = NULL; expstring_t effective_module_lines = NULL; expstring_t effective_module_functions = NULL; @@ -68,7 +71,7 @@ boolean generate_skeleton = FALSE, force_overwrite = FALSE, use_runtime_2 = FALSE, gcc_compat = FALSE, asn1_xer = FALSE, check_subtype = TRUE, suppress_context = FALSE, display_up_to_date = FALSE, implicit_json_encoding = FALSE, json_refs_for_all_types = TRUE, - profiler_enabled = FALSE; + force_gen_seof = FALSE; // Default code splitting mode is set to 'no splitting'. CodeGenHelper::split_type code_splitting_mode = CodeGenHelper::SPLIT_NONE; @@ -286,7 +289,8 @@ boolean in_tcov_files(const char *file_name) return get_tcov_file_name(file_name) ? TRUE : FALSE; } -static bool check_file_list(const char *file_name, module_struct *module_list, size_t n_modules) +static bool check_file_list(const char *file_name, module_struct *module_list, + size_t n_modules, tcov_file_list *&file_list_head) { FILE *fp = fopen(file_name, "r"); if (fp == NULL) { @@ -316,11 +320,11 @@ static bool check_file_list(const char *file_name, module_struct *module_list, s for (; i < n_modules; ++i) { const module_struct *module = module_list + i; if (!strncmp(module->file_name, line, line_len)) { - tcov_file_list *next_file = new tcov_file_list; - next_file->next = tcov_files; + tcov_file_list *next_file = (tcov_file_list*)Malloc(sizeof(tcov_file_list)); + next_file->next = file_list_head; // We'll need the `.ttcnpp' file name. next_file->file_name = mcopystr(line); - tcov_files = next_file; + file_list_head = next_file; break; } } @@ -332,13 +336,13 @@ static bool check_file_list(const char *file_name, module_struct *module_list, s } fclose(fp); if (unlisted_files) { - while (tcov_files != NULL) { - tcov_file_list *next_file = tcov_files->next; - Free(tcov_files->file_name); - delete tcov_files; - tcov_files = next_file; + while (file_list_head != NULL) { + tcov_file_list *next_file = file_list_head->next; + Free(file_list_head->file_name); + Free(file_list_head); + file_list_head = next_file; } - tcov_files = NULL; + file_list_head = NULL; } return !unlisted_files; } @@ -354,8 +358,8 @@ static boolean is_valid_asn1_filename(const char* file_name) static void usage() { fprintf(stderr, "\n" - "usage: %s [-abcdfgilLOpqrRsStuwxXjy] [-K file] [-V verb_level] [-o dir]\n" - " [-U none|type] [-P modulename.top_level_pdu_name] [-Q number] ...\n" + "usage: %s [-abcdfgijlLOpqrRsStuwxXyY] [-K file] [-z file] [-V verb_level]\n" + " [-o dir] [-U none|type] [-P modulename.top_level_pdu_name] [-Q number] ...\n" " [-T] module.ttcn [-A] module.asn ...\n" " or %s -v\n" " or %s --ttcn2json [-jf] ... [-T] module.ttcn [-A] module.asn ... [- schema.json]\n" @@ -390,7 +394,7 @@ static void usage() " -X: disable XER encoder/decoder functions\n" " -y: disable subtype checking\n" " -Y: Enforces legacy behaviour of the \"out\" function parameters (see refguide)\n" - //" -z: enable profiling and code coverage for TTCN-3 files\n" - not open to the public yet + " -z file: enable profiling and code coverage for the TTCN-3 files in the argument\n" " -T file: force interpretation of file as TTCN-3 module\n" " -A file: force interpretation of file as ASN.1 module\n" " -v: show version\n" @@ -438,7 +442,7 @@ int main(int argc, char *argv[]) usage(); return EXIT_FAILURE; } - + bool Aflag = false, Lflag = false, Yflag = false, Pflag = false, Tflag = false, Vflag = false, bflag = false, @@ -447,7 +451,7 @@ int main(int argc, char *argv[]) tflag = false, uflag = false, vflag = false, wflag = false, xflag = false, dflag = false, Xflag = false, Rflag = false, gflag = false, aflag = false, s0flag = false, Cflag = false, yflag = false, Uflag = false, Qflag = false, - Sflag = false, Kflag = false, jflag = false, zflag = false, + Sflag = false, Kflag = false, jflag = false, zflag = false, Fflag = false, errflag = false, print_usage = false, ttcn2json = false; CodeGenHelper cgh; @@ -540,7 +544,7 @@ int main(int argc, char *argv[]) if (!ttcn2json) { for ( ; ; ) { - int c = getopt(argc, argv, "aA:C:K:LP:T:V:bcdfgilo:YpqQ:rRs0StuU:vwxXjyz-"); + int c = getopt(argc, argv, "aA:C:K:LP:T:V:bcdfFgilo:YpqQ:rRs0StuU:vwxXjyz:-"); if (c == -1) break; switch (c) { case 'a': @@ -697,7 +701,11 @@ int main(int argc, char *argv[]) break; case 'z': SET_FLAG(z); - profiler_enabled = TRUE; + profiler_file_name = optarg; + break; + case 'F': + SET_FLAG(F); + force_gen_seof = TRUE; break; case 'Q': { @@ -722,8 +730,8 @@ int main(int argc, char *argv[]) Error_Context::set_max_errors(max_errs); break; } - - case '-': + + case '-': if (!strcmp(argv[optind], "--ttcn2json")) { ERROR("Option `--ttcn2json' is only allowed as the first option"); } else { @@ -743,7 +751,7 @@ int main(int argc, char *argv[]) if (Aflag || Lflag || Pflag || Tflag || Vflag || Yflag || bflag || fflag || iflag || lflag || oflag || pflag || qflag || rflag || sflag || tflag || uflag || wflag || xflag || Xflag || Rflag || - Uflag || yflag || Kflag || jflag || zflag) { + Uflag || yflag || Kflag || jflag || zflag || Fflag) { errflag = true; print_usage = true; } @@ -966,11 +974,20 @@ int main(int argc, char *argv[]) has_xer_feature = check_feature(&lstr, FEATURE_XER); free_license(&lstr); #endif - if (Kflag && !check_file_list(tcov_file_name, module_list, n_modules)) { + if (Kflag && !check_file_list(tcov_file_name, module_list, n_modules, tcov_files)) { ERROR("Error while processing `%s' provided for code coverage data " "generation.", tcov_file_name); return EXIT_FAILURE; } + if (zflag) { + tcov_file_list *file_list_head = NULL; + if(!check_file_list(profiler_file_name, module_list, n_modules, file_list_head)) { + ERROR("Error while processing `%s' provided for profiling and code coverage.", + profiler_file_name); + return EXIT_FAILURE; + } + init_profiler_data(file_list_head); + } { STOPWATCH("Parsing modules"); @@ -1069,7 +1086,7 @@ int main(int argc, char *argv[]) while (tcov_files != NULL) { tcov_file_list *next_file = tcov_files->next; Free(tcov_files->file_name); - delete tcov_files; + Free(tcov_files); tcov_files = next_file; } tcov_files = NULL; @@ -1081,6 +1098,9 @@ int main(int argc, char *argv[]) Common::Node::chk_counter(); Location::delete_source_file_names(); Free(json_schema_name); + if (zflag) { + free_profiler_data(); + } // dbgnew.hh already does it: check_mem_leak(argv[0]); diff --git a/compiler2/main.hh b/compiler2/main.hh index 18ec896..4e52203 100644 --- a/compiler2/main.hh +++ b/compiler2/main.hh @@ -13,6 +13,7 @@ extern "C" { #endif #include "datatypes.h" +#include "../common/memory.h" typedef struct tcov_file_list { @@ -34,7 +35,7 @@ extern boolean generate_skeleton, force_overwrite, include_line_info, include_location_info, duplicate_underscores, parse_only, semantic_check_only, output_only_linenum, default_as_optional, use_runtime_2, gcc_compat, asn1_xer, check_subtype, suppress_context, enable_set_bound_out_param, display_up_to_date, - implicit_json_encoding, json_refs_for_all_types, profiler_enabled; + implicit_json_encoding, json_refs_for_all_types, force_gen_seof; extern const char *expected_platform; diff --git a/compiler2/record.c b/compiler2/record.c index 79e914f..eeda176 100644 --- a/compiler2/record.c +++ b/compiler2/record.c @@ -2118,10 +2118,17 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " embed_values_enc_struct_t* emb_val = 0;\n" " if (e_xer && (p_td.xer_bits & EMBED_VALUES) && field_%s.size_of() > 1) {\n" " emb_val = new embed_values_enc_struct_t;\n" - " emb_val->embval_array = &field_%s;\n" + /* If the first field is a record of ANY-ELEMENTs, then it won't be a pre-generated + * record of universal charstring, so it needs a cast to avoid a compilation error */ + " emb_val->embval_array%s = (const PreGenRecordOf::PREGEN__RECORD__OF__UNIVERSAL__CHARSTRING%s*)&field_%s;\n" + " emb_val->embval_array%s = NULL;\n" " emb_val->embval_index = 1;\n" - " emb_val->embval_size = field_%s.size_of();\n" - " }\n", sdef->elements[0].name, sdef->elements[0].name, sdef->elements[0].name); + " }\n" + , sdef->elements[0].name + , sdef->elements[0].optimizedMemAlloc ? "_opt" : "_reg" + , sdef->elements[0].optimizedMemAlloc ? "__OPTIMIZED" : "" + , sdef->elements[0].name + , sdef->elements[0].optimizedMemAlloc ? "_reg" : "_opt"); } if (sdef->xerUseOrderPossible) { @@ -2223,12 +2230,12 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) if (sdef->xerEmbedValuesPossible) { src = mputprintf(src, " if (e_xer && (p_td.xer_bits & EMBED_VALUES) && 0 != emb_val &&\n" - " emb_val->embval_index < emb_val->embval_size) { // embed-val\n" + " emb_val->embval_index < field_%s.size_of()) { // embed-val\n" " field_%s[emb_val->embval_index].XER_encode(\n" " UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n" " ++emb_val->embval_index;\n" " }\n" - , sdef->elements[0].name); + , sdef->elements[0].name, sdef->elements[0].name); } @@ -2255,27 +2262,27 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) if (sdef->xerEmbedValuesPossible) { src = mputprintf(src, " if (e_xer && (p_td.xer_bits & EMBED_VALUES) && 0 != emb_val &&\n" - " emb_val->embval_index < emb_val->embval_size) {\n" + " emb_val->embval_index < field_%s.size_of()) {\n" " field_%s[emb_val->embval_index].XER_encode(\n" " UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n" " ++emb_val->embval_index;\n" " }\n" - , sdef->elements[0].name); + , sdef->elements[0].name, sdef->elements[0].name); } } /* next field when not USE-ORDER */ if (sdef->xerEmbedValuesPossible) { src = mputprintf(src, " if (0 != emb_val) {\n" - " if (emb_val->embval_index < emb_val->embval_size) {\n" + " if (emb_val->embval_index < field_%s.size_of()) {\n" " ec_1.set_msg(\"%s': \");\n" " TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_CONSTRAINT,\n" " \"Too many EMBED-VALUEs specified: %%d (expected %%d or less)\",\n" - " emb_val->embval_size, emb_val->embval_index);\n" + " field_%s.size_of(), emb_val->embval_index);\n" " }\n" " delete emb_val;\n" " }\n" - , sdef->elements[0].name); + , sdef->elements[0].name, sdef->elements[0].name, sdef->elements[0].name); } src = mputstr(src, " } // QN?\n"); @@ -2636,10 +2643,18 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " embed_values_dec_struct_t* emb_val = 0;\n" " if (e_xer && (p_td.xer_bits & EMBED_VALUES)) {\n" " emb_val = new embed_values_dec_struct_t;\n" - " emb_val->embval_array = &field_%s;\n" + /* If the first field is a record of ANY-ELEMENTs, then it won't be a pre-generated + * record of universal charstring, so it needs a cast to avoid a compilation error */ + " emb_val->embval_array%s = (PreGenRecordOf::PREGEN__RECORD__OF__UNIVERSAL__CHARSTRING%s*)&field_%s;\n" + " emb_val->embval_array%s = NULL;\n" " emb_val->embval_index = 0;\n" " field_%s.set_size(0);\n" - " }\n", sdef->elements[0].name, sdef->elements[0].name); + " }\n" + , sdef->elements[0].optimizedMemAlloc ? "_opt" : "_reg" + , sdef->elements[0].optimizedMemAlloc ? "__OPTIMIZED" : "" + , sdef->elements[0].name + , sdef->elements[0].optimizedMemAlloc ? "_reg" : "_opt" + , sdef->elements[0].name); } if (sdef->xerUseOrderPossible) { diff --git a/compiler2/record_of.c b/compiler2/record_of.c index b820722..5f97b3d 100644 --- a/compiler2/record_of.c +++ b/compiler2/record_of.c @@ -39,11 +39,11 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) char *def = NULL, *src = NULL; const char *name = sdef->name, *dispname = sdef->dispname; const char *type = sdef->type; - boolean ber_needed = sdef->isASN1 && enable_ber(); - boolean raw_needed = sdef->hasRaw && enable_raw(); - boolean text_needed = sdef->hasText && enable_text(); - boolean xer_needed = sdef->hasXer && enable_xer(); - boolean json_needed = sdef->hasJson && enable_json(); + boolean ber_needed = force_gen_seof || (sdef->isASN1 && enable_ber()); + boolean raw_needed = force_gen_seof || (sdef->hasRaw && enable_raw()); + boolean text_needed = force_gen_seof || (sdef->hasText && enable_text()); + boolean xer_needed = force_gen_seof || (sdef->hasXer && enable_xer()); + boolean json_needed = force_gen_seof || (sdef->hasJson && enable_json()); /* Class definition and private data members */ def = mputprintf(def, @@ -723,7 +723,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " p_buf.put_cs(*p_td.text->separator_encode);\n" " encoded_length+=p_td.text->separator_encode->lengthof();\n" " }\n" - " encoded_length+=(*this)[a].TEXT_encode(%s_descr_,p_buf);\n" + " encoded_length+=(*this)[a].TEXT_encode(*p_td.oftype_descr,p_buf);\n" " }\n" " if(p_td.text->end_encode){\n" " p_buf.put_cs(*p_td.text->end_encode);\n" @@ -731,7 +731,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n" " return encoded_length;\n" "}\n" - ,name,sdef->oftypedescrname + ,name ); src = mputprintf(src, "int %s::TEXT_decode(const TTCN_Typedescriptor_t& p_td," @@ -774,7 +774,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " while(TRUE){\n" " %s *val=new %s;\n" " pos=p_buf.get_pos();\n" - " int len=val->TEXT_decode(%s_descr_,p_buf,limit,TRUE);\n" + " int len=val->TEXT_decode(*p_td.oftype_descr,p_buf,limit,TRUE);\n" " if(len==-1 || (len==0 && !limit.has_token())){\n" " p_buf.set_pos(pos);\n" " delete val;\n" @@ -816,7 +816,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n" " }\n" " }\n" - ,name,type,type,sdef->oftypedescrname,type + ,name,type,type,type ); src = mputstr(src, " limit.remove_tokens(ml);\n" @@ -871,7 +871,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " for(int elem_i=0; elem_in_elements; elem_i++) {\n" " ec.set_msg(\"Component #%%d: \", elem_i);\n" " new_tlv->add_TLV((*this)[elem_i].BER_encode_TLV" - "(%s_descr_, p_coding));\n" + "(*p_td.oftype_descr, p_coding));\n" " }\n" "%s" " }\n" @@ -905,16 +905,16 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "val_ptr->n_elements + 1);\n" " val_ptr->n_elements++;\n" " val_ptr->value_elements[val_ptr->n_elements - 1] = new %s;\n" - " val_ptr->value_elements[val_ptr->n_elements - 1]->BER_decode_TLV(%s_descr_, tmp_tlv, " + " val_ptr->value_elements[val_ptr->n_elements - 1]->BER_decode_TLV(*p_td.oftype_descr, tmp_tlv, " "L_form);\n" " ec_2.set_msg(\"%%d: \", val_ptr->n_elements);\n" " }\n" " return TRUE;\n" "}\n" "\n" - , name, sdef->oftypedescrname + , name , sdef->kind==SET_OF?" new_tlv->sort_tlvs();\n":"" - , name, type, type, sdef->oftypedescrname + , name, type, type ); if(sdef->has_opentypes) { @@ -966,7 +966,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " int a=0;\n" " if(sel_field==-1) sel_field=p_td.raw->fieldlength;\n" " for(a=0;a0){\n" " start_of_field=p_buf.get_pos_bit();\n" - " decoded_field_length=(*this)[a].RAW_decode(%s_descr_,p_buf,limit," + " decoded_field_length=(*this)[a].RAW_decode(*p_td.oftype_descr,p_buf,limit," "top_bit_ord,TRUE);\n" " if(decoded_field_length < 0){\n" " delete &(*this)[a];\n" @@ -997,13 +997,16 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " decoded_length+=decoded_field_length;\n" " limit-=decoded_field_length;\n" " a++;\n" - ,name,sdef->oftypedescrname,sdef->oftypedescrname + ,name ); - if(sdef->raw.extension_bit!=XDEFNO && sdef->raw.extension_bit!=XDEFDEFAULT){ + if (force_gen_seof || (sdef->raw.extension_bit!=XDEFNO && sdef->raw.extension_bit!=XDEFDEFAULT)){ src=mputprintf(src, - " if (%sp_buf.get_last_bit())\n" + " if (%s%sp_buf.get_last_bit()%s)\n" " return decoded_length+p_buf.increase_pos_padd(p_td.raw->padding)" - "+prepaddlength;\n", sdef->raw.extension_bit == XDEFYES ? "" : "!"); + "+prepaddlength;\n" + , force_gen_seof ? "EXT_BIT_NO != p_td.raw->extension_bit && ((EXT_BIT_YES != p_td.raw->extension_bit) ^ " : "" + , (force_gen_seof || sdef->raw.extension_bit == XDEFYES) ? "" : "!" + , force_gen_seof ? ")" : ""); } src=mputprintf(src, " }\n" @@ -1023,12 +1026,12 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " myleaf.body.node.nodes=init_nodes_of_enc_tree(encoded_num_of_records);\n" " for(int a=0;araw);\n" + " encoded_length+=(*this)[a].RAW_encode(*p_td.oftype_descr," "*myleaf.body.node.nodes[a]);\n" " }\n" " return myleaf.length=encoded_length;\n}\n\n" - , name, sdef->oftypedescrname, sdef->oftypedescrname + , name ); } @@ -1042,10 +1045,12 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "boolean %s::can_start(const char *name, const char *uri, " "XERdescriptor_t const& xd, unsigned int flavor) {\n" " boolean e_xer = is_exer(flavor);\n" - " if (e_xer && (xd.xer_bits & ANY_ELEMENT)) " + " if ((!e_xer || !(xd.xer_bits & UNTAGGED)) && !(flavor & XER_RECOF)) return " + "check_name(name, xd, e_xer) && (!e_xer || check_namespace(uri, xd));\n" + " if (e_xer && (xd.oftype_descr->xer_bits & ANY_ELEMENT)) " , name ); - if (sdef->nFollowers) { + if (!force_gen_seof && sdef->nFollowers) { /* If there are optional fields following the record-of, then seeing * {any XML tag that belongs to those fields} where the record-of may be * means that the record-of is empty. */ @@ -1065,12 +1070,9 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) else src = mputstr(src, "return TRUE;\n"); src = mputprintf(src, - " if ((!e_xer || !(xd.xer_bits & UNTAGGED)) && !(flavor & XER_RECOF)) return " - "check_name(name, xd, e_xer) && (!e_xer || check_namespace(uri, xd));\n" - " else return %s::can_start(name, uri, %s_xer_, flavor | XER_RECOF);\n" + " return %s::can_start(name, uri, *xd.oftype_descr, flavor | XER_RECOF);\n" "}\n\n" , sdef->type - , sdef->oftypedescrname ); src = mputprintf(src, @@ -1083,7 +1085,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " size_t num_new;\n" " for (int i = 0; i < val_ptr->n_elements; ++i) {\n" " bool def_ns_1 = false;" - " new_ns = (*this)[i].collect_ns(%s_xer_, num_new, def_ns_1);\n" + " new_ns = (*this)[i].collect_ns(*p_td.oftype_descr, num_new, def_ns_1);\n" " merge_ns(collected_ns, num_collected, new_ns, num_new);\n" " def_ns = def_ns || def_ns_1;\n" /* alas, no ||= */ " }\n" @@ -1098,7 +1100,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " num = num_collected;\n" " return collected_ns;\n" "}\n\n" - , name, sdef->oftypedescrname); + , name); src=mputprintf(src, "int %s::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, " @@ -1112,16 +1114,18 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "%s" /* Factor out p_indent if not attribute */ " if (val_ptr->n_elements==0) {\n" /* Empty record of */ , name - , sdef->xerAttribute ? "" : " if (indenting) do_indent(p_buf, p_indent);\n" + , force_gen_seof ? " if (indenting && !(p_td.xer_bits & XER_ATTRIBUTE)) do_indent(p_buf, p_indent);\n" + : (sdef->xerAttribute ? "" : " if (indenting) do_indent(p_buf, p_indent);\n") ); - if (sdef->xerAttribute) { - src=mputstr(src, - " if (e_xer) {\n" /* Empty attribute. */ + if (force_gen_seof || sdef->xerAttribute) { + src=mputprintf(src, + " if (e_xer%s) {\n" /* Empty attribute. */ " begin_attribute(p_td, p_buf);\n" " p_buf.put_c('\\'');\n" - " } else\n"); + " } else\n" + , force_gen_seof ? " && (p_td.xer_bits & XER_ATTRIBUTE)" : ""); } - else { + if (force_gen_seof || !sdef->xerAttribute) { src = mputstr(src, " if (own_tag)"); } @@ -1149,7 +1153,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n" " }\n" " else {\n" /* Not empty record of. Start tag or attribute */ - , sdef->xerAttribute ? " if (indenting) do_indent(p_buf, p_indent);\n" : "" + , force_gen_seof ? " if (indenting && (p_td.xer_bits & XER_ATTRIBUTE)) do_indent(p_buf, p_indent);\n" + : (sdef->xerAttribute ? " if (indenting) do_indent(p_buf, p_indent);\n" : "") ); if (sdef->xerAnyAttrElem) { src = mputstr(src, @@ -1236,11 +1241,12 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " p_buf.put_s(shorter, saved);\n" /* restore the '>' and anything after */ " } else {\n"); } - if (sdef->xerAttribute) { - src=mputstr(src, - " if (e_xer) {\n" + if (force_gen_seof || sdef->xerAttribute) { + src=mputprintf(src, + " if (e_xer%s) {\n" " begin_attribute(p_td, p_buf);\n" - " } else\n"); + " } else\n" + , force_gen_seof ? " && (p_td.xer_bits & XER_ATTRIBUTE)" : ""); } src=mputprintf(src, " if (own_tag) {\n" @@ -1266,7 +1272,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " Free(collected_ns);\n" " p_buf.put_s(1 + keep_newline, (cbyte*)\">\\n\");\n" " }\n" - , sdef->xerAttribute ? " if (indenting) do_indent(p_buf, p_indent);\n" : "" + , force_gen_seof ? " if (indenting && (p_td.xer_bits & XER_ATTRIBUTE)) do_indent(p_buf, p_indent);\n" + : (sdef->xerAttribute ? " if (indenting) do_indent(p_buf, p_indent);\n" : "") ); if (sdef->xmlValueList) { src=mputstr(src, " if (indenting && !e_xer) do_indent(p_buf, p_indent+1);\n"); /* !e_xer or GDMO */ @@ -1277,20 +1284,26 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " TTCN_EncDec_ErrorContext ec_0(\"Index \");\n" " TTCN_EncDec_ErrorContext ec_1;\n" ); - src=mputprintf(src, + src=mputstr(src, " for (int i = 0; i < val_ptr->n_elements; ++i) {\n" - /*" if (i > 0 && !own_tag && 0 != emb_val &&\n" - " emb_val->embval_index < emb_val->embval_size) {\n" - " emb_val->embval_array->get_embedded_value(emb_val->embval_index).XER_encode(\n" - " UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n" + " if (i > 0 && !own_tag && 0 != emb_val &&\n" + " emb_val->embval_index < (0 != emb_val->embval_array_reg ?\n" + " emb_val->embval_array_reg->size_of() : emb_val->embval_array_opt->size_of())) {\n" + " if (0 != emb_val->embval_array_reg) {\n" + " (*emb_val->embval_array_reg)[emb_val->embval_index].XER_encode(\n" + " UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n" + " }\n" + " else {\n" + " (*emb_val->embval_array_opt)[emb_val->embval_index].XER_encode(\n" + " UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n" + " }\n" " ++emb_val->embval_index;\n" - " }\n" - temporarily removed in RT1 */ - " ec_1.set_msg(\"%%d: \", i);\n" + " }\n" + " ec_1.set_msg(\"%d: \", i);\n" " if (e_xer && (p_td.xer_bits & XER_LIST) && i>0) p_buf.put_c(' ');\n" - " (*this)[i].XER_encode(%s_xer_, p_buf, p_flavor, p_indent+own_tag, emb_val);\n" + " (*this)[i].XER_encode(*p_td.oftype_descr, p_buf, p_flavor, p_indent+own_tag, emb_val);\n" " }\n" - " if (indenting && !is_exerlist(p_flavor)) {\n", - sdef->oftypedescrname + " if (indenting && !is_exerlist(p_flavor)) {\n" ); if (sdef->xmlValueList) { src=mputstr(src, " if (!e_xer) p_buf.put_c('\\n');\n"); /* !e_xer or GDMO */ @@ -1298,10 +1311,11 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) src=mputstr(src, " do_indent(p_buf, p_indent);\n" " }\n"); - if (sdef->xerAttribute) { - src=mputstr(src, - " if (e_xer) p_buf.put_c('\\'');\n" - " else\n"); + if (force_gen_seof || sdef->xerAttribute) { + src=mputprintf(src, + " if (e_xer%s) p_buf.put_c('\\'');\n" + " else\n" + , force_gen_seof ? " && (p_td.xer_bits & XER_ATTRIBUTE)" : ""); } src=mputstr(src, " if (own_tag){\n" @@ -1357,13 +1371,15 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n" /* next read */ " else xml_depth = p_reader.Depth();\n" " p_flavor |= XER_RECOF;\n" + " TTCN_EncDec_ErrorContext ec_0(\"Index \");\n" + " TTCN_EncDec_ErrorContext ec_1;\n" #ifndef NDEBUG , __FUNCTION__, __LINE__ #endif , name ); - src = mputprintf(src, + src = mputstr(src, " if (e_xer && (p_td.xer_bits & XER_LIST)) {\n" /* LIST decoding*/ " char *x_val = (char*)p_reader.NewValue();\n" /* we own it */ " size_t x_pos = 0;\n" @@ -1377,13 +1393,13 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " x_pos += strlen(str) + 1;\n" " TTCN_Buffer buf_2;\n" " buf_2.put_c('<');\n" - " write_ns_prefix(%s_xer_, buf_2);\n" - " const char * const exer_name = %s_xer_.names[1];\n" - " boolean i_can_has_ns = %s_xer_.my_module != 0 && %s_xer_.ns_index != -1;\n" + " write_ns_prefix(*p_td.oftype_descr, buf_2);\n" + " const char * const exer_name = p_td.oftype_descr->names[1];\n" + " boolean i_can_has_ns = p_td.oftype_descr->my_module != 0 && p_td.oftype_descr->ns_index != -1;\n" /* If it has a namespace, chop off the '>' from the end */ - " buf_2.put_s((size_t)%s_xer_.namelens[1]-1-i_can_has_ns, (cbyte*)exer_name);\n" + " buf_2.put_s((size_t)p_td.oftype_descr->namelens[1]-1-i_can_has_ns, (cbyte*)exer_name);\n" " if (i_can_has_ns) {\n" - " const namespace_t * const pns = %s_xer_.my_module->get_ns(%s_xer_.ns_index);\n" + " const namespace_t * const pns = p_td.oftype_descr->my_module->get_ns(p_td.oftype_descr->ns_index);\n" " buf_2.put_s(7 - (*pns->px == 0), (cbyte*)\" xmlns:\");\n" " buf_2.put_s(strlen(pns->px), (cbyte*)pns->px);\n" " buf_2.put_s(2, (cbyte*)\"='\");\n" @@ -1394,14 +1410,15 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " buf_2.put_s(strlen(str), (cbyte*)str);\n" " buf_2.put_c('<');\n" " buf_2.put_c('/');\n" - " write_ns_prefix(%s_xer_, buf_2);\n" - " buf_2.put_s((size_t)%s_xer_.namelens[1], (cbyte*)exer_name);\n" + " write_ns_prefix(*p_td.oftype_descr, buf_2);\n" + " buf_2.put_s((size_t)p_td.oftype_descr->namelens[1], (cbyte*)exer_name);\n" " XmlReaderWrap reader_2(buf_2);\n" " rd_ok = reader_2.Read();\n" /* Move to the start element. */ + " ec_1.set_msg(\"%d: \", val_ptr->n_elements);\n" /* Don't move to the #text, that's the callee's responsibility. */ /* The call to the non-const operator[] creates a new element object, * then we call its XER_decode with the temporary XML reader. */ - " (*this)[val_ptr->n_elements].XER_decode(%s_xer_, reader_2, p_flavor, 0);\n" + " (*this)[val_ptr->n_elements].XER_decode(*p_td.oftype_descr, reader_2, p_flavor, 0);\n" " if (p_flavor & EXIT_ON_ERROR && !(*this)[val_ptr->n_elements - 1].is_bound()) {\n" " if (1 == val_ptr->n_elements) {\n" // Failed to decode even the first element @@ -1423,11 +1440,6 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " p_reader.Read();\n" /* past it */ " }\n" " }\n" - , sdef->oftypedescrname, sdef->oftypedescrname - , sdef->oftypedescrname, sdef->oftypedescrname - , sdef->oftypedescrname, sdef->oftypedescrname - , sdef->oftypedescrname, sdef->oftypedescrname - , sdef->oftypedescrname, sdef->oftypedescrname ); src = mputprintf(src, @@ -1457,17 +1469,18 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " if (p_reader.NodeType() != XML_READER_TYPE_ELEMENT) rd_ok = p_reader.Read();\n" " } else"); } - src = mputprintf(src, + src = mputstr(src, " {\n" /* An untagged record-of ends if it encounters an element with a name * that doesn't match its component */ " if (!own_tag && !can_start((const char*)p_reader.LocalName(), " - "(const char*)p_reader.NamespaceUri(), %s_xer_, p_flavor)) {\n" + "(const char*)p_reader.NamespaceUri(), p_td, p_flavor)) {\n" " for (; rd_ok == 1 && p_reader.Depth() > xml_depth; rd_ok = p_reader.Read()) ;\n" " break;\n" " }\n" + " ec_1.set_msg(\"%d: \", val_ptr->n_elements);\n" /* The call to the non-const operator[] creates the element */ - " (*this)[val_ptr->n_elements].XER_decode(%s_xer_, p_reader, p_flavor, emb_val);\n" + " (*this)[val_ptr->n_elements].XER_decode(*p_td.oftype_descr, p_reader, p_flavor, emb_val);\n" " if (0 != emb_val && !own_tag && val_ptr->n_elements > 1) {\n" " ++emb_val->embval_index;\n" " }\n" @@ -1481,11 +1494,16 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n" " break;\n" " }\n" - /*" else if (XML_READER_TYPE_TEXT == type && 0 != emb_val && !own_tag && get_nof_elements() > 0) {\n" + " else if (XML_READER_TYPE_TEXT == type && 0 != emb_val && !own_tag && val_ptr->n_elements > 0) {\n" " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" - " emb_val->embval_array->set_embedded_value(emb_val->embval_index, emb_ustr);\n" + " if (0 != emb_val->embval_array_reg) {\n" + " (*emb_val->embval_array_reg)[emb_val->embval_index] = emb_ustr;\n" + " }\n" + " else {\n" + " (*emb_val->embval_array_opt)[emb_val->embval_index] = emb_ustr;\n" + " }\n" " rd_ok = p_reader.Read();\n" - " }\n" - temporarily removed in RT1 */ + " }\n" " else {\n" " rd_ok = p_reader.Read();\n" " }\n" @@ -1494,13 +1512,12 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n" /* if not LIST */ " return 1;\n" "}\n\n" - , sdef->oftypedescrname, sdef->oftypedescrname ); } if (json_needed) { // JSON encode, RT1 src = mputprintf(src, - "int %s::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const\n" + "int %s::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok) const\n" "{\n" " if (!is_bound()) {\n" " TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n" @@ -1509,18 +1526,18 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n\n" " int enc_len = p_tok.put_next_token(JSON_TOKEN_ARRAY_START, NULL);\n" " for(int i = 0; i < val_ptr->n_elements; ++i) {\n" - " int ret_val = (*this)[i].JSON_encode(%s_descr_, p_tok);\n" + " int ret_val = (*this)[i].JSON_encode(*p_td.oftype_descr, p_tok);\n" " if (0 > ret_val) break;\n" " enc_len += ret_val;\n" " }\n" " enc_len += p_tok.put_next_token(JSON_TOKEN_ARRAY_END, NULL);\n" " return enc_len;\n" "}\n\n" - , name, dispname, sdef->oftypedescrname); + , name, dispname); // JSON decode, RT1 src = mputprintf(src, - "int %s::JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok, boolean p_silent)\n" + "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent)\n" "{\n" " json_token_t token = JSON_TOKEN_NONE;\n" " int dec_len = p_tok.get_next_token(&token, NULL, NULL);\n" @@ -1535,7 +1552,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " while (true) {\n" " size_t buf_pos = p_tok.get_buf_pos();\n" " %s* val = new %s;\n" - " int ret_val = val->JSON_decode(%s_descr_, p_tok, p_silent);\n" + " int ret_val = val->JSON_decode(*p_td.oftype_descr, p_tok, p_silent);\n" " if (JSON_ERROR_INVALID_TOKEN == ret_val) {\n" " p_tok.set_buf_pos(buf_pos);\n" " delete val;\n" @@ -1564,7 +1581,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n\n" " return dec_len;\n" "}\n\n" - , name, type, type, sdef->oftypedescrname, type); + , name, type, type, type); } /* end of class */ def = mputstr(def, "};\n\n"); @@ -1604,11 +1621,11 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct char *def = NULL, *src = NULL; const char *name = sdef->name, *dispname = sdef->dispname; const char *type = sdef->type; - boolean ber_needed = sdef->isASN1 && enable_ber(); - boolean raw_needed = sdef->hasRaw && enable_raw(); - boolean text_needed = sdef->hasText && enable_text(); - boolean xer_needed = sdef->hasXer && enable_xer(); - boolean json_needed = sdef->hasJson && enable_json(); + boolean ber_needed = force_gen_seof || (sdef->isASN1 && enable_ber()); + boolean raw_needed = force_gen_seof || (sdef->hasRaw && enable_raw()); + boolean text_needed = force_gen_seof || (sdef->hasText && enable_text()); + boolean xer_needed = force_gen_seof || (sdef->hasXer && enable_xer()); + boolean json_needed = force_gen_seof || (sdef->hasJson && enable_json()); /* Class definition and private data members */ def = mputprintf(def, @@ -1684,7 +1701,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct /* constructors */ def = mputprintf(def, "%s(): n_elements(-1), value_elements(NULL) {}\n", name); - def = mputprintf(def, "%s(null_type other_value): n_elements(0), value_elements(NULL) {}\n", name); + def = mputprintf(def, "%s(null_type): n_elements(0), value_elements(NULL) {}\n", name); /* copy constructor */ def = mputprintf(def, "%s(const %s& other_value) { copy_value(other_value); }\n", name, name); @@ -2176,7 +2193,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " p_buf.put_cs(*p_td.text->separator_encode);\n" " encoded_length+=p_td.text->separator_encode->lengthof();\n" " }\n" - " encoded_length+=value_elements[a].TEXT_encode(%s_descr_,p_buf);\n" + " encoded_length+=value_elements[a].TEXT_encode(*p_td.oftype_descr,p_buf);\n" " }\n" " if(p_td.text->end_encode){\n" " p_buf.put_cs(*p_td.text->end_encode);\n" @@ -2184,7 +2201,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " }\n" " return encoded_length;\n" "}\n" - ,name,sdef->oftypedescrname + ,name ); src = mputprintf(src, "int %s::TEXT_decode(const TTCN_Typedescriptor_t& p_td," @@ -2223,7 +2240,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " while(TRUE){\n" " %s val;\n" " pos=p_buf.get_pos();\n" - " int len=val.TEXT_decode(%s_descr_,p_buf,limit,TRUE);\n" + " int len=val.TEXT_decode(*p_td.oftype_descr,p_buf,limit,TRUE);\n" " if(len==-1 || (len==0 && !limit.has_token())){\n" " p_buf.set_pos(pos);\n" " if(sep_found){\n" @@ -2261,7 +2278,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " }\n" " }\n" " }\n" - ,name,type,sdef->oftypedescrname + ,name,type ); src = mputstr(src, " limit.remove_tokens(ml);\n" @@ -2315,7 +2332,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " for(int elem_i=0; elem_iadd_TLV(value_elements[elem_i].BER_encode_TLV" - "(%s_descr_, p_coding));\n" + "(*p_td.oftype_descr, p_coding));\n" " }\n" "%s" " }\n" @@ -2341,16 +2358,16 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " while(BER_decode_constdTLV_next(stripped_tlv, V_pos, L_form, " "tmp_tlv)) {\n" " set_size(n_elements+1);\n" - " value_elements[n_elements-1].BER_decode_TLV(%s_descr_, tmp_tlv, " + " value_elements[n_elements-1].BER_decode_TLV(*p_td.oftype_descr, tmp_tlv, " "L_form);\n" " ec_2.set_msg(\"%%d: \", n_elements);\n" " }\n" " return TRUE;\n" "}\n" "\n" - , name, sdef->oftypedescrname + , name , sdef->kind==SET_OF?" new_tlv->sort_tlvs();\n":"" - , name, sdef->oftypedescrname + , name ); if(sdef->has_opentypes) { @@ -2396,7 +2413,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " int a=0;\n" " if(sel_field==-1) sel_field=p_td.raw->fieldlength;\n" " for(a=0;a0){\n" " start_of_field=p_buf.get_pos_bit();\n" - " decoded_field_length=(*this)[a].RAW_decode(%s_descr_,p_buf,limit," + " decoded_field_length=(*this)[a].RAW_decode(*p_td.oftype_descr,p_buf,limit," "top_bit_ord,TRUE);\n" " if(decoded_field_length < 0){\n" /*" delete &(*this)[a];\n"*/ @@ -2427,7 +2444,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " decoded_length+=decoded_field_length;\n" " limit-=decoded_field_length;\n" " a++;\n" - ,name,sdef->oftypedescrname,sdef->oftypedescrname + ,name ); if(sdef->raw.extension_bit!=XDEFNO && sdef->raw.extension_bit!=XDEFDEFAULT){ src=mputprintf(src, @@ -2452,12 +2469,12 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " myleaf.body.node.nodes=init_nodes_of_enc_tree(encoded_num_of_records);\n" " for(int a=0;araw);\n" + " encoded_length+=(*this)[a].RAW_encode(*p_td.oftype_descr," "*myleaf.body.node.nodes[a]);\n" " }\n" " return myleaf.length=encoded_length;\n}\n\n" - , name, sdef->oftypedescrname, sdef->oftypedescrname + , name ); } @@ -2471,10 +2488,12 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct "boolean %s::can_start(const char *name, const char *uri, " "XERdescriptor_t const& xd, unsigned int flavor) {\n" " boolean e_xer = is_exer(flavor);\n" - " if (e_xer && (xd.xer_bits & ANY_ELEMENT)) " + " if ((!e_xer || !(xd.xer_bits & UNTAGGED)) && !(flavor & XER_RECOF)) return " + "check_name(name, xd, e_xer) && (!e_xer || check_namespace(uri, xd));\n" + " if (e_xer && (xd.oftype_descr->xer_bits & ANY_ELEMENT)) " , name ); - if (sdef->nFollowers) { + if (!force_gen_seof && sdef->nFollowers) { /* If there are optional fields following the record-of, then seeing * {any XML tag that belongs to those fields} where the record-of may be * means that the record-of is empty. */ @@ -2494,12 +2513,9 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct else src = mputstr(src, "return TRUE;\n"); src = mputprintf(src, - " if ((!e_xer || !(xd.xer_bits & UNTAGGED)) && !(flavor & XER_RECOF)) return " - "check_name(name, xd, e_xer) && (!e_xer || check_namespace(uri, xd));\n" - " else return %s::can_start(name, uri, %s_xer_, flavor | XER_RECOF);\n" + " return %s::can_start(name, uri, *xd.oftype_descr, flavor | XER_RECOF);\n" "}\n\n" , sdef->type - , sdef->oftypedescrname ); src = mputprintf(src, @@ -2512,7 +2528,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " size_t num_new;\n" " for (int i = 0; i < n_elements; ++i) {\n" " bool def_ns_1 = false;" - " new_ns = value_elements[i].collect_ns(%s_xer_, num_new, def_ns_1);\n" + " new_ns = value_elements[i].collect_ns(*p_td.oftype_descr, num_new, def_ns_1);\n" " merge_ns(collected_ns, num_collected, new_ns, num_new);\n" " def_ns = def_ns || def_ns_1;\n" /* alas, no ||= */ " }\n" @@ -2527,7 +2543,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " num = num_collected;\n" " return collected_ns;\n" "}\n\n" - , name, sdef->oftypedescrname); + , name); src=mputprintf(src, "int %s::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, " @@ -2541,16 +2557,18 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct "%s" /* Factor out p_indent if not attribute */ " if (n_elements==0) {\n" /* Empty record of */ , name - , sdef->xerAttribute ? "" : " if (indenting) do_indent(p_buf, p_indent);\n" + , force_gen_seof ? " if (indenting && !(p_td.xer_bits & XER_ATTRIBUTE)) do_indent(p_buf, p_indent);\n" + : (sdef->xerAttribute ? "" : " if (indenting) do_indent(p_buf, p_indent);\n") ); - if (sdef->xerAttribute) { - src=mputstr(src, - " if (e_xer) {\n" /* Empty attribute. */ + if (force_gen_seof || sdef->xerAttribute) { + src=mputprintf(src, + " if (e_xer%s) {\n" /* Empty attribute. */ " begin_attribute(p_td, p_buf);\n" " p_buf.put_c('\\'');\n" - " } else\n"); + " } else\n" + , force_gen_seof ? " && (p_td.xer_bits & XER_ATTRIBUTE)" : ""); } - else { + if (force_gen_seof || !sdef->xerAttribute) { src = mputstr(src, " if (own_tag)"); } @@ -2578,7 +2596,8 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " }\n" " }\n" " else {\n" /* Not empty record of. Start tag or attribute */ - , sdef->xerAttribute ? " if (indenting) do_indent(p_buf, p_indent);\n" : "" + , force_gen_seof ? " if (indenting && !(p_td.xer_bits & XER_ATTRIBUTE)) do_indent(p_buf, p_indent);\n" + : (sdef->xerAttribute ? "" : " if (indenting) do_indent(p_buf, p_indent);\n") ); if (sdef->xerAnyAttrElem) { src = mputstr(src, @@ -2660,11 +2679,12 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " p_buf.put_s(shorter, saved);\n" /* restore the '>' and anything after */ " } else {\n"); } - if (sdef->xerAttribute) { - src=mputstr(src, - " if (e_xer) {\n" + if (force_gen_seof || sdef->xerAttribute) { + src=mputprintf(src, + " if (e_xer%s) {\n" " begin_attribute(p_td, p_buf);\n" - " } else\n"); + " } else\n" + , force_gen_seof ? " && (p_td.xer_bits & XER_ATTRIBUTE)" : ""); } src=mputprintf(src, " if (own_tag) {\n" @@ -2690,7 +2710,8 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " Free(collected_ns);\n" " p_buf.put_s(1 + keep_newline, (cbyte*)\">\\n\");\n" " }\n" - , sdef->xerAttribute ? " if (indenting) do_indent(p_buf, p_indent);\n" : "" + , force_gen_seof ? " if (indenting && (p_td.xer_bits & XER_ATTRIBUTE)) do_indent(p_buf, p_indent);\n" + : (sdef->xerAttribute ? " if (indenting) do_indent(p_buf, p_indent);\n" : "") ); if (sdef->xmlValueList) { src=mputstr(src, " if (indenting && !e_xer) do_indent(p_buf, p_indent+1);\n"); /* !e_xer or GDMO */ @@ -2701,20 +2722,26 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " TTCN_EncDec_ErrorContext ec_0(\"Index \");\n" " TTCN_EncDec_ErrorContext ec_1;\n" ); - src=mputprintf(src, + src=mputstr(src, " for (int i = 0; i < n_elements; ++i) {\n" - /*" if (i > 0 && !own_tag && 0 != emb_val &&\n" - " emb_val->embval_index < emb_val->embval_size) {\n" - " emb_val->embval_array->get_embedded_value(emb_val->embval_index).XER_encode(\n" - " UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n" + " if (i > 0 && !own_tag && 0 != emb_val &&\n" + " emb_val->embval_index < (0 != emb_val->embval_array_reg ?\n" + " emb_val->embval_array_reg->size_of() : emb_val->embval_array_opt->size_of())) {\n" + " if (0 != emb_val->embval_array_reg) {\n" + " (*emb_val->embval_array_reg)[emb_val->embval_index].XER_encode(\n" + " UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n" + " }\n" + " else {\n" + " (*emb_val->embval_array_opt)[emb_val->embval_index].XER_encode(\n" + " UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n" + " }\n" " ++emb_val->embval_index;\n" - " }\n" - temporarily removed in RT1 */ - " ec_1.set_msg(\"%%d: \", i);\n" + " }\n" + " ec_1.set_msg(\"%d: \", i);\n" " if (e_xer && (p_td.xer_bits & XER_LIST) && i>0) p_buf.put_c(' ');\n" - " value_elements[i].XER_encode(%s_xer_, p_buf, p_flavor, p_indent+own_tag, emb_val);\n" + " value_elements[i].XER_encode(*p_td.oftype_descr, p_buf, p_flavor, p_indent+own_tag, emb_val);\n" " }\n" - " if (indenting && !is_exerlist(p_flavor)) {\n", - sdef->oftypedescrname + " if (indenting && !is_exerlist(p_flavor)) {\n" ); if (sdef->xmlValueList) { src=mputstr(src, " if (!e_xer) p_buf.put_c('\\n');\n"); /* !e_xer or GDMO */ @@ -2722,10 +2749,11 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct src=mputstr(src, " do_indent(p_buf, p_indent);\n" " }\n"); - if (sdef->xerAttribute) { - src=mputstr(src, - " if (e_xer) p_buf.put_c('\\'');\n" - " else\n"); + if (force_gen_seof || sdef->xerAttribute) { + src=mputprintf(src, + " if (e_xer%s) p_buf.put_c('\\'');\n" + " else\n" + , force_gen_seof ? " && (p_td.xer_bits & XER_ATTRIBUTE)" : ""); } src=mputstr(src, " if (own_tag){\n" @@ -2787,7 +2815,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct , name ); - src = mputprintf(src, + src = mputstr(src, " if (e_xer && (p_td.xer_bits & XER_LIST)) {\n" /* LIST decoding*/ " char *x_val = (char*)p_reader.NewValue();\n" /* we own it */ " size_t x_pos = 0;\n" @@ -2801,13 +2829,13 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " x_pos += strlen(str) + 1;\n" " TTCN_Buffer buf_2;\n" " buf_2.put_c('<');\n" - " write_ns_prefix(%s_xer_, buf_2);\n" - " const char * const exer_name = %s_xer_.names[1];\n" - " boolean i_can_has_ns = %s_xer_.my_module != 0 && %s_xer_.ns_index != -1;\n" + " write_ns_prefix(*p_td.oftype_descr, buf_2);\n" + " const char * const exer_name = p_td.oftype_descr->names[1];\n" + " boolean i_can_has_ns = p_td.oftype_descr->my_module != 0 && p_td.oftype_descr->ns_index != -1;\n" /* If it has a namespace, chop off the '>' from the end */ - " buf_2.put_s((size_t)%s_xer_.namelens[1]-1-i_can_has_ns, (cbyte*)exer_name);\n" + " buf_2.put_s((size_t)p_td.oftype_descr->namelens[1]-1-i_can_has_ns, (cbyte*)exer_name);\n" " if (i_can_has_ns) {\n" - " const namespace_t * const pns = %s_xer_.my_module->get_ns(%s_xer_.ns_index);\n" + " const namespace_t * const pns = p_td.oftype_descr->my_module->get_ns(p_td.oftype_descr->ns_index);\n" " buf_2.put_s(7 - (*pns->px == 0), (cbyte*)\" xmlns:\");\n" " buf_2.put_s(strlen(pns->px), (cbyte*)pns->px);\n" " buf_2.put_s(2, (cbyte*)\"='\");\n" @@ -2818,14 +2846,14 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " buf_2.put_s(strlen(str), (cbyte*)str);\n" " buf_2.put_c('<');\n" " buf_2.put_c('/');\n" - " write_ns_prefix(%s_xer_, buf_2);\n" - " buf_2.put_s((size_t)%s_xer_.namelens[1], (cbyte*)exer_name);\n" + " write_ns_prefix(*p_td.oftype_descr, buf_2);\n" + " buf_2.put_s((size_t)p_td.oftype_descr->namelens[1], (cbyte*)exer_name);\n" " XmlReaderWrap reader_2(buf_2);\n" " rd_ok = reader_2.Read();\n" /* Move to the start element. */ /* Don't move to the #text, that's the callee's responsibility. */ /* The call to the non-const operator[] creates a new element object, * then we call its XER_decode with the temporary XML reader. */ - " (*this)[n_elements].XER_decode(%s_xer_, reader_2, p_flavor, 0);\n" + " (*this)[n_elements].XER_decode(*p_td.oftype_descr, reader_2, p_flavor, 0);\n" " if (p_flavor & EXIT_ON_ERROR && !(*this)[n_elements - 1].is_bound()) {\n" " if (1 == n_elements) {\n" // Failed to decode even the first element @@ -2847,11 +2875,6 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " p_reader.Read();\n" /* past it */ " }\n" " }\n" - , sdef->oftypedescrname, sdef->oftypedescrname - , sdef->oftypedescrname, sdef->oftypedescrname - , sdef->oftypedescrname, sdef->oftypedescrname - , sdef->oftypedescrname, sdef->oftypedescrname - , sdef->oftypedescrname, sdef->oftypedescrname ); src = mputprintf(src, @@ -2881,17 +2904,17 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " if (p_reader.NodeType() != XML_READER_TYPE_ELEMENT) rd_ok = p_reader.Read();\n" " } else"); } - src = mputprintf(src, + src = mputstr(src, " {\n" /* An untagged record-of ends if it encounters an element with a name * that doesn't match its component */ " if (!own_tag && !can_start((const char*)p_reader.LocalName(), " - "(const char*)p_reader.NamespaceUri(), %s_xer_, p_flavor)) {\n" + "(const char*)p_reader.NamespaceUri(), p_td, p_flavor)) {\n" " for (; rd_ok == 1 && p_reader.Depth() > xml_depth; rd_ok = p_reader.Read()) ;\n" " break;\n" " }\n" /* The call to the non-const operator[] creates the element */ - " operator [](n_elements).XER_decode(%s_xer_, p_reader, p_flavor, emb_val);\n" + " operator [](n_elements).XER_decode(*p_td.oftype_descr, p_reader, p_flavor, emb_val);\n" " if (0 != emb_val && !own_tag && n_elements > 1) {\n" " ++emb_val->embval_index;\n" " }\n" @@ -2905,11 +2928,16 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " }\n" " break;\n" " }\n" - /*" else if (XML_READER_TYPE_TEXT == type && 0 != emb_val && !own_tag && n_elements > 0) {\n" + " else if (XML_READER_TYPE_TEXT == type && 0 != emb_val && !own_tag && n_elements > 0) {\n" " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" - " emb_val->embval_array->set_embedded_value(emb_val->embval_index, emb_ustr);\n" + " if (0 != emb_val->embval_array_reg) {\n" + " (*emb_val->embval_array_reg)[emb_val->embval_index] = emb_ustr;\n" + " }\n" + " else {\n" + " (*emb_val->embval_array_opt)[emb_val->embval_index] = emb_ustr;\n" + " }\n" " rd_ok = p_reader.Read();\n" - " }\n" - temporarily removed in RT1 */ + " }\n" " else {\n" " rd_ok = p_reader.Read();\n" " }\n" @@ -2918,13 +2946,12 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " }\n" /* if not LIST */ " return 1;\n" "}\n\n" - , sdef->oftypedescrname, sdef->oftypedescrname ); } if (json_needed) { // JSON encode, RT1, mem. alloc. optimised src = mputprintf(src, - "int %s::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const\n" + "int %s::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok) const\n" "{\n" " if (!is_bound()) {\n" " TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n" @@ -2933,18 +2960,18 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " }\n\n" " int enc_len = p_tok.put_next_token(JSON_TOKEN_ARRAY_START, NULL);\n" " for(int i = 0; i < n_elements; ++i) {\n" - " int ret_val = value_elements[i].JSON_encode(%s_descr_, p_tok);\n" + " int ret_val = value_elements[i].JSON_encode(*p_td.oftype_descr, p_tok);\n" " if (0 > ret_val) break;\n" " enc_len += ret_val;\n" " }\n" " enc_len += p_tok.put_next_token(JSON_TOKEN_ARRAY_END, NULL);\n" " return enc_len;\n" "}\n\n" - , name, dispname, sdef->oftypedescrname); + , name, dispname); // JSON decode, RT1, mem. alloc. optimised src = mputprintf(src, - "int %s::JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok, boolean p_silent)\n" + "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent)\n" "{\n" " json_token_t token = JSON_TOKEN_NONE;\n" " int dec_len = p_tok.get_next_token(&token, NULL, NULL);\n" @@ -2959,7 +2986,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " while (true) {\n" " size_t buf_pos = p_tok.get_buf_pos();\n" " %s val;\n" - " int ret_val = val.JSON_decode(%s_descr_, p_tok, p_silent);\n" + " int ret_val = val.JSON_decode(*p_td.oftype_descr, p_tok, p_silent);\n" " if (JSON_ERROR_INVALID_TOKEN == ret_val) {\n" " p_tok.set_buf_pos(buf_pos);\n" " break;\n" @@ -2984,7 +3011,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " }\n\n" " return dec_len;\n" "}\n\n" - , name, type, sdef->oftypedescrname); + , name, type); } /* end of class */ def = mputstr(def, "};\n\n"); @@ -3024,8 +3051,8 @@ void defRecordOfClass2(const struct_of_def *sdef, output_struct *output) char *def = NULL, *src = NULL; const char *name = sdef->name; const char *type = sdef->type; - boolean raw_needed = sdef->hasRaw && enable_raw(); - boolean xer_needed = sdef->hasXer && enable_xer(); + boolean raw_needed = force_gen_seof || (sdef->hasRaw && enable_raw()); + boolean xer_needed = force_gen_seof || (sdef->hasXer && enable_xer()); /* Class definition */ def = mputprintf(def, @@ -3164,12 +3191,10 @@ void defRecordOfClass2(const struct_of_def *sdef, output_struct *output) src = mputprintf(src, "Base_Type* %s::create_elem() const { return new %s; }\n" "const Base_Type* %s::get_unbound_elem() const { return &UNBOUND_ELEM; }\n" - "const TTCN_Typedescriptor_t* %s::get_descriptor() const { return &%s_descr_; }\n" - "const TTCN_Typedescriptor_t* %s::get_elem_descr() const { return &%s_descr_; }\n\n", + "const TTCN_Typedescriptor_t* %s::get_descriptor() const { return &%s_descr_; }\n", name, type, name, - name, name, - name, sdef->oftypedescrname); + name, name); /* helper functions called by enc/dec members of the ancestor class */ if (raw_needed) { @@ -3194,13 +3219,20 @@ void defRecordOfClass2(const struct_of_def *sdef, output_struct *output) "boolean %s::can_start(const char *name, const char *uri, " "XERdescriptor_t const& xd, unsigned int flavor) {\n" " boolean e_xer = is_exer(flavor);\n" + /* if EXER and UNTAGGED, it can begin with the tag of the element, + * otherwise it must be the tag of the type itself, + * specified in the supplied parameter. + * If flavor contains UNTAGGED, that's a signal to go directly + * to the embedded type. */ + " if (!e_xer || !((xd.xer_bits|flavor) & UNTAGGED)) return " + "check_name(name, xd, e_xer) && (!e_xer || check_namespace(uri, xd));\n" /* a record-of with ANY-ELEMENT can start with any tag * :-( with some exceptions )-: */ - " if (e_xer && (xd.xer_bits & ANY_ELEMENT)) " + " if (e_xer && (xd.oftype_descr->xer_bits & ANY_ELEMENT)) " , name, name ); - if (sdef->nFollowers) { + if (!force_gen_seof && sdef->nFollowers) { size_t f; src = mputstr(src, "{\n"); for (f = 0; f < sdef->nFollowers; ++f) { @@ -3218,15 +3250,8 @@ void defRecordOfClass2(const struct_of_def *sdef, output_struct *output) src = mputstr(src, "return TRUE;\n"); } src = mputprintf(src, - /* if EXER and UNTAGGED, it can begin with the tag of the element, - * otherwise it must be the tag of the type itself, - * specified in the supplied parameter. - * If flavor contains UNTAGGED, that's a signal to go directly - * to the embedded type. */ - " if (!e_xer || !((xd.xer_bits|flavor) & UNTAGGED)) return " - "check_name(name, xd, e_xer) && (!e_xer || check_namespace(uri, xd));\n" - " else return %s::can_start(name, uri, %s_xer_, flavor | XER_RECOF);\n" - "}\n\n", sdef->type, sdef->oftypedescrname); + " return %s::can_start(name, uri, *xd.oftype_descr, flavor | XER_RECOF);\n" + "}\n\n", sdef->type); def = mputprintf(def, "boolean isXmlValueList() const { return %s; }\n\n", sdef->xmlValueList ? "TRUE" : "FALSE"); } diff --git a/compiler2/subtype.cc b/compiler2/subtype.cc index 29b0232..60f81ae 100644 --- a/compiler2/subtype.cc +++ b/compiler2/subtype.cc @@ -1930,6 +1930,9 @@ void SubType::chk_this_template(Template *templ) case Template::VALUE_RANGE: /* Should be canonical before */ break; + case Template::ALL_FROM: + case Template::VALUE_LIST_ALL_FROM: + break; case Template::SUPERSET_MATCH: case Template::SUBSET_MATCH: if (subtype!=ST_SETOF){ diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 7b0a70c..8449e69 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -205,7 +205,7 @@ namespace Ttcn { Node::set_fullname(p_fullname); for (size_t i = 0; i < refs.size(); i++) refs[i]->set_fullname(p_fullname + - "."); + "."); } void FieldOrArrayRefs::set_my_scope(Scope *p_scope) @@ -218,9 +218,9 @@ namespace Ttcn { for (size_t i = 0; i < refs.size(); i++) { FieldOrArrayRef *ref = refs[i]; if (ref->get_type() == FieldOrArrayRef::ARRAY_REF) { - Value *v = ref->get_val(); - v->set_lowerid_to_ref(); - if (v->is_unfoldable()) return true; + Value *v = ref->get_val(); + v->set_lowerid_to_ref(); + if (v->is_unfoldable()) return true; } } return false; @@ -312,38 +312,38 @@ namespace Ttcn { expr->expr = mputprintf(expr->expr, ".%s%s()", ((type!=0 && type->get_typetype()==Type::T_ANYTYPE) ? "AT_" : ""), id.get_name().c_str()); - if (type) { - CompField *cf = type->get_comp_byName(id); - // If the field is optional, the return type of the accessor is an - // OPTIONAL. Write a call to OPTIONAL::operator(), - // which "reaches into" the OPTIONAL to get the contained type T. - // Don't do this at the end of the reference chain. - // Accessor methods for a foo_template return a bar_template - // and OPTIONAL<> is not involved, hence no "()". - if (!is_template && i < n_refs - 1 && cf->get_is_optional()) - expr->expr = mputstr(expr->expr, "()"); + if (type) { + CompField *cf = type->get_comp_byName(id); + // If the field is optional, the return type of the accessor is an + // OPTIONAL. Write a call to OPTIONAL::operator(), + // which "reaches into" the OPTIONAL to get the contained type T. + // Don't do this at the end of the reference chain. + // Accessor methods for a foo_template return a bar_template + // and OPTIONAL<> is not involved, hence no "()". + if (!is_template && i < n_refs - 1 && cf->get_is_optional()) + expr->expr = mputstr(expr->expr, "()"); // Follow the field type. - type = cf->get_type(); - } + type = cf->get_type(); + } } else { // Generate code for array reference. expr->expr = mputc(expr->expr, '['); - ref->get_val()->generate_code_expr(expr); + ref->get_val()->generate_code_expr(expr); expr->expr = mputc(expr->expr, ']'); - if (type) { + if (type) { // Follow the embedded type. - switch (type->get_typetype()) { - case Type::T_SEQOF: - case Type::T_SETOF: - case Type::T_ARRAY: - type = type->get_ofType(); - break; - default: - // The index points to a string element. - // There are no further sub-references. - type = 0; - } // switch - } // if (type) + switch (type->get_typetype()) { + case Type::T_SEQOF: + case Type::T_SETOF: + case Type::T_ARRAY: + type = type->get_ofType(); + break; + default: + // The index points to a string element. + // There are no further sub-references. + type = 0; + } // switch + } // if (type) } // if (ref->get_type) } // next reference } @@ -451,10 +451,10 @@ namespace Ttcn { } /* Called by: - * Common::PortTypeBody::PortTypeBody - * Common::Type::Type - * Common::TypeMappingTarget::TypeMappingTarget - * Common::PatternString::ps_elem_t::chk_ref */ + * Common::PortTypeBody::PortTypeBody + * Common::Type::Type + * Common::TypeMappingTarget::TypeMappingTarget + * Common::PatternString::ps_elem_t::chk_ref */ Reference *Reference::clone() const { return new Reference(*this); @@ -465,8 +465,8 @@ namespace Ttcn { string ret_val; if (id) { if (modid) { - ret_val += modid->get_dispname(); - ret_val += '.'; + ret_val += modid->get_dispname(); + ret_val += '.'; } ret_val += id->get_dispname(); subrefs.append_stringRepr(ret_val); @@ -498,7 +498,7 @@ namespace Ttcn { parlist->set_my_scope(my_scope); } else { error("Reference to parameterized definition `%s' without " - "actual parameter list", ass->get_id().get_dispname().c_str()); + "actual parameter list", ass->get_id().get_dispname().c_str()); } } } @@ -531,7 +531,7 @@ namespace Ttcn { break; default: error("Reference to a variable or value parameter was " - "expected instead of %s", t_ass->get_description().c_str()); + "expected instead of %s", t_ass->get_description().c_str()); return 0; } FieldOrArrayRefs *t_subrefs = get_subrefs(); @@ -539,7 +539,7 @@ namespace Ttcn { Type::EXPECTED_DYNAMIC_VALUE); if (ret_val && t_subrefs && t_subrefs->refers_to_string_element()) { error("Reference to a string element of type `%s' cannot be used in " - "this context", ret_val->get_typename().c_str()); + "this context", ret_val->get_typename().c_str()); } return ret_val; } @@ -550,19 +550,19 @@ namespace Ttcn { if (ass) { if (ass->get_asstype() == Common::Assignment::A_TYPE) { Type *t = ass->get_Type()->get_type_refd_last(); - switch (t->get_typetype()) { - case Type::T_ERROR: - // remain silent - break; - case Type::T_COMPONENT: - return t; - default: - error("Reference `%s' does not refer to a component type", - get_dispname().c_str()); - } + switch (t->get_typetype()) { + case Type::T_ERROR: + // remain silent + break; + case Type::T_COMPONENT: + return t; + default: + error("Reference `%s' does not refer to a component type", + get_dispname().c_str()); + } } else { - error("Reference `%s' does not refer to a type", - get_dispname().c_str()); + error("Reference `%s' does not refer to a type", + get_dispname().c_str()); } } return 0; @@ -720,21 +720,21 @@ namespace Ttcn { FieldOrArrayRef *second_ref = subrefs.get_ref(1); if (second_ref->get_type() == FieldOrArrayRef::FIELD_REF) { // the reference begins with . (most complicated case) - // there are 3 possible situations: - // 1. first_id points to a local definition (this has the priority) - // modid: 0, id: first_id - // 2. first_id points to an imported module (trivial case) - // modid: first_id, id: second_id - // 3. none of the above (first_id might be an imported symbol) - // modid: 0, id: first_id - // Note: Rule 1 has the priority because it can be overridden using - // the notation .objid { ... }. (modid and id are set in the - // constructor), but there is no work-around in the reverse way. - if (!my_scope->has_ass_withId(*first_id) - && my_scope->is_valid_moduleid(*first_id)) { - // rule 1 is not fulfilled, but rule 2 is fulfilled - second_id = second_ref->get_id(); - } + // there are 3 possible situations: + // 1. first_id points to a local definition (this has the priority) + // modid: 0, id: first_id + // 2. first_id points to an imported module (trivial case) + // modid: first_id, id: second_id + // 3. none of the above (first_id might be an imported symbol) + // modid: 0, id: first_id + // Note: Rule 1 has the priority because it can be overridden using + // the notation .objid { ... }. (modid and id are set in the + // constructor), but there is no work-around in the reverse way. + if (!my_scope->has_ass_withId(*first_id) + && my_scope->is_valid_moduleid(*first_id)) { + // rule 1 is not fulfilled, but rule 2 is fulfilled + second_id = second_ref->get_id(); + } } // else: the reference begins with [] -> there is no modid } // else: the reference consists of a single -> there is no modid if (second_id) { @@ -804,14 +804,14 @@ namespace Ttcn { if (params_checked) { // used after semantic analysis for (size_t i = 0; i < parlist.get_nof_pars(); i++) { - if (i > 0) ret_val += ", "; - parlist.get_par(i)->append_stringRepr(ret_val); + if (i > 0) ret_val += ", "; + parlist.get_par(i)->append_stringRepr(ret_val); } } else { // used before semantic analysis for (size_t i = 0; i < params->get_nof_tis(); i++) { - if (i > 0) ret_val += ", "; - params->get_ti_byIndex(i)->append_stringRepr(ret_val); + if (i > 0) ret_val += ", "; + params->get_ti_byIndex(i)->append_stringRepr(ret_val); } } ret_val += ')'; @@ -826,17 +826,17 @@ namespace Ttcn { params_checked = true; FormalParList *fplist = ass->get_FormalParList(); if (fplist) { - Error_Context cntxt(params, "In actual parameter list of %s", - ass->get_description().c_str()); - is_erroneous = fplist->fold_named_and_chk(params, &parlist); - parlist.set_fullname(get_fullname()); - parlist.set_my_scope(my_scope); - // the parsed parameter list is no longer needed - delete params; - params = 0; + Error_Context cntxt(params, "In actual parameter list of %s", + ass->get_description().c_str()); + is_erroneous = fplist->fold_named_and_chk(params, &parlist); + parlist.set_fullname(get_fullname()); + parlist.set_my_scope(my_scope); + // the parsed parameter list is no longer needed + delete params; + params = 0; } else { params->error("The referenced %s cannot have actual parameters", - ass->get_description().c_str()); + ass->get_description().c_str()); } } return ass; @@ -864,7 +864,7 @@ namespace Ttcn { if (!t_ass) return false; if (t_ass->get_asstype() != Common::Assignment::A_ALTSTEP) { error("Reference to an altstep was expected in the argument instead of " - "%s", t_ass->get_description().c_str()); + "%s", t_ass->get_description().c_str()); return false; } my_scope->chk_runs_on_clause(t_ass, *this, "activate"); @@ -1048,11 +1048,11 @@ namespace Ttcn { const Identifier& id = comp_def->get_id(); if (parent_scope->has_ass_withId(id)) { comp_def->warning("Imported component element definition `%s' hides a " - "definition at module scope", comp_def->get_fullname().c_str()); - Reference ref(0, id.clone()); - Common::Assignment *hidden_ass = parent_scope->get_ass_bySRef(&ref); - hidden_ass->warning("Hidden definition `%s' is here", - hidden_ass->get_fullname().c_str()); + "definition at module scope", comp_def->get_fullname().c_str()); + Reference ref(0, id.clone()); + Common::Assignment *hidden_ass = parent_scope->get_ass_bySRef(&ref); + hidden_ass->warning("Hidden definition `%s' is here", + hidden_ass->get_fullname().c_str()); } } @@ -1424,12 +1424,12 @@ namespace Ttcn { duplicate_underscores ? module_name : modid->get_ttcnname().c_str()); target->functions.pre_init = mputprintf(target->functions.pre_init, - "%s%s.pre_init_module();\n", module_name, + "%s%s.pre_init_module();\n", module_name, "::module_object"); if (mod->get_moduletype() == Common::Module::MOD_TTCN) { target->functions.post_init = mputprintf(target->functions.post_init, - "%s%s.post_init_module();\n", module_name, + "%s%s.post_init_module();\n", module_name, "::module_object"); } @@ -1441,8 +1441,8 @@ namespace Ttcn { if (w_attrib_path) { MultiWithAttrib *attrib = w_attrib_path->get_with_attr(); if (attrib) { - DEBUG(level + 1, "Attributes:"); - attrib->dump(level + 2); + DEBUG(level + 1, "Attributes:"); + attrib->dump(level + 2); } } } @@ -1614,19 +1614,19 @@ namespace Ttcn { // imported module that imports m bool covered = false; for (size_t j = 0; j < impmods_v.size(); j++) { - // skip over the same import definition - if (j == i) continue; - ImpMod *im2 = impmods_v[j]; - Common::Module *m2 = im2->get_mod(); - // a module that is equivalent to the current module due to - // circular imports cannot be used to cover anything - if (m2->is_visible(my_mod)) continue; - if (m2->is_visible(m) && !m->is_visible(m2)) { - // m2 covers m (i.e. m is visible from m2) - // and they are not in the same import loop - covered = true; - break; - } + // skip over the same import definition + if (j == i) continue; + ImpMod *im2 = impmods_v[j]; + Common::Module *m2 = im2->get_mod(); + // a module that is equivalent to the current module due to + // circular imports cannot be used to cover anything + if (m2->is_visible(my_mod)) continue; + if (m2->is_visible(m) && !m->is_visible(m2)) { + // m2 covers m (i.e. m is visible from m2) + // and they are not in the same import loop + covered = true; + break; + } } // do not generate the #include if a covering module is found if (!covered) im->generate_code(target); @@ -1729,11 +1729,11 @@ namespace Ttcn { ass->error("Duplicate definition with name `%s'", dispname_str); ass_m[name]->note("Previous definition of `%s' is here", dispname_str); } else { - ass_m.add(name, ass); - if (parent_scope->is_valid_moduleid(id)) { - ass->warning("Definition with name `%s' hides a module identifier", - id.get_dispname().c_str()); - } + ass_m.add(name, ass); + if (parent_scope->is_valid_moduleid(id)) { + ass->warning("Definition with name `%s' hides a module identifier", + id.get_dispname().c_str()); + } } } checked = true; @@ -1756,26 +1756,26 @@ namespace Ttcn { const Identifier& id = def->get_id(); const string& name = id.get_name(); if (ass_m.has_key(name)) { - const char *dispname_str = id.get_dispname().c_str(); - def->error("Duplicate definition with name `%s'", dispname_str); - ass_m[name]->note("Previous definition of `%s' is here", dispname_str); + const char *dispname_str = id.get_dispname().c_str(); + def->error("Duplicate definition with name `%s'", dispname_str); + ass_m[name]->note("Previous definition of `%s' is here", dispname_str); } else { - ass_m.add(name, def); - if (parent_scope) { - if (parent_scope->has_ass_withId(id)) { - const char *dispname_str = id.get_dispname().c_str(); - def->error("Definition with identifier `%s' is not unique in the " - "scope hierarchy", dispname_str); - Reference ref(0, id.clone()); - Common::Assignment *ass = parent_scope->get_ass_bySRef(&ref); - if (!ass) FATAL_ERROR("OtherDefinitions::chk_for()"); - ass->note("Previous definition with identifier `%s' in higher " - "scope unit is here", dispname_str); - } else if (parent_scope->is_valid_moduleid(id)) { - def->warning("Definition with name `%s' hides a module identifier", - id.get_dispname().c_str()); - } - } + ass_m.add(name, def); + if (parent_scope) { + if (parent_scope->has_ass_withId(id)) { + const char *dispname_str = id.get_dispname().c_str(); + def->error("Definition with identifier `%s' is not unique in the " + "scope hierarchy", dispname_str); + Reference ref(0, id.clone()); + Common::Assignment *ass = parent_scope->get_ass_bySRef(&ref); + if (!ass) FATAL_ERROR("OtherDefinitions::chk_for()"); + ass->note("Previous definition with identifier `%s' in higher " + "scope unit is here", dispname_str); + } else if (parent_scope->is_valid_moduleid(id)) { + def->warning("Definition with name `%s' hides a module identifier", + id.get_dispname().c_str()); + } + } } def->chk(); } @@ -1914,15 +1914,15 @@ namespace Ttcn { const string& group_name = group_id.get_name(); if (ass_m.has_key(group_name)) { group->error("Group name `%s' clashes with a definition", - group_id.get_dispname().c_str()); + group_id.get_dispname().c_str()); ass_m[group_name]->note("Definition of `%s' is here", - group_id.get_dispname().c_str()); + group_id.get_dispname().c_str()); } if (group_m.has_key(group_name)) { group->error("Duplicate group with name `%s'", - group_id.get_dispname().c_str()); + group_id.get_dispname().c_str()); group_m[group_name]->note("Group `%s' is already defined here", - group_id.get_dispname().c_str()); + group_id.get_dispname().c_str()); } else group_m.add(group_name, group); } checked = true; @@ -1969,8 +1969,8 @@ namespace Ttcn { if (w_attrib_path) { MultiWithAttrib *attrib = w_attrib_path->get_with_attr(); if (attrib) { - DEBUG(level + 1, "Group Attributes:"); - attrib->dump(level + 2); + DEBUG(level + 1, "Group Attributes:"); + attrib->dump(level + 2); } } } @@ -2063,8 +2063,8 @@ namespace Ttcn { if (w_attrib_path) { MultiWithAttrib *attrib = w_attrib_path->get_with_attr(); if (attrib) { - DEBUG(level + 1, "Attributes:"); - attrib->dump(level + 2); + DEBUG(level + 1, "Attributes:"); + attrib->dump(level + 2); } } } @@ -2583,16 +2583,16 @@ namespace Ttcn { if(ass_m.has_key(group_name)) { group->error("Group name `%s' clashes with a definition", - group_id.get_dispname().c_str()); + group_id.get_dispname().c_str()); ass_m[group_name]->note("Definition of `%s' is here", - group_id.get_dispname().c_str()); + group_id.get_dispname().c_str()); } if(group_m.has_key(group_name)) { group->error("Duplicate group with name `%s'", - group_id.get_dispname().c_str()); + group_id.get_dispname().c_str()); group_m[group_name]->note("Group `%s' is already defined here", - group_id.get_dispname().c_str()); + group_id.get_dispname().c_str()); }else{ group_m.add(group_name,group_v[i]); } @@ -2645,8 +2645,8 @@ namespace Ttcn { if (w_attrib_path) { MultiWithAttrib *attrib = w_attrib_path->get_with_attr(); if (attrib) { - DEBUG(level, "Module Attributes:"); - attrib->dump(level + 1); + DEBUG(level, "Module Attributes:"); + attrib->dump(level + 1); } } } @@ -2920,8 +2920,8 @@ namespace Ttcn { if (w_attrib_path) { MultiWithAttrib *attrib = w_attrib_path->get_with_attr(); if (attrib) { - DEBUG(level + 1, "Definition Attributes:"); - attrib->dump(level + 2); + DEBUG(level + 1, "Definition Attributes:"); + attrib->dump(level + 2); } } if (erroneous_attrs) erroneous_attrs->dump(level+1); @@ -3260,7 +3260,7 @@ namespace Ttcn { if (p_def->get_asstype() != A_CONST) { const char *dispname_str = id->get_dispname().c_str(); error("Local definition `%s' is a constant, but the definition " - "inherited from component type `%s' is a %s", dispname_str, + "inherited from component type `%s' is a %s", dispname_str, p_def->get_my_scope()->get_fullname().c_str(), p_def->get_assname()); p_def->note("The inherited definition of `%s' is here", dispname_str); return false; @@ -3270,16 +3270,16 @@ namespace Ttcn { if (!type->is_identical(p_def_const->type)) { const char *dispname_str = id->get_dispname().c_str(); type->error("Local constant `%s' has type `%s', but the constant " - "inherited from component type `%s' has type `%s'", dispname_str, - type->get_typename().c_str(), + "inherited from component type `%s' has type `%s'", dispname_str, + type->get_typename().c_str(), p_def_const->get_my_scope()->get_fullname().c_str(), - p_def_const->type->get_typename().c_str()); + p_def_const->type->get_typename().c_str()); p_def_const->note("The inherited constant `%s' is here", dispname_str); return false; } else if (!(*value == *p_def_const->value)) { const char *dispname_str = id->get_dispname().c_str(); value->error("Local constant `%s' and the constant inherited from " - "component type `%s' have different values", dispname_str, + "component type `%s' have different values", dispname_str, p_def_const->get_my_scope()->get_fullname().c_str()); p_def_const->note("The inherited constant `%s' is here", dispname_str); return false; @@ -3515,8 +3515,6 @@ namespace Ttcn { map type_chain; map not_allowed; not_allowed.add(Type::T_PORT, 0); - not_allowed.add(Type::T_COMPONENT, 0); - not_allowed.add(Type::T_DEFAULT, 0); Type *t = type->get_type_refd_last(); // if the type is valid the original will be returned Type::typetype_t tt = t->search_for_not_allowed_type(type_chain, not_allowed); @@ -3531,14 +3529,6 @@ namespace Ttcn { error("Type of module parameter cannot be signature `%s'", t->get_fullname().c_str()); break; - case Type::T_COMPONENT: - error("Type of module parameter cannot be or embed component `%s'", - t->get_fullname().c_str()); - break; - case Type::T_DEFAULT: - error("Type of module parameter cannot be or embed default `%s'", - t->get_fullname().c_str()); - break; case Type::T_FUNCTION: case Type::T_ALTSTEP: case Type::T_TESTCASE: @@ -3599,11 +3589,11 @@ namespace Ttcn { if (target->functions.log_param) { // this is not the first modulepar target->functions.log_param = mputprintf(target->functions.log_param, - "TTCN_Logger::log_event_str(\", %s := \");\n", dispname); + "TTCN_Logger::log_event_str(\", %s := \");\n", dispname); } else { // this is the first modulepar target->functions.log_param = mputprintf(target->functions.log_param, - "TTCN_Logger::log_event_str(\"%s := \");\n", dispname); + "TTCN_Logger::log_event_str(\"%s := \");\n", dispname); } target->functions.log_param = mputprintf(target->functions.log_param, "%s.log();\n", name); @@ -3767,11 +3757,11 @@ namespace Ttcn { if (target->functions.log_param) { // this is not the first modulepar target->functions.log_param = mputprintf(target->functions.log_param, - "TTCN_Logger::log_event_str(\", %s := \");\n", dispname); + "TTCN_Logger::log_event_str(\", %s := \");\n", dispname); } else { // this is the first modulepar target->functions.log_param = mputprintf(target->functions.log_param, - "TTCN_Logger::log_event_str(\"%s := \");\n", dispname); + "TTCN_Logger::log_event_str(\"%s := \");\n", dispname); } target->functions.log_param = mputprintf(target->functions.log_param, "%s.log();\n", name); @@ -4148,8 +4138,8 @@ namespace Ttcn { { if (iter->recurs_deriv_checked) break; else if (refch.add(iter->get_fullname())) - iter->recurs_deriv_checked = true; - else break; + iter->recurs_deriv_checked = true; + else break; } } recurs_deriv_checked = true; @@ -4170,8 +4160,8 @@ namespace Ttcn { fp_list->generate_code_defval(target); target->header.function_prototypes = mputprintf(target->header.function_prototypes, - "extern %s %s(%s);\n", - type_genname_str, template_name, formal_par_list); + "extern %s %s(%s);\n", + type_genname_str, template_name, formal_par_list); char *function_body = mprintf("%s %s(%s)\n" "{\n", type_genname_str, template_name, formal_par_list); function_body = create_location_object(function_body, "TEMPLATE", @@ -4179,24 +4169,24 @@ namespace Ttcn { if (base_template) { // modified template function_body = mputprintf(function_body, "%s ret_val(%s", - type_genname_str, - base_template->get_genname_from_scope(my_scope).c_str()); - if (base_template->fp_list) { - // the base template is also parameterized - function_body = mputc(function_body, '('); - size_t nof_base_pars = base_template->fp_list->get_nof_fps(); - for (size_t i = 0; i < nof_base_pars; i++) { - if (i > 0) function_body = mputstr(function_body, ", "); - function_body = mputstr(function_body, - fp_list->get_fp_byIndex(i)->get_id().get_name().c_str()); - } - function_body = mputc(function_body, ')'); - } - function_body = mputstr(function_body, ");\n"); + type_genname_str, + base_template->get_genname_from_scope(my_scope).c_str()); + if (base_template->fp_list) { + // the base template is also parameterized + function_body = mputc(function_body, '('); + size_t nof_base_pars = base_template->fp_list->get_nof_fps(); + for (size_t i = 0; i < nof_base_pars; i++) { + if (i > 0) function_body = mputstr(function_body, ", "); + function_body = mputstr(function_body, + fp_list->get_fp_byIndex(i)->get_id().get_name().c_str()); + } + function_body = mputc(function_body, ')'); + } + function_body = mputstr(function_body, ");\n"); } else { // simple template function_body = mputprintf(function_body, "%s ret_val;\n", - type_genname_str); + type_genname_str); } if (erroneous_attrs && erroneous_attrs->get_err_descr()) { function_body = erroneous_attrs->get_err_descr()-> @@ -4347,19 +4337,19 @@ namespace Ttcn { if (fp_list) { const char *dispname_str = id->get_dispname().c_str(); NOTSUPP("Code generation for parameterized local template `%s'", - dispname_str); + dispname_str); def = mputprintf(def, "/* NOT SUPPORTED: template %s */\n", dispname_str); init = mputprintf(init, "/* NOT SUPPORTED: template %s */\n", - dispname_str); + dispname_str); } else { // non-parameterized template // use the default constructor for initialization def = mputprintf(def, "%s %s;\n", - type->get_genname_template(my_scope).c_str(), genname_str); + type->get_genname_template(my_scope).c_str(), genname_str); if (base_template) { - // copy the base template with an assignment - init = mputprintf(init, "%s = %s;\n", genname_str, - base_template->get_genname_from_scope(my_scope).c_str()); + // copy the base template with an assignment + init = mputprintf(init, "%s = %s;\n", genname_str, + base_template->get_genname_from_scope(my_scope).c_str()); } // finally assign the body init = body->generate_code_init(init, genname_str); @@ -4471,7 +4461,7 @@ namespace Ttcn { if (p_def->get_asstype() != A_VAR) { const char *dispname_str = id->get_dispname().c_str(); error("Local definition `%s' is a variable, but the definition " - "inherited from component type `%s' is a %s", dispname_str, + "inherited from component type `%s' is a %s", dispname_str, p_def->get_my_scope()->get_fullname().c_str(), p_def->get_assname()); p_def->note("The inherited definition of `%s' is here", dispname_str); return false; @@ -4481,36 +4471,36 @@ namespace Ttcn { if (!type->is_identical(p_def_var->type)) { const char *dispname_str = id->get_dispname().c_str(); type->error("Local variable `%s' has type `%s', but the variable " - "inherited from component type `%s' has type `%s'", dispname_str, - type->get_typename().c_str(), + "inherited from component type `%s' has type `%s'", dispname_str, + type->get_typename().c_str(), p_def_var->get_my_scope()->get_fullname().c_str(), - p_def_var->type->get_typename().c_str()); + p_def_var->type->get_typename().c_str()); p_def_var->note("The inherited variable `%s' is here", dispname_str); return false; } if (initial_value) { if (p_def_var->initial_value) { if (!initial_value->is_unfoldable() && - !p_def_var->initial_value->is_unfoldable() && - !(*initial_value == *p_def_var->initial_value)) { - const char *dispname_str = id->get_dispname().c_str(); - initial_value->warning("Local variable `%s' and the variable " - "inherited from component type `%s' have different initial values", - dispname_str, p_def_var->get_my_scope()->get_fullname().c_str()); - p_def_var->note("The inherited variable `%s' is here", dispname_str); - } + !p_def_var->initial_value->is_unfoldable() && + !(*initial_value == *p_def_var->initial_value)) { + const char *dispname_str = id->get_dispname().c_str(); + initial_value->warning("Local variable `%s' and the variable " + "inherited from component type `%s' have different initial values", + dispname_str, p_def_var->get_my_scope()->get_fullname().c_str()); + p_def_var->note("The inherited variable `%s' is here", dispname_str); + } } else { - const char *dispname_str = id->get_dispname().c_str(); - initial_value->warning("Local variable `%s' has initial value, but " - "the variable inherited from component type `%s' does not", - dispname_str, p_def_var->get_my_scope()->get_fullname().c_str()); - p_def_var->note("The inherited variable `%s' is here", dispname_str); + const char *dispname_str = id->get_dispname().c_str(); + initial_value->warning("Local variable `%s' has initial value, but " + "the variable inherited from component type `%s' does not", + dispname_str, p_def_var->get_my_scope()->get_fullname().c_str()); + p_def_var->note("The inherited variable `%s' is here", dispname_str); } } else if (p_def_var->initial_value) { const char *dispname_str = id->get_dispname().c_str(); warning("Local variable `%s' does not have initial value, but the " - "variable inherited from component type `%s' has", dispname_str, - p_def_var->get_my_scope()->get_fullname().c_str()); + "variable inherited from component type `%s' has", dispname_str, + p_def_var->get_my_scope()->get_fullname().c_str()); p_def_var->note("The inherited variable `%s' is here", dispname_str); } return true; @@ -4547,15 +4537,15 @@ namespace Ttcn { // the initial value can be represented by a single C++ expression // the object is initialized by the constructor str = mputprintf(str, "%s %s(%s);\n", - type->get_genname_value(my_scope).c_str(), genname_str, - initial_value->get_single_expr().c_str()); + type->get_genname_value(my_scope).c_str(), genname_str, + initial_value->get_single_expr().c_str()); } else { // use the default constructor str = mputprintf(str, "%s %s;\n", - type->get_genname_value(my_scope).c_str(), genname_str); + type->get_genname_value(my_scope).c_str(), genname_str); if (initial_value) { - // the initial value is assigned using subsequent statements - str = initial_value->generate_code_init(str, genname_str); + // the initial value is assigned using subsequent statements + str = initial_value->generate_code_init(str, genname_str); } } return str; @@ -4577,7 +4567,7 @@ namespace Ttcn { { if (initial_value) { str = initial_value->generate_code_init(str, - base_defn->get_genname_from_scope(my_scope).c_str()); + base_defn->get_genname_from_scope(my_scope).c_str()); } return str; } @@ -4685,7 +4675,7 @@ namespace Ttcn { if (p_def->get_asstype() != A_VAR_TEMPLATE) { const char *dispname_str = id->get_dispname().c_str(); error("Local definition `%s' is a template variable, but the definition " - "inherited from component type `%s' is a %s", dispname_str, + "inherited from component type `%s' is a %s", dispname_str, p_def->get_my_scope()->get_fullname().c_str(), p_def->get_assname()); p_def->note("The inherited definition of `%s' is here", dispname_str); return false; @@ -4696,32 +4686,32 @@ namespace Ttcn { if (!type->is_identical(p_def_var_template->type)) { const char *dispname_str = id->get_dispname().c_str(); type->error("Local template variable `%s' has type `%s', but the " - "template variable inherited from component type `%s' has type `%s'", - dispname_str, type->get_typename().c_str(), + "template variable inherited from component type `%s' has type `%s'", + dispname_str, type->get_typename().c_str(), p_def_var_template->get_my_scope()->get_fullname().c_str(), - p_def_var_template->type->get_typename().c_str()); + p_def_var_template->type->get_typename().c_str()); p_def_var_template->note("The inherited template variable `%s' is here", - dispname_str); + dispname_str); return false; } if (initial_value) { if (!p_def_var_template->initial_value) { - const char *dispname_str = id->get_dispname().c_str(); - initial_value->warning("Local template variable `%s' has initial " - "value, but the template variable inherited from component type " - "`%s' does not", dispname_str, - p_def_var_template->get_my_scope()->get_fullname().c_str()); - p_def_var_template->note("The inherited template variable `%s' is here", - dispname_str); + const char *dispname_str = id->get_dispname().c_str(); + initial_value->warning("Local template variable `%s' has initial " + "value, but the template variable inherited from component type " + "`%s' does not", dispname_str, + p_def_var_template->get_my_scope()->get_fullname().c_str()); + p_def_var_template->note("The inherited template variable `%s' is here", + dispname_str); } } else if (p_def_var_template->initial_value) { const char *dispname_str = id->get_dispname().c_str(); warning("Local template variable `%s' does not have initial value, but " - "the template variable inherited from component type `%s' has", - dispname_str, - p_def_var_template->get_my_scope()->get_fullname().c_str()); + "the template variable inherited from component type `%s' has", + dispname_str, + p_def_var_template->get_my_scope()->get_fullname().c_str()); p_def_var_template->note("The inherited template variable `%s' is here", - dispname_str); + dispname_str); } return true; } @@ -4809,7 +4799,7 @@ namespace Ttcn { { if (initial_value) { str = initial_value->generate_code_init(str, - base_defn->get_genname_from_scope(my_scope).c_str()); + base_defn->get_genname_from_scope(my_scope).c_str()); if (template_restriction != TR_NONE && gen_restriction_check) str = Template::generate_restriction_check_code(str, base_defn->get_genname_from_scope(my_scope).c_str(), @@ -4892,7 +4882,7 @@ namespace Ttcn { if (p_def->get_asstype() != A_TIMER) { const char *dispname_str = id->get_dispname().c_str(); error("Local definition `%s' is a timer, but the definition inherited " - "from component type `%s' is a %s", dispname_str, + "from component type `%s' is a %s", dispname_str, p_def->get_my_scope()->get_fullname().c_str(), p_def->get_assname()); p_def->note("The inherited definition of `%s' is here", dispname_str); return false; @@ -4902,25 +4892,25 @@ namespace Ttcn { if (dimensions) { if (p_def_timer->dimensions) { if (!dimensions->is_identical(p_def_timer->dimensions)) { - const char *dispname_str = id->get_dispname().c_str(); - error("Local timer `%s' and the timer inherited from component type " - "`%s' have different array dimensions", dispname_str, + const char *dispname_str = id->get_dispname().c_str(); + error("Local timer `%s' and the timer inherited from component type " + "`%s' have different array dimensions", dispname_str, p_def_timer->get_my_scope()->get_fullname().c_str()); - p_def_timer->note("The inherited timer `%s' is here", dispname_str); - return false; - } + p_def_timer->note("The inherited timer `%s' is here", dispname_str); + return false; + } } else { - const char *dispname_str = id->get_dispname().c_str(); - error("Local definition `%s' is a timer array, but the definition " - "inherited from component type `%s' is a single timer", dispname_str, + const char *dispname_str = id->get_dispname().c_str(); + error("Local definition `%s' is a timer array, but the definition " + "inherited from component type `%s' is a single timer", dispname_str, p_def_timer->get_my_scope()->get_fullname().c_str()); - p_def_timer->note("The inherited timer `%s' is here", dispname_str); - return false; + p_def_timer->note("The inherited timer `%s' is here", dispname_str); + return false; } } else if (p_def_timer->dimensions) { const char *dispname_str = id->get_dispname().c_str(); error("Local definition `%s' is a single timer, but the definition " - "inherited from component type `%s' is a timer array", dispname_str, + "inherited from component type `%s' is a timer array", dispname_str, p_def_timer->get_my_scope()->get_fullname().c_str()); p_def_timer->note("The inherited timer `%s' is here", dispname_str); return false; @@ -4928,27 +4918,27 @@ namespace Ttcn { if (default_duration) { if (p_def_timer->default_duration) { if (!default_duration->is_unfoldable() && - !p_def_timer->default_duration->is_unfoldable() && - !(*default_duration == *p_def_timer->default_duration)) { - const char *dispname_str = id->get_dispname().c_str(); - default_duration->warning("Local timer `%s' and the timer inherited " - "from component type `%s' have different default durations", - dispname_str, p_def_timer->get_my_scope()->get_fullname().c_str()); - p_def_timer->note("The inherited timer `%s' is here", dispname_str); - } + !p_def_timer->default_duration->is_unfoldable() && + !(*default_duration == *p_def_timer->default_duration)) { + const char *dispname_str = id->get_dispname().c_str(); + default_duration->warning("Local timer `%s' and the timer inherited " + "from component type `%s' have different default durations", + dispname_str, p_def_timer->get_my_scope()->get_fullname().c_str()); + p_def_timer->note("The inherited timer `%s' is here", dispname_str); + } } else { - const char *dispname_str = id->get_dispname().c_str(); - default_duration->error("Local timer `%s' has default duration, but " - "the timer inherited from component type `%s' does not", dispname_str, + const char *dispname_str = id->get_dispname().c_str(); + default_duration->error("Local timer `%s' has default duration, but " + "the timer inherited from component type `%s' does not", dispname_str, p_def_timer->get_my_scope()->get_fullname().c_str()); - p_def_timer->note("The inherited timer `%s' is here", dispname_str); - return false; + p_def_timer->note("The inherited timer `%s' is here", dispname_str); + return false; } } else if (p_def_timer->default_duration) { const char *dispname_str = id->get_dispname().c_str(); error("Local timer `%s' does not have default duration, but the timer " - "inherited from component type `%s' has", dispname_str, - p_def_timer->get_my_scope()->get_fullname().c_str()); + "inherited from component type `%s' has", dispname_str, + p_def_timer->get_my_scope()->get_fullname().c_str()); p_def_timer->note("The inherited timer `%s' is here", dispname_str); return false; } @@ -5094,49 +5084,49 @@ namespace Ttcn { const string& array_type = dimensions->get_timer_type(); const char *array_type_str = array_type.c_str(); target->header.global_vars = mputprintf(target->header.global_vars, - "extern %s %s;\n", array_type_str, genname_str); + "extern %s %s;\n", array_type_str, genname_str); target->source.global_vars = mputprintf(target->source.global_vars, - "%s %s;\n", array_type_str, genname_str); + "%s %s;\n", array_type_str, genname_str); target->functions.pre_init = mputstr(target->functions.pre_init, "{\n" - "static const char * const timer_name = \""); + "static const char * const timer_name = \""); target->functions.pre_init = mputstr(target->functions.pre_init, - dispname.c_str()); + dispname.c_str()); target->functions.pre_init = mputprintf(target->functions.pre_init, - "\";\n" + "\";\n" "%s.set_name(timer_name);\n" - "}\n", genname_str); + "}\n", genname_str); if (default_duration) target->functions.post_init = - generate_code_array_duration(target->functions.post_init, genname_str, - default_duration); + generate_code_array_duration(target->functions.post_init, genname_str, + default_duration); } else { // single timer target->header.global_vars = mputprintf(target->header.global_vars, - "extern TIMER %s;\n", genname_str); + "extern TIMER %s;\n", genname_str); if (default_duration) { - // has default duration - Value *v = default_duration->get_value_refd_last(); - if (v->get_valuetype() == Value::V_REAL) { - // duration is known at compilation time -> set in the constructor - target->source.global_vars = mputprintf(target->source.global_vars, - "TIMER %s(\"%s\", %s);\n", genname_str, dispname.c_str(), - v->get_single_expr().c_str()); - } else { - // duration is known only at runtime -> set in post_init - target->source.global_vars = mputprintf(target->source.global_vars, - "TIMER %s(\"%s\");\n", genname_str, dispname.c_str()); - expression_struct expr; - Code::init_expr(&expr); - expr.expr = mputprintf(expr.expr, "%s.set_default_duration(", - genname_str); - default_duration->generate_code_expr(&expr); - expr.expr = mputc(expr.expr, ')'); - target->functions.post_init = - Code::merge_free_expr(target->functions.post_init, &expr); - } + // has default duration + Value *v = default_duration->get_value_refd_last(); + if (v->get_valuetype() == Value::V_REAL) { + // duration is known at compilation time -> set in the constructor + target->source.global_vars = mputprintf(target->source.global_vars, + "TIMER %s(\"%s\", %s);\n", genname_str, dispname.c_str(), + v->get_single_expr().c_str()); + } else { + // duration is known only at runtime -> set in post_init + target->source.global_vars = mputprintf(target->source.global_vars, + "TIMER %s(\"%s\");\n", genname_str, dispname.c_str()); + expression_struct expr; + Code::init_expr(&expr); + expr.expr = mputprintf(expr.expr, "%s.set_default_duration(", + genname_str); + default_duration->generate_code_expr(&expr); + expr.expr = mputc(expr.expr, ')'); + target->functions.post_init = + Code::merge_free_expr(target->functions.post_init, &expr); + } } else { - // does not have default duration - target->source.global_vars = mputprintf(target->source.global_vars, - "TIMER %s(\"%s\");\n", genname_str, dispname.c_str()); + // does not have default duration + target->source.global_vars = mputprintf(target->source.global_vars, + "TIMER %s(\"%s\");\n", genname_str, dispname.c_str()); } } } @@ -5274,33 +5264,33 @@ namespace Ttcn { const char *array_type_str = array_type.c_str(); str = mputprintf(str, "%s %s;\n", array_type_str, genname_str); str = mputstr(str, "{\n" - "static const char * const timer_name = \""); + "static const char * const timer_name = \""); str = mputstr(str, dispname.c_str()); str = mputprintf(str, "\";\n" "%s.set_name(timer_name);\n" - "}\n", genname_str); + "}\n", genname_str); if (default_duration) str = generate_code_array_duration(str, - genname_str, default_duration); + genname_str, default_duration); } else { // single timer if (default_duration && default_duration->has_single_expr()) { - // the default duration can be passed to the constructor - str = mputprintf(str, "TIMER %s(\"%s\", %s);\n", genname_str, - dispname.c_str(), default_duration->get_single_expr().c_str()); + // the default duration can be passed to the constructor + str = mputprintf(str, "TIMER %s(\"%s\", %s);\n", genname_str, + dispname.c_str(), default_duration->get_single_expr().c_str()); } else { - // only the name is passed to the constructor - str = mputprintf(str, "TIMER %s(\"%s\");\n", genname_str, - dispname.c_str()); - if (default_duration) { - // the default duration is set explicitly - expression_struct expr; - Code::init_expr(&expr); - expr.expr = mputprintf(expr.expr, "%s.set_default_duration(", - genname_str); - default_duration->generate_code_expr(&expr); - expr.expr = mputc(expr.expr, ')'); - str = Code::merge_free_expr(str, &expr); - } + // only the name is passed to the constructor + str = mputprintf(str, "TIMER %s(\"%s\");\n", genname_str, + dispname.c_str()); + if (default_duration) { + // the default duration is set explicitly + expression_struct expr; + Code::init_expr(&expr); + expr.expr = mputprintf(expr.expr, "%s.set_default_duration(", + genname_str); + default_duration->generate_code_expr(&expr); + expr.expr = mputc(expr.expr, ')'); + str = Code::merge_free_expr(str, &expr); + } } } return str; @@ -5321,39 +5311,39 @@ namespace Ttcn { const char *array_type_str = array_type.c_str(); def = mputprintf(def, "%s %s;\n", array_type_str, genname_str); def = mputstr(def, "{\n" - "static const char * const timer_names[] = { "); + "static const char * const timer_names[] = { "); def = dimensions->generate_element_names(def, dispname); def = mputprintf(def, " };\n" "%s.set_name(%lu, timer_names);\n" - "}\n", genname_str, (unsigned long) dimensions->get_array_size()); + "}\n", genname_str, (unsigned long) dimensions->get_array_size()); if (default_duration) init = generate_code_array_duration(init, - genname_str, default_duration); + genname_str, default_duration); } else { // single timer if (default_duration) { - // has default duration - Value *v = default_duration->get_value_refd_last(); - if (v->get_valuetype() == Value::V_REAL) { - // duration is known at compilation time -> set in the constructor - def = mputprintf(def, "TIMER %s(\"%s\", %s);\n", genname_str, - dispname.c_str(), v->get_single_expr().c_str()); - } else { - // duration is known only at runtime -> set when control reaches the - // timer definition - def = mputprintf(def, "TIMER %s(\"%s\");\n", genname_str, - dispname.c_str()); + // has default duration + Value *v = default_duration->get_value_refd_last(); + if (v->get_valuetype() == Value::V_REAL) { + // duration is known at compilation time -> set in the constructor + def = mputprintf(def, "TIMER %s(\"%s\", %s);\n", genname_str, + dispname.c_str(), v->get_single_expr().c_str()); + } else { + // duration is known only at runtime -> set when control reaches the + // timer definition + def = mputprintf(def, "TIMER %s(\"%s\");\n", genname_str, + dispname.c_str()); expression_struct expr; Code::init_expr(&expr); - expr.expr = mputprintf(expr.expr, "%s.set_default_duration(", - genname_str); - default_duration->generate_code_expr(&expr); - expr.expr = mputc(expr.expr, ')'); - init = Code::merge_free_expr(init, &expr); - } + expr.expr = mputprintf(expr.expr, "%s.set_default_duration(", + genname_str); + default_duration->generate_code_expr(&expr); + expr.expr = mputc(expr.expr, ')'); + init = Code::merge_free_expr(init, &expr); + } } else { - // does not have default duration - def = mputprintf(def, "TIMER %s(\"%s\");\n", genname_str, - dispname.c_str()); + // does not have default duration + def = mputprintf(def, "TIMER %s(\"%s\");\n", genname_str, + dispname.c_str()); } } } @@ -5363,25 +5353,25 @@ namespace Ttcn { if (default_duration) { Def_Timer *base_timer_defn = dynamic_cast(base_defn); if (!base_timer_defn || !base_timer_defn->default_duration) - FATAL_ERROR("Def_Timer::generate_code_init_comp()"); + FATAL_ERROR("Def_Timer::generate_code_init_comp()"); // initializer is not needed if the default durations are the same // constants in both timers if (default_duration->is_unfoldable() || - base_timer_defn->default_duration->is_unfoldable() || - !(*default_duration == *base_timer_defn->default_duration)) { - if (dimensions) { - str = generate_code_array_duration(str, - base_timer_defn->get_genname_from_scope(my_scope).c_str(), - default_duration); - } else { - expression_struct expr; - Code::init_expr(&expr); - expr.expr = mputprintf(expr.expr, "%s.set_default_duration(", - base_timer_defn->get_genname_from_scope(my_scope).c_str()); - default_duration->generate_code_expr(&expr); - expr.expr = mputc(expr.expr, ')'); - str = Code::merge_free_expr(str, &expr); - } + base_timer_defn->default_duration->is_unfoldable() || + !(*default_duration == *base_timer_defn->default_duration)) { + if (dimensions) { + str = generate_code_array_duration(str, + base_timer_defn->get_genname_from_scope(my_scope).c_str(), + default_duration); + } else { + expression_struct expr; + Code::init_expr(&expr); + expr.expr = mputprintf(expr.expr, "%s.set_default_duration(", + base_timer_defn->get_genname_from_scope(my_scope).c_str()); + default_duration->generate_code_expr(&expr); + expr.expr = mputc(expr.expr, ')'); + str = Code::merge_free_expr(str, &expr); + } } } return str; @@ -5456,9 +5446,9 @@ namespace Ttcn { if (ass) { if (ass->get_asstype() == A_TYPE) { Type *t = ass->get_Type()->get_type_refd_last(); - if (t->get_typetype() == Type::T_PORT) port_type = t; - else type_ref->error("Type reference `%s' does not refer to a " - "port type", type_ref->get_dispname().c_str()); + if (t->get_typetype() == Type::T_PORT) port_type = t; + else type_ref->error("Type reference `%s' does not refer to a " + "port type", type_ref->get_dispname().c_str()); } else type_ref->error("Reference `%s' does not refer to a " "type", type_ref->get_dispname().c_str()); } @@ -5476,7 +5466,7 @@ namespace Ttcn { if (p_def->get_asstype() != A_PORT) { const char *dispname_str = id->get_dispname().c_str(); error("Local definition `%s' is a port, but the definition inherited " - "from component type `%s' is a %s", dispname_str, + "from component type `%s' is a %s", dispname_str, p_def->get_my_scope()->get_fullname().c_str(), p_def->get_assname()); p_def->note("The inherited definition of `%s' is here", dispname_str); return false; @@ -5484,38 +5474,38 @@ namespace Ttcn { Def_Port *p_def_port = dynamic_cast(p_def); if (!p_def_port) FATAL_ERROR("Def_Port::chk_identical()"); if (port_type && p_def_port->port_type && - port_type != p_def_port->port_type) { + port_type != p_def_port->port_type) { const char *dispname_str = id->get_dispname().c_str(); type_ref->error("Local port `%s' has type `%s', but the port inherited " - "from component type `%s' has type `%s'", dispname_str, - port_type->get_typename().c_str(), + "from component type `%s' has type `%s'", dispname_str, + port_type->get_typename().c_str(), p_def_port->get_my_scope()->get_fullname().c_str(), - p_def_port->port_type->get_typename().c_str()); + p_def_port->port_type->get_typename().c_str()); p_def_port->note("The inherited port `%s' is here", dispname_str); return false; } if (dimensions) { if (p_def_port->dimensions) { if (!dimensions->is_identical(p_def_port->dimensions)) { - const char *dispname_str = id->get_dispname().c_str(); - error("Local port `%s' and the port inherited from component type " - "`%s' have different array dimensions", dispname_str, + const char *dispname_str = id->get_dispname().c_str(); + error("Local port `%s' and the port inherited from component type " + "`%s' have different array dimensions", dispname_str, p_def_port->get_my_scope()->get_fullname().c_str()); - p_def_port->note("The inherited port `%s' is here", dispname_str); - return false; - } + p_def_port->note("The inherited port `%s' is here", dispname_str); + return false; + } } else { - const char *dispname_str = id->get_dispname().c_str(); - error("Local definition `%s' is a port array, but the definition " - "inherited from component type `%s' is a single port", dispname_str, + const char *dispname_str = id->get_dispname().c_str(); + error("Local definition `%s' is a port array, but the definition " + "inherited from component type `%s' is a single port", dispname_str, p_def_port->get_my_scope()->get_fullname().c_str()); - p_def_port->note("The inherited port `%s' is here", dispname_str); - return false; + p_def_port->note("The inherited port `%s' is here", dispname_str); + return false; } } else if (p_def_port->dimensions) { const char *dispname_str = id->get_dispname().c_str(); error("Local definition `%s' is a single port, but the definition " - "inherited from component type `%s' is a port array", dispname_str, + "inherited from component type `%s' is a port array", dispname_str, p_def_port->get_my_scope()->get_fullname().c_str()); p_def_port->note("The inherited port `%s' is here", dispname_str); return false; @@ -5534,24 +5524,24 @@ namespace Ttcn { const string& array_type = dimensions->get_port_type(type_genname); const char *array_type_str = array_type.c_str(); target->header.global_vars = mputprintf(target->header.global_vars, - "extern %s %s;\n", array_type_str, genname_str); + "extern %s %s;\n", array_type_str, genname_str); target->source.global_vars = mputprintf(target->source.global_vars, - "%s %s;\n", array_type_str, genname_str); + "%s %s;\n", array_type_str, genname_str); target->functions.pre_init = mputstr(target->functions.pre_init, "{\n" - "static const char * const port_name = \""); + "static const char * const port_name = \""); target->functions.pre_init = mputstr(target->functions.pre_init, - dispname.c_str()); + dispname.c_str()); target->functions.pre_init = mputprintf(target->functions.pre_init, - "\";\n" + "\";\n" "%s.set_name(port_name);\n" - "}\n", genname_str); + "}\n", genname_str); } else { // single port const char *type_genname_str = type_genname.c_str(); target->header.global_vars = mputprintf(target->header.global_vars, - "extern %s %s;\n", type_genname_str, genname_str); + "extern %s %s;\n", type_genname_str, genname_str); target->source.global_vars = mputprintf(target->source.global_vars, - "%s %s(\"%s\");\n", type_genname_str, genname_str, dispname.c_str()); + "%s %s(\"%s\");\n", type_genname_str, genname_str, dispname.c_str()); } target->functions.init_comp = mputprintf(target->functions.init_comp, "%s.activate_port();\n", genname_str); @@ -5584,21 +5574,21 @@ namespace Ttcn { { if (is_external) { if (has_return_type) { - if (returns_template) return A_EXT_FUNCTION_RTEMP; - else return A_EXT_FUNCTION_RVAL; + if (returns_template) return A_EXT_FUNCTION_RTEMP; + else return A_EXT_FUNCTION_RVAL; } else { - if (returns_template) - FATAL_ERROR("Def_Function_Base::determine_asstype()"); - return A_EXT_FUNCTION; + if (returns_template) + FATAL_ERROR("Def_Function_Base::determine_asstype()"); + return A_EXT_FUNCTION; } } else { // not an external function if (has_return_type) { - if (returns_template) return A_FUNCTION_RTEMP; - else return A_FUNCTION_RVAL; + if (returns_template) return A_FUNCTION_RTEMP; + else return A_FUNCTION_RVAL; } else { - if (returns_template) - FATAL_ERROR("Def_Function_Base::determine_asstype()"); - return A_FUNCTION; + if (returns_template) + FATAL_ERROR("Def_Function_Base::determine_asstype()"); + return A_FUNCTION; } } } @@ -5616,8 +5606,8 @@ namespace Ttcn { FormalParList *p_fpl, Type *p_return_type, bool returns_template, template_restriction_t p_template_restriction) : Definition(determine_asstype(is_external, p_return_type != 0, - returns_template), p_id), fp_list(p_fpl), return_type(p_return_type), - prototype(PROTOTYPE_NONE), input_type(0), output_type(0), + returns_template), p_id), fp_list(p_fpl), return_type(p_return_type), + prototype(PROTOTYPE_NONE), input_type(0), output_type(0), template_restriction(p_template_restriction) { if (!p_fpl) FATAL_ERROR("Def_Function_Base::Def_Function_Base()"); @@ -5693,100 +5683,100 @@ namespace Ttcn { // checking the formal parameter list if (prototype == PROTOTYPE_CONVERT) { if (fp_list->get_nof_fps() == 1) { - FormalPar *par = fp_list->get_fp_byIndex(0); - if (par->get_asstype() == A_PAR_VAL_IN) { - input_type = par->get_Type(); - } else { - par->error("The parameter must be an `in' value parameter for " - "attribute `prototype(%s)' instead of %s", get_prototype_name(), - par->get_assname()); - } + FormalPar *par = fp_list->get_fp_byIndex(0); + if (par->get_asstype() == A_PAR_VAL_IN) { + input_type = par->get_Type(); + } else { + par->error("The parameter must be an `in' value parameter for " + "attribute `prototype(%s)' instead of %s", get_prototype_name(), + par->get_assname()); + } } else { - fp_list->error("The function must have one parameter instead of %lu " - "for attribute `prototype(%s)'", (unsigned long) fp_list->get_nof_fps(), - get_prototype_name()); + fp_list->error("The function must have one parameter instead of %lu " + "for attribute `prototype(%s)'", (unsigned long) fp_list->get_nof_fps(), + get_prototype_name()); } } else { // not PROTOTYPE_CONVERT if (fp_list->get_nof_fps() == 2) { - FormalPar *first_par = fp_list->get_fp_byIndex(0); - if (prototype == PROTOTYPE_SLIDING) { - if (first_par->get_asstype() == A_PAR_VAL_INOUT) { - Type *first_par_type = first_par->get_Type(); - switch (first_par_type->get_type_refd_last() - ->get_typetype_ttcn3()) { - case Type::T_ERROR: - case Type::T_OSTR: - case Type::T_CSTR: - case Type::T_BSTR: - input_type = first_par_type; - break; - default: - first_par_type->error("The type of the first parameter must be " - "`octetstring' or `charstring' or `bitstring' for attribute " - "`prototype(%s)' instead of `%s'", get_prototype_name(), - first_par_type->get_typename().c_str()); - } - } else { - first_par->error("The first parameter must be an `inout' value " - "parameter for attribute `prototype(%s)' instead of %s", - get_prototype_name(), first_par->get_assname()); - } - } else { - if (first_par->get_asstype() == A_PAR_VAL_IN) { - input_type = first_par->get_Type(); - } else { - first_par->error("The first parameter must be an `in' value " - "parameter for attribute `prototype(%s)' instead of %s", - get_prototype_name(), first_par->get_assname()); - } - } - FormalPar *second_par = fp_list->get_fp_byIndex(1); - if (second_par->get_asstype() == A_PAR_VAL_OUT) { - output_type = second_par->get_Type(); - } else { - second_par->error("The second parameter must be an `out' value " - "parameter for attribute `prototype(%s)' instead of %s", - get_prototype_name(), second_par->get_assname()); - } + FormalPar *first_par = fp_list->get_fp_byIndex(0); + if (prototype == PROTOTYPE_SLIDING) { + if (first_par->get_asstype() == A_PAR_VAL_INOUT) { + Type *first_par_type = first_par->get_Type(); + switch (first_par_type->get_type_refd_last() + ->get_typetype_ttcn3()) { + case Type::T_ERROR: + case Type::T_OSTR: + case Type::T_CSTR: + case Type::T_BSTR: + input_type = first_par_type; + break; + default: + first_par_type->error("The type of the first parameter must be " + "`octetstring' or `charstring' or `bitstring' for attribute " + "`prototype(%s)' instead of `%s'", get_prototype_name(), + first_par_type->get_typename().c_str()); + } + } else { + first_par->error("The first parameter must be an `inout' value " + "parameter for attribute `prototype(%s)' instead of %s", + get_prototype_name(), first_par->get_assname()); + } + } else { + if (first_par->get_asstype() == A_PAR_VAL_IN) { + input_type = first_par->get_Type(); + } else { + first_par->error("The first parameter must be an `in' value " + "parameter for attribute `prototype(%s)' instead of %s", + get_prototype_name(), first_par->get_assname()); + } + } + FormalPar *second_par = fp_list->get_fp_byIndex(1); + if (second_par->get_asstype() == A_PAR_VAL_OUT) { + output_type = second_par->get_Type(); + } else { + second_par->error("The second parameter must be an `out' value " + "parameter for attribute `prototype(%s)' instead of %s", + get_prototype_name(), second_par->get_assname()); + } } else { - fp_list->error("The function must have two parameters for attribute " - "`prototype(%s)' instead of %lu", get_prototype_name(), - (unsigned long) fp_list->get_nof_fps()); + fp_list->error("The function must have two parameters for attribute " + "`prototype(%s)' instead of %lu", get_prototype_name(), + (unsigned long) fp_list->get_nof_fps()); } } // checking the return type if (prototype == PROTOTYPE_FAST) { if (return_type) { - return_type->error("The function cannot have return type for " - "attribute `prototype(%s)'", get_prototype_name()); + return_type->error("The function cannot have return type for " + "attribute `prototype(%s)'", get_prototype_name()); } } else { if (return_type) { - if (asstype == A_FUNCTION_RTEMP || asstype == A_EXT_FUNCTION_RTEMP) - return_type->error("The function must return a value instead of a " - "template for attribute `prototype(%s)'", get_prototype_name()); - if (prototype == PROTOTYPE_CONVERT) { - output_type = return_type; - } else { - switch (return_type->get_type_refd_last()->get_typetype_ttcn3()) { - case Type::T_ERROR: - case Type::T_INT: - break; - default: - return_type->error("The return type of the function must be " - "`integer' instead of `%s' for attribute `prototype(%s)'", - return_type->get_typename().c_str(), get_prototype_name()); - } - } + if (asstype == A_FUNCTION_RTEMP || asstype == A_EXT_FUNCTION_RTEMP) + return_type->error("The function must return a value instead of a " + "template for attribute `prototype(%s)'", get_prototype_name()); + if (prototype == PROTOTYPE_CONVERT) { + output_type = return_type; + } else { + switch (return_type->get_type_refd_last()->get_typetype_ttcn3()) { + case Type::T_ERROR: + case Type::T_INT: + break; + default: + return_type->error("The return type of the function must be " + "`integer' instead of `%s' for attribute `prototype(%s)'", + return_type->get_typename().c_str(), get_prototype_name()); + } + } } else { - error("The function must have return type for attribute " - "`prototype(%s)'", get_prototype_name()); + error("The function must have return type for attribute " + "`prototype(%s)'", get_prototype_name()); } } // checking the 'runs on' clause if (get_RunsOnType()) { error("The function cannot have `runs on' clause for attribute " - "`prototype(%s)'", get_prototype_name()); + "`prototype(%s)'", get_prototype_name()); } } @@ -5814,8 +5804,8 @@ namespace Ttcn { StatementBlock *p_block) : Def_Function_Base(false, p_id, p_fpl, p_return_type, returns_template, p_template_restriction), - runs_on_ref(p_runs_on_ref), runs_on_type(0), block(p_block), - is_startable(false), transparent(false) + runs_on_ref(p_runs_on_ref), runs_on_type(0), block(p_block), + is_startable(false), transparent(false) { if (!p_block) FATAL_ERROR("Def_Function::Def_Function()"); block->set_my_def(this); @@ -5891,7 +5881,7 @@ namespace Ttcn { is_startable = runs_on_ref != 0; if (is_startable && !fp_list->get_startability()) is_startable = false; if (is_startable && return_type && return_type->is_component_internal()) - is_startable = false; + is_startable = false; // checking of statement block block->chk(); if (return_type) { @@ -5899,13 +5889,13 @@ namespace Ttcn { switch (block->has_return()) { case StatementBlock::RS_NO: error("The function has return type, but it does not have any return " - "statement"); + "statement"); break; case StatementBlock::RS_MAYBE: - error("The function has return type, but control might leave it " - "without reaching a return statement"); + error("The function has return type, but control might leave it " + "without reaching a return statement"); default: - break; + break; } } if (!semantic_check_only) { @@ -6002,7 +5992,7 @@ namespace Ttcn { // function prototype target->header.function_prototypes = mputprintf(target->header.function_prototypes, "extern %s %s(%s);\n", - return_type_str, genname_str, formal_par_list); + return_type_str, genname_str, formal_par_list); // function body char *body = mprintf("%s %s(%s)\n" @@ -6020,107 +6010,107 @@ namespace Ttcn { if (is_startable) { size_t nof_fps = fp_list->get_nof_fps(); // starter function (stub) - // function prototype - target->header.function_prototypes = - mputprintf(target->header.function_prototypes, - "extern void start_%s(const COMPONENT& component_reference%s%s);\n", - genname_str, nof_fps>0?", ":"", formal_par_list); - // function body - body = mprintf("void start_%s(const COMPONENT& component_reference%s" - "%s)\n" - "{\n" - "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n" - "TTCN_Logger::log_event_str(\"Starting function %s(\");\n", - genname_str, nof_fps>0?", ":"", formal_par_list, dispname_str); - for (size_t i = 0; i < nof_fps; i++) { - if (i > 0) body = mputstr(body, + // function prototype + target->header.function_prototypes = + mputprintf(target->header.function_prototypes, + "extern void start_%s(const COMPONENT& component_reference%s%s);\n", + genname_str, nof_fps>0?", ":"", formal_par_list); + // function body + body = mprintf("void start_%s(const COMPONENT& component_reference%s" + "%s)\n" + "{\n" + "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n" + "TTCN_Logger::log_event_str(\"Starting function %s(\");\n", + genname_str, nof_fps>0?", ":"", formal_par_list, dispname_str); + for (size_t i = 0; i < nof_fps; i++) { + if (i > 0) body = mputstr(body, "TTCN_Logger::log_event_str(\", \");\n"); - body = mputprintf(body, "%s.log();\n", - fp_list->get_fp_byIndex(i)->get_reference_name(my_scope).c_str()); - } - body = mputprintf(body, - "TTCN_Logger::log_event_str(\") on component \");\n" - "component_reference.log();\n" - "TTCN_Logger::log_char('.');\n" - "TTCN_Logger::end_event();\n" - "Text_Buf text_buf;\n" - "TTCN_Runtime::prepare_start_component(component_reference, " - "\"%s\", \"%s\", text_buf);\n", - my_scope->get_scope_mod()->get_modid().get_dispname().c_str(), - dispname_str); - for (size_t i = 0; i < nof_fps; i++) { - body = mputprintf(body, "%s.encode_text(text_buf);\n", - fp_list->get_fp_byIndex(i)->get_reference_name(my_scope).c_str()); - } - body = mputstr(body, "TTCN_Runtime::send_start_component(text_buf);\n" - "}\n\n"); - target->source.function_bodies = mputstr(target->source.function_bodies, - body); - Free(body); + body = mputprintf(body, "%s.log();\n", + fp_list->get_fp_byIndex(i)->get_reference_name(my_scope).c_str()); + } + body = mputprintf(body, + "TTCN_Logger::log_event_str(\") on component \");\n" + "component_reference.log();\n" + "TTCN_Logger::log_char('.');\n" + "TTCN_Logger::end_event();\n" + "Text_Buf text_buf;\n" + "TTCN_Runtime::prepare_start_component(component_reference, " + "\"%s\", \"%s\", text_buf);\n", + my_scope->get_scope_mod()->get_modid().get_dispname().c_str(), + dispname_str); + for (size_t i = 0; i < nof_fps; i++) { + body = mputprintf(body, "%s.encode_text(text_buf);\n", + fp_list->get_fp_byIndex(i)->get_reference_name(my_scope).c_str()); + } + body = mputstr(body, "TTCN_Runtime::send_start_component(text_buf);\n" + "}\n\n"); + target->source.function_bodies = mputstr(target->source.function_bodies, + body); + Free(body); // an entry in start_ptc_function body = mprintf("if (!strcmp(function_name, \"%s\")) {\n", - dispname_str); + dispname_str); if (nof_fps > 0) { - body = fp_list->generate_code_object(body, "", ' '); - for (size_t i = 0; i < nof_fps; i++) { - body = mputprintf(body, "%s.decode_text(function_arguments);\n", - fp_list->get_fp_byIndex(i)->get_reference_name(my_scope).c_str()); - } - body = mputprintf(body, - "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n" - "TTCN_Logger::log_event_str(\"Starting function %s(\");\n", - dispname_str); - for (size_t i = 0; i < nof_fps; i++) { - if (i > 0) body = mputstr(body, + body = fp_list->generate_code_object(body, "", ' '); + for (size_t i = 0; i < nof_fps; i++) { + body = mputprintf(body, "%s.decode_text(function_arguments);\n", + fp_list->get_fp_byIndex(i)->get_reference_name(my_scope).c_str()); + } + body = mputprintf(body, + "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n" + "TTCN_Logger::log_event_str(\"Starting function %s(\");\n", + dispname_str); + for (size_t i = 0; i < nof_fps; i++) { + if (i > 0) body = mputstr(body, "TTCN_Logger::log_event_str(\", \");\n"); - body = mputprintf(body, "%s.log();\n", - fp_list->get_fp_byIndex(i)->get_reference_name(my_scope).c_str()); - } - body = mputstr(body, "TTCN_Logger::log_event_str(\").\");\n" - "TTCN_Logger::end_event();\n"); + body = mputprintf(body, "%s.log();\n", + fp_list->get_fp_byIndex(i)->get_reference_name(my_scope).c_str()); + } + body = mputstr(body, "TTCN_Logger::log_event_str(\").\");\n" + "TTCN_Logger::end_event();\n"); } else { - body = mputprintf(body, - "TTCN_Logger::log_str(TTCN_Logger::PARALLEL_PTC, \"Starting function " + body = mputprintf(body, + "TTCN_Logger::log_str(TTCN_Logger::PARALLEL_PTC, \"Starting function " "%s().\");\n", dispname_str); } body = mputstr(body, - "TTCN_Runtime::function_started(function_arguments);\n"); + "TTCN_Runtime::function_started(function_arguments);\n"); char *actual_par_list = - fp_list->generate_code_actual_parlist(memptystr(), ""); + fp_list->generate_code_actual_parlist(memptystr(), ""); bool return_value_kept = false; if (asstype == A_FUNCTION_RVAL) { - // the return value is kept only if the function returns a value - // (rather than a template) and the return type has the "done" - // extension attribute - for (Type *t = return_type; ; t = t->get_type_refd()) { - if (t->has_done_attribute()) { - return_value_kept = true; - break; - } else if (!t->is_ref()) break; - } + // the return value is kept only if the function returns a value + // (rather than a template) and the return type has the "done" + // extension attribute + for (Type *t = return_type; ; t = t->get_type_refd()) { + if (t->has_done_attribute()) { + return_value_kept = true; + break; + } else if (!t->is_ref()) break; + } } if (return_value_kept) { - const string& return_type_dispname = return_type->get_typename(); - const char *return_type_dispname_str = return_type_dispname.c_str(); - body = mputprintf(body, "%s ret_val(%s(%s));\n" - "TTCN_Logger::begin_event(TTCN_PARALLEL);\n" - "TTCN_Logger::log_event_str(\"Function %s returned %s : \");\n" - "ret_val.log();\n" - "Text_Buf text_buf;\n" - "TTCN_Runtime::prepare_function_finished(\"%s\", text_buf);\n" - "ret_val.encode_text(text_buf);\n" - "TTCN_Runtime::send_function_finished(text_buf);\n", - return_type_str, genname_str, actual_par_list, dispname_str, - return_type_dispname_str, return_type_dispname_str); + const string& return_type_dispname = return_type->get_typename(); + const char *return_type_dispname_str = return_type_dispname.c_str(); + body = mputprintf(body, "%s ret_val(%s(%s));\n" + "TTCN_Logger::begin_event(TTCN_PARALLEL);\n" + "TTCN_Logger::log_event_str(\"Function %s returned %s : \");\n" + "ret_val.log();\n" + "Text_Buf text_buf;\n" + "TTCN_Runtime::prepare_function_finished(\"%s\", text_buf);\n" + "ret_val.encode_text(text_buf);\n" + "TTCN_Runtime::send_function_finished(text_buf);\n", + return_type_str, genname_str, actual_par_list, dispname_str, + return_type_dispname_str, return_type_dispname_str); } else { - body = mputprintf(body, "%s(%s);\n" - "TTCN_Runtime::function_finished(\"%s\");\n", - genname_str, actual_par_list, dispname_str); + body = mputprintf(body, "%s(%s);\n" + "TTCN_Runtime::function_finished(\"%s\");\n", + genname_str, actual_par_list, dispname_str); } Free(actual_par_list); body = mputstr(body, "return TRUE;\n" - "} else "); + "} else "); target->functions.start = mputstr(target->functions.start, body); Free(body); } @@ -6225,20 +6215,20 @@ namespace Ttcn { switch (function_type) { case EXTFUNC_MANUAL: if (eb_list) { - eb_list->error("Attribute `errorbehavior' can only be used together " - "with `encode' or `decode'"); - eb_list->chk(); + eb_list->error("Attribute `errorbehavior' can only be used together " + "with `encode' or `decode'"); + eb_list->chk(); } break; case EXTFUNC_ENCODE: switch (prototype) { case PROTOTYPE_NONE: - error("Attribute `encode' cannot be used without `prototype'"); - break; + error("Attribute `encode' cannot be used without `prototype'"); + break; case PROTOTYPE_BACKTRACK: case PROTOTYPE_SLIDING: - error("Attribute `encode' cannot be used with `prototype(%s)'", - get_prototype_name()); + error("Attribute `encode' cannot be used with `prototype(%s)'", + get_prototype_name()); default: /* CONVERT and FAST allowed */ break; } @@ -6256,34 +6246,59 @@ namespace Ttcn { } } if (output_type) { - Type *stream_type = Type::get_stream_type(encoding_type); - if (!stream_type->is_identical(output_type)) { - output_type->error("The output type of %s encoding should be `%s' " - "instead of `%s'", Type::get_encoding_name(encoding_type), - stream_type->get_typename().c_str(), - output_type->get_typename().c_str()); - } + if(encoding_type == Common::Type::CT_TEXT){ // the TEXT encoding support both octetstring ans charstring stream type + Type *stream_type = Type::get_stream_type(encoding_type,0); + Type *stream_type2 = Type::get_stream_type(encoding_type,1); + if ( (!stream_type->is_identical(output_type)) && (!stream_type2->is_identical(output_type)) ) { + input_type->error("The output type of %s encoding should be `%s' or `%s' " + "instead of `%s'", Type::get_encoding_name(encoding_type), + stream_type->get_typename().c_str(), + stream_type2->get_typename().c_str(), + input_type->get_typename().c_str()); + } + } else { + Type *stream_type = Type::get_stream_type(encoding_type); + if (!stream_type->is_identical(output_type)) { + input_type->error("The output type of %s encoding should be `%s' " + "instead of `%s'", Type::get_encoding_name(encoding_type), + stream_type->get_typename().c_str(), + input_type->get_typename().c_str()); + } + } } if (eb_list) eb_list->chk(); chk_allowed_encode(); break; case EXTFUNC_DECODE: if (prototype == PROTOTYPE_NONE) { - error("Attribute `decode' cannot be used without `prototype'"); + error("Attribute `decode' cannot be used without `prototype'"); } if (input_type) { - Type *stream_type = Type::get_stream_type(encoding_type); - if (!stream_type->is_identical(input_type)) { - input_type->error("The input type of %s encoding should be `%s' " - "instead of `%s'", Type::get_encoding_name(encoding_type), - stream_type->get_typename().c_str(), - input_type->get_typename().c_str()); - } + if(encoding_type == Common::Type::CT_TEXT){ // the TEXT encoding support both octetstring ans charstring stream type + Type *stream_type = Type::get_stream_type(encoding_type,0); + Type *stream_type2 = Type::get_stream_type(encoding_type,1); + if ( (!stream_type->is_identical(input_type)) && (!stream_type2->is_identical(input_type)) ) { + input_type->error("The input type of %s encoding should be `%s' or `%s' " + "instead of `%s'", Type::get_encoding_name(encoding_type), + stream_type->get_typename().c_str(), + stream_type2->get_typename().c_str(), + input_type->get_typename().c_str()); + } + } else { + Type *stream_type = Type::get_stream_type(encoding_type); + if (!stream_type->is_identical(input_type)) { + input_type->error("The input type of %s encoding should be `%s' " + "instead of `%s'", Type::get_encoding_name(encoding_type), + stream_type->get_typename().c_str(), + input_type->get_typename().c_str()); + } + } + } if (output_type && !output_type->has_encoding(encoding_type)) { - output_type->error("Output type `%s' does not support %s encoding", - output_type->get_typename().c_str(), - Type::get_encoding_name(encoding_type)); + output_type->error("Output type `%s' does not support %s encoding", + output_type->get_typename().c_str(), + Type::get_encoding_name(encoding_type)); } if (eb_list) eb_list->chk(); chk_allowed_encode(); @@ -6334,7 +6349,7 @@ namespace Ttcn { Error_Context cntxt2(return_type, "In return type"); return_type->chk(); return_type->chk_as_return_type(asstype == A_EXT_FUNCTION_RVAL, - "external function"); + "external function"); } if (!semantic_check_only) fp_list->set_genname(get_genname()); if (w_attrib_path) { @@ -6477,7 +6492,7 @@ namespace Ttcn { result_name = "ret_val"; // creating a local variable for the result stream str = mputprintf(str, "%s ret_val;\n", - output_type->get_genname_value(my_scope).c_str()); + output_type->get_genname_value(my_scope).c_str()); break; case PROTOTYPE_FAST: result_name = fp_list->get_fp_byIndex(1)->get_id().get_name().c_str(); @@ -6522,7 +6537,7 @@ namespace Ttcn { // setting error behavior if (eb_list) str = eb_list->generate_code(str); else if (prototype == PROTOTYPE_BACKTRACK || prototype == PROTOTYPE_SLIDING) { - str = mputstr(str, "TTCN_EncDec::set_error_behavior(" + str = mputstr(str, "TTCN_EncDec::set_error_behavior(" "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);\n"); } else str = mputstr(str, "TTCN_EncDec::set_error_behavior(" "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);\n"); @@ -6533,7 +6548,7 @@ namespace Ttcn { if (prototype == PROTOTYPE_CONVERT) { // creating a local variable for the result str = mputprintf(str, "%s ret_val;\n", - output_type->get_genname_value(my_scope).c_str()); + output_type->get_genname_value(my_scope).c_str()); result_name = "ret_val"; } else { result_name = fp_list->get_fp_byIndex(1)->get_id().get_name().c_str(); @@ -6562,47 +6577,47 @@ namespace Ttcn { if (prototype != PROTOTYPE_SLIDING) { // checking for remaining data in the buffer if decoding was successful str = mputprintf(str, "if (TTCN_EncDec::get_last_error_type() == " - "TTCN_EncDec::ET_NONE) {\n" - "if (ttcn_buffer.get_pos() < ttcn_buffer.get_len()-1 && " - "TTCN_Logger::log_this_event(TTCN_WARNING)) {\n" - "ttcn_buffer.cut();\n" - "%s remaining_stream;\n" - "ttcn_buffer.get_string(remaining_stream);\n" - "TTCN_Logger::begin_event(TTCN_WARNING);\n" - "TTCN_Logger::log_event_str(\"%s(): Warning: Data remained at the end " - "of the stream after successful decoding: \");\n" - "remaining_stream.log();\n" - "TTCN_Logger::end_event();\n" - "}\n", input_type->get_genname_value(my_scope).c_str(), function_name); + "TTCN_EncDec::ET_NONE) {\n" + "if (ttcn_buffer.get_pos() < ttcn_buffer.get_len()-1 && " + "TTCN_Logger::log_this_event(TTCN_WARNING)) {\n" + "ttcn_buffer.cut();\n" + "%s remaining_stream;\n" + "ttcn_buffer.get_string(remaining_stream);\n" + "TTCN_Logger::begin_event(TTCN_WARNING);\n" + "TTCN_Logger::log_event_str(\"%s(): Warning: Data remained at the end " + "of the stream after successful decoding: \");\n" + "remaining_stream.log();\n" + "TTCN_Logger::end_event();\n" + "}\n", input_type->get_genname_value(my_scope).c_str(), function_name); // closing the block and returning the appropriate result or status code if (prototype == PROTOTYPE_BACKTRACK) { - str = mputstr(str, "return 0;\n" - "} else return 1;\n"); + str = mputstr(str, "return 0;\n" + "} else return 1;\n"); } else { - str = mputstr(str, "}\n"); - if (prototype == PROTOTYPE_CONVERT) + str = mputstr(str, "}\n"); + if (prototype == PROTOTYPE_CONVERT) str = mputstr(str, "return ret_val;\n"); } } else { // result handling and debug printout for sliding decoders str = mputprintf(str, "switch (TTCN_EncDec::get_last_error_type()) {\n" - "case TTCN_EncDec::ET_NONE:\n" - // TTCN_Buffer::get_string will call OCTETSTRING::clean_up() - "ttcn_buffer.cut();\n" - "ttcn_buffer.get_string(%s);\n" - "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n" - "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n" - "TTCN_Logger::log_event_str(\"%s(): Stream after decoding: \");\n" - "%s.log();\n" - "TTCN_Logger::end_event();\n" - "}\n" - "return 0;\n" + "case TTCN_EncDec::ET_NONE:\n" + // TTCN_Buffer::get_string will call OCTETSTRING::clean_up() + "ttcn_buffer.cut();\n" + "ttcn_buffer.get_string(%s);\n" + "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n" + "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n" + "TTCN_Logger::log_event_str(\"%s(): Stream after decoding: \");\n" + "%s.log();\n" + "TTCN_Logger::end_event();\n" + "}\n" + "return 0;\n" "case TTCN_EncDec::ET_INCOMPL_MSG:\n" - "case TTCN_EncDec::ET_LEN_ERR:\n" - "return 2;\n" - "default:\n" - "return 1;\n" - "}\n", first_par_name, function_name, first_par_name); + "case TTCN_EncDec::ET_LEN_ERR:\n" + "return 2;\n" + "default:\n" + "return 1;\n" + "}\n", first_par_name, function_name, first_par_name); } return str; } @@ -6631,7 +6646,7 @@ namespace Ttcn { // function prototype target->header.function_prototypes = mputprintf(target->header.function_prototypes, "extern %s %s(%s);\n", - return_type_str, genname_str, formal_par_list); + return_type_str, genname_str, formal_par_list); if (function_type != EXTFUNC_MANUAL) { // function body written by the compiler @@ -6641,22 +6656,22 @@ namespace Ttcn { , __FUNCTION__, __LINE__); #endif body = mputprintf(body, - "%s %s(%s)\n" - "{\n" - , return_type_str, genname_str, formal_par_list); + "%s %s(%s)\n" + "{\n" + , return_type_str, genname_str, formal_par_list); switch (function_type) { case EXTFUNC_ENCODE: body = generate_code_encode(body); - break; + break; case EXTFUNC_DECODE: body = generate_code_decode(body); - break; + break; default: FATAL_ERROR("Def_ExtFunction::generate_code()"); } body = mputstr(body, "}\n\n"); target->source.function_bodies = mputstr(target->source.function_bodies, - body); + body); Free(body); } @@ -6685,11 +6700,11 @@ namespace Ttcn { DEBUG(level + 1, "Prototype: %s", get_prototype_name()); if (function_type != EXTFUNC_MANUAL) { DEBUG(level + 1, "Automatically generated: %s", - function_type == EXTFUNC_ENCODE ? "encoder" : "decoder"); + function_type == EXTFUNC_ENCODE ? "encoder" : "decoder"); DEBUG(level + 2, "Encoding type: %s", - Type::get_encoding_name(encoding_type)); + Type::get_encoding_name(encoding_type)); if (encoding_options) - DEBUG(level + 2, "Encoding options: %s", encoding_options->c_str()); + DEBUG(level + 2, "Encoding options: %s", encoding_options->c_str()); } if (eb_list) eb_list->dump(level + 1); } @@ -6925,7 +6940,7 @@ namespace Ttcn { // function for altstep instance: prototype target->header.function_prototypes = mputprintf(target->header.function_prototypes, - "extern alt_status %s_instance(%s);\n", genname_str, formal_par_list); + "extern alt_status %s_instance(%s);\n", genname_str, formal_par_list); // function for altstep instance: body char *str = mprintf("alt_status %s_instance(%s)\n" @@ -6945,34 +6960,34 @@ namespace Ttcn { // wrapper function for stand-alone instantiation: prototype target->header.function_prototypes = mputprintf(target->header.function_prototypes, - "extern void %s(%s);\n", genname_str, formal_par_list); + "extern void %s(%s);\n", genname_str, formal_par_list); // wrapper function for stand-alone instantiation: body target->source.function_bodies = mputprintf(target->source.function_bodies, "void %s(%s)\n" - "{\n" - "altstep_begin:\n" - "boolean block_flag = FALSE;\n" - "alt_status altstep_flag = ALT_UNCHECKED, " - "default_flag = ALT_UNCHECKED;\n" - "for ( ; ; ) {\n" - "TTCN_Snapshot::take_new(block_flag);\n" - "if (altstep_flag != ALT_NO) {\n" - "altstep_flag = %s_instance(%s);\n" - "if (altstep_flag == ALT_YES || altstep_flag == ALT_BREAK) return;\n" - "else if (altstep_flag == ALT_REPEAT) goto altstep_begin;\n" - "}\n" - "if (default_flag != ALT_NO) {\n" - "default_flag = TTCN_Default::try_altsteps();\n" - "if (default_flag == ALT_YES || default_flag == ALT_BREAK) return;\n" - "else if (default_flag == ALT_REPEAT) goto altstep_begin;\n" - "}\n" - "if (altstep_flag == ALT_NO && default_flag == ALT_NO) " - "TTCN_error(\"None of the branches can be chosen in altstep %s.\");\n" - "else block_flag = TRUE;\n" - "}\n" - "}\n\n", genname_str, formal_par_list, genname_str, actual_par_list, - dispname_str); + "{\n" + "altstep_begin:\n" + "boolean block_flag = FALSE;\n" + "alt_status altstep_flag = ALT_UNCHECKED, " + "default_flag = ALT_UNCHECKED;\n" + "for ( ; ; ) {\n" + "TTCN_Snapshot::take_new(block_flag);\n" + "if (altstep_flag != ALT_NO) {\n" + "altstep_flag = %s_instance(%s);\n" + "if (altstep_flag == ALT_YES || altstep_flag == ALT_BREAK) return;\n" + "else if (altstep_flag == ALT_REPEAT) goto altstep_begin;\n" + "}\n" + "if (default_flag != ALT_NO) {\n" + "default_flag = TTCN_Default::try_altsteps();\n" + "if (default_flag == ALT_YES || default_flag == ALT_BREAK) return;\n" + "else if (default_flag == ALT_REPEAT) goto altstep_begin;\n" + "}\n" + "if (altstep_flag == ALT_NO && default_flag == ALT_NO) " + "TTCN_error(\"None of the branches can be chosen in altstep %s.\");\n" + "else block_flag = TRUE;\n" + "}\n" + "}\n\n", genname_str, formal_par_list, genname_str, actual_par_list, + dispname_str); // class for keeping the altstep in the default context // the class is for internal use, we do not need to publish it in the @@ -6987,11 +7002,11 @@ namespace Ttcn { Free(str); // member functions of the class str = mprintf("%s_Default::%s_Default(%s)\n" - " : Default_Base(\"%s\")", genname_str, genname_str, formal_par_list, - dispname_str); + " : Default_Base(\"%s\")", genname_str, genname_str, formal_par_list, + dispname_str); for (size_t i = 0; i < fp_list->get_nof_fps(); i++) { const char *fp_name_str = - fp_list->get_fp_byIndex(i)->get_id().get_name().c_str(); + fp_list->get_fp_byIndex(i)->get_id().get_name().c_str(); str = mputprintf(str, ", par_%s(%s)", fp_name_str, fp_name_str); } str = mputstr(str, "\n{\n}\n\n"); @@ -7008,8 +7023,8 @@ namespace Ttcn { // function for default activation: prototype target->header.function_prototypes = mputprintf(target->header.function_prototypes, - "extern Default_Base *activate_%s(%s);\n", genname_str, - formal_par_list); + "extern Default_Base *activate_%s(%s);\n", genname_str, + formal_par_list); // function for default activation: body str = mprintf("Default_Base *activate_%s(%s)\n" @@ -7025,7 +7040,7 @@ namespace Ttcn { target->functions.pre_init = mputprintf(target->functions.pre_init, "%s.add_altstep(\"%s\", (genericfunc_t)&%s_instance, (genericfunc_t )&activate_%s, " - "(genericfunc_t )&%s);\n", get_module_object_name(), dispname_str, genname_str, + "(genericfunc_t )&%s);\n", get_module_object_name(), dispname_str, genname_str, genname_str, genname_str); } @@ -7179,7 +7194,7 @@ namespace Ttcn { // function prototype target->header.function_prototypes = mputprintf(target->header.function_prototypes, - "extern verdicttype testcase_%s(%s);\n", genname_str, formal_par_list); + "extern verdicttype testcase_%s(%s);\n", genname_str, formal_par_list); // function body char *body = mprintf("verdicttype testcase_%s(%s)\n" @@ -7189,7 +7204,7 @@ namespace Ttcn { // At this point the location information should refer to the execute() // statement rather than this testcase. body = mputstr(body, "TTCN_Runtime::check_begin_testcase(has_timer, " - "timer_value);\n"); + "timer_value);\n"); body = create_location_object(body, "TESTCASE", dispname_str); body = fp_list->generate_shadow_objects(body); body = mputprintf(body, "try {\n" @@ -7218,8 +7233,8 @@ namespace Ttcn { if (fp_list->get_nof_fps() == 0) { // adding to the list of startable testcases target->functions.pre_init = mputprintf(target->functions.pre_init, - "%s.add_testcase_nonpard(\"%s\", testcase_%s);\n", - get_module_object_name(), dispname_str, genname_str); + "%s.add_testcase_nonpard(\"%s\", testcase_%s);\n", + get_module_object_name(), dispname_str, genname_str); } else { target->functions.pre_init = mputprintf(target->functions.pre_init, "%s.add_testcase_pard(\"%s\", (genericfunc_t)&testcase_%s);\n", @@ -7441,36 +7456,36 @@ namespace Ttcn { switch (t->get_typetype()) { case Type::T_PORT: switch (asstype) { - case A_PAR_VAL: - case A_PAR_VAL_INOUT: - asstype = A_PAR_PORT; - break; - default: - error("Port type `%s' cannot be used as %s", - t->get_fullname().c_str(), get_assname()); - } - break; + case A_PAR_VAL: + case A_PAR_VAL_INOUT: + asstype = A_PAR_PORT; + break; + default: + error("Port type `%s' cannot be used as %s", + t->get_fullname().c_str(), get_assname()); + } + break; case Type::T_SIGNATURE: switch (asstype) { - case A_PAR_TEMPL_IN: - case A_PAR_TEMPL_OUT: - case A_PAR_TEMPL_INOUT: - break; - default: - error("Signature `%s' cannot be used as %s", - t->get_fullname().c_str(), get_assname()); - } - break; + case A_PAR_TEMPL_IN: + case A_PAR_TEMPL_OUT: + case A_PAR_TEMPL_INOUT: + break; + default: + error("Signature `%s' cannot be used as %s", + t->get_fullname().c_str(), get_assname()); + } + break; default: switch (asstype) { - case A_PAR_PORT: - case A_PAR_TIMER: - FATAL_ERROR("FormalPar::chk()"); - case A_PAR_VAL: - asstype = A_PAR_VAL_IN; - default: + case A_PAR_PORT: + case A_PAR_TIMER: + FATAL_ERROR("FormalPar::chk()"); + case A_PAR_VAL: + asstype = A_PAR_VAL_IN; + default: break; - } + } } } else if (asstype != A_PAR_TIMER) FATAL_ERROR("FormalPar::chk()"); @@ -7479,7 +7494,7 @@ namespace Ttcn { defval.ap = chk_actual_par(default_value, Type::EXPECTED_STATIC_VALUE); delete default_value; if (!semantic_check_only) - defval.ap->set_code_section(GovernedSimple::CS_POST_INIT); + defval.ap->set_code_section(GovernedSimple::CS_POST_INIT); } } @@ -7583,7 +7598,7 @@ namespace Ttcn { return new ActualPar(v); } else { actual_par->error("A specific value without matching symbols " - "was expected for a %s", get_assname()); + "was expected for a %s", get_assname()); return new ActualPar(); } } @@ -7785,13 +7800,13 @@ namespace Ttcn { Type *ap_type = actual_par->get_Type(); if (ap_type) { ap_type->warning("Explicit type specification is useless for an %s", - get_assname()); + get_assname()); actual_par->chk_Type(type); } Ref_base *derived_ref = actual_par->get_DerivedRef(); if (derived_ref) { derived_ref->error("An in-line modified template cannot be used as %s", - get_assname()); + get_assname()); actual_par->chk_DerivedRef(type); } // needed for the error messages @@ -7803,59 +7818,59 @@ namespace Ttcn { Ref_base *ref = ap_template->get_Ref(); Common::Assignment *ass = ref->get_refd_assignment(); if (!ass) { - delete ref; - return new ActualPar(); + delete ref; + return new ActualPar(); } bool asstype_correct = false; switch (ass->get_asstype()) { case A_PAR_VAL_IN: - ass->use_as_lvalue(*ref); - if (get_asstype() == A_PAR_VAL_OUT || get_asstype() == A_PAR_TEMPL_OUT) { - ass->warning("Passing an `in' parameter as another function's `out' parameter"); - } - // no break + ass->use_as_lvalue(*ref); + if (get_asstype() == A_PAR_VAL_OUT || get_asstype() == A_PAR_TEMPL_OUT) { + ass->warning("Passing an `in' parameter as another function's `out' parameter"); + } + // no break case A_VAR: case A_PAR_VAL_OUT: case A_PAR_VAL_INOUT: if (!is_template) asstype_correct = true; - break; + break; case A_PAR_TEMPL_IN: - ass->use_as_lvalue(*ref); - if (get_asstype() == A_PAR_VAL_OUT || get_asstype() == A_PAR_TEMPL_OUT) { - ass->warning("Passing an `in' parameter as another function's `out' parameter"); - } - // no break + ass->use_as_lvalue(*ref); + if (get_asstype() == A_PAR_VAL_OUT || get_asstype() == A_PAR_TEMPL_OUT) { + ass->warning("Passing an `in' parameter as another function's `out' parameter"); + } + // no break case A_VAR_TEMPLATE: case A_PAR_TEMPL_OUT: case A_PAR_TEMPL_INOUT: if (is_template) asstype_correct = true; - break; + break; default: - break; + break; } if (asstype_correct) { - FieldOrArrayRefs *t_subrefs = ref->get_subrefs(); - Type *ref_type = ass->get_Type()->get_field_type(t_subrefs, exp_val); - if (ref_type) { - if (!type->is_identical(ref_type)) { - ref->error("Type mismatch: Reference to a %s of type " - "`%s' was expected instead of `%s'", expected_string, - type->get_typename().c_str(), ref_type->get_typename().c_str()); - } else if (type->get_sub_type() && ref_type->get_sub_type() && + FieldOrArrayRefs *t_subrefs = ref->get_subrefs(); + Type *ref_type = ass->get_Type()->get_field_type(t_subrefs, exp_val); + if (ref_type) { + if (!type->is_identical(ref_type)) { + ref->error("Type mismatch: Reference to a %s of type " + "`%s' was expected instead of `%s'", expected_string, + type->get_typename().c_str(), ref_type->get_typename().c_str()); + } else if (type->get_sub_type() && ref_type->get_sub_type() && (type->get_sub_type()->get_subtypetype()==ref_type->get_sub_type()->get_subtypetype()) && (!type->get_sub_type()->is_compatible(ref_type->get_sub_type()))) { ref->error("Subtype mismatch: subtype %s has no common value with subtype %s", type->get_sub_type()->to_string().c_str(), ref_type->get_sub_type()->to_string().c_str()); } - if (t_subrefs && t_subrefs->refers_to_string_element()) { - ref->error("Reference to a string element of type `%s' cannot be " - "used in this context", ref_type->get_typename().c_str()); - } - } + if (t_subrefs && t_subrefs->refers_to_string_element()) { + ref->error("Reference to a string element of type `%s' cannot be " + "used in this context", ref_type->get_typename().c_str()); + } + } } else { ref->error("Reference to a %s was expected for an %s instead of %s", - expected_string, get_assname(), ass->get_description().c_str()); + expected_string, get_assname(), ass->get_description().c_str()); } ActualPar* ret_val_ap = new ActualPar(ref); // restriction checking if this is a reference to a template variable @@ -7938,24 +7953,24 @@ namespace Ttcn { Ref_base *ref = ap_template->get_Ref(); Common::Assignment *ass = ref->get_refd_assignment(); if (!ass) { - delete ref; - return new ActualPar(); + delete ref; + return new ActualPar(); } switch (ass->get_asstype()) { case A_TIMER: { ArrayDimensions *dims = ass->get_Dimensions(); - if (dims) dims->chk_indices(ref, "timer", false, exp_val); - else if (ref->get_subrefs()) ref->error("Reference to single %s " - "cannot have field or array sub-references", - ass->get_description().c_str()); - break; } + if (dims) dims->chk_indices(ref, "timer", false, exp_val); + else if (ref->get_subrefs()) ref->error("Reference to single %s " + "cannot have field or array sub-references", + ass->get_description().c_str()); + break; } case A_PAR_TIMER: if (ref->get_subrefs()) ref->error("Reference to %s cannot have " - "field or array sub-references", ass->get_description().c_str()); - break; + "field or array sub-references", ass->get_description().c_str()); + break; default: ref->error("Reference to a timer or timer parameter was expected for " - "a timer parameter instead of %s", ass->get_description().c_str()); + "a timer parameter instead of %s", ass->get_description().c_str()); } return new ActualPar(ref); } else { @@ -7985,34 +8000,34 @@ namespace Ttcn { Ref_base *ref = ap_template->get_Ref(); Common::Assignment *ass = ref->get_refd_assignment(); if (!ass) { - delete ref; - return new ActualPar(); + delete ref; + return new ActualPar(); } bool asstype_correct = false; switch (ass->get_asstype()) { case A_PORT: { ArrayDimensions *dims = ass->get_Dimensions(); - if (dims) dims->chk_indices(ref, "port", false, exp_val); - else if (ref->get_subrefs()) ref->error("Reference to single %s " - "cannot have field or array sub-references", - ass->get_description().c_str()); + if (dims) dims->chk_indices(ref, "port", false, exp_val); + else if (ref->get_subrefs()) ref->error("Reference to single %s " + "cannot have field or array sub-references", + ass->get_description().c_str()); asstype_correct = true; - break; } + break; } case A_PAR_PORT: if (ref->get_subrefs()) ref->error("Reference to %s cannot have " - "field or array sub-references", ass->get_description().c_str()); + "field or array sub-references", ass->get_description().c_str()); asstype_correct = true; - break; + break; default: ref->error("Reference to a port or port parameter was expected for a " - "port parameter instead of %s", ass->get_description().c_str()); + "port parameter instead of %s", ass->get_description().c_str()); } if (asstype_correct) { - Type *ref_type = ass->get_Type(); - if (ref_type && !type->is_identical(ref_type)) - ref->error("Type mismatch: Reference to a port or port parameter " - "of type `%s' was expected instead of `%s'", - type->get_typename().c_str(), ref_type->get_typename().c_str()); + Type *ref_type = ass->get_Type(); + if (ref_type && !type->is_identical(ref_type)) + ref->error("Type mismatch: Reference to a port or port parameter " + "of type `%s' was expected instead of `%s'", + type->get_typename().c_str(), ref_type->get_typename().c_str()); } return new ActualPar(ref); } else { @@ -8035,15 +8050,15 @@ namespace Ttcn { Definition *my_def = my_parlist->get_my_def(); if (!my_def) FATAL_ERROR("FormalPar::use_as_lvalue()"); if (my_def->get_asstype() == A_TEMPLATE) - p_loc.error("Parameter `%s' of the template cannot be passed further " - "as `out' or `inout' parameter", id->get_dispname().c_str()); + p_loc.error("Parameter `%s' of the template cannot be passed further " + "as `out' or `inout' parameter", id->get_dispname().c_str()); else { - // update the genname so that all references in the generated code - // will point to the shadow object + // update the genname so that all references in the generated code + // will point to the shadow object if (!lazy_eval) { - set_genname(id->get_name() + "_shadow"); + set_genname(id->get_name() + "_shadow"); } - used_as_lvalue = true; + used_as_lvalue = true; } } } @@ -8122,7 +8137,7 @@ namespace Ttcn { case A_PAR_VAL_INOUT: case A_PAR_PORT: str = mputprintf(str, "%s& %s", type->get_genname_value(my_scope).c_str(), - name_str); + name_str); break; case A_PAR_TEMPL_IN: if (lazy_eval) { @@ -8134,7 +8149,7 @@ namespace Ttcn { case A_PAR_TEMPL_OUT: case A_PAR_TEMPL_INOUT: str = mputprintf(str, "%s& %s", - type->get_genname_template(my_scope).c_str(), name_str); + type->get_genname_template(my_scope).c_str(), name_str); break; case A_PAR_TIMER: str = mputprintf(str, "TIMER& %s", name_str); @@ -8182,7 +8197,7 @@ namespace Ttcn { case A_PAR_VAL_INOUT: case A_PAR_PORT: str = mputprintf(str, "%s%c %s%s;\n", - type->get_genname_value(my_scope).c_str(), refch, p_prefix, name_str); + type->get_genname_value(my_scope).c_str(), refch, p_prefix, name_str); break; case A_PAR_TEMPL_IN: if (lazy_eval) { @@ -8194,7 +8209,7 @@ namespace Ttcn { case A_PAR_TEMPL_OUT: case A_PAR_TEMPL_INOUT: str = mputprintf(str, "%s%c %s%s;\n", - type->get_genname_template(my_scope).c_str(), refch, p_prefix, name_str); + type->get_genname_template(my_scope).c_str(), refch, p_prefix, name_str); break; case A_PAR_TIMER: str = mputprintf(str, "TIMER& %s%s;\n", p_prefix, name_str); @@ -8213,15 +8228,15 @@ namespace Ttcn { const char *name_str = id->get_name().c_str(); switch (asstype) { case A_PAR_VAL_IN: - str = mputprintf(str, "%s %s(%s);\n", - type->get_genname_value(my_scope).c_str(), genname_str, name_str); - break; + str = mputprintf(str, "%s %s(%s);\n", + type->get_genname_value(my_scope).c_str(), genname_str, name_str); + break; case A_PAR_TEMPL_IN: - str = mputprintf(str, "%s %s(%s);\n", - type->get_genname_template(my_scope).c_str(), genname_str, name_str); - break; + str = mputprintf(str, "%s %s(%s);\n", + type->get_genname_template(my_scope).c_str(), genname_str, name_str); + break; default: - FATAL_ERROR("FormalPar::generate_shadow_object()"); + FATAL_ERROR("FormalPar::generate_shadow_object()"); } } return str; @@ -8362,27 +8377,27 @@ namespace Ttcn { FormalPar *par = pars_v[i]; const string& par_name = par->get_id().get_name(); if (par->get_asstype() != Definition::A_PAR_TIMER) - par->get_Type()->set_genname(p_prefix, par_name); + par->get_Type()->set_genname(p_prefix, par_name); if (par->has_defval()) { - string embedded_genname(p_prefix); - embedded_genname += '_'; - embedded_genname += par_name; - embedded_genname += "_defval"; + string embedded_genname(p_prefix); + embedded_genname += '_'; + embedded_genname += par_name; + embedded_genname += "_defval"; ActualPar *defval = par->get_defval(); switch (defval->get_selection()) { case ActualPar::AP_ERROR: case ActualPar::AP_REF: break; case ActualPar::AP_VALUE: { - Value *v = defval->get_Value(); + Value *v = defval->get_Value(); v->set_genname_prefix("const_"); - v->set_genname_recursive(embedded_genname); + v->set_genname_recursive(embedded_genname); break; } case ActualPar::AP_TEMPLATE: { - Template *t = defval->get_TemplateInstance()->get_Template(); - t->set_genname_prefix("template_"); - t->set_genname_recursive(embedded_genname); - break; } + Template *t = defval->get_TemplateInstance()->get_Template(); + t->set_genname_prefix("template_"); + t->set_genname_recursive(embedded_genname); + break; } default: FATAL_ERROR("FormalParList::set_genname()"); } @@ -8403,19 +8418,19 @@ namespace Ttcn { const string& name = id.get_name(); const char *dispname = id.get_dispname().c_str(); if (pars_m.has_key(name)) { - par->error("Duplicate parameter with name `%s'", dispname); - pars_m[name]->note("Previous definition of `%s' is here", dispname); + par->error("Duplicate parameter with name `%s'", dispname); + pars_m[name]->note("Previous definition of `%s' is here", dispname); } else { - pars_m.add(name, par); - if (parent_scope && parent_scope->has_ass_withId(id)) { - par->error("Parameter name `%s' is not unique in the scope " - "hierarchy", dispname); - Reference ref(0, id.clone()); - Common::Assignment *ass = parent_scope->get_ass_bySRef(&ref); - if (!ass) FATAL_ERROR("FormalParList::chk()"); - ass->note("Symbol `%s' is already defined here in a higher scope " - "unit", dispname); - } + pars_m.add(name, par); + if (parent_scope && parent_scope->has_ass_withId(id)) { + par->error("Parameter name `%s' is not unique in the scope " + "hierarchy", dispname); + Reference ref(0, id.clone()); + Common::Assignment *ass = parent_scope->get_ass_bySRef(&ref); + if (!ass) FATAL_ERROR("FormalParList::chk()"); + ass->note("Symbol `%s' is already defined here in a higher scope " + "unit", dispname); + } } Error_Context cntxt2(par, "In parameter `%s'", dispname); par->chk(); @@ -8423,23 +8438,23 @@ namespace Ttcn { switch (deftype) { case Definition::A_TEMPLATE: switch (par->get_asstype()) { - case Definition::A_PAR_VAL_IN: - case Definition::A_PAR_TEMPL_IN: - // these are allowed + case Definition::A_PAR_VAL_IN: + case Definition::A_PAR_TEMPL_IN: + // these are allowed break; - default: + default: par->error("A template cannot have %s", par->get_assname()); - } - break; + } + break; case Definition::A_TESTCASE: switch (par->get_asstype()) { - case Definition::A_PAR_TIMER: - case Definition::A_PAR_PORT: - // these are forbidden + case Definition::A_PAR_TIMER: + case Definition::A_PAR_PORT: + // these are forbidden par->error("A testcase cannot have %s", par->get_assname()); - default: + default: break; - } + } default: // everything is allowed for functions and altsteps break; @@ -8497,7 +8512,7 @@ namespace Ttcn { break; default: par->error("%s `%s' cannot be started on a parallel test component " - "because it has %s", p_what, p_name, par->get_description().c_str()); + "because it has %s", p_what, p_name, par->get_description().c_str()); } } } @@ -8510,8 +8525,8 @@ namespace Ttcn { // check for the number of parameters if (nof_type_pars != nof_function_pars) { p_fp_list->error("Too %s parameters: %lu was expected instead of %lu", - nof_type_pars < nof_function_pars ? "many" : "few", - (unsigned long) nof_type_pars, (unsigned long) nof_function_pars); + nof_type_pars < nof_function_pars ? "many" : "few", + (unsigned long) nof_type_pars, (unsigned long) nof_function_pars); } size_t upper_limit = nof_type_pars < nof_function_pars ? nof_type_pars : nof_function_pars; @@ -8525,21 +8540,21 @@ namespace Ttcn { // check for parameter kind equivalence // (in, out or inout / value or template) if (type_par_asstype != function_par_asstype) { - function_par->error("The kind of the parameter is not the same as in " - "type `%s': %s was expected instead of %s", where, - type_par->get_assname(), function_par->get_assname()); + function_par->error("The kind of the parameter is not the same as in " + "type `%s': %s was expected instead of %s", where, + type_par->get_assname(), function_par->get_assname()); } // check for type equivalence if (type_par_asstype != FormalPar::A_PAR_TIMER && - function_par_asstype != FormalPar::A_PAR_TIMER) { - Type *type_par_type = type_par->get_Type(); - Type *function_par_type = function_par->get_Type(); - if (!type_par_type->is_identical(function_par_type)) { - function_par_type->error("The type of the parameter is not the same " - "as in type `%s': `%s' was expected instead of `%s'", where, - type_par_type->get_typename().c_str(), - function_par_type->get_typename().c_str()); - } else if (type_par_type->get_sub_type() && function_par_type->get_sub_type() && + function_par_asstype != FormalPar::A_PAR_TIMER) { + Type *type_par_type = type_par->get_Type(); + Type *function_par_type = function_par->get_Type(); + if (!type_par_type->is_identical(function_par_type)) { + function_par_type->error("The type of the parameter is not the same " + "as in type `%s': `%s' was expected instead of `%s'", where, + type_par_type->get_typename().c_str(), + function_par_type->get_typename().c_str()); + } else if (type_par_type->get_sub_type() && function_par_type->get_sub_type() && (type_par_type->get_sub_type()->get_subtypetype()==function_par_type->get_sub_type()->get_subtypetype()) && (!type_par_type->get_sub_type()->is_compatible(function_par_type->get_sub_type()))) { // TODO: maybe equivalence should be checked, or maybe that is too strict @@ -8555,7 +8570,7 @@ namespace Ttcn { function_par->error("The template restriction of the parameter is " "not the same as in type `%s': %s restriction was expected instead " "of %s restriction", where, - type_par->get_template_restriction()==TR_NONE ? "no" : + type_par->get_template_restriction()==TR_NONE ? "no" : Template::get_restriction_name(type_par->get_template_restriction()), function_par->get_template_restriction()==TR_NONE ? "no" : Template::get_restriction_name(function_par-> @@ -8569,10 +8584,10 @@ namespace Ttcn { const Identifier& type_par_id = type_par->get_id(); const Identifier& function_par_id = function_par->get_id(); if (type_par_id != function_par_id) { - function_par->warning("The name of the parameter is not the same " - "as in type `%s': `%s' was expected instead of `%s'", where, - type_par_id.get_dispname().c_str(), - function_par_id.get_dispname().c_str()); + function_par->warning("The name of the parameter is not the same " + "as in type `%s': `%s' was expected instead of `%s'", where, + type_par_id.get_dispname().c_str(), + function_par_id.get_dispname().c_str()); } } } @@ -8600,82 +8615,82 @@ namespace Ttcn { // We are now responsible for np. if (has_fp_withName(*np->get_name())) { - // there is a formal parameter with that name - FormalPar *fp = get_fp_byName(*np->get_name()); - const size_t is_at = *formalpar_map[fp]; // the index of the formal par - if (is_at >= num_actual) { - // There is no actual par in the unnamed part. - // Create one from the named param. - - // First, pad the gap with '-' - for (; num_actual < is_at; ++num_actual) { - Template *not_used; - if (pars_v[num_actual]->has_defval()) { - not_used = new Template(Template::TEMPLATE_NOTUSED); - } - else { // cannot use '-' if no default value - not_used = new Template(Template::TEMPLATE_ERROR); - } - TemplateInstance *new_ti = new TemplateInstance(0, 0, not_used); - // Conjure a location info at the beginning of the unnamed part - // (that is, the beginning of the actual parameter list) - new_ti->set_location(p_paps->get_tis()->get_filename(), - p_paps->get_tis()->get_first_line(), - p_paps->get_tis()->get_first_column(), 0, 0); - p_paps->get_tis()->add_ti(new_ti); - } - TemplateInstance * namedti = np->extract_ti(); - p_paps->get_tis()->add_ti(namedti); - ++num_actual; - } else { - // There is already an actual par at that position, fetch it - TemplateInstance * ti = p_paps->get_tis()->get_ti_byIndex(is_at); - Template::templatetype_t tt = ti->get_Template()->get_templatetype(); - - if (is_at >= num_unnamed && !ti->get_Type() && !ti->get_DerivedRef() - && (tt == Template::TEMPLATE_NOTUSED || tt == Template::TEMPLATE_ERROR)) { - // NotUsed in the named part => padding - np->error("Named parameter `%s' out of order", - np->get_name()->get_dispname().c_str()); - } else { - // attempt to override an original unnamed param with a named one - np->error("Formal parameter `%s' assigned more than once", - np->get_name()->get_dispname().c_str()); - } - } + // there is a formal parameter with that name + FormalPar *fp = get_fp_byName(*np->get_name()); + const size_t is_at = *formalpar_map[fp]; // the index of the formal par + if (is_at >= num_actual) { + // There is no actual par in the unnamed part. + // Create one from the named param. + + // First, pad the gap with '-' + for (; num_actual < is_at; ++num_actual) { + Template *not_used; + if (pars_v[num_actual]->has_defval()) { + not_used = new Template(Template::TEMPLATE_NOTUSED); + } + else { // cannot use '-' if no default value + not_used = new Template(Template::TEMPLATE_ERROR); + } + TemplateInstance *new_ti = new TemplateInstance(0, 0, not_used); + // Conjure a location info at the beginning of the unnamed part + // (that is, the beginning of the actual parameter list) + new_ti->set_location(p_paps->get_tis()->get_filename(), + p_paps->get_tis()->get_first_line(), + p_paps->get_tis()->get_first_column(), 0, 0); + p_paps->get_tis()->add_ti(new_ti); + } + TemplateInstance * namedti = np->extract_ti(); + p_paps->get_tis()->add_ti(namedti); + ++num_actual; + } else { + // There is already an actual par at that position, fetch it + TemplateInstance * ti = p_paps->get_tis()->get_ti_byIndex(is_at); + Template::templatetype_t tt = ti->get_Template()->get_templatetype(); + + if (is_at >= num_unnamed && !ti->get_Type() && !ti->get_DerivedRef() + && (tt == Template::TEMPLATE_NOTUSED || tt == Template::TEMPLATE_ERROR)) { + // NotUsed in the named part => padding + np->error("Named parameter `%s' out of order", + np->get_name()->get_dispname().c_str()); + } else { + // attempt to override an original unnamed param with a named one + np->error("Formal parameter `%s' assigned more than once", + np->get_name()->get_dispname().c_str()); + } + } } else { // no formal parameter with that name - char * nam = 0; - switch (my_def->get_asstype()) { - case Common::Assignment::A_TYPE: { - Type *t = my_def->get_Type(); - - switch (t ? t->get_typetype() : 0) { - case Type::T_FUNCTION: - nam = mcopystr("Function reference"); - break; - case Type::T_ALTSTEP: - nam = mcopystr("Altstep reference"); - break; - case Type::T_TESTCASE: - nam = mcopystr("Testcase reference"); - break; - default: - FATAL_ERROR("FormalParList::chk_actual_parlist() " - "Unexpected type %s", t->get_typename().c_str()); - } // switch(typetype) - break; } - default: - nam = mcopystr(my_def->get_assname()); - break; - } // switch(asstype) - - *nam &= ~('a'-'A'); // Make the first letter uppercase - p_paps->get_tis()->error("%s `%s' has no formal parameter `%s'", - nam, - my_def->get_fullname().c_str(), - np->get_name()->get_dispname().c_str()); - Free(nam); + char * nam = 0; + switch (my_def->get_asstype()) { + case Common::Assignment::A_TYPE: { + Type *t = my_def->get_Type(); + + switch (t ? t->get_typetype() : 0) { + case Type::T_FUNCTION: + nam = mcopystr("Function reference"); + break; + case Type::T_ALTSTEP: + nam = mcopystr("Altstep reference"); + break; + case Type::T_TESTCASE: + nam = mcopystr("Testcase reference"); + break; + default: + FATAL_ERROR("FormalParList::chk_actual_parlist() " + "Unexpected type %s", t->get_typename().c_str()); + } // switch(typetype) + break; } + default: + nam = mcopystr(my_def->get_assname()); + break; + } // switch(asstype) + + *nam &= ~('a'-'A'); // Make the first letter uppercase + p_paps->get_tis()->error("%s `%s' has no formal parameter `%s'", + nam, + my_def->get_fullname().c_str(), + np->get_name()->get_dispname().c_str()); + Free(nam); } delete np; } @@ -8728,22 +8743,22 @@ namespace Ttcn { // the formal parameter for the current actual parameter FormalPar *fp = pars_v[i]; Error_Context cntxt(ti, "In parameter #%lu for `%s'", - (unsigned long) (i + 1), fp->get_id().get_dispname().c_str()); + (unsigned long) (i + 1), fp->get_id().get_dispname().c_str()); if (!ti->get_Type() && !ti->get_DerivedRef() && ti->get_Template() - ->get_templatetype() == Template::TEMPLATE_NOTUSED) { - if (fp->has_defval()) { - ActualPar *defval = fp->get_defval(); - p_aplist->add(new ActualPar(defval)); - if (defval->is_erroneous()) error_flag = true; - } else { - ti->error("Not used symbol (`-') cannot be used for parameter " - "that does not have default value"); - p_aplist->add(new ActualPar()); - error_flag = true; - } + ->get_templatetype() == Template::TEMPLATE_NOTUSED) { + if (fp->has_defval()) { + ActualPar *defval = fp->get_defval(); + p_aplist->add(new ActualPar(defval)); + if (defval->is_erroneous()) error_flag = true; + } else { + ti->error("Not used symbol (`-') cannot be used for parameter " + "that does not have default value"); + p_aplist->add(new ActualPar()); + error_flag = true; + } } else if (!ti->get_Type() && !ti->get_DerivedRef() && ti->get_Template() - ->get_templatetype() == Template::TEMPLATE_ERROR) { - ti->error("Parameter not specified"); + ->get_templatetype() == Template::TEMPLATE_ERROR) { + ti->error("Parameter not specified"); } else { ActualPar *ap = fp->chk_actual_par(ti, Type::EXPECTED_DYNAMIC_VALUE); p_aplist->add(ap); @@ -8757,7 +8772,7 @@ namespace Ttcn { for (size_t i = upper_limit; i < formal_pars; i++) { FormalPar *fp = pars_v[i]; if (fp->has_defval()) { - ActualPar *defval = fp->get_defval(); + ActualPar *defval = fp->get_defval(); p_aplist->add(new ActualPar(defval)); if (defval->is_erroneous()) error_flag = true; } else { @@ -8798,17 +8813,17 @@ namespace Ttcn { case Common::Assignment::A_VAR: case Common::Assignment::A_VAR_TEMPLATE: case Common::Assignment::A_TIMER: - // it is not allowed to pass references of local variables or timers - if (t_par_ass->is_local()) { - t_ref->error("Parameter #%lu of %s refers to %s, which is a local " - "definition within a statement block and may have shorter " - "lifespan than the activated default. Only references to " - "variables and timers defined in the component type can be passed " - "to activated defaults", (unsigned long) (i + 1), p_description, - t_par_ass->get_description().c_str()); - ret_val = false; - } - break; + // it is not allowed to pass references of local variables or timers + if (t_par_ass->is_local()) { + t_ref->error("Parameter #%lu of %s refers to %s, which is a local " + "definition within a statement block and may have shorter " + "lifespan than the activated default. Only references to " + "variables and timers defined in the component type can be passed " + "to activated defaults", (unsigned long) (i + 1), p_description, + t_par_ass->get_description().c_str()); + ret_val = false; + } + break; case Common::Assignment::A_PAR_VAL_IN: case Common::Assignment::A_PAR_VAL_OUT: case Common::Assignment::A_PAR_VAL_INOUT: @@ -8816,24 +8831,24 @@ namespace Ttcn { case Common::Assignment::A_PAR_TEMPL_OUT: case Common::Assignment::A_PAR_TEMPL_INOUT: case Common::Assignment::A_PAR_TIMER: { - // it is not allowed to pass references pointing to formal parameters - // except for activate() statements within testcases - // note: all defaults are deactivated at the end of the testcase - FormalPar *t_refd_fp = dynamic_cast(t_par_ass); - if (!t_refd_fp) FATAL_ERROR("FormalParList::chk_activate_argument()"); - FormalParList *t_fpl = t_refd_fp->get_my_parlist(); - if (!t_fpl || !t_fpl->my_def) - FATAL_ERROR("FormalParList::chk_activate_argument()"); - if (t_fpl->my_def->get_asstype() != Common::Assignment::A_TESTCASE) { + // it is not allowed to pass references pointing to formal parameters + // except for activate() statements within testcases + // note: all defaults are deactivated at the end of the testcase + FormalPar *t_refd_fp = dynamic_cast(t_par_ass); + if (!t_refd_fp) FATAL_ERROR("FormalParList::chk_activate_argument()"); + FormalParList *t_fpl = t_refd_fp->get_my_parlist(); + if (!t_fpl || !t_fpl->my_def) + FATAL_ERROR("FormalParList::chk_activate_argument()"); + if (t_fpl->my_def->get_asstype() != Common::Assignment::A_TESTCASE) { t_ref->error("Parameter #%lu of %s refers to %s, which may have " - "shorter lifespan than the activated default. Only references to " - "variables and timers defined in the component type can be passed " - "to activated defaults", (unsigned long) (i + 1), p_description, - t_par_ass->get_description().c_str()); + "shorter lifespan than the activated default. Only references to " + "variables and timers defined in the component type can be passed " + "to activated defaults", (unsigned long) (i + 1), p_description, + t_par_ass->get_description().c_str()); ret_val = false; - } } + } } default: - break; + break; } } return ret_val; @@ -9351,7 +9366,7 @@ namespace Ttcn { size_t nof_pars = params.size(); for(size_t i = 0; i < nof_pars; i++) params[i]->set_fullname(p_fullname + - "."); + "."); } void ActualParList::set_my_scope(Scope *p_scope) @@ -9385,24 +9400,24 @@ namespace Ttcn { for (size_t i = 0; i < nof_pars; i++) { ActualPar *par = params[i]; if (par->get_selection() == ActualPar::AP_DEFAULT) - par = par->get_ActualPar(); + par = par->get_ActualPar(); if (par->get_selection() == ActualPar::AP_REF) { - Common::Assignment *ass = par->get_Ref()->get_refd_assignment(); - switch (ass->get_asstype()) { - case Common::Assignment::A_VAR: - case Common::Assignment::A_PAR_VAL_IN: - case Common::Assignment::A_PAR_VAL_OUT: - case Common::Assignment::A_PAR_VAL_INOUT: - if (!value_refs.has_key(ass)) value_refs.add(ass, 0); - break; - case Common::Assignment::A_VAR_TEMPLATE: - case Common::Assignment::A_PAR_TEMPL_IN: - case Common::Assignment::A_PAR_TEMPL_OUT: - case Common::Assignment::A_PAR_TEMPL_INOUT: - if (!template_refs.has_key(ass)) template_refs.add(ass, 0); - default: - break; - } + Common::Assignment *ass = par->get_Ref()->get_refd_assignment(); + switch (ass->get_asstype()) { + case Common::Assignment::A_VAR: + case Common::Assignment::A_PAR_VAL_IN: + case Common::Assignment::A_PAR_VAL_OUT: + case Common::Assignment::A_PAR_VAL_INOUT: + if (!value_refs.has_key(ass)) value_refs.add(ass, 0); + break; + case Common::Assignment::A_VAR_TEMPLATE: + case Common::Assignment::A_PAR_TEMPL_IN: + case Common::Assignment::A_PAR_TEMPL_OUT: + case Common::Assignment::A_PAR_TEMPL_INOUT: + if (!template_refs.has_key(ass)) template_refs.add(ass, 0); + default: + break; + } } } // walk through the parameter list and generate the code @@ -9416,72 +9431,72 @@ namespace Ttcn { // the copy constructor call is not needed if the parameter is copied // into a shadow object in the body of the called function if (!p_fpl || !p_fpl->get_fp_byIndex(i)->get_used_as_lvalue()) { - switch (par->get_selection()) { - case ActualPar::AP_VALUE: { - Value *v = par->get_Value(); - if (v->get_valuetype() == Value::V_REFD) { - Common::Assignment *t_ass = - v->get_reference()->get_refd_assignment(); - if (value_refs.has_key(t_ass)) { - // a reference to the same variable is also passed to the called - // definition - copy_needed = true; - } else if (p_comptype || p_compself) { - // the called definition has a 'runs on' clause so it can access - // component variables - switch (t_ass->get_asstype()) { - case Common::Assignment::A_PAR_VAL_OUT: - case Common::Assignment::A_PAR_VAL_INOUT: - // the parameter may be an alias of a component variable - copy_needed = true; - break; - case Common::Assignment::A_VAR: - // copy is needed if t_ass is a component variable that is - // visible by the called definition - if (!t_ass->is_local()) copy_needed = true; - /** \todo component type compatibility: check whether t_ass is - * visible from p_comptype (otherwise copy is not needed) */ - default: - break; - } - } - } - break; } - case ActualPar::AP_TEMPLATE: { - TemplateInstance *ti = par->get_TemplateInstance(); - if (!ti->get_DerivedRef()) { - Template *t = ti->get_Template(); - if (t->get_templatetype() == Template::TEMPLATE_REFD) { - Common::Assignment *t_ass = - t->get_reference()->get_refd_assignment(); - if (template_refs.has_key(t_ass)) { - // a reference to the same variable is also passed to the called - // definition - copy_needed = true; - } else if (p_comptype || p_compself) { - // the called definition has a 'runs on' clause so it can access - // component variables - switch (t_ass->get_asstype()) { - case Common::Assignment::A_PAR_TEMPL_OUT: - case Common::Assignment::A_PAR_TEMPL_INOUT: - // the parameter may be an alias of a component variable - copy_needed = true; - break; - case Common::Assignment::A_VAR_TEMPLATE: - // copy is needed if t_ass is a component variable that is - // visible by the called definition - if (!t_ass->is_local()) copy_needed = true; - /** \todo component type compatibility: check whether t_ass is - * visible from p_comptype (otherwise copy is not needed) */ - default: - break; - } - } - } - } } - default: - break; - } + switch (par->get_selection()) { + case ActualPar::AP_VALUE: { + Value *v = par->get_Value(); + if (v->get_valuetype() == Value::V_REFD) { + Common::Assignment *t_ass = + v->get_reference()->get_refd_assignment(); + if (value_refs.has_key(t_ass)) { + // a reference to the same variable is also passed to the called + // definition + copy_needed = true; + } else if (p_comptype || p_compself) { + // the called definition has a 'runs on' clause so it can access + // component variables + switch (t_ass->get_asstype()) { + case Common::Assignment::A_PAR_VAL_OUT: + case Common::Assignment::A_PAR_VAL_INOUT: + // the parameter may be an alias of a component variable + copy_needed = true; + break; + case Common::Assignment::A_VAR: + // copy is needed if t_ass is a component variable that is + // visible by the called definition + if (!t_ass->is_local()) copy_needed = true; + /** \todo component type compatibility: check whether t_ass is + * visible from p_comptype (otherwise copy is not needed) */ + default: + break; + } + } + } + break; } + case ActualPar::AP_TEMPLATE: { + TemplateInstance *ti = par->get_TemplateInstance(); + if (!ti->get_DerivedRef()) { + Template *t = ti->get_Template(); + if (t->get_templatetype() == Template::TEMPLATE_REFD) { + Common::Assignment *t_ass = + t->get_reference()->get_refd_assignment(); + if (template_refs.has_key(t_ass)) { + // a reference to the same variable is also passed to the called + // definition + copy_needed = true; + } else if (p_comptype || p_compself) { + // the called definition has a 'runs on' clause so it can access + // component variables + switch (t_ass->get_asstype()) { + case Common::Assignment::A_PAR_TEMPL_OUT: + case Common::Assignment::A_PAR_TEMPL_INOUT: + // the parameter may be an alias of a component variable + copy_needed = true; + break; + case Common::Assignment::A_VAR_TEMPLATE: + // copy is needed if t_ass is a component variable that is + // visible by the called definition + if (!t_ass->is_local()) copy_needed = true; + /** \todo component type compatibility: check whether t_ass is + * visible from p_comptype (otherwise copy is not needed) */ + default: + break; + } + } + } + } } + default: + break; + } } if (use_runtime_2 && ActualPar::AP_REF == par->get_selection()) { @@ -9521,13 +9536,12 @@ namespace Ttcn { } // let the array object know that the index is referenced before // calling the function, and let it know that it's now longer - // referenced after the function call + // referenced after the function call (this is done with the help + // of the RefdIndexHandler's constructor and destructor) + string tmp_id = ref->get_my_scope()->get_scope_mod_gen()->get_temporary_id(); expr->preamble = mputprintf(expr->preamble, - "%s.add_refd_index(%s);\n", - array_expr.expr, index_expr.expr); - expr->postamble = mputprintf(expr->postamble, - "%s.remove_refd_index(%s);\n", - array_expr.expr, index_expr.expr); + "RefdIndexHandler %s(&%s, %s);\n", + tmp_id.c_str(), array_expr.expr, index_expr.expr); // insert any postambles the array object or the index might have if (array_expr.postamble != NULL) { expr->preamble = mputstr(expr->preamble, array_expr.postamble); diff --git a/compiler2/ttcn3/Makefile b/compiler2/ttcn3/Makefile index fecfc9d..cdac827 100644 --- a/compiler2/ttcn3/Makefile +++ b/compiler2/ttcn3/Makefile @@ -38,7 +38,7 @@ GENERATED_OTHERS := compiler.output rawAST.output coding_attrib_p.output lex.bac STATIC_SOURCES := ArrayDimensions.cc AST_ttcn3.cc Attributes.cc ILT.cc PatternString.cc \ RawAST.cc Statement.cc TtcnTemplate.cc Templatestuff.cc TextAST.cc Ttcnstuff.cc \ -compiler.c port.c signature.c BerAST.cc JsonAST.cc Ttcn2Json.cc +compiler.c port.c signature.c BerAST.cc JsonAST.cc Ttcn2Json.cc profiler.c SOURCES := $(STATIC_SOURCES) $(GENERATED_SOURCES) diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 2a452a9..02d28a6 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -468,6 +468,8 @@ namespace Ttcn { case S_CONTINUE: case S_STOP_EXEC: case S_REPEAT: + case S_START_PROFILER: + case S_STOP_PROFILER: break; case S_START_UNDEF: case S_STOP_UNDEF: @@ -689,6 +691,8 @@ namespace Ttcn { ags=0; case S_ERROR: case S_STOP_EXEC: + case S_START_PROFILER: + case S_STOP_PROFILER: break; case S_BREAK: case S_CONTINUE: @@ -1451,6 +1455,8 @@ namespace Ttcn { case S_TESTCASE_INSTANCE_REFD: return "execute"; case S_STRING2TTCN: return "string2ttcn"; + case S_START_PROFILER: return "@profiler.start"; + case S_STOP_PROFILER: return "@profiler.stop"; default: FATAL_ERROR("Statement::get_stmt_name()"); return ""; @@ -1529,6 +1535,8 @@ namespace Ttcn { case S_CONTINUE: case S_STOP_EXEC: case S_REPEAT: + case S_START_PROFILER: + case S_STOP_PROFILER: break; case S_START_UNDEF: case S_STOP_UNDEF: @@ -1756,6 +1764,8 @@ namespace Ttcn { case S_CONTINUE: case S_STOP_EXEC: case S_REPEAT: + case S_START_PROFILER: + case S_STOP_PROFILER: break; case S_START_UNDEF: case S_STOP_UNDEF: @@ -2256,6 +2266,8 @@ namespace Ttcn { case S_SETVERDICT: case S_TESTCASE_INSTANCE: case S_TESTCASE_INSTANCE_REFD: + case S_START_PROFILER: + case S_STOP_PROFILER: return false; case S_ALT: case S_INTERLEAVE: @@ -2496,6 +2508,10 @@ namespace Ttcn { case S_STRING2TTCN: chk_string2ttcn(); break; + case S_START_PROFILER: + case S_STOP_PROFILER: + // do nothing + break; default: FATAL_ERROR("Statement::chk()"); } // switch statementtype @@ -5079,6 +5095,8 @@ error: case S_CONTINUE: case S_STOP_EXEC: case S_REPEAT: + case S_START_PROFILER: + case S_STOP_PROFILER: break; case S_ASSIGNMENT: ass->set_code_section(p_code_section); @@ -5467,6 +5485,12 @@ error: case S_STRING2TTCN: str=generate_code_string2ttcn(str); break; + case S_START_PROFILER: + str = mputstr(str, "ttcn3_prof.start();\n"); + break; + case S_STOP_PROFILER: + str = mputstr(str, "ttcn3_prof.stop();\n"); + break; default: FATAL_ERROR("Statement::generate_code()"); } // switch @@ -7124,6 +7148,8 @@ error: case S_FUNCTION_INVOKED: case S_ALTSTEP_INVOKED: case S_STRING2TTCN: + case S_START_PROFILER: + case S_STOP_PROFILER: break; default: FATAL_ERROR("Statement::set_parent_path()"); @@ -9086,22 +9112,32 @@ error: for(size_t i=0; iget_nof_tis(); i++) { TemplateInstance *ti=tis->get_ti_byIndex(i); Template *tb=ti->get_Template(); - bool specval = tb->is_Value(); + bool is_value = NULL == ti->get_DerivedRef() && tb->is_Value(); expression_struct exprs; Code::init_expr(&exprs); - if (!specval) ti->generate_code(&exprs); - else if (tb->get_templatetype() == Template::SPECIFIC_VALUE) { - tb->get_specific_value()->generate_code_expr_mandatory(&exprs); + if (is_value) { + if (tb->get_templatetype() == Template::SPECIFIC_VALUE) { + tb->get_specific_value()->generate_code_expr_mandatory(&exprs); + } + else { + Value* val = tb->get_Value(); + if (NULL == val->get_my_governor()) { + // the value's governor could not be determined, treat it as a non-value template + is_value = false; + } + else { + val->generate_code_expr_mandatory(&exprs); + } + delete val; + } } - else { - Value* val = tb->get_Value(); - val->generate_code_expr_mandatory(&exprs); - delete val; + if (!is_value) { + ti->generate_code(&exprs); } str=tb->update_location_object(str); if(!exprs.preamble && !exprs.postamble) { str=mputstr(str, "if("); - if(!specval) + if(!is_value) str=mputprintf(str, "%s.match(%s)", exprs.expr, expr_name); else str=mputprintf(str, "%s == %s", expr_name, exprs.expr); str=mputprintf(str, ") goto %s_%lu;\n", tmp_prefix, @@ -9113,7 +9149,7 @@ error: (unsigned long) idx); char *s=exprs.expr; exprs.expr=mprintf("%s_%lub = ", tmp_prefix, (unsigned long) idx); - if(!specval) + if(!is_value) exprs.expr=mputprintf(exprs.expr, "%s.match(%s)", s, expr_name); else exprs.expr=mputprintf(exprs.expr, "(%s == %s)", expr_name, s); Free(s); diff --git a/compiler2/ttcn3/Statement.hh b/compiler2/ttcn3/Statement.hh index 1c1aa6c..7abce56 100644 --- a/compiler2/ttcn3/Statement.hh +++ b/compiler2/ttcn3/Statement.hh @@ -235,7 +235,10 @@ namespace Ttcn { /* control statement */ S_TESTCASE_INSTANCE, // testcase_inst S_TESTCASE_INSTANCE_REFD, //execute_refd - S_STRING2TTCN // str2ttcn + S_STRING2TTCN, // str2ttcn + /* TTCN-3 Profiler statements */ + S_START_PROFILER, + S_STOP_PROFILER }; enum component_t { @@ -437,8 +440,8 @@ namespace Ttcn { Statement& operator=(const Statement& p); ///< assignment disabled void clean_up(); public: - /** Constructor used by S_ERROR, S_STOP_EXEC and S_REPEAT, S_BREAK and - * S_CONTINUE */ + /** Constructor used by S_ERROR, S_STOP_EXEC and S_REPEAT, S_BREAK, + * S_CONTINUE, S_START_PROFILER and S_STOP_PROFILER */ Statement(statementtype_t p_st); /** Constructor used by S_START_UNDEF and S_STOP_UNDEF */ Statement(statementtype_t p_st, Ref_base *p_ref, Value *p_val); diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc index bf646c6..03f6d5e 100644 --- a/compiler2/ttcn3/TtcnTemplate.cc +++ b/compiler2/ttcn3/TtcnTemplate.cc @@ -1964,6 +1964,21 @@ end: // Cannot flatten at compile time if the template has parameters. can_flatten = false; } + + // check for subreferences in the 'all from' target + FieldOrArrayRefs* subrefs = ref->get_subrefs(); + if (NULL != subrefs) { + // flattening values/templates with subreferences is not implemented yet + can_flatten = false; + for (size_t i = 0; i < subrefs->get_nof_refs(); ++i) { + FieldOrArrayRef* subref = subrefs->get_ref(i); + if (FieldOrArrayRef::ARRAY_REF == subref->get_type()) { + // set any array indexes from undefined lowerID to reference + subref->get_val()->set_lowerid_to_ref(); + } + } + } + Common::Assignment *ass = ref->get_refd_assignment(); if (ass == NULL) { // perhaps erroneous break; @@ -2073,11 +2088,18 @@ end: switch (val->get_valuetype()) { case Common::Value::V_SEQOF: case Common::Value::V_SETOF: case Common::Value::V_ARRAY: { - const size_t ncomp = val->get_nof_comps(); - for (size_t i = 0; i < ncomp; ++i) { - Value *v = val->get_comp_byIndex(i); - Template *newt = new Template(v->clone()); - new_templates->add_t(newt); + if (can_flatten) { + const size_t ncomp = val->get_nof_comps(); + for (size_t i = 0; i < ncomp; ++i) { + Value *v = val->get_comp_byIndex(i); + Template *newt = new Template(v->clone()); + new_templates->add_t(newt); + } + } + else { + delete new_templates; + new_templates = 0; + killer = false; } break; } @@ -2095,7 +2117,9 @@ end: case Common::Assignment::A_MODULEPAR: // all from a module parameter case Common::Assignment::A_VAR: // all from a variable case Common::Assignment::A_PAR_VAL_IN: - case Common::Assignment::A_PAR_VAL_INOUT: { + case Common::Assignment::A_PAR_VAL_INOUT: + case Common::Assignment::A_FUNCTION_RVAL: + case Common::Assignment::A_EXT_FUNCTION_RVAL: { delete new_templates; // cannot flatten at compile time new_templates = 0; break; } @@ -3232,7 +3256,6 @@ end: // variable part for (size_t i = 0; i < nof_ts; i++) { Template *t = u.templates->get_t_byIndex(i); - printf("generate_code_init_seof ALL_FROM: temptype %u\n", t->templatetype); for (size_t k = 0, v = variables.size(); k < v; ++k) { if (t->templatetype == ALL_FROM) { Value *refv = t->u.all_from->u.specific_value; diff --git a/compiler2/ttcn3/compiler.c b/compiler2/ttcn3/compiler.c index ce428ba..b9cb1af 100644 --- a/compiler2/ttcn3/compiler.c +++ b/compiler2/ttcn3/compiler.c @@ -21,6 +21,7 @@ #include "compiler.h" #include "../main.hh" #include "../error.h" +#include "profiler.h" #ifdef LICENSE #include "../../common/license.h" @@ -310,10 +311,6 @@ void write_output(output_struct *output, const char *module_name, COPYRIGHT_STRING "\n\n" "// Do not edit this file unless you know what you are doing.\n", is_ttcn ? "TTCN-3" : "ASN.1", user_info); - - if (profiler_enabled) { - output->source.includes = mputstr(output->source.includes, "#include \"Profiler.hh\"\n"); - } if (output->source.includes != NULL) { fputs("\n/* Including header files */\n\n", fp); diff --git a/compiler2/ttcn3/compiler.l b/compiler2/ttcn3/compiler.l index 3746fb3..4497b6c 100644 --- a/compiler2/ttcn3/compiler.l +++ b/compiler2/ttcn3/compiler.l @@ -504,6 +504,7 @@ xor4b RETURN(Xor4bKeyword); "@try" RETURN(TitanSpecificTryKeyword); "@catch" RETURN(TitanSpecificCatchKeyword); "@lazy" RETURN(TitanSpecificLazyKeyword); +"@profiler" RETURN(TitanSpecificProfilerKeyword); /* Predefined function identifiers */ diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index dc5a760..5f07d02 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -706,6 +706,7 @@ static const string anyname("anytype"); %token TitanSpecificTryKeyword %token TitanSpecificCatchKeyword %token TitanSpecificLazyKeyword +%token TitanSpecificProfilerKeyword /* Keywords combined with a leading dot */ @@ -900,7 +901,7 @@ static const string anyname("anytype"); StartTimerStatement StopExecutionStatement StopStatement StopTCStatement StopTimerStatement TimeoutStatement TimerStatements TriggerStatement UnmapStatement VerdictStatements WhileStatement SelectCaseConstruct - StopTestcaseStatement String2TtcnStatement + StopTestcaseStatement String2TtcnStatement ProfilerStatement %type StatementBlock optElseClause FunctionStatementOrDefList ControlStatementOrDefList ModuleControlBody %type ValueOrRange @@ -940,7 +941,7 @@ static const string anyname("anytype"); PredefinedValue ReadTimerOp ReferOp ReferencedValue RunningOp RunningTimerOp SelfOp SingleExpression SingleLowerBound SystemOp TemplateOps TimerOps TimerValue UpperBound Value ValueofOp VerdictOps VerdictValue optReplyValue - optTestcaseTimerValue optToClause + optTestcaseTimerValue optToClause ProfilerRunningOp %type ArrayElementExpressionList seqArrayExpressionSpec %type VariableList %type VariableEntry @@ -1204,6 +1205,8 @@ PortType PredefOrIdentifier PredefinedOps PredefinedValue +ProfilerRunningOp +ProfilerStatement RaiseStatement Range ReadTimerOp @@ -1711,12 +1714,12 @@ optRunsOnComprefOrSelf %left '*' '/' ModKeyword RemKeyword %left UnarySign -%expect 24 +%expect 25 %start GrammarRoot /* -XXX Source of conflicts (24 S/R): +XXX Source of conflicts (25 S/R): 1.) 8 conflicts in one state The Expression after 'return' keyword is optional in ReturnStatement. @@ -1754,9 +1757,14 @@ non-standard language extension. 6.) 1 Conflict due to pattern concatenation +7.) 1 conflict +The TitanSpecificProfilerKeyword following the ReturnKeyword in a ReturnStatement +can either be the returned boolean value if followed by the DotRunningKeyword (shift) +or the next statement if followed by the DotStartKeyword or the DotStopKeyword (reduce). + Note that the parser implemented by bison always chooses to shift instead of reduce in case of conflicts. This is the desired behaviour in situations 1.), -2.) and 4.) since the opposite alternative can be forced by the correct usage +2.), 4.) and 7.) since the opposite alternative can be forced by the correct usage of semi-colons. Situation 3.) does not cause any problems as anytype is not supported at the moment. */ @@ -3910,6 +3918,7 @@ FunctionStatement: // 180 | SUTStatements {$$=$1;} | StopExecutionStatement { $$ = $1; } | StopTestcaseStatement { $$ = $1; } +| ProfilerStatement { $$ = $1; } ; FunctionInstance: /* refpard */ // 181 @@ -5078,6 +5087,7 @@ ControlStatement: /* Statement *stmt */ // 295 | BehaviourStatements { $$ = $1; } | SUTStatements { $$ = $1; } | StopExecutionStatement { $$ = $1; } +| ProfilerStatement { $$ = $1; } ; /* A.1.6.2.1 Variable instantiation */ @@ -7538,6 +7548,26 @@ StopTestcaseStatement: } ; + /* these deliberately don't have their locations set */ +ProfilerStatement: + TitanSpecificProfilerKeyword DotStartKeyword + { + $$ = new Statement(Statement::S_START_PROFILER); + } +| TitanSpecificProfilerKeyword DotStopKeyword + { + $$ = new Statement(Statement::S_STOP_PROFILER); + } +; + +ProfilerRunningOp: + TitanSpecificProfilerKeyword DotRunningKeyword + { + $$ = new Value(Value::OPTYPE_PROF_RUNNING); + $$->set_location(infile, @$); + } +; + ReturnStatement: // 552 ReturnKeyword { @@ -8336,6 +8366,7 @@ OpCall: // 611 else $$ = new Value(Value::V_ERROR); $$->set_location(infile, @$); } +| ProfilerRunningOp { $$ = $1; } ; PredefinedOps: diff --git a/compiler2/ttcn3/profiler.c b/compiler2/ttcn3/profiler.c new file mode 100644 index 0000000..4c09a3e --- /dev/null +++ b/compiler2/ttcn3/profiler.c @@ -0,0 +1,126 @@ +/****************************************************************************** + * Copyright (c) 2000-2015 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ + +#include "profiler.h" +#include "../../common/memory.h" +#include +#include + +/** The file list */ +static tcov_file_list *the_files = 0; + +/** The database */ +static profiler_data_t *the_data = 0; + +/** The current database index for the next get_profiler_code_line() call */ +static int current_index = 0; + +/** The file parameter for the last get_profiler_code_line() call */ +static char* last_file_name = 0; + +void init_profiler_data(tcov_file_list* p_file_list) +{ + the_files = p_file_list; + the_data = (profiler_data_t*)Malloc(sizeof(profiler_data_t)); + the_data->nof_lines = 0; + the_data->size = 4; + the_data->lines = (profiler_code_line_t*)Malloc( + the_data->size * sizeof(profiler_code_line_t)); +} + +boolean is_file_profiled(const char* p_file_name) +{ + tcov_file_list* file_walker = the_files; + while (0 != file_walker) { + if (0 == strcmp(p_file_name, file_walker->file_name)) { + return TRUE; + } + /* check for .ttcnpp instead of .ttcn */ + size_t file_name_len = strlen(file_walker->file_name); + if ('p' == file_walker->file_name[file_name_len - 1] && + 'p' == file_walker->file_name[file_name_len - 2] && + 0 == strncmp(p_file_name, file_walker->file_name, file_name_len - 2)) { + return TRUE; + } + file_walker = file_walker->next; + } + return FALSE; +} + +void insert_profiler_code_line(const char* p_file_name, + const char* p_function_name, int p_line_no) +{ + /* check if the entry already exists */ + int i; + for (i = 0; i < the_data->nof_lines; ++i) { + if (0 == strcmp(p_file_name,the_data->lines[i].file_name) && + p_line_no == the_data->lines[i].line_no) { + if (0 == the_data->lines[i].function_name && 0 != p_function_name) { + the_data->lines[i].function_name = mcopystr(p_function_name); + } + return; + } + } + if (the_data->nof_lines == the_data->size) { + /* database size reached, increase the buffer size (exponentially) */ + the_data->size *= 2; + the_data->lines = (profiler_code_line_t*)Realloc(the_data->lines, + the_data->size * sizeof(profiler_code_line_t)); + } + the_data->lines[the_data->nof_lines].file_name = mcopystr(p_file_name); + if (0 != p_function_name) { + the_data->lines[the_data->nof_lines].function_name = mcopystr(p_function_name); + } + else { + the_data->lines[the_data->nof_lines].function_name = 0; + } + the_data->lines[the_data->nof_lines].line_no = p_line_no; + ++the_data->nof_lines; +} + +boolean get_profiler_code_line(const char *p_file_name, + char **p_function_name, int *p_line_no) +{ + if (0 == last_file_name || 0 != strcmp(last_file_name, p_file_name)) { + /* file parameter changed, reset the current index and store the new file name */ + current_index = 0; + Free(last_file_name); + last_file_name = mcopystr(p_file_name); + } + while (current_index < the_data->nof_lines) { + /* find the first entry in the specified file and return it */ + if (0 == strcmp(p_file_name, the_data->lines[current_index].file_name)) { + *p_function_name = the_data->lines[current_index].function_name; + *p_line_no = the_data->lines[current_index].line_no; + ++current_index; + return TRUE; + } + ++current_index; + } + /* no entry found with the specified file name */ + return FALSE; +} + +void free_profiler_data() +{ + int i; + for (i = 0; i < the_data->nof_lines; ++i) { + Free(the_data->lines[i].file_name); + Free(the_data->lines[i].function_name); + } + Free(the_data->lines); + Free(the_data); + Free(last_file_name); + + while (0 != the_files) { + tcov_file_list *next_file = the_files->next; + Free(the_files->file_name); + Free(the_files); + the_files = next_file; + } +} diff --git a/compiler2/ttcn3/profiler.h b/compiler2/ttcn3/profiler.h new file mode 100644 index 0000000..ab00ccc --- /dev/null +++ b/compiler2/ttcn3/profiler.h @@ -0,0 +1,74 @@ +/****************************************************************************** + * Copyright (c) 2000-2015 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ + +#ifndef PROFILER_H +#define PROFILER_H + +#include "../main.hh" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Structure containing one code line or function for the profiler */ +typedef struct profiler_code_line_t { + /** Name of the file containing this line */ + char* file_name; + /** Name of the function that starts at this line (or null if no function starts here) */ + char* function_name; + /** Code line number */ + int line_no; +} profiler_code_line_t; + +/** Profiler database + * + * Contains entries for the code lines in the processed TTCN-3 files. + * Used for initializing the TTCN3_Profiler (in runtime) with all the code + * lines and functions in the processed files, so it can determine which the + * unused lines and functions. */ +typedef struct profiler_data_t { + profiler_code_line_t *lines; + int nof_lines; + int size; +} profiler_data_t; + +/** Initializes the database (must be called once, at the start of compilation) */ +void init_profiler_data(tcov_file_list* p_file_list); + +/** Returns 1 if the specified file is in the profiler's file list, + * otherwise returns 0.*/ +boolean is_file_profiled(const char* p_file_name); + +/** Inserts one code line or function to the database + * @param p_file_name [in] name of the file containing the line/function + * @param p_function_name [in] name of the function (for functions) or null (for lines) + * @param p_line_no [in] line number (for lines) or the function's starting line + * (for functions) */ +void insert_profiler_code_line(const char* p_file_name, + const char* p_function_name, int p_line_no); + +/** Retrieves the next code line or function from the specified file. Calling this + * function with the same file parameter will keep returning the next code line + * or function until the end of the database is reached. If the file parameter is + * changed, the function will start again from the beginning of the database. + * @param p_file_name [in] name of the file to search for + * @param p_function_name [out] contains the function name if a function was found + * @param p_line_no [out] contains the line number of function start line + * @return 1 if a line or function was found, otherwise 0 */ +boolean get_profiler_code_line(const char *p_file_name, + char **p_function_name, int *p_line_no); + +/** Frees the database (must be called once, at the end of compilation) */ +void free_profiler_data(); + +#ifdef __cplusplus +} +#endif + +#endif /* PROFILER_H */ + diff --git a/core/ASN_CharacterString.cc b/core/ASN_CharacterString.cc index f4ae4a5..edbd97a 100644 --- a/core/ASN_CharacterString.cc +++ b/core/ASN_CharacterString.cc @@ -37,55 +37,55 @@ make the type descriptors of embedded types static static const ASN_Tag_t CHARACTER_STRING_identification_tag_[] = { { ASN_TAG_CONT, 0u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_identification_ber_ = { 1u, CHARACTER_STRING_identification_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_descr_ = { "CHARACTER STRING.identification", &CHARACTER_STRING_identification_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_descr_ = { "CHARACTER STRING.identification", &CHARACTER_STRING_identification_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t CHARACTER_STRING_identification_syntaxes_abstract_tag_[] = { { ASN_TAG_CONT, 0u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_identification_syntaxes_abstract_ber_ = { 1u, CHARACTER_STRING_identification_syntaxes_abstract_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_syntaxes_abstract_descr_ = { "CHARACTER STRING.identification.syntaxes.abstract", &CHARACTER_STRING_identification_syntaxes_abstract_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_syntaxes_abstract_descr_ = { "CHARACTER STRING.identification.syntaxes.abstract", &CHARACTER_STRING_identification_syntaxes_abstract_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; static const ASN_Tag_t CHARACTER_STRING_identification_syntaxes_transfer_tag_[] = { { ASN_TAG_CONT, 1u }}; const ASN_BERdescriptor_t CHARACTER_STRING_identification_syntaxes_transfer_ber_ = { 1u, CHARACTER_STRING_identification_syntaxes_transfer_tag_ }; -const TTCN_Typedescriptor_t CHARACTER_STRING_identification_syntaxes_transfer_descr_ = { "CHARACTER STRING.identification.syntaxes.transfer", &CHARACTER_STRING_identification_syntaxes_transfer_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; +const TTCN_Typedescriptor_t CHARACTER_STRING_identification_syntaxes_transfer_descr_ = { "CHARACTER STRING.identification.syntaxes.transfer", &CHARACTER_STRING_identification_syntaxes_transfer_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; static const ASN_Tag_t CHARACTER_STRING_identification_syntaxes_tag_[] = { { ASN_TAG_CONT, 0u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_identification_syntaxes_ber_ = { 1u, CHARACTER_STRING_identification_syntaxes_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_syntaxes_descr_ = { "CHARACTER STRING.identification.syntaxes", &CHARACTER_STRING_identification_syntaxes_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_syntaxes_descr_ = { "CHARACTER STRING.identification.syntaxes", &CHARACTER_STRING_identification_syntaxes_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t CHARACTER_STRING_identification_syntax_tag_[] = { { ASN_TAG_CONT, 1u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_identification_syntax_ber_ = { 1u, CHARACTER_STRING_identification_syntax_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_syntax_descr_ = { "CHARACTER STRING.identification.syntax", &CHARACTER_STRING_identification_syntax_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_syntax_descr_ = { "CHARACTER STRING.identification.syntax", &CHARACTER_STRING_identification_syntax_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; static const ASN_Tag_t CHARACTER_STRING_identification_presentation__context__id_tag_[] = { { ASN_TAG_CONT, 2u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_identification_presentation__context__id_ber_ = { 1u, CHARACTER_STRING_identification_presentation__context__id_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_presentation__context__id_descr_ = { "CHARACTER STRING.identification.presentation-context-id", &CHARACTER_STRING_identification_presentation__context__id_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_presentation__context__id_descr_ = { "CHARACTER STRING.identification.presentation-context-id", &CHARACTER_STRING_identification_presentation__context__id_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t CHARACTER_STRING_identification_context__negotiation_presentation__context__id_tag_[] = { { ASN_TAG_CONT, 0u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_identification_context__negotiation_presentation__context__id_ber_ = { 1u, CHARACTER_STRING_identification_context__negotiation_presentation__context__id_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_context__negotiation_presentation__context__id_descr_ = { "CHARACTER STRING.identification.context-negotiation.presentation-context-id", &CHARACTER_STRING_identification_context__negotiation_presentation__context__id_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_context__negotiation_presentation__context__id_descr_ = { "CHARACTER STRING.identification.context-negotiation.presentation-context-id", &CHARACTER_STRING_identification_context__negotiation_presentation__context__id_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t CHARACTER_STRING_identification_context__negotiation_transfer__syntax_tag_[] = { { ASN_TAG_CONT, 1u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_identification_context__negotiation_transfer__syntax_ber_ = { 1u, CHARACTER_STRING_identification_context__negotiation_transfer__syntax_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_context__negotiation_transfer__syntax_descr_ = { "CHARACTER STRING.identification.context-negotiation.transfer-syntax", &CHARACTER_STRING_identification_context__negotiation_transfer__syntax_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_context__negotiation_transfer__syntax_descr_ = { "CHARACTER STRING.identification.context-negotiation.transfer-syntax", &CHARACTER_STRING_identification_context__negotiation_transfer__syntax_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; static const ASN_Tag_t CHARACTER_STRING_identification_context__negotiation_tag_[] = { { ASN_TAG_CONT, 3u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_identification_context__negotiation_ber_ = { 1u, CHARACTER_STRING_identification_context__negotiation_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_context__negotiation_descr_ = { "CHARACTER STRING.identification.context-negotiation", &CHARACTER_STRING_identification_context__negotiation_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_context__negotiation_descr_ = { "CHARACTER STRING.identification.context-negotiation", &CHARACTER_STRING_identification_context__negotiation_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t CHARACTER_STRING_identification_transfer__syntax_tag_[] = { { ASN_TAG_CONT, 4u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_identification_transfer__syntax_ber_ = { 1u, CHARACTER_STRING_identification_transfer__syntax_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_transfer__syntax_descr_ = { "CHARACTER STRING.identification.transfer-syntax", &CHARACTER_STRING_identification_transfer__syntax_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_transfer__syntax_descr_ = { "CHARACTER STRING.identification.transfer-syntax", &CHARACTER_STRING_identification_transfer__syntax_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; static const ASN_Tag_t CHARACTER_STRING_identification_fixed_tag_[] = { { ASN_TAG_CONT, 5u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_identification_fixed_ber_ = { 1u, CHARACTER_STRING_identification_fixed_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_fixed_descr_ = { "CHARACTER STRING.identification.fixed", &CHARACTER_STRING_identification_fixed_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_identification_fixed_descr_ = { "CHARACTER STRING.identification.fixed", &CHARACTER_STRING_identification_fixed_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t CHARACTER_STRING_string__value_tag_[] = { { ASN_TAG_CONT, 2u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_string__value_ber_ = { 1u, CHARACTER_STRING_string__value_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_string__value_descr_ = { "CHARACTER STRING.string-value", &CHARACTER_STRING_string__value_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_string__value_descr_ = { "CHARACTER STRING.string-value", &CHARACTER_STRING_string__value_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t CHARACTER_STRING_data__value__descriptor_tag_[] = { { ASN_TAG_CONT, 1u }}; static const ASN_BERdescriptor_t CHARACTER_STRING_data__value__descriptor_ber_ = { 1u, CHARACTER_STRING_data__value__descriptor_tag_ }; -static const TTCN_Typedescriptor_t CHARACTER_STRING_data__value__descriptor_descr_ = { "CHARACTER STRING.data-value-descriptor", &CHARACTER_STRING_data__value__descriptor_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::GRAPHICSTRING }; +static const TTCN_Typedescriptor_t CHARACTER_STRING_data__value__descriptor_descr_ = { "CHARACTER STRING.data-value-descriptor", &CHARACTER_STRING_data__value__descriptor_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::GRAPHICSTRING }; void CHARACTER_STRING_identification::clean_up() { diff --git a/core/ASN_EmbeddedPDV.cc b/core/ASN_EmbeddedPDV.cc index 7a05319..11cfeed 100644 --- a/core/ASN_EmbeddedPDV.cc +++ b/core/ASN_EmbeddedPDV.cc @@ -37,55 +37,55 @@ make the type descriptors of embedded types static static const ASN_Tag_t EMBEDDED_PDV_identification_tag_[] = { { ASN_TAG_CONT, 0u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_ber_ = { 1u, EMBEDDED_PDV_identification_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_descr_ = { "EMBEDDED PDV.identification", &EMBEDDED_PDV_identification_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_descr_ = { "EMBEDDED PDV.identification", &EMBEDDED_PDV_identification_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t EMBEDDED_PDV_identification_syntaxes_abstract_tag_[] = { { ASN_TAG_CONT, 0u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_syntaxes_abstract_ber_ = { 1u, EMBEDDED_PDV_identification_syntaxes_abstract_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_syntaxes_abstract_descr_ = { "EMBEDDED PDV.identification.syntaxes.abstract", &EMBEDDED_PDV_identification_syntaxes_abstract_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_syntaxes_abstract_descr_ = { "EMBEDDED PDV.identification.syntaxes.abstract", &EMBEDDED_PDV_identification_syntaxes_abstract_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; static const ASN_Tag_t EMBEDDED_PDV_identification_syntaxes_transfer_tag_[] = { { ASN_TAG_CONT, 1u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_syntaxes_transfer_ber_ = { 1u, EMBEDDED_PDV_identification_syntaxes_transfer_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_syntaxes_transfer_descr_ = { "EMBEDDED PDV.identification.syntaxes.transfer", &EMBEDDED_PDV_identification_syntaxes_transfer_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_syntaxes_transfer_descr_ = { "EMBEDDED PDV.identification.syntaxes.transfer", &EMBEDDED_PDV_identification_syntaxes_transfer_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; static const ASN_Tag_t EMBEDDED_PDV_identification_syntaxes_tag_[] = { { ASN_TAG_CONT, 0u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_syntaxes_ber_ = { 1u, EMBEDDED_PDV_identification_syntaxes_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_syntaxes_descr_ = { "EMBEDDED PDV.identification.syntaxes", &EMBEDDED_PDV_identification_syntaxes_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_syntaxes_descr_ = { "EMBEDDED PDV.identification.syntaxes", &EMBEDDED_PDV_identification_syntaxes_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t EMBEDDED_PDV_identification_syntax_tag_[] = { { ASN_TAG_CONT, 1u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_syntax_ber_ = { 1u, EMBEDDED_PDV_identification_syntax_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_syntax_descr_ = { "EMBEDDED PDV.identification.syntax", &EMBEDDED_PDV_identification_syntax_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_syntax_descr_ = { "EMBEDDED PDV.identification.syntax", &EMBEDDED_PDV_identification_syntax_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; static const ASN_Tag_t EMBEDDED_PDV_identification_presentation__context__id_tag_[] = { { ASN_TAG_CONT, 2u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_presentation__context__id_ber_ = { 1u, EMBEDDED_PDV_identification_presentation__context__id_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_presentation__context__id_descr_ = { "EMBEDDED PDV.identification.presentation-context-id", &EMBEDDED_PDV_identification_presentation__context__id_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_presentation__context__id_descr_ = { "EMBEDDED PDV.identification.presentation-context-id", &EMBEDDED_PDV_identification_presentation__context__id_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t EMBEDDED_PDV_identification_context__negotiation_presentation__context__id_tag_[] = { { ASN_TAG_CONT, 0u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_context__negotiation_presentation__context__id_ber_ = { 1u, EMBEDDED_PDV_identification_context__negotiation_presentation__context__id_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_context__negotiation_presentation__context__id_descr_ = { "EMBEDDED PDV.identification.context-negotiation.presentation-context-id", &EMBEDDED_PDV_identification_context__negotiation_presentation__context__id_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_context__negotiation_presentation__context__id_descr_ = { "EMBEDDED PDV.identification.context-negotiation.presentation-context-id", &EMBEDDED_PDV_identification_context__negotiation_presentation__context__id_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t EMBEDDED_PDV_identification_context__negotiation_transfer__syntax_tag_[] = { { ASN_TAG_CONT, 1u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_context__negotiation_transfer__syntax_ber_ = { 1u, EMBEDDED_PDV_identification_context__negotiation_transfer__syntax_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_context__negotiation_transfer__syntax_descr_ = { "EMBEDDED PDV.identification.context-negotiation.transfer-syntax", &EMBEDDED_PDV_identification_context__negotiation_transfer__syntax_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_context__negotiation_transfer__syntax_descr_ = { "EMBEDDED PDV.identification.context-negotiation.transfer-syntax", &EMBEDDED_PDV_identification_context__negotiation_transfer__syntax_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; static const ASN_Tag_t EMBEDDED_PDV_identification_context__negotiation_tag_[] = { { ASN_TAG_CONT, 3u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_context__negotiation_ber_ = { 1u, EMBEDDED_PDV_identification_context__negotiation_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_context__negotiation_descr_ = { "EMBEDDED PDV.identification.context-negotiation", &EMBEDDED_PDV_identification_context__negotiation_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_context__negotiation_descr_ = { "EMBEDDED PDV.identification.context-negotiation", &EMBEDDED_PDV_identification_context__negotiation_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t EMBEDDED_PDV_identification_transfer__syntax_tag_[] = { { ASN_TAG_CONT, 4u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_transfer__syntax_ber_ = { 1u, EMBEDDED_PDV_identification_transfer__syntax_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_transfer__syntax_descr_ = { "EMBEDDED PDV.identification.transfer-syntax", &EMBEDDED_PDV_identification_transfer__syntax_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_transfer__syntax_descr_ = { "EMBEDDED PDV.identification.transfer-syntax", &EMBEDDED_PDV_identification_transfer__syntax_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::OBJID }; static const ASN_Tag_t EMBEDDED_PDV_identification_fixed_tag_[] = { { ASN_TAG_CONT, 5u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_identification_fixed_ber_ = { 1u, EMBEDDED_PDV_identification_fixed_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_fixed_descr_ = { "EMBEDDED PDV.identification.fixed", &EMBEDDED_PDV_identification_fixed_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_identification_fixed_descr_ = { "EMBEDDED PDV.identification.fixed", &EMBEDDED_PDV_identification_fixed_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t EMBEDDED_PDV_data__value_tag_[] = { { ASN_TAG_CONT, 2u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_data__value_ber_ = { 1u, EMBEDDED_PDV_data__value_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_data__value_descr_ = { "EMBEDDED PDV.data-value", &EMBEDDED_PDV_data__value_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_data__value_descr_ = { "EMBEDDED PDV.data-value", &EMBEDDED_PDV_data__value_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t EMBEDDED_PDV_data__value__descriptor_tag_[] = { { ASN_TAG_CONT, 1u }}; static const ASN_BERdescriptor_t EMBEDDED_PDV_data__value__descriptor_ber_ = { 1u, EMBEDDED_PDV_data__value__descriptor_tag_ }; -static const TTCN_Typedescriptor_t EMBEDDED_PDV_data__value__descriptor_descr_ = { "EMBEDDED PDV.data-value-descriptor", &EMBEDDED_PDV_data__value__descriptor_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::GRAPHICSTRING }; +static const TTCN_Typedescriptor_t EMBEDDED_PDV_data__value__descriptor_descr_ = { "EMBEDDED PDV.data-value-descriptor", &EMBEDDED_PDV_data__value__descriptor_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::GRAPHICSTRING }; /******************** EMBEDDED_PDV_identification ********************/ diff --git a/core/ASN_External.cc b/core/ASN_External.cc index 65e7e3d..4cc701f 100644 --- a/core/ASN_External.cc +++ b/core/ASN_External.cc @@ -197,19 +197,19 @@ namespace { /* anonymous namespace */ field_encoding.octet__aligned()=ex.data__value(); } - static const TTCN_Typedescriptor_t EXTERNALtransfer_encoding_descr_ = { "EXTERNALtransfer.encoding", &CHOICE_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; + static const TTCN_Typedescriptor_t EXTERNALtransfer_encoding_descr_ = { "EXTERNALtransfer.encoding", &CHOICE_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t EXTERNALtransfer_encoding_single__ASN1__type_tag_[] = { { ASN_TAG_CONT, 0u } }; static const ASN_BERdescriptor_t EXTERNALtransfer_encoding_single__ASN1__type_ber_ = { 1u, EXTERNALtransfer_encoding_single__ASN1__type_tag_ }; - static const TTCN_Typedescriptor_t EXTERNALtransfer_encoding_single__ASN1__type_descr_ = { "EXTERNALtransfer.encoding.single-ASN1-type", &EXTERNALtransfer_encoding_single__ASN1__type_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; + static const TTCN_Typedescriptor_t EXTERNALtransfer_encoding_single__ASN1__type_descr_ = { "EXTERNALtransfer.encoding.single-ASN1-type", &EXTERNALtransfer_encoding_single__ASN1__type_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t EXTERNALtransfer_encoding_octet__aligned_tag_[] = { { ASN_TAG_CONT, 1u } }; static const ASN_BERdescriptor_t EXTERNALtransfer_encoding_octet__aligned_ber_ = { 1u, EXTERNALtransfer_encoding_octet__aligned_tag_ }; - static const TTCN_Typedescriptor_t EXTERNALtransfer_encoding_octet__aligned_descr_ = { "EXTERNALtransfer.encoding.octet-aligned", &EXTERNALtransfer_encoding_octet__aligned_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; + static const TTCN_Typedescriptor_t EXTERNALtransfer_encoding_octet__aligned_descr_ = { "EXTERNALtransfer.encoding.octet-aligned", &EXTERNALtransfer_encoding_octet__aligned_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; static const ASN_Tag_t EXTERNALtransfer_encoding_arbitrary_tag_[] = { { ASN_TAG_CONT, 2u } }; static const ASN_BERdescriptor_t EXTERNALtransfer_encoding_arbitrary_ber_ = { 1u, EXTERNALtransfer_encoding_arbitrary_tag_ }; - static const TTCN_Typedescriptor_t EXTERNALtransfer_encoding_arbitrary_descr_ = { "EXTERNALtransfer.encoding.arbitrary", &EXTERNALtransfer_encoding_arbitrary_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; + static const TTCN_Typedescriptor_t EXTERNALtransfer_encoding_arbitrary_descr_ = { "EXTERNALtransfer.encoding.arbitrary", &EXTERNALtransfer_encoding_arbitrary_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; /* Member functions of C++ classes */ diff --git a/core/Array.hh b/core/Array.hh index bfbfde7..bb34bb2 100644 --- a/core/Array.hh +++ b/core/Array.hh @@ -36,7 +36,11 @@ extern unsigned int get_timer_array_index(const INTEGER& index_value, * * */ template -class TIMER_ARRAY { +class TIMER_ARRAY +#ifdef TITAN_RUNTIME_2 + : public RefdIndexInterface +#endif +{ T_type array_elements[array_size]; char * names[array_size]; @@ -85,13 +89,6 @@ public: } TTCN_Logger::log_event_str(" }"); } - -#ifdef TITAN_RUNTIME_2 - // Dummy functions, only used in record of/set of in RT2 (the referenced indices - // cannot be deleted, since arrays have a fixed size) - void add_refd_index(int) {} - void remove_refd_index(int) {} -#endif }; extern unsigned int get_port_array_index(int index_value, @@ -100,7 +97,11 @@ extern unsigned int get_port_array_index(const INTEGER& index_value, unsigned int array_size, int index_offset); template -class PORT_ARRAY { +class PORT_ARRAY +#ifdef TITAN_RUNTIME_2 + : public RefdIndexInterface +#endif +{ T_type array_elements[array_size]; char * names[array_size]; @@ -152,13 +153,6 @@ public: } TTCN_Logger::log_event_str(" }"); } - -#ifdef TITAN_RUNTIME_2 - // Dummy functions, only used in record of/set of in RT2 (the referenced indices - // cannot be deleted, since arrays have a fixed size) - void add_refd_index(int) {} - void remove_refd_index(int) {} -#endif }; //////////////////////////////////////////////////////////////////////////////// @@ -170,6 +164,9 @@ extern unsigned int get_array_index(const INTEGER& index_value, template class VALUE_ARRAY : public Base_Type +#ifdef TITAN_RUNTIME_2 + , public RefdIndexInterface +#endif { T_type array_elements[array_size]; public: @@ -240,13 +237,6 @@ public: /** Decodes accordingly to the JSON encoding rules. * Returns the length of the decoded data. */ int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean); - -#ifdef TITAN_RUNTIME_2 - // Dummy functions, only used in record of/set of in RT2 (the referenced indices - // cannot be deleted, since arrays have a fixed size) - void add_refd_index(int) {} - void remove_refd_index(int) {} -#endif }; template diff --git a/core/Basetype.cc b/core/Basetype.cc index 104e6b0..c64c2f7 100644 --- a/core/Basetype.cc +++ b/core/Basetype.cc @@ -1086,101 +1086,101 @@ const Base_Type* TTCN_Type_list::get_nth(size_t pos) const } const TTCN_Typedescriptor_t BOOLEAN_descr_={"BOOLEAN", &BOOLEAN_ber_, - &BOOLEAN_raw_, &BOOLEAN_text_, &BOOLEAN_xer_, &BOOLEAN_json_, TTCN_Typedescriptor_t::DONTCARE}; + &BOOLEAN_raw_, &BOOLEAN_text_, &BOOLEAN_xer_, &BOOLEAN_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t INTEGER_descr_={"INTEGER", &INTEGER_ber_, - &INTEGER_raw_, &INTEGER_text_, &INTEGER_xer_, &INTEGER_json_, TTCN_Typedescriptor_t::DONTCARE}; + &INTEGER_raw_, &INTEGER_text_, &INTEGER_xer_, &INTEGER_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t FLOAT_descr_={"REAL", &FLOAT_ber_, &FLOAT_raw_, - NULL, &FLOAT_xer_, &FLOAT_json_, TTCN_Typedescriptor_t::DONTCARE}; + NULL, &FLOAT_xer_, &FLOAT_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t VERDICTTYPE_descr_={"verdicttype", NULL, NULL, - NULL, &VERDICTTYPE_xer_, &VERDICTTYPE_json_, TTCN_Typedescriptor_t::DONTCARE}; + NULL, &VERDICTTYPE_xer_, &VERDICTTYPE_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t OBJID_descr_={"OBJECT IDENTIFIER", &OBJID_ber_, - NULL, NULL, &OBJID_xer_, &OBJID_json_, TTCN_Typedescriptor_t::OBJID}; + NULL, NULL, &OBJID_xer_, &OBJID_json_, NULL, TTCN_Typedescriptor_t::OBJID}; const TTCN_Typedescriptor_t BITSTRING_descr_={"BIT STRING", &BITSTRING_ber_, - &BITSTRING_raw_, NULL, &BITSTRING_xer_, &BITSTRING_json_, TTCN_Typedescriptor_t::DONTCARE}; + &BITSTRING_raw_, NULL, &BITSTRING_xer_, &BITSTRING_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t HEXSTRING_descr_={"hexstring", NULL, - &HEXSTRING_raw_, NULL, &HEXSTRING_xer_, &HEXSTRING_json_, TTCN_Typedescriptor_t::DONTCARE}; + &HEXSTRING_raw_, NULL, &HEXSTRING_xer_, &HEXSTRING_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t OCTETSTRING_descr_={"OCTET STRING", - &OCTETSTRING_ber_, &OCTETSTRING_raw_, &OCTETSTRING_text_, &OCTETSTRING_xer_, &OCTETSTRING_json_, TTCN_Typedescriptor_t::DONTCARE}; + &OCTETSTRING_ber_, &OCTETSTRING_raw_, &OCTETSTRING_text_, &OCTETSTRING_xer_, &OCTETSTRING_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t CHARSTRING_descr_={"charstring", NULL, - &CHARSTRING_raw_, &CHARSTRING_text_, &CHARSTRING_xer_, &CHARSTRING_json_, TTCN_Typedescriptor_t::DONTCARE}; + &CHARSTRING_raw_, &CHARSTRING_text_, &CHARSTRING_xer_, &CHARSTRING_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t UNIVERSAL_CHARSTRING_descr_={"universal charstring", - NULL, NULL, NULL, &UNIVERSAL_CHARSTRING_xer_, &UNIVERSAL_CHARSTRING_json_, TTCN_Typedescriptor_t::DONTCARE}; + NULL, NULL, &UNIVERSAL_CHARSTRING_text_, &UNIVERSAL_CHARSTRING_xer_, &UNIVERSAL_CHARSTRING_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t COMPONENT_descr_={"component", NULL, NULL, NULL, - NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; + NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t DEFAULT_descr_={"default", NULL, NULL, NULL, - NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; + NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t ASN_NULL_descr_={"NULL", &ASN_NULL_ber_, NULL, - NULL, &ASN_NULL_xer_, &ASN_NULL_json_, TTCN_Typedescriptor_t::DONTCARE}; + NULL, &ASN_NULL_xer_, &ASN_NULL_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t ASN_ANY_descr_={"ANY", &ASN_ANY_ber_, NULL, - NULL, NULL, &ASN_ANY_json_, TTCN_Typedescriptor_t::DONTCARE}; + NULL, NULL, &ASN_ANY_json_, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t EXTERNAL_descr_={"EXTERNAL", &EXTERNAL_ber_, NULL, - NULL, &EXTERNAL_xer_, NULL, TTCN_Typedescriptor_t::DONTCARE}; + NULL, &EXTERNAL_xer_, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t EMBEDDED_PDV_descr_={"EMBEDDED PDV", - &EMBEDDED_PDV_ber_, NULL, NULL, &EMBEDDED_PDV_xer_, NULL, TTCN_Typedescriptor_t::DONTCARE}; + &EMBEDDED_PDV_ber_, NULL, NULL, &EMBEDDED_PDV_xer_, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t CHARACTER_STRING_descr_={"CHARACTER STRING", - &CHARACTER_STRING_ber_, NULL, NULL, &CHARACTER_STRING_xer_, NULL, TTCN_Typedescriptor_t::DONTCARE}; + &CHARACTER_STRING_ber_, NULL, NULL, &CHARACTER_STRING_xer_, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t ObjectDescriptor_descr_={"ObjectDescriptor", - &ObjectDescriptor_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::GRAPHICSTRING}; + &ObjectDescriptor_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::GRAPHICSTRING}; const TTCN_Typedescriptor_t UTF8String_descr_={"UTF8String", &UTF8String_ber_, - NULL, NULL, &UTF8String_xer_, NULL, TTCN_Typedescriptor_t::UTF8STRING}; + NULL, NULL, &UTF8String_xer_, NULL, NULL, TTCN_Typedescriptor_t::UTF8STRING}; const TTCN_Typedescriptor_t ASN_ROID_descr_={"RELATIVE-OID", &ASN_ROID_ber_, - NULL, NULL, &ASN_ROID_xer_, &ASN_ROID_json_, TTCN_Typedescriptor_t::ROID}; + NULL, NULL, &ASN_ROID_xer_, &ASN_ROID_json_, NULL, TTCN_Typedescriptor_t::ROID}; const TTCN_Typedescriptor_t NumericString_descr_={"NumericString", - &NumericString_ber_, NULL, NULL, &NumericString_xer_, NULL, TTCN_Typedescriptor_t::DONTCARE}; + &NumericString_ber_, NULL, NULL, &NumericString_xer_, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t PrintableString_descr_={"PrintableString", - &PrintableString_ber_, NULL, NULL, &PrintableString_xer_, NULL, TTCN_Typedescriptor_t::DONTCARE}; + &PrintableString_ber_, NULL, NULL, &PrintableString_xer_, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t TeletexString_descr_={"TeletexString", - &TeletexString_ber_, NULL, NULL, &TeletexString_xer_, NULL, TTCN_Typedescriptor_t::TELETEXSTRING}; + &TeletexString_ber_, NULL, NULL, &TeletexString_xer_, NULL, NULL, TTCN_Typedescriptor_t::TELETEXSTRING}; const TTCN_Typedescriptor_t& T61String_descr_=TeletexString_descr_; const TTCN_Typedescriptor_t VideotexString_descr_={"VideotexString", - &VideotexString_ber_, NULL, NULL, &VideotexString_xer_, NULL, TTCN_Typedescriptor_t::VIDEOTEXSTRING}; + &VideotexString_ber_, NULL, NULL, &VideotexString_xer_, NULL, NULL, TTCN_Typedescriptor_t::VIDEOTEXSTRING}; const TTCN_Typedescriptor_t IA5String_descr_={"IA5String", &IA5String_ber_, - NULL, NULL, &IA5String_xer_, NULL, TTCN_Typedescriptor_t::DONTCARE}; + NULL, NULL, &IA5String_xer_, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t ASN_GeneralizedTime_descr_={"GeneralizedTime", - &ASN_GeneralizedTime_ber_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; + &ASN_GeneralizedTime_ber_, NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t ASN_UTCTime_descr_={"UTCTime", &ASN_UTCTime_ber_, - NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; + NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t GraphicString_descr_={"GraphicString", - &GraphicString_ber_, NULL, NULL, &GraphicString_xer_, NULL, TTCN_Typedescriptor_t::GRAPHICSTRING}; + &GraphicString_ber_, NULL, NULL, &GraphicString_xer_, NULL, NULL, TTCN_Typedescriptor_t::GRAPHICSTRING}; const TTCN_Typedescriptor_t VisibleString_descr_={"VisibleString", - &VisibleString_ber_, NULL, NULL, &VisibleString_xer_, NULL, TTCN_Typedescriptor_t::DONTCARE}; + &VisibleString_ber_, NULL, NULL, &VisibleString_xer_, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t& ISO646String_descr_=VisibleString_descr_; const TTCN_Typedescriptor_t GeneralString_descr_={"GeneralString", - &GeneralString_ber_, NULL, NULL, &GeneralString_xer_, NULL, TTCN_Typedescriptor_t::GENERALSTRING}; + &GeneralString_ber_, NULL, NULL, &GeneralString_xer_, NULL, NULL, TTCN_Typedescriptor_t::GENERALSTRING}; const TTCN_Typedescriptor_t UniversalString_descr_={"UniversalString", - &UniversalString_ber_, NULL, NULL, &UniversalString_xer_, NULL, TTCN_Typedescriptor_t::UNIVERSALSTRING}; + &UniversalString_ber_, NULL, NULL, &UniversalString_xer_, NULL, NULL, TTCN_Typedescriptor_t::UNIVERSALSTRING}; const TTCN_Typedescriptor_t BMPString_descr_={"BMPString", &BMPString_ber_, - NULL, NULL, &BMPString_xer_, NULL, TTCN_Typedescriptor_t::BMPSTRING}; + NULL, NULL, &BMPString_xer_, NULL, NULL, TTCN_Typedescriptor_t::BMPSTRING}; diff --git a/core/Basetype.hh b/core/Basetype.hh index 2e49375..76323a4 100644 --- a/core/Basetype.hh +++ b/core/Basetype.hh @@ -12,10 +12,11 @@ #include "Encdec.hh" #include "RInt.hh" #include "JSON_Tokenizer.hh" -#include "Vector.hh" #ifdef TITAN_RUNTIME_2 #include "Struct_of.hh" #include "XER.hh" +#include "Vector.hh" +#include "RefdIndex.hh" #endif struct ASN_BERdescriptor_t; @@ -43,6 +44,7 @@ struct TTCN_Typedescriptor_t { const TTCN_TEXTdescriptor_t * const text; /**< Information for TEXT coding */ const XERdescriptor_t * const xer; /**< Information for XER */ const TTCN_JSONdescriptor_t * const json; /**< Information for JSON coding */ + const TTCN_Typedescriptor_t * const oftype_descr; /**< Record-of element's type descriptor */ /** ASN subtype * * Used by classes implementing more than one ASN.1 type @@ -642,7 +644,7 @@ class INTEGER; * */ // Record_Of_Template can be found in Template.hh -class Record_Of_Type : public Base_Type +class Record_Of_Type : public Base_Type, public RefdIndexInterface { friend class Set_Of_Template; friend class Record_Of_Template; @@ -776,7 +778,7 @@ public: virtual int XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned flavor, int indent, embed_values_enc_struct_t*) const; /// Helper for XER_encode_negtest - int encode_element(int i, const Erroneous_values_t* err_vals, + int encode_element(int i, const XERdescriptor_t& p_td, const Erroneous_values_t* err_vals, const Erroneous_descriptor_t* emb_descr, TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t* emb_val) const; virtual int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int, embed_values_dec_struct_t*); @@ -794,8 +796,6 @@ public: /** @returns \c true if this is a set-of type, * \c false if this is a record-of type */ virtual boolean is_set() const = 0; - /** return the type descriptor of the element */ - virtual const TTCN_Typedescriptor_t* get_elem_descr() const = 0; /** creates an instance of the record's element class, using the default constructor */ virtual Base_Type* create_elem() const = 0; @@ -812,12 +812,12 @@ public: /** Indicates that the element at the given index is referenced by an 'out' or * 'inout' parameter and must not be deleted. * Used just before the actual function call that references the element. */ - void add_refd_index(int index); + virtual void add_refd_index(int index); /** Indicates that the element at the given index is no longer referenced by * an 'out' or 'inout' parameter. * Used immediately after the actual function call that referenced the element. */ - void remove_refd_index(int index); + virtual void remove_refd_index(int index); }; extern boolean operator==(null_type null_value, diff --git a/core/Component.cc b/core/Component.cc index 7d57b54..66f3604 100644 --- a/core/Component.cc +++ b/core/Component.cc @@ -124,21 +124,31 @@ void COMPONENT::kill() const void COMPONENT::set_param(Module_Param& param) { param.basic_check(Module_Param::BC_VALUE, "component reference (integer or null) value"); - switch (param.get_type()) { - case Module_Param::MP_Integer: - component_value = (component)param.get_integer()->get_val(); - break; - case Module_Param::MP_Ttcn_Null: + if (Ttcn_String_Parsing::happening()) { + // accept all component values in case it's a string2ttcn operation + switch (param.get_type()) { + case Module_Param::MP_Integer: + component_value = (component)param.get_integer()->get_val(); + break; + case Module_Param::MP_Ttcn_Null: + component_value = NULL_COMPREF; + break; + case Module_Param::MP_Ttcn_mtc: + component_value = MTC_COMPREF; + break; + case Module_Param::MP_Ttcn_system: + component_value = SYSTEM_COMPREF; + break; + default: + param.type_error("component reference (integer or null) value"); + } + } + else { + // only accept the null value if it's a module parameter + if (Module_Param::MP_Ttcn_Null != param.get_type()) { + param.error("Only the 'null' value is allowed for module parameters of type 'component'."); + } component_value = NULL_COMPREF; - break; - case Module_Param::MP_Ttcn_mtc: - component_value = MTC_COMPREF; - break; - case Module_Param::MP_Ttcn_system: - component_value = SYSTEM_COMPREF; - break; - default: - param.type_error("component reference (integer or null) value"); } } diff --git a/core/Float.cc b/core/Float.cc index 50c1c91..59d6a43 100644 --- a/core/Float.cc +++ b/core/Float.cc @@ -793,9 +793,66 @@ int FLOAT::XER_encode(const XERdescriptor_t& p_td, return (int)p_buf.get_len() - encoded_length; } +boolean FLOAT::is_float(const char* p_str) +{ + bool first_digit = false; // first digit reached + bool decimal_point = false; // decimal point (.) reached + bool exponent_mark = false; // exponential mark (e or E) reached + bool exponent_sign = false; // sign of the exponential (- or +) reached + + if ('-' == *p_str || '+' == *p_str) { + ++p_str; + } + + while (0 != *p_str) { + switch(*p_str) { + case '.': + if (decimal_point || exponent_mark || !first_digit) { + return false; + } + decimal_point = true; + first_digit = false; + break; + case 'e': + case 'E': + if (exponent_mark || !first_digit) { + return false; + } + exponent_mark = true; + first_digit = false; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + first_digit = true; + break; + case '-': + case '+': + if (exponent_sign || !exponent_mark || first_digit) { + return false; + } + exponent_sign = true; + break; + default: + return false; + } + + ++p_str; + } + return first_digit; +} + int FLOAT::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { + bound_flag = false; int exer = is_exer(flavor); int success = reader.Ok(), depth = -1; if (success <= 0) return 0; @@ -807,8 +864,10 @@ int FLOAT::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, tagless: const char * value = (const char *)reader.Value(); - if (value && sscanf(value, "%lf", &float_value)) + if (value && is_float(value)) { bound_flag = true; + sscanf(value, "%lf", &float_value); + } // Let the caller do reader.AdvanceAttribute(); } @@ -828,8 +887,10 @@ tagless: } else if (XML_READER_TYPE_TEXT == type && depth != -1) { const char * value = (const char*)reader.Value(); - if (value && sscanf(value, "%lf", &float_value) == 1) + if (value && is_float(value)) { bound_flag = true; + sscanf(value, "%lf", &float_value); + } } else if (XML_READER_TYPE_END_ELEMENT == type) { verify_end(reader, p_td, depth, exer); diff --git a/core/Float.hh b/core/Float.hh index 013d39d..18e6faa 100644 --- a/core/Float.hh +++ b/core/Float.hh @@ -41,6 +41,10 @@ class FLOAT : public Base_Type { boolean bound_flag; ttcn3float float_value; + + /** Returns true if the string parameter contains the string representation + * of a real number, otherwise returns false. */ + boolean is_float(const char* p_str); public: diff --git a/core/Makefile b/core/Makefile index ff35320..ce0f040 100644 --- a/core/Makefile +++ b/core/Makefile @@ -12,9 +12,13 @@ include $(TOP)/Makefile.cfg SCHEMAS := TitanLoggerApi.xsd # Generated from `TitanLoggerApi.xsd'. GENERATED_MODULES := TitanLoggerApi.ttcn + +PREGENERATOR_MODULES := PreGenRecordOf.ttcn GENERATED_LOGGERAPI_SOURCES := $(GENERATED_MODULES:.ttcn=.cc) GENERATED_LOGGERCONTROL_SOURCES := TitanLoggerControl.cc + +PREGENERATED_SOURCES := $(PREGENERATOR_MODULES:.ttcn=.cc) ORIGINATORS := TitanLoggerApi.xsd TitanLoggerApi.ttcn TitanLoggerControl.ttcn gccversion.c \ config_process.l config_process.y @@ -33,12 +37,14 @@ endif # These directories (RT1/RT2) are replicated inside $(INCDIR) GENERATED_LOGGERAPI_SOURCES := $(addprefix $(APIDIR)/,$(GENERATED_LOGGERAPI_SOURCES)) GENERATED_LOGGERCONTROL_SOURCES := $(addprefix $(APIDIR)/,$(GENERATED_LOGGERCONTROL_SOURCES)) +PREGENERATED_SOURCES := $(addprefix $(APIDIR)/,$(PREGENERATED_SOURCES)) GENERATED_SOURCES := $(GENERATED_LOGGERAPI_SOURCES) $(GENERATED_LOGGERCONTROL_SOURCES) config_process.lex.cc config_process.tab.cc +GENERATED_SOURCES += $(PREGENERATED_SOURCES) GENERATED_HEADERS := $(GENERATED_LOGGERAPI_SOURCES:.cc=.hh) $(GENERATED_LOGGERCONTROL_SOURCES:.cc=.hh) config_process.tab.hh config_process.lex.hh -GENERATED_HEADERS += $(GENERATED_LOGGERAPI_SOURCES:.cc=Simple.hh) +GENERATED_HEADERS += $(GENERATED_LOGGERAPI_SOURCES:.cc=Simple.hh) $(PREGENERATED_SOURCES:.cc=.hh) GENERATED_OTHERS := $(GENERATED_LOGGERAPI_SOURCES).compiled $(GENERATED_LOGGERCONTROL_SOURCES).compiled -GENERATED_OTHERS += config_process.output lex.backup +GENERATED_OTHERS += $(PREGENERATED_SOURCES).compiled config_process.output lex.backup TTCN_COMPILER_FLAGS := ifeq ($(FUNCTION_TEST_RUNTIME), yes) @@ -157,7 +163,7 @@ Port.hh Event_Handler.hh Struct_of.hh Array.hh Optional.hh Textbuf.hh Encdec.hh Module_list.hh Parameters.h Addfunc.hh RAW.hh BER.hh TEXT.hh ASN_Null.hh \ ASN_Any.hh ASN_External.hh ASN_EmbeddedPDV.hh ASN_CharacterString.hh XER.hh \ XmlReader.hh cversion.h TitanLoggerControl.ttcn TitanLoggerApi.xsd Vector.hh \ -JSON.hh Profiler.hh +JSON.hh Profiler.hh RefdIndex.hh # Copied during "make install" ifdef REGEX_DIR @@ -257,6 +263,7 @@ endif endif mkdir -p $(INCDIR)/$(APIDIR) cp $(APIDIR)/TitanLoggerApi*.hh $(INCDIR)/$(APIDIR) + cp $(APIDIR)/PreGenRecordOf.hh $(INCDIR)/$(APIDIR) # # # # executables single$(RT2_SUFFIX)$(EXESUFFIX): $(LIBRARY) @@ -350,6 +357,17 @@ $(GENERATED_LOGGERCONTROL_SOURCES).compiled:: TitanLoggerControl.ttcn mkdir -p $(APIDIR) ../compiler2/compiler$(EXESUFFIX) $(TTCN_COMPILER_FLAGS) $^ - $? touch $@ + +$(PREGENERATED_SOURCES): $(PREGENERATED_SOURCES).compiled + @if [ ! -f $@ ]; then $(RM) $<; $(MAKE) $<; fi + +$(PREGENERATED_SOURCES).compiled:: ../compiler2/compiler$(EXESUFFIX) + @if [ -f $@ ]; then $(RM) $@; $(MAKE) $@; fi + +$(PREGENERATED_SOURCES).compiled:: $(PREGENERATOR_MODULES) + mkdir -p $(APIDIR) + ../compiler2/compiler$(EXESUFFIX) -F $(TTCN_COMPILER_FLAGS) $^ - $? + touch $@ include ../Makefile.genrules diff --git a/core/Module_list.cc b/core/Module_list.cc index a382c4d..e6f19ba 100644 --- a/core/Module_list.cc +++ b/core/Module_list.cc @@ -95,8 +95,6 @@ void Module_List::pre_init_modules() { for (TTCN_Module *list_iter = list_head; list_iter != NULL; list_iter = list_iter->list_next) list_iter->pre_init_module(); - - send_versions(); } void Module_List::post_init_modules() diff --git a/core/Optional.hh b/core/Optional.hh index 85e1475..3ac4d32 100644 --- a/core/Optional.hh +++ b/core/Optional.hh @@ -25,7 +25,11 @@ enum optional_sel { OPTIONAL_UNBOUND, OPTIONAL_OMIT, OPTIONAL_PRESENT }; template -class OPTIONAL : public Base_Type { +class OPTIONAL : public Base_Type +#ifdef TITAN_RUNTIME_2 + , public RefdIndexInterface +#endif +{ /** The value, if present (owned by OPTIONAL) * In Runtime2 the pointer is null, when the value is not present. * In Runtime1 its presence is indicated by the optional_selection member. */ @@ -319,19 +323,13 @@ public: * 'inout' or 'out' parameter to a function (only in Runtime2). * Sets the optional value to present (this would be done by the indexing operation * anyway) and redirects the call to the optional value. */ - void add_refd_index(int index); + virtual void add_refd_index(int index); /** Called after an element of an optional record of/set of is passed as an * 'inout' or 'out' parameter to a function (only in Runtime2). * Redirects the call to the optional value. */ - void remove_refd_index(int index); + virtual void remove_refd_index(int index); #endif - - /** Called before an element of an optional record of/set of is passed as an - * 'inout' or 'out' parameter to a function. Returns the size of the record of/ - * set of. - * Redirects the call to the optional value. */ - int size_of(); }; #if HAVE_GCC(4,6) @@ -827,14 +825,20 @@ void OPTIONAL::add_refd_index(int index) { ++param_refs; set_to_present(); - optional_value->add_refd_index(index); + RefdIndexInterface* refd_opt_val = dynamic_cast(optional_value); + if (0 != refd_opt_val) { + refd_opt_val->add_refd_index(index); + } } template void OPTIONAL::remove_refd_index(int index) { --param_refs; - optional_value->remove_refd_index(index); + RefdIndexInterface* refd_opt_val = dynamic_cast(optional_value); + if (0 != refd_opt_val) { + refd_opt_val->remove_refd_index(index); + } } #endif @@ -1005,6 +1009,12 @@ OPTIONAL::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, // we already checked for exer==1 if (!check_namespace((const char*)reader.NamespaceUri(), p_td)) break; + // set to omit if the attribute is empty + const char * value = (const char *)reader.Value(); + if (strlen(value) == 0) { + break; + } + set_to_present(); optional_value->XER_decode(p_td, reader, flavor, emb_val); goto finished; diff --git a/core/Parallel_main.cc b/core/Parallel_main.cc index ddd0242..2f6bdd2 100644 --- a/core/Parallel_main.cc +++ b/core/Parallel_main.cc @@ -24,6 +24,9 @@ #include "Error.hh" #include "Encdec.hh" #include "TCov.hh" +#ifdef LINUX +#include +#endif #ifdef LICENSE #include "../common/license.h" @@ -35,7 +38,7 @@ const char * stored_argv = "Unidentified program"; //static const char segfault[] = " : Segmentation fault occurred\n"; -void signal_handler(int) +void signal_handler(int signum) { int retval; time_t now=time(0); @@ -44,7 +47,7 @@ void signal_handler(int) struct tm *tmp; tmp=localtime(&now); if(tmp==NULL){ - fprintf(stderr," %s: Segmentation fault occurred\n",stored_argv); + fprintf(stderr," %s: %s\n",stored_argv, signum==SIGABRT?"Abort was called":"Segmentation fault occurred"); } else { /* retval = write(STDERR_FILENO, stored_argv, strlen(stored_argv)); retval = write(STDERR_FILENO, segfault , sizeof(segfault)-1); // sizeof includes \0 @@ -52,10 +55,18 @@ void signal_handler(int) (void)retval; */ retval=strftime(ts,60,"%F %T",tmp); - fprintf(stderr,"%s %s: Segmentation fault occurred\n",ts,stored_argv); + fprintf(stderr,"%s %s: %s\n",ts,stored_argv,signum==SIGABRT?"Abort was called":"Segmentation fault occurred"); } fflush(stderr); +#ifdef LINUX + int nptrs; + void *buffer[100]; + nptrs = backtrace(buffer, 100); + backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO); + fflush(stderr); +#endif + signal(SIGABRT, SIG_DFL); abort(); } @@ -185,6 +196,7 @@ int main(int argc, char *argv[]) sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGSEGV, &act, 0); + sigaction(SIGABRT, &act, 0); #ifdef MEMORY_DEBUG debug_new_counter.set_program_name(argv[0]); diff --git a/core/PreGenRecordOf.ttcn b/core/PreGenRecordOf.ttcn new file mode 100644 index 0000000..da2b0d5 --- /dev/null +++ b/core/PreGenRecordOf.ttcn @@ -0,0 +1,83 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2000-2015 Ericsson Telecom AB +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +/////////////////////////////////////////////////////////////////////////////// + +// This module contains 'record of' and 'set of' type declarations for certain base types. +// It is used for pre-generating the C++ classes that represent these types, +// so they are not re-generated every time they are declared in TTCN-3 or ASN.1 +// modules. +module PreGenRecordOf { + +// 'record of' declarations (regular): +type record of boolean PREGEN_RECORD_OF_BOOLEAN; + +type record of integer PREGEN_RECORD_OF_INTEGER; + +type record of float PREGEN_RECORD_OF_FLOAT; + +type record of bitstring PREGEN_RECORD_OF_BITSTRING; + +type record of hexstring PREGEN_RECORD_OF_HEXSTRING; + +type record of octetstring PREGEN_RECORD_OF_OCTETSTRING; + +type record of charstring PREGEN_RECORD_OF_CHARSTRING; + +type record of universal charstring PREGEN_RECORD_OF_UNIVERSAL_CHARSTRING; + +// 'record of' declarations (with optimized memory allocation): +type record of boolean PREGEN_RECORD_OF_BOOLEAN_OPTIMIZED with { extension "optimize:memalloc" }; + +type record of integer PREGEN_RECORD_OF_INTEGER_OPTIMIZED with { extension "optimize:memalloc" }; + +type record of float PREGEN_RECORD_OF_FLOAT_OPTIMIZED with { extension "optimize:memalloc" }; + +type record of bitstring PREGEN_RECORD_OF_BITSTRING_OPTIMIZED with { extension "optimize:memalloc" }; + +type record of hexstring PREGEN_RECORD_OF_HEXSTRING_OPTIMIZED with { extension "optimize:memalloc" }; + +type record of octetstring PREGEN_RECORD_OF_OCTETSTRING_OPTIMIZED with { extension "optimize:memalloc" }; + +type record of charstring PREGEN_RECORD_OF_CHARSTRING_OPTIMIZED with { extension "optimize:memalloc" }; + +type record of universal charstring PREGEN_RECORD_OF_UNIVERSAL_CHARSTRING_OPTIMIZED with { extension "optimize:memalloc" }; + +// 'set of' declarations (regular): +type set of boolean PREGEN_SET_OF_BOOLEAN; + +type set of integer PREGEN_SET_OF_INTEGER; + +type set of float PREGEN_SET_OF_FLOAT; + +type set of bitstring PREGEN_SET_OF_BITSTRING; + +type set of hexstring PREGEN_SET_OF_HEXSTRING; + +type set of octetstring PREGEN_SET_OF_OCTETSTRING; + +type set of charstring PREGEN_SET_OF_CHARSTRING; + +type set of universal charstring PREGEN_SET_OF_UNIVERSAL_CHARSTRING; + +// 'set of' declarations (with optimized memory allocation): +type set of boolean PREGEN_SET_OF_BOOLEAN_OPTIMIZED with { extension "optimize:memalloc" }; + +type set of integer PREGEN_SET_OF_INTEGER_OPTIMIZED with { extension "optimize:memalloc" }; + +type set of float PREGEN_SET_OF_FLOAT_OPTIMIZED with { extension "optimize:memalloc" }; + +type set of bitstring PREGEN_SET_OF_BITSTRING_OPTIMIZED with { extension "optimize:memalloc" }; + +type set of hexstring PREGEN_SET_OF_HEXSTRING_OPTIMIZED with { extension "optimize:memalloc" }; + +type set of octetstring PREGEN_SET_OF_OCTETSTRING_OPTIMIZED with { extension "optimize:memalloc" }; + +type set of charstring PREGEN_SET_OF_CHARSTRING_OPTIMIZED with { extension "optimize:memalloc" }; + +type set of universal charstring PREGEN_SET_OF_UNIVERSAL_CHARSTRING_OPTIMIZED with { extension "optimize:memalloc" }; + +} diff --git a/core/Profiler.cc b/core/Profiler.cc index 860e5c8..e9d3b9f 100644 --- a/core/Profiler.cc +++ b/core/Profiler.cc @@ -7,13 +7,83 @@ /////////////////////////////////////////////////////////////////////////////// #include "Profiler.hh" -#include #include #include #include #include "JSON_Tokenizer.hh" #include "memory.h" #include "Runtime.hh" +#include +#include "Component.hh" + +//////////////////////////////////// +//////// timeval operations //////// +//////////////////////////////////// + +/** Reads a timeval value from the given string. The parameter must contain the + * string representation of a real number with 6 digits after the decimal dot. */ +static timeval string2timeval(const char* str) +{ + // read and store the first part (atoi will read until the decimal dot) + long int sec = atoi(str); + timeval tv; + tv.tv_sec = sec; + + do { + // step over each digit + sec /= 10; + ++str; + } + while (sec > 9); + + // step over the decimal dot and read the second part of the number + tv.tv_usec = atoi(str + 1); + return tv; +} + +/** Returns the string representation of a real number (with 6 digits after the + * decimal dot) equivalent to the timeval parameter. + * The returned character pointer needs to be freed. */ +static char* timeval2string(timeval tv) +{ + // convert the first part and set the second part to all zeros + char* str = mprintf("%ld.000000", tv.tv_sec); + + // go through each digit of the second part and add them to the zeros in the string + size_t pos = mstrlen(str) - 1; + while (tv.tv_usec > 0) { + str[pos] += tv.tv_usec % 10; + tv.tv_usec /= 10; + --pos; + } + return str; +} + +/** Adds the two timeval parameters together and returns the result. */ +static timeval add_timeval(const timeval operand1, const timeval operand2) +{ + timeval tv; + tv.tv_usec = operand1.tv_usec + operand2.tv_usec; + tv.tv_sec = operand1.tv_sec + operand2.tv_sec; + if (tv.tv_usec >= 1000000) { + ++tv.tv_sec; + tv.tv_usec -= 1000000; + } + return tv; +} + +/** Subtracts the second timeval parameter from the first one and returns the result. */ +static timeval subtract_timeval(const timeval operand1, const timeval operand2) +{ + timeval tv; + tv.tv_usec = operand1.tv_usec - operand2.tv_usec; + tv.tv_sec = operand1.tv_sec - operand2.tv_sec; + if (tv.tv_usec < 0) { + --tv.tv_sec; + tv.tv_usec += 1000000; + } + return tv; +} //////////////////////////////////// ////////// TTCN3_Profiler ////////// @@ -22,8 +92,8 @@ TTCN3_Profiler ttcn3_prof; TTCN3_Profiler::TTCN3_Profiler() -: disable_profiler(FALSE), disable_coverage(FALSE), aggregate_data(FALSE) -, disable_stats(FALSE) +: stopped(FALSE), disable_profiler(FALSE), disable_coverage(FALSE) +, aggregate_data(FALSE), disable_stats(FALSE), stats_flags(STATS_ALL) { database_filename = mcopystr("profiler.db"); stats_filename = mcopystr("profiler.stats"); @@ -32,8 +102,19 @@ TTCN3_Profiler::TTCN3_Profiler() TTCN3_Profiler::~TTCN3_Profiler() { - if (!disable_profiler || !disable_coverage) { - import_data(); + if (!profiler_db.empty() && (!disable_profiler || !disable_coverage)) { + if (aggregate_data && (TTCN_Runtime::is_single() || TTCN_Runtime::is_hc())) { + // import the data from the previous run + import_data(); + } + if (TTCN_Runtime::is_hc()) { + // import the data gathered by the other processes (the import function + // waits for them to finish exporting) + import_data(MTC_COMPREF); + for (size_t i = 0; i < ptc_list.size(); ++i) { + import_data(ptc_list[i]); + } + } export_data(); if (!disable_stats && (TTCN_Runtime::is_single() || TTCN_Runtime::is_hc())) { print_stats(); @@ -49,6 +130,27 @@ TTCN3_Profiler::~TTCN3_Profiler() Free(stats_filename); } +void TTCN3_Profiler::start() +{ + if (stopped) { + set_prev(disable_profiler ? -1 : TTCN3_Stack_Depth::depth(), NULL, -1); + stopped = FALSE; + } +} + +void TTCN3_Profiler::stop() +{ + if (!stopped) { + if (NULL != prev_file) { + // update the previous line's time + timeval elapsed = subtract_timeval(get_time(), prev_time); + add_line_time(elapsed, get_element(prev_file), prev_line); + TTCN3_Stack_Depth::update_stack_elapsed(elapsed); + } + stopped = TRUE; + } +} + void TTCN3_Profiler::set_disable_profiler(boolean p_disable_profiler) { disable_profiler = p_disable_profiler; @@ -81,41 +183,94 @@ void TTCN3_Profiler::set_disable_stats(boolean p_disable_stats) disable_stats = p_disable_stats; } +void TTCN3_Profiler::reset_stats_flags() +{ + stats_flags = 0; +} + +void TTCN3_Profiler::add_stats_flags(unsigned int p_flags) +{ + stats_flags |= p_flags; +} + boolean TTCN3_Profiler::is_profiler_disabled() const { return disable_profiler; } +boolean TTCN3_Profiler::is_running() const +{ + return !stopped; +} + +void TTCN3_Profiler::add_ptc(component p_comp_ref) +{ + ptc_list.push_back(p_comp_ref); +} + #define IMPORT_FORMAT_ERROR(cond) \ if (cond) { \ TTCN_warning("Database format is invalid. Profiler and/or code coverage data will not be loaded."); \ return; \ } -void TTCN3_Profiler::init_data_file() +void TTCN3_Profiler::import_data(component p_comp_ref /* = NULL_COMPREF */) { - // delete the database file (from the previous run) if data aggregation is not set - if (!aggregate_data && (!disable_profiler || !disable_coverage)) { - remove(database_filename); + char* file_name = NULL; + if (NULL_COMPREF == p_comp_ref) { + // this is the main database file (from the previous run), no suffix needed + file_name = database_filename; } -} - -void TTCN3_Profiler::import_data() -{ + else if (MTC_COMPREF == p_comp_ref) { + // this is the database for the MTC, suffix the file name with "mtc" + file_name = mprintf("%s.mtc", database_filename); + } + else { + // this is the database for one of the PTCs, suffix the file name with the + // component reference + file_name = mprintf("%s.%d", database_filename, p_comp_ref); + } + // open the file, if it exists - FILE* file = fopen(database_filename, "r"); - if (NULL == file) { - return; + int file_size = 0; + FILE* file = fopen(file_name, "r"); + if (NULL != file) { + // get the file size + fseek(file, 0, SEEK_END); + file_size = ftell(file); + } + while (0 == file_size) { + if (NULL_COMPREF == p_comp_ref) { + // no data from the previous run + return; + } + // as for the process-specific database files: keep reading until it appears + if (NULL != file) { + fclose(file); + } + usleep(1000); + file = fopen(file_name, "r"); + if (NULL != file) { + // refresh the file size + fseek(file, 0, SEEK_END); + file_size = ftell(file); + } } - // get the file size - fseek(file, 0, SEEK_END); - int file_size = ftell(file); + // rewind the file (the file pointer has been moved to the end of the file to + // calculate its size) rewind(file); // read the entire file into a character buffer char* buffer = (char*)Malloc(file_size); fread(buffer, 1, file_size, file); + fclose(file); + + if (NULL_COMPREF != p_comp_ref) { + // the process-specific database file is no longer needed + remove(file_name); + Free(file_name); + } // initialize a JSON tokenizer with the buffer JSON_Tokenizer json(buffer, file_size); @@ -202,33 +357,32 @@ void TTCN3_Profiler::import_data() func_data.name = function_name; func_data.lineno = start_line; func_data.exec_count = 0; - func_data.total_time = 0.0; + func_data.total_time.tv_sec = 0; + func_data.total_time.tv_usec = 0; profiler_db[file_index].functions.push_back(func_data); } - if (!disable_coverage) { - // function execution count: - json.get_next_token(&token, &value, &value_len); - IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 15 || - 0 != strncmp(value, "execution count", value_len)); + // function execution count: + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 15 || + 0 != strncmp(value, "execution count", value_len)); - // read the execution count and add it to the current data - json.get_next_token(&token, &value, &value_len); - IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token); - profiler_db[file_index].functions[function_index].exec_count += atoi(value); - } - - if (!disable_profiler) { - // total function execution time: - json.get_next_token(&token, &value, &value_len); - IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 || - 0 != strncmp(value, "total time", value_len)); + // read the execution count and add it to the current data + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token); + profiler_db[file_index].functions[function_index].exec_count += atoi(value); - // read the total time and add it to the current data - json.get_next_token(&token, &value, &value_len); - IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token); - profiler_db[file_index].functions[function_index].total_time += atof(value); - } + // total function execution time: + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 || + 0 != strncmp(value, "total time", value_len)); + + // read the total time and add it to the current data + // note: the database contains a real number, this needs to be split into 2 integers + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token); + profiler_db[file_index].functions[function_index].total_time = add_timeval( + profiler_db[file_index].functions[function_index].total_time, string2timeval(value)); // end of the function's object json.get_next_token(&token, NULL, NULL); @@ -251,6 +405,7 @@ void TTCN3_Profiler::import_data() IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token); json.get_next_token(&token, NULL, NULL); while (JSON_TOKEN_OBJECT_START == token) { + int line_index = 0; // line number: json.get_next_token(&token, &value, &value_len); @@ -262,39 +417,32 @@ void TTCN3_Profiler::import_data() IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token); int lineno = atoi(value); IMPORT_FORMAT_ERROR(lineno < 0); - size_t line_no = lineno; - if (line_no >= profiler_db[file_index].lines.size()) { - for (size_t i = profiler_db[file_index].lines.size(); i <= line_no; ++i) { - profiler_db_item_t::profiler_line_data_t line_data; - line_data.total_time = 0.0; - line_data.exec_count = 0; - profiler_db[file_index].lines.push_back(line_data); - } + line_index = get_line(file_index, lineno); + if (-1 == line_index) { + create_line(file_index, lineno); + line_index = profiler_db[file_index].lines.size() - 1; } - if (!disable_coverage) { - // line execution count: - json.get_next_token(&token, &value, &value_len); - IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 15 || - 0 != strncmp(value, "execution count", value_len)); + // line execution count: + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 15 || + 0 != strncmp(value, "execution count", value_len)); - // read the execution count and add it to the current data - json.get_next_token(&token, &value, &value_len); - IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token); - profiler_db[file_index].lines[line_no].exec_count += atoi(value); - } + // read the execution count and add it to the current data + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token); + profiler_db[file_index].lines[line_index].exec_count += atoi(value); - if (!disable_profiler) { - // total line execution time: - json.get_next_token(&token, &value, &value_len); - IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 || - 0 != strncmp(value, "total time", value_len)); + // total line execution time: + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 || + 0 != strncmp(value, "total time", value_len)); - // read the total time and add it to the current data - json.get_next_token(&token, &value, &value_len); - IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token); - profiler_db[file_index].lines[line_no].total_time += atof(value); - } + // read the total time and add it to the current data + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token); + profiler_db[file_index].lines[line_index].total_time = add_timeval( + profiler_db[file_index].lines[line_index].total_time, string2timeval(value)); // end of the line's object json.get_next_token(&token, NULL, NULL); @@ -321,19 +469,36 @@ void TTCN3_Profiler::import_data() void TTCN3_Profiler::export_data() { - // nothing to export if the database is empty - if (profiler_db.empty()) { - return; + char* file_name = NULL; + if (TTCN_Runtime::is_single() || TTCN_Runtime::is_hc()) { + // this is the main database file, no suffix needed + file_name = database_filename; + } + else if (TTCN_Runtime::is_mtc()) { + // this is the database for the MTC, suffix the file name with "mtc" + file_name = mprintf("%s.mtc", database_filename); + } + else { + // this is the database for one of the PTCs, suffix the file name with the + // component reference + file_name = mprintf("%s.%d", database_filename, (component)self); } // check whether the file can be opened for writing - FILE* file = fopen(database_filename, "w"); + FILE* file = fopen(file_name, "w"); if (NULL == file) { TTCN_warning("Could not open file '%s' for writing. Profiler and/or code coverage " - "data will not be saved.", database_filename); + "data will not be saved.", file_name); + if (file_name != database_filename) { + Free(file_name); + } return; } + if (file_name != database_filename) { + Free(file_name); + } + // use the JSON tokenizer to create a JSON document from the database JSON_Tokenizer json(true); @@ -354,40 +519,47 @@ void TTCN3_Profiler::export_data() json.put_next_token(JSON_TOKEN_NAME, "functions"); json.put_next_token(JSON_TOKEN_ARRAY_START, NULL); for (size_t j = 0; j < profiler_db[i].functions.size(); ++j) { + // only store functions with actual data + if ((0 != profiler_db[i].functions[j].total_time.tv_sec && + 0 != profiler_db[i].functions[j].total_time.tv_usec) || + 0 != profiler_db[i].functions[j].exec_count) { - // the data is stored in an object for each function - json.put_next_token(JSON_TOKEN_OBJECT_START, NULL); - - // store the function name - json.put_next_token(JSON_TOKEN_NAME, "name"); - char* func_name_str = mprintf("\"%s\"", profiler_db[i].functions[j].name); - json.put_next_token(JSON_TOKEN_STRING, func_name_str); - Free(func_name_str); - - // store the function start line - json.put_next_token(JSON_TOKEN_NAME, "start line"); - char* start_line_str = mprintf("%d", profiler_db[i].functions[j].lineno); - json.put_next_token(JSON_TOKEN_NUMBER, start_line_str); - Free(start_line_str); - - if (!disable_coverage) { + // the data is stored in an object for each function + json.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + + // store the function name + json.put_next_token(JSON_TOKEN_NAME, "name"); + char* func_name_str = mprintf("\"%s\"", profiler_db[i].functions[j].name); + json.put_next_token(JSON_TOKEN_STRING, func_name_str); + Free(func_name_str); + + // store the function start line + json.put_next_token(JSON_TOKEN_NAME, "start line"); + char* start_line_str = mprintf("%d", profiler_db[i].functions[j].lineno); + json.put_next_token(JSON_TOKEN_NUMBER, start_line_str); + Free(start_line_str); + // store the function execution count json.put_next_token(JSON_TOKEN_NAME, "execution count"); - char* exec_count_str = mprintf("%d", profiler_db[i].functions[j].exec_count); + char* exec_count_str = mprintf("%d", disable_coverage ? 0 : + profiler_db[i].functions[j].exec_count); json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str); Free(exec_count_str); - } - - if (!disable_profiler) { + // store the function's total execution time json.put_next_token(JSON_TOKEN_NAME, "total time"); - char* exec_count_str = mprintf("%.6lf", profiler_db[i].functions[j].total_time); - json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str); - Free(exec_count_str); + if (disable_profiler) { + json.put_next_token(JSON_TOKEN_NUMBER, "0.000000"); + } + else { + char* total_time_str = timeval2string(profiler_db[i].functions[j].total_time); + json.put_next_token(JSON_TOKEN_NUMBER, total_time_str); + Free(total_time_str); + } + + // end of function object + json.put_next_token(JSON_TOKEN_OBJECT_END, NULL); } - - // end of function object - json.put_next_token(JSON_TOKEN_OBJECT_END, NULL); } // end of function data array @@ -397,34 +569,38 @@ void TTCN3_Profiler::export_data() json.put_next_token(JSON_TOKEN_NAME, "lines"); json.put_next_token(JSON_TOKEN_ARRAY_START, NULL); for (size_t j = 0; j < profiler_db[i].lines.size(); ++j) { - if (0.0 != profiler_db[i].lines[j].total_time || + // only store lines with actual data + if ((0 != profiler_db[i].lines[j].total_time.tv_sec && + 0 != profiler_db[i].lines[j].total_time.tv_usec) || 0 != profiler_db[i].lines[j].exec_count) { - + // store line data in an object json.put_next_token(JSON_TOKEN_OBJECT_START, NULL); - + // store the line number json.put_next_token(JSON_TOKEN_NAME, "number"); - char* line_number_str = mprintf("%lu", j); + char* line_number_str = mprintf("%d", profiler_db[i].lines[j].lineno); json.put_next_token(JSON_TOKEN_NUMBER, line_number_str); Free(line_number_str); - - if (!disable_coverage) { - // store the line execution count - json.put_next_token(JSON_TOKEN_NAME, "execution count"); - char* exec_count_str = mprintf("%d", profiler_db[i].lines[j].exec_count); - json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str); - Free(exec_count_str); - } - if (!disable_profiler) { - // store the line's total execution time - json.put_next_token(JSON_TOKEN_NAME, "total time"); - char* exec_count_str = mprintf("%.6lf", profiler_db[i].lines[j].total_time); - json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str); - Free(exec_count_str); + // store the line execution count + json.put_next_token(JSON_TOKEN_NAME, "execution count"); + char* exec_count_str = mprintf("%d", disable_coverage ? 0 : + profiler_db[i].lines[j].exec_count); + json.put_next_token(JSON_TOKEN_NUMBER, exec_count_str); + Free(exec_count_str); + + // store the line's total execution time + json.put_next_token(JSON_TOKEN_NAME, "total time"); + if (disable_profiler) { + json.put_next_token(JSON_TOKEN_NUMBER, "0.000000"); } - + else { + char* total_time_str = timeval2string(profiler_db[i].lines[j].total_time); + json.put_next_token(JSON_TOKEN_NUMBER, total_time_str); + Free(total_time_str); + } + // end of this line's object json.put_next_token(JSON_TOKEN_OBJECT_END, NULL); } @@ -445,6 +621,43 @@ void TTCN3_Profiler::export_data() fclose(file); } +// Structure for one code line or function, used by print_stats for sorting +struct stats_data_t { + const char* filename; // not owned + const char* funcname; // not owned, NULL for code lines that don't start a function + int lineno; + timeval total_time; + int exec_count; +}; + +// Compare function for sorting stats data based on total execution time (descending) +int stats_data_cmp_time(const void* p_left, const void* p_right) { + const stats_data_t* p_left_data = (stats_data_t*)p_left; + const stats_data_t* p_right_data = (stats_data_t*)p_right; + if (p_left_data->total_time.tv_sec > p_right_data->total_time.tv_sec) return -1; + if (p_left_data->total_time.tv_sec < p_right_data->total_time.tv_sec) return 1; + if (p_left_data->total_time.tv_usec > p_right_data->total_time.tv_usec) return -1; + if (p_left_data->total_time.tv_usec < p_right_data->total_time.tv_usec) return 1; + return 0; +} + +// Compare function for sorting stats data based on execution count (descending) +int stats_data_cmp_count(const void* p_left, const void* p_right) { + return ((stats_data_t*)p_right)->exec_count - ((stats_data_t*)p_left)->exec_count; +} + +// Compare function for sorting stats data based on total time per execution count (descending) +int stats_data_cmp_avg(const void* p_left, const void* p_right) { + const stats_data_t* p_left_data = (stats_data_t*)p_left; + const stats_data_t* p_right_data = (stats_data_t*)p_right; + double left_time = p_left_data->total_time.tv_sec + p_left_data->total_time.tv_usec / 1000000.0; + double right_time = p_right_data->total_time.tv_sec + p_right_data->total_time.tv_usec / 1000000.0; + double diff = (right_time / p_right_data->exec_count) - (left_time / p_left_data->exec_count); + if (diff < 0) return -1; + if (diff > 0) return 1; + return 0; +} + void TTCN3_Profiler::print_stats() { if (profiler_db.empty()) { @@ -462,122 +675,804 @@ void TTCN3_Profiler::print_stats() , disable_coverage ? "" : "code coverage " , disable_profiler ? "######" : (disable_coverage ? "#########" : "")); + char* line_func_count_str = NULL; + if (stats_flags & STATS_NUMBER_OF_LINES) { + line_func_count_str = mcopystr( + "--------------------------------------\n" + "- Number of code lines and functions -\n" + "--------------------------------------\n"); + } + // line data - char* line_data_str = mprintf( - "-------------------------------------------------\n" - "%s- Code line data (%s%s%s) -%s\n" - "-------------------------------------------------\n" - , disable_profiler ? "-------" : (disable_coverage ? "---------" : "") - , disable_profiler ? "" : "total time" - , (disable_profiler || disable_coverage) ? "" : " / " - , disable_coverage ? "" : "execution count" - , disable_profiler ? "------" : (disable_coverage ? "---------" : "")); + char* line_data_str = NULL; + if (stats_flags & STATS_LINE_DATA_RAW) { + line_data_str = mprintf( + "-------------------------------------------------\n" + "%s- Code line data (%s%s%s) -%s\n" + "-------------------------------------------------\n" + , disable_profiler ? "-------" : (disable_coverage ? "---------" : "") + , disable_profiler ? "" : "total time" + , (disable_profiler || disable_coverage) ? "" : " / " + , disable_coverage ? "" : "execution count" + , disable_profiler ? "------" : (disable_coverage ? "---------" : "")); + } // average time / exec count for lines char* line_avg_str = NULL; - if (!disable_coverage && !disable_profiler) { + if (!disable_coverage && !disable_profiler && (stats_flags & STATS_LINE_AVG_RAW)) { line_avg_str = mcopystr( - "-------------------------------------------------\n" - "- Average time / execution count for code lines -\n" - "-------------------------------------------------\n"); + "-------------------------------------------\n" + "- Average time / execution for code lines -\n" + "-------------------------------------------\n"); } // function data - char* func_data_str = mprintf( - "------------------------------------------------\n" - "%s- Function data (%s%s%s) -%s\n" - "------------------------------------------------\n" - , disable_profiler ? "-------" : (disable_coverage ? "---------" : "") - , disable_profiler ? "" : "total time" - , (disable_profiler || disable_coverage) ? "" : " / " - , disable_coverage ? "" : "execution count" - , disable_profiler ? "------" : (disable_coverage ? "---------" : "")); + char* func_data_str = NULL; + if (stats_flags & STATS_FUNC_DATA_RAW) { + func_data_str = mprintf( + "------------------------------------------------\n" + "%s- Function data (%s%s%s) -%s\n" + "------------------------------------------------\n" + , disable_profiler ? "-------" : (disable_coverage ? "---------" : "") + , disable_profiler ? "" : "total time" + , (disable_profiler || disable_coverage) ? "" : " / " + , disable_coverage ? "" : "execution count" + , disable_profiler ? "------" : (disable_coverage ? "---------" : "")); + } // average time / exec count for functions char* func_avg_str = NULL; - if (!disable_coverage && !disable_profiler) { + if (!disable_coverage && !disable_profiler && (stats_flags & STATS_FUNC_AVG_RAW)) { func_avg_str = mcopystr( + "------------------------------------------\n" + "- Average time / execution for functions -\n" + "------------------------------------------\n"); + } + + char* line_time_sorted_mod_str = NULL; + if (!disable_profiler && (stats_flags & STATS_LINE_TIMES_SORTED_BY_MOD)) { + line_time_sorted_mod_str = mcopystr( + "------------------------------------------------\n" + "- Total time of code lines, sorted, per module -\n" + "------------------------------------------------\n"); + } + + char* line_count_sorted_mod_str = NULL; + if (!disable_coverage && (stats_flags & STATS_LINE_COUNT_SORTED_BY_MOD)) { + line_count_sorted_mod_str = mcopystr( + "-----------------------------------------------------\n" + "- Execution count of code lines, sorted, per module -\n" + "-----------------------------------------------------\n"); + } + + char* line_avg_sorted_mod_str = NULL; + if (!disable_profiler && !disable_coverage && (stats_flags & STATS_LINE_AVG_SORTED_BY_MOD)) { + line_avg_sorted_mod_str = mcopystr( + "--------------------------------------------------------------\n" + "- Average time / execution of code lines, sorted, per module -\n" + "--------------------------------------------------------------\n"); + } + + char* line_time_sorted_tot_str = NULL; + if (!disable_profiler && (stats_flags & STATS_LINE_TIMES_SORTED_TOTAL)) { + line_time_sorted_tot_str = mcopystr( + "-------------------------------------------\n" + "- Total time of code lines, sorted, total -\n" + "-------------------------------------------\n"); + } + + char* line_count_sorted_tot_str = NULL; + if (!disable_coverage && (stats_flags & STATS_LINE_COUNT_SORTED_TOTAL)) { + line_count_sorted_tot_str = mcopystr( "------------------------------------------------\n" - "- Average time / execution count for functions -\n" + "- Execution count of code lines, sorted, total -\n" "------------------------------------------------\n"); } + char* line_avg_sorted_tot_str = NULL; + if (!disable_profiler && !disable_coverage && (stats_flags & STATS_LINE_AVG_SORTED_TOTAL)) { + line_avg_sorted_tot_str = mcopystr( + "---------------------------------------------------------\n" + "- Average time / execution of code lines, sorted, total -\n" + "---------------------------------------------------------\n"); + } + + char* func_time_sorted_mod_str = NULL; + if (!disable_profiler && (stats_flags & STATS_FUNC_TIMES_SORTED_BY_MOD)) { + func_time_sorted_mod_str = mcopystr( + "-----------------------------------------------\n" + "- Total time of functions, sorted, per module -\n" + "-----------------------------------------------\n"); + } + + char* func_count_sorted_mod_str = NULL; + if (!disable_coverage && (stats_flags & STATS_FUNC_COUNT_SORTED_BY_MOD)) { + func_count_sorted_mod_str = mcopystr( + "----------------------------------------------------\n" + "- Execution count of functions, sorted, per module -\n" + "----------------------------------------------------\n"); + } + + char* func_avg_sorted_mod_str = NULL; + if (!disable_profiler && !disable_coverage && (stats_flags & STATS_FUNC_AVG_SORTED_BY_MOD)) { + func_avg_sorted_mod_str = mcopystr( + "-------------------------------------------------------------\n" + "- Average time / execution of functions, sorted, per module -\n" + "-------------------------------------------------------------\n"); + } + + char* func_time_sorted_tot_str = NULL; + if (!disable_profiler && (stats_flags & STATS_FUNC_TIMES_SORTED_TOTAL)) { + func_time_sorted_tot_str = mcopystr( + "------------------------------------------\n" + "- Total time of functions, sorted, total -\n" + "------------------------------------------\n"); + } + + char* func_count_sorted_tot_str = NULL; + if (!disable_coverage && (stats_flags & STATS_FUNC_COUNT_SORTED_TOTAL)) { + func_count_sorted_tot_str = mcopystr( + "-----------------------------------------------\n" + "- Execution count of functions, sorted, total -\n" + "-----------------------------------------------\n"); + } + + char* func_avg_sorted_tot_str = NULL; + if (!disable_profiler && !disable_coverage && (stats_flags & STATS_FUNC_AVG_SORTED_TOTAL)) { + func_avg_sorted_tot_str = mcopystr( + "--------------------------------------------------------\n" + "- Average time / execution of functions, sorted, total -\n" + "--------------------------------------------------------\n"); + } + + char* line_time_sorted_top10_str = NULL; + if (!disable_profiler && (stats_flags & STATS_TOP10_LINE_TIMES)) { + line_time_sorted_top10_str = mcopystr( + "------------------------------------\n" + "- Total time of code lines, top 10 -\n" + "------------------------------------\n"); + } + + char* line_count_sorted_top10_str = NULL; + if (!disable_coverage && (stats_flags & STATS_TOP10_LINE_COUNT)) { + line_count_sorted_top10_str = mcopystr( + "-----------------------------------------\n" + "- Execution count of code lines, top 10 -\n" + "-----------------------------------------\n"); + } + + char* line_avg_sorted_top10_str = NULL; + if (!disable_profiler && !disable_coverage && (stats_flags & STATS_TOP10_LINE_AVG)) { + line_avg_sorted_top10_str = mcopystr( + "--------------------------------------------------\n" + "- Average time / execution of code lines, top 10 -\n" + "--------------------------------------------------\n"); + } + + char* func_time_sorted_top10_str = NULL; + if (!disable_profiler && (stats_flags & STATS_TOP10_FUNC_TIMES)) { + func_time_sorted_top10_str = mcopystr( + "-----------------------------------\n" + "- Total time of functions, top 10 -\n" + "-----------------------------------\n"); + } + + char* func_count_sorted_top10_str = NULL; + if (!disable_coverage && (stats_flags & STATS_TOP10_FUNC_COUNT)) { + func_count_sorted_top10_str = mcopystr( + "----------------------------------------\n" + "- Execution count of functions, top 10 -\n" + "----------------------------------------\n"); + } + + char* func_avg_sorted_top10_str = NULL; + if (!disable_profiler && !disable_coverage && (stats_flags & STATS_TOP10_FUNC_AVG)) { + func_avg_sorted_top10_str = mcopystr( + "-------------------------------------------------\n" + "- Average time / execution of functions, top 10 -\n" + "-------------------------------------------------\n"); + } + + char* unused_lines_str = NULL; + char* unused_func_str = NULL; + if (!disable_coverage && (stats_flags & STATS_UNUSED_LINES)) { + unused_lines_str = mcopystr( + "---------------------\n" + "- Unused code lines -\n" + "---------------------\n"); + } + if (!disable_coverage && (stats_flags & STATS_UNUSED_FUNC)) { + unused_func_str = mcopystr( + "--------------------\n" + "- Unused functions -\n" + "--------------------\n"); + } + + // variables for counting totals, and for determining the amount of unused lines/functions + size_t total_code_lines = 0; + size_t total_functions = 0; + size_t used_code_lines = 0; + size_t used_functions = 0; + + // cached sizes of statistics data segments, needed to determine whether a separator + // is needed or not + size_t line_data_str_len = mstrlen(line_data_str); + size_t func_data_str_len = mstrlen(func_data_str); + size_t unused_lines_str_len = mstrlen(unused_lines_str); + size_t unused_func_str_len = mstrlen(unused_func_str); + size_t line_avg_str_len = mstrlen(line_avg_str); + size_t func_avg_str_len = mstrlen(func_avg_str); + // cycle through the database and gather the necessary data for (size_t i = 0; i < profiler_db.size(); ++i) { if (i > 0) { - // add separators between files - line_data_str = mputstr(line_data_str, "-------------------------------------------------\n"); - func_data_str = mputstr(func_data_str, "------------------------------------------------\n"); - if (!disable_profiler && !disable_coverage) { - line_avg_str = mputstr(line_avg_str, "-------------------------------------------------\n"); - func_avg_str = mputstr(func_avg_str, "------------------------------------------------\n"); + // add separators between files (only add them if the previous file actually added something) + if ((stats_flags & STATS_LINE_DATA_RAW) && line_data_str_len != mstrlen(line_data_str)) { + line_data_str = mputstr(line_data_str, "-------------------------------------------------\n"); + line_data_str_len = mstrlen(line_data_str); + } + if ((stats_flags & STATS_FUNC_DATA_RAW) && func_data_str_len != mstrlen(func_data_str)) { + func_data_str = mputstr(func_data_str, "------------------------------------------------\n"); + func_data_str_len = mstrlen(func_data_str); + } + if (!disable_coverage) { + if ((stats_flags & STATS_UNUSED_LINES) && unused_lines_str_len != mstrlen(unused_lines_str)) { + unused_lines_str = mputstr(unused_lines_str, "---------------------\n"); + unused_lines_str_len = mstrlen(unused_lines_str); + } + if ((stats_flags & STATS_UNUSED_FUNC) && unused_func_str_len != mstrlen(unused_func_str)) { + unused_func_str = mputstr(unused_func_str, "--------------------\n"); + unused_func_str_len = mstrlen(unused_func_str); + } + if (!disable_profiler) { + if ((stats_flags & STATS_LINE_AVG_RAW) && line_avg_str_len != mstrlen(line_avg_str)) { + line_avg_str = mputstr(line_avg_str, "-------------------------------------------\n"); + line_avg_str_len = mstrlen(line_avg_str); + } + if ((stats_flags & STATS_FUNC_AVG_RAW) && func_avg_str_len != mstrlen(func_avg_str)) { + func_avg_str = mputstr(func_avg_str, "------------------------------------------\n"); + func_avg_str_len = mstrlen(func_avg_str); + } + } } } // lines for (size_t j = 0; j < profiler_db[i].lines.size(); ++j) { - if (0.0 != profiler_db[i].lines[j].total_time || - 0 != profiler_db[i].lines[j].exec_count) { + // line specification (including function name for the function's start line) + char* line_spec_str = mprintf("%s:%d", profiler_db[i].filename, + profiler_db[i].lines[j].lineno); + int func = get_function(i, profiler_db[i].lines[j].lineno); + if (-1 != func) { + line_spec_str = mputprintf(line_spec_str, " [%s]", profiler_db[i].functions[func].name); + } + line_spec_str = mputstrn(line_spec_str, "\n", 1); + + if (disable_coverage || 0 != profiler_db[i].lines[j].exec_count) { if (!disable_profiler) { - line_data_str = mputprintf(line_data_str, "%.6lfs", profiler_db[i].lines[j].total_time); + if (stats_flags & STATS_LINE_DATA_RAW) { + char* total_time_str = timeval2string(profiler_db[i].lines[j].total_time); + line_data_str = mputprintf(line_data_str, "%ss", total_time_str); + Free(total_time_str); + } if (!disable_coverage) { - line_data_str = mputstrn(line_data_str, "\t/\t", 3); - line_avg_str = mputprintf(line_avg_str, "%.6lfs", - profiler_db[i].lines[j].total_time / profiler_db[i].lines[j].exec_count); + if (stats_flags & STATS_LINE_DATA_RAW) { + line_data_str = mputstrn(line_data_str, "\t/\t", 3); + } + if (stats_flags & STATS_LINE_AVG_RAW) { + double avg = (profiler_db[i].lines[j].total_time.tv_sec + + profiler_db[i].lines[j].total_time.tv_usec / 1000000.0) / + profiler_db[i].lines[j].exec_count; + char* total_time_str = timeval2string(profiler_db[i].lines[j].total_time); + line_avg_str = mputprintf(line_avg_str, "%.6lfs\t(%ss / %d)", + avg, total_time_str, profiler_db[i].lines[j].exec_count); + Free(total_time_str); + } } } - if (!disable_coverage) { + if (!disable_coverage && (stats_flags & STATS_LINE_DATA_RAW)) { line_data_str = mputprintf(line_data_str, "%d", profiler_db[i].lines[j].exec_count); } - - // line specification (including function name for the function's start line) - char* line_spec_str = mprintf("\t%s:%lu", profiler_db[i].filename, j); - int func = get_function(i, j); - if (-1 != func) { - line_spec_str = mputprintf(line_spec_str, " [%s]", profiler_db[i].functions[func].name); - } - line_spec_str = mputstrn(line_spec_str, "\n", 1); - + // add the line spec string to the other strings - line_data_str = mputstr(line_data_str, line_spec_str); - if (!disable_profiler && !disable_coverage) { - line_avg_str = mputstr(line_avg_str, line_spec_str); + if (stats_flags & STATS_LINE_DATA_RAW) { + line_data_str = mputprintf(line_data_str, "\t%s", line_spec_str); + } + if (!disable_profiler && !disable_coverage && (stats_flags & STATS_LINE_AVG_RAW)) { + line_avg_str = mputprintf(line_avg_str, "\t%s", line_spec_str); } + ++used_code_lines; } + else if (stats_flags & STATS_UNUSED_LINES) { + // unused line + unused_lines_str = mputstr(unused_lines_str, line_spec_str); + } + Free(line_spec_str); } // functions for (size_t j = 0; j < profiler_db[i].functions.size(); ++j) { - if (!disable_profiler) { - func_data_str = mputprintf(func_data_str, "%.6lfs", profiler_db[i].functions[j].total_time); - if (!disable_coverage) { - func_data_str = mputstrn(func_data_str, "\t/\t", 3); - func_avg_str = mputprintf(func_avg_str, "%.6lfs", - profiler_db[i].functions[j].total_time / profiler_db[i].functions[j].exec_count); + // functions specification + char* func_spec_str = mprintf("%s:%d [%s]\n", profiler_db[i].filename, + profiler_db[i].functions[j].lineno, profiler_db[i].functions[j].name); + + if (disable_coverage || 0 != profiler_db[i].functions[j].exec_count) { + if (!disable_profiler) { + if (stats_flags & STATS_FUNC_DATA_RAW) { + char* total_time_str = timeval2string(profiler_db[i].functions[j].total_time); + func_data_str = mputprintf(func_data_str, "%ss", total_time_str); + Free(total_time_str); + } + if (!disable_coverage) { + if (stats_flags & STATS_FUNC_DATA_RAW) { + func_data_str = mputstrn(func_data_str, "\t/\t", 3); + } + if (stats_flags & STATS_FUNC_AVG_RAW) { + double avg = (profiler_db[i].functions[j].total_time.tv_sec + + profiler_db[i].functions[j].total_time.tv_usec / 1000000.0) / + profiler_db[i].functions[j].exec_count; + char* total_time_str = timeval2string(profiler_db[i].functions[j].total_time); + func_avg_str = mputprintf(func_avg_str, "%.6lfs\t(%ss / %d)", + avg, total_time_str, profiler_db[i].functions[j].exec_count); + Free(total_time_str); + } + } + } + if (!disable_coverage && (stats_flags & STATS_FUNC_DATA_RAW)) { + func_data_str = mputprintf(func_data_str, "%d", profiler_db[i].functions[j].exec_count); + } + + // add the line spec string to the other strings + if (stats_flags & STATS_FUNC_DATA_RAW) { + func_data_str = mputprintf(func_data_str, "\t%s", func_spec_str); } + if (!disable_profiler && !disable_coverage && (stats_flags & STATS_FUNC_AVG_RAW)) { + func_avg_str = mputprintf(func_avg_str, "\t%s", func_spec_str); + } + + ++used_functions; } - if (!disable_coverage) { - func_data_str = mputprintf(func_data_str, "%d", profiler_db[i].functions[j].exec_count); + else if (stats_flags & STATS_UNUSED_FUNC) { + // unused function + unused_func_str = mputprintf(unused_func_str, func_spec_str); + } + Free(func_spec_str); + } + + // number of lines and functions + if (stats_flags & STATS_NUMBER_OF_LINES) { + line_func_count_str = mputprintf(line_func_count_str, "%s:\t%lu lines,\t%lu functions\n", + profiler_db[i].filename, profiler_db[i].lines.size(), profiler_db[i].functions.size()); + } + total_code_lines += profiler_db[i].lines.size(); + total_functions += profiler_db[i].functions.size(); + } + if (stats_flags & STATS_NUMBER_OF_LINES) { + line_func_count_str = mputprintf(line_func_count_str, + "--------------------------------------\n" + "Total:\t%lu lines,\t%lu functions\n", total_code_lines, total_functions); + } + + if (stats_flags & (STATS_TOP10_ALL_DATA | STATS_ALL_DATA_SORTED)) { + // copy code line and function info into stats_data_t containers for sorting + stats_data_t* code_line_stats = (stats_data_t*)Malloc(used_code_lines * sizeof(stats_data_t)); + stats_data_t* function_stats = (stats_data_t*)Malloc(used_functions * sizeof(stats_data_t)); + int line_index = 0; + int func_index = 0; + + for (size_t i = 0; i < profiler_db.size(); ++i) { + for (size_t j = 0; j < profiler_db[i].lines.size(); ++j) { + if (disable_coverage || 0 != profiler_db[i].lines[j].exec_count) { + code_line_stats[line_index].filename = profiler_db[i].filename; + code_line_stats[line_index].funcname = NULL; + code_line_stats[line_index].lineno = profiler_db[i].lines[j].lineno; + code_line_stats[line_index].total_time = profiler_db[i].lines[j].total_time; + code_line_stats[line_index].exec_count = profiler_db[i].lines[j].exec_count; + int func = get_function(i, profiler_db[i].lines[j].lineno); + if (-1 != func) { + code_line_stats[line_index].funcname = profiler_db[i].functions[func].name; + } + ++line_index; + } + } + for (size_t j = 0; j < profiler_db[i].functions.size(); ++j) { + if (disable_coverage || 0 != profiler_db[i].functions[j].exec_count) { + function_stats[func_index].filename = profiler_db[i].filename; + function_stats[func_index].funcname = profiler_db[i].functions[j].name; + function_stats[func_index].lineno = profiler_db[i].functions[j].lineno; + function_stats[func_index].total_time = profiler_db[i].functions[j].total_time; + function_stats[func_index].exec_count = profiler_db[i].functions[j].exec_count; + ++func_index; + } } + } - // functions specification - char* func_spec_str = mprintf("\t%s:%d [%s]\n", profiler_db[i].filename, - profiler_db[i].functions[j].lineno, profiler_db[i].functions[j].name); + if (!disable_profiler) { + // sort the code lines and functions by total time + qsort(code_line_stats, used_code_lines, sizeof(stats_data_t), &stats_data_cmp_time); + qsort(function_stats, used_functions, sizeof(stats_data_t), &stats_data_cmp_time); + + if (stats_flags & (STATS_LINE_TIMES_SORTED_TOTAL | STATS_TOP10_LINE_TIMES)) { + // cycle through the sorted code lines and gather the necessary data + for (size_t i = 0; i < used_code_lines; ++i) { + char* total_time_str = timeval2string(code_line_stats[i].total_time); + char* the_data = mprintf("%ss\t%s:%d", total_time_str, + code_line_stats[i].filename, code_line_stats[i].lineno); + Free(total_time_str); + if (NULL != code_line_stats[i].funcname) { + the_data = mputprintf(the_data, " [%s]", code_line_stats[i].funcname); + } + the_data = mputstrn(the_data, "\n", 1); + if (stats_flags & STATS_LINE_TIMES_SORTED_TOTAL) { + line_time_sorted_tot_str = mputstr(line_time_sorted_tot_str, the_data); + } + if (i < 10 && (stats_flags & STATS_TOP10_LINE_TIMES)) { + line_time_sorted_top10_str = mputprintf(line_time_sorted_top10_str, + "%2lu.\t%s", i + 1, the_data); + } + Free(the_data); + } + } + + if (stats_flags & (STATS_FUNC_TIMES_SORTED_TOTAL | STATS_TOP10_FUNC_TIMES)) { + // cycle through the sorted functions and gather the necessary data + for (size_t i = 0; i < used_functions; ++i) { + char* total_time_str = timeval2string(function_stats[i].total_time); + char* the_data = mprintf("%ss\t%s:%d [%s]\n", total_time_str, + function_stats[i].filename, function_stats[i].lineno, function_stats[i].funcname); + Free(total_time_str); + if (stats_flags & STATS_FUNC_TIMES_SORTED_TOTAL) { + func_time_sorted_tot_str = mputstr(func_time_sorted_tot_str, the_data); + } + if (i < 10 && (stats_flags & STATS_TOP10_FUNC_TIMES)) { + func_time_sorted_top10_str = mputprintf(func_time_sorted_top10_str, + "%2lu.\t%s", i + 1, the_data); + } + Free(the_data); + } + } + + if (stats_flags & (STATS_LINE_TIMES_SORTED_BY_MOD | STATS_FUNC_TIMES_SORTED_BY_MOD)) { + // cached string lengths, to avoid multiple separators after each other + size_t line_time_sorted_mod_str_len = mstrlen(line_time_sorted_mod_str); + size_t func_time_sorted_mod_str_len = mstrlen(func_time_sorted_mod_str); + + // cycle through the sorted statistics and gather the necessary data per module + for (size_t i = 0; i < profiler_db.size(); ++i) { + if (i > 0) { + if ((stats_flags & STATS_LINE_TIMES_SORTED_BY_MOD) && + line_time_sorted_mod_str_len != mstrlen(line_time_sorted_mod_str)) { + line_time_sorted_mod_str = mputstr(line_time_sorted_mod_str, + "------------------------------------------------\n"); + line_time_sorted_mod_str_len = mstrlen(line_time_sorted_mod_str); + } + if ((stats_flags & STATS_FUNC_TIMES_SORTED_BY_MOD) && + func_time_sorted_mod_str_len != mstrlen(func_time_sorted_mod_str)) { + func_time_sorted_mod_str = mputstr(func_time_sorted_mod_str, + "-----------------------------------------------\n"); + func_time_sorted_mod_str_len = mstrlen(func_time_sorted_mod_str); + } + } + if (stats_flags & STATS_LINE_TIMES_SORTED_BY_MOD) { + for (size_t j = 0; j < used_code_lines; ++j) { + if (0 == strcmp(code_line_stats[j].filename, profiler_db[i].filename)) { + char* total_time_str = timeval2string(code_line_stats[j].total_time); + line_time_sorted_mod_str = mputprintf(line_time_sorted_mod_str, + "%ss\t%s:%d", total_time_str, code_line_stats[j].filename, + code_line_stats[j].lineno); + Free(total_time_str); + if (NULL != code_line_stats[j].funcname) { + line_time_sorted_mod_str = mputprintf(line_time_sorted_mod_str, + " [%s]", code_line_stats[j].funcname); + } + line_time_sorted_mod_str = mputstrn(line_time_sorted_mod_str, "\n", 1); + } + } + } + if (stats_flags & STATS_FUNC_TIMES_SORTED_BY_MOD) { + for (size_t j = 0; j < used_functions; ++j) { + if (0 == strcmp(function_stats[j].filename, profiler_db[i].filename)) { + char* total_time_str = timeval2string(function_stats[j].total_time); + func_time_sorted_mod_str = mputprintf(func_time_sorted_mod_str, + "%ss\t%s:%d [%s]\n", total_time_str, function_stats[j].filename, + function_stats[j].lineno, function_stats[j].funcname); + Free(total_time_str); + } + } + } + } + } + } + + if (!disable_coverage) { + // sort the code lines and functions by execution count + qsort(code_line_stats, used_code_lines, sizeof(stats_data_t), &stats_data_cmp_count); + qsort(function_stats, used_functions, sizeof(stats_data_t), &stats_data_cmp_count); + + if (stats_flags & (STATS_LINE_COUNT_SORTED_TOTAL | STATS_TOP10_LINE_COUNT)) { + // cycle through the sorted code lines and gather the necessary data + for (size_t i = 0; i < used_code_lines; ++i) { + char* the_data = mprintf("%d\t%s:%d", code_line_stats[i].exec_count, + code_line_stats[i].filename, code_line_stats[i].lineno); + if (NULL != code_line_stats[i].funcname) { + the_data = mputprintf(the_data, " [%s]", code_line_stats[i].funcname); + } + the_data = mputstrn(the_data, "\n", 1); + if (stats_flags & STATS_LINE_COUNT_SORTED_TOTAL) { + line_count_sorted_tot_str = mputstr(line_count_sorted_tot_str, the_data); + } + if (i < 10 && (stats_flags & STATS_TOP10_LINE_COUNT)) { + line_count_sorted_top10_str = mputprintf(line_count_sorted_top10_str, + "%2lu.\t%s", i + 1, the_data); + } + Free(the_data); + } + } + + if (stats_flags & (STATS_FUNC_COUNT_SORTED_TOTAL | STATS_TOP10_FUNC_COUNT)) { + // cycle through the sorted functions and gather the necessary data + for (size_t i = 0; i < used_functions; ++i) { + char* the_data = mprintf("%d\t%s:%d [%s]\n", + function_stats[i].exec_count, function_stats[i].filename, + function_stats[i].lineno, function_stats[i].funcname); + if (stats_flags & STATS_FUNC_COUNT_SORTED_TOTAL) { + func_count_sorted_tot_str = mputstr(func_count_sorted_tot_str, the_data); + } + if (i < 10 && (stats_flags & STATS_TOP10_FUNC_COUNT)) { + func_count_sorted_top10_str = mputprintf(func_count_sorted_top10_str, + "%2lu.\t%s", i + 1, the_data); + } + Free(the_data); + } + } + + if (stats_flags & (STATS_LINE_COUNT_SORTED_BY_MOD | STATS_FUNC_COUNT_SORTED_BY_MOD)) { + // cached string lengths, to avoid multiple separators after each other + size_t line_count_sorted_mod_str_len = mstrlen(line_count_sorted_mod_str); + size_t func_count_sorted_mod_str_len = mstrlen(func_count_sorted_mod_str); + + // cycle through the sorted statistics and gather the necessary data per module + for (size_t i = 0; i < profiler_db.size(); ++i) { + if (i > 0) { + if ((stats_flags & STATS_LINE_COUNT_SORTED_BY_MOD) && + line_count_sorted_mod_str_len != mstrlen(line_count_sorted_mod_str)) { + line_count_sorted_mod_str = mputstr(line_count_sorted_mod_str, + "-----------------------------------------------------\n"); + line_count_sorted_mod_str_len = mstrlen(line_count_sorted_mod_str); + } + if ((stats_flags & STATS_FUNC_COUNT_SORTED_BY_MOD) && + func_count_sorted_mod_str_len != mstrlen(func_count_sorted_mod_str)) { + func_count_sorted_mod_str = mputstr(func_count_sorted_mod_str, + "----------------------------------------------------\n"); + func_count_sorted_mod_str_len = mstrlen(func_count_sorted_mod_str); + } + } + if (stats_flags & STATS_LINE_COUNT_SORTED_BY_MOD) { + for (size_t j = 0; j < used_code_lines; ++j) { + if (0 == strcmp(code_line_stats[j].filename, profiler_db[i].filename)) { + line_count_sorted_mod_str = mputprintf(line_count_sorted_mod_str, + "%d\t%s:%d", code_line_stats[j].exec_count, code_line_stats[j].filename, + code_line_stats[j].lineno); + if (NULL != code_line_stats[j].funcname) { + line_count_sorted_mod_str = mputprintf(line_count_sorted_mod_str, + " [%s]", code_line_stats[j].funcname); + } + line_count_sorted_mod_str = mputstrn(line_count_sorted_mod_str, "\n", 1); + } + } + } + if (stats_flags & STATS_FUNC_COUNT_SORTED_BY_MOD) { + for (size_t j = 0; j < used_functions; ++j) { + if (0 == strcmp(function_stats[j].filename, profiler_db[i].filename)) { + func_count_sorted_mod_str = mputprintf(func_count_sorted_mod_str, + "%d\t%s:%d [%s]\n", function_stats[j].exec_count, function_stats[j].filename, + function_stats[j].lineno, function_stats[j].funcname); + } + } + } + } + } + } + + if (!disable_profiler && !disable_coverage) { + // sort the code lines and functions by average time / execution + qsort(code_line_stats, used_code_lines, sizeof(stats_data_t), &stats_data_cmp_avg); + qsort(function_stats, used_functions, sizeof(stats_data_t), &stats_data_cmp_avg); + + if (stats_flags & (STATS_LINE_AVG_SORTED_TOTAL | STATS_TOP10_LINE_AVG)) { + // cycle through the sorted code lines and gather the necessary data + for (size_t i = 0; i < used_code_lines; ++i) { + double avg = (code_line_stats[i].total_time.tv_sec + + code_line_stats[i].total_time.tv_usec / 1000000.0) / + code_line_stats[i].exec_count; + char* total_time_str = timeval2string(code_line_stats[i].total_time); + char* the_data = mprintf("%.6lfs\t(%ss / %d)\t%s:%d", + avg, total_time_str, code_line_stats[i].exec_count, + code_line_stats[i].filename, code_line_stats[i].lineno); + Free(total_time_str); + if (NULL != code_line_stats[i].funcname) { + the_data = mputprintf(the_data, " [%s]", code_line_stats[i].funcname); + } + the_data = mputstrn(the_data, "\n", 1); + if (stats_flags & STATS_LINE_AVG_SORTED_TOTAL) { + line_avg_sorted_tot_str = mputstr(line_avg_sorted_tot_str, the_data); + } + if (i < 10 && (stats_flags & STATS_TOP10_LINE_AVG)) { + line_avg_sorted_top10_str = mputprintf(line_avg_sorted_top10_str, + "%2lu.\t%s", i + 1, the_data); + } + Free(the_data); + } + } + + if (stats_flags & (STATS_FUNC_AVG_SORTED_TOTAL | STATS_TOP10_FUNC_AVG)) { + // cycle through the sorted functions and gather the necessary data + for (size_t i = 0; i < used_functions; ++i) { + double avg = (function_stats[i].total_time.tv_sec + + function_stats[i].total_time.tv_usec / 1000000.0) / + function_stats[i].exec_count; + char* total_time_str = timeval2string(function_stats[i].total_time); + char* the_data = mprintf("%.6lfs\t(%ss / %d)\t%s:%d [%s]\n", + avg, total_time_str, function_stats[i].exec_count, + function_stats[i].filename, function_stats[i].lineno, function_stats[i].funcname); + Free(total_time_str); + if (stats_flags & STATS_FUNC_AVG_SORTED_TOTAL) { + func_avg_sorted_tot_str = mputstr(func_avg_sorted_tot_str, the_data); + } + if (i < 10 && (stats_flags & STATS_TOP10_FUNC_AVG)) { + func_avg_sorted_top10_str = mputprintf(func_avg_sorted_top10_str, + "%2lu.\t%s", i + 1, the_data); + } + Free(the_data); + } + } + + if (stats_flags & (STATS_LINE_AVG_SORTED_BY_MOD | STATS_FUNC_AVG_SORTED_BY_MOD)) { + // cached string lengths, to avoid multiple separators after each other + size_t line_avg_sorted_mod_str_len = mstrlen(line_avg_sorted_mod_str); + size_t func_avg_sorted_mod_str_len = mstrlen(func_avg_sorted_mod_str); - // add the line spec string to the other strings - func_data_str = mputstr(func_data_str, func_spec_str); - if (!disable_profiler && !disable_coverage) { - func_avg_str = mputstr(func_avg_str, func_spec_str); + // cycle through the sorted statistics and gather the necessary data per module + for (size_t i = 0; i < profiler_db.size(); ++i) { + if (i > 0) { + if ((stats_flags & STATS_LINE_AVG_SORTED_BY_MOD) && + line_avg_sorted_mod_str_len != mstrlen(line_avg_sorted_mod_str)) { + line_avg_sorted_mod_str = mputstr(line_avg_sorted_mod_str, + "--------------------------------------------------------------\n"); + line_avg_sorted_mod_str_len = mstrlen(line_avg_sorted_mod_str); + } + if ((stats_flags & STATS_FUNC_AVG_SORTED_BY_MOD) && + func_avg_sorted_mod_str_len != mstrlen(func_avg_sorted_mod_str)) { + func_avg_sorted_mod_str = mputstr(func_avg_sorted_mod_str, + "-------------------------------------------------------------\n"); + func_avg_sorted_mod_str_len = mstrlen(func_avg_sorted_mod_str); + } + } + if (stats_flags & STATS_LINE_AVG_SORTED_BY_MOD) { + for (size_t j = 0; j < used_code_lines; ++j) { + if (0 == strcmp(code_line_stats[j].filename, profiler_db[i].filename)) { + double avg = (code_line_stats[j].total_time.tv_sec + + code_line_stats[j].total_time.tv_usec / 1000000.0) / + code_line_stats[j].exec_count; + char* total_time_str = timeval2string(code_line_stats[j].total_time); + line_avg_sorted_mod_str = mputprintf(line_avg_sorted_mod_str, + "%.6lfs\t(%ss / %d)\t%s:%d", + avg, total_time_str, code_line_stats[j].exec_count, + code_line_stats[j].filename, code_line_stats[j].lineno); + Free(total_time_str); + if (NULL != code_line_stats[j].funcname) { + line_avg_sorted_mod_str = mputprintf(line_avg_sorted_mod_str, + " [%s]", code_line_stats[j].funcname); + } + line_avg_sorted_mod_str = mputstrn(line_avg_sorted_mod_str, "\n", 1); + } + } + } + if (stats_flags & STATS_FUNC_AVG_SORTED_BY_MOD) { + for (size_t j = 0; j < used_functions; ++j) { + if (0 == strcmp(function_stats[j].filename, profiler_db[i].filename)) { + double avg = (function_stats[j].total_time.tv_sec + + function_stats[j].total_time.tv_usec / 1000000.0) / + function_stats[j].exec_count; + char* total_time_str = timeval2string(function_stats[j].total_time); + func_avg_sorted_mod_str = mputprintf(func_avg_sorted_mod_str, + "%.6lfs\t(%ss / %d)\t%s:%d [%s]\n", + avg, total_time_str, function_stats[j].exec_count, + function_stats[j].filename, function_stats[j].lineno, function_stats[j].funcname); + Free(total_time_str); + } + } + } + } } } + + // free the stats data + Free(code_line_stats); + Free(function_stats); } // add new lines at the end of each segment - line_data_str = mputstrn(line_data_str, "\n", 1); - func_data_str = mputstrn(func_data_str, "\n", 1); - if (!disable_profiler && !disable_coverage) { - line_avg_str = mputstrn(line_avg_str, "\n", 1); - func_avg_str = mputstrn(func_avg_str, "\n", 1); + if (stats_flags & STATS_NUMBER_OF_LINES) { + line_func_count_str = mputstrn(line_func_count_str, "\n", 1); + } + if (stats_flags & STATS_LINE_DATA_RAW) { + line_data_str = mputstrn(line_data_str, "\n", 1); + } + if (stats_flags & STATS_FUNC_DATA_RAW) { + func_data_str = mputstrn(func_data_str, "\n", 1); + } + if (!disable_profiler) { + if (stats_flags & STATS_LINE_TIMES_SORTED_BY_MOD) { + line_time_sorted_mod_str = mputstrn(line_time_sorted_mod_str, "\n", 1); + } + if (stats_flags & STATS_LINE_TIMES_SORTED_TOTAL) { + line_time_sorted_tot_str = mputstrn(line_time_sorted_tot_str, "\n", 1); + } + if (stats_flags & STATS_FUNC_TIMES_SORTED_BY_MOD) { + func_time_sorted_mod_str = mputstrn(func_time_sorted_mod_str, "\n", 1); + } + if (stats_flags & STATS_FUNC_TIMES_SORTED_TOTAL) { + func_time_sorted_tot_str = mputstrn(func_time_sorted_tot_str, "\n", 1); + } + if (stats_flags & STATS_TOP10_LINE_TIMES) { + line_time_sorted_top10_str = mputstrn(line_time_sorted_top10_str, "\n", 1); + } + if (stats_flags & STATS_TOP10_FUNC_TIMES) { + func_time_sorted_top10_str = mputstrn(func_time_sorted_top10_str, "\n", 1); + } + if (!disable_coverage) { + if (stats_flags & STATS_LINE_AVG_RAW) { + line_avg_str = mputstrn(line_avg_str, "\n", 1); + } + if (stats_flags & STATS_LINE_AVG_RAW) { + func_avg_str = mputstrn(func_avg_str, "\n", 1); + } + if (stats_flags & STATS_LINE_AVG_SORTED_BY_MOD) { + line_avg_sorted_mod_str = mputstrn(line_avg_sorted_mod_str, "\n", 1); + } + if (stats_flags & STATS_LINE_AVG_SORTED_TOTAL) { + line_avg_sorted_tot_str = mputstrn(line_avg_sorted_tot_str, "\n", 1); + } + if (stats_flags & STATS_FUNC_AVG_SORTED_BY_MOD) { + func_avg_sorted_mod_str = mputstrn(func_avg_sorted_mod_str, "\n", 1); + } + if (stats_flags & STATS_FUNC_AVG_SORTED_TOTAL) { + func_avg_sorted_tot_str = mputstrn(func_avg_sorted_tot_str, "\n", 1); + } + if (stats_flags & STATS_TOP10_LINE_AVG) { + line_avg_sorted_top10_str = mputstrn(line_avg_sorted_top10_str, "\n", 1); + } + if (stats_flags & STATS_TOP10_FUNC_AVG) { + func_avg_sorted_top10_str = mputstrn(func_avg_sorted_top10_str, "\n", 1); + } + } + } + if (!disable_coverage) { + if (stats_flags & STATS_LINE_COUNT_SORTED_BY_MOD) { + line_count_sorted_mod_str = mputstrn(line_count_sorted_mod_str, "\n", 1); + } + if (stats_flags & STATS_LINE_COUNT_SORTED_TOTAL) { + line_count_sorted_tot_str = mputstrn(line_count_sorted_tot_str, "\n", 1); + } + if (stats_flags & STATS_FUNC_COUNT_SORTED_BY_MOD) { + func_count_sorted_mod_str = mputstrn(func_count_sorted_mod_str, "\n", 1); + } + if (stats_flags & STATS_FUNC_COUNT_SORTED_TOTAL) { + func_count_sorted_tot_str = mputstrn(func_count_sorted_tot_str, "\n", 1); + } + if (stats_flags & STATS_TOP10_LINE_COUNT) { + line_count_sorted_top10_str = mputstrn(line_count_sorted_top10_str, "\n", 1); + } + if (stats_flags & STATS_TOP10_FUNC_COUNT) { + func_count_sorted_top10_str = mputstrn(func_count_sorted_top10_str, "\n", 1); + } + if (stats_flags & STATS_UNUSED_LINES) { + unused_lines_str = mputstrn(unused_lines_str, "\n", 1); + } + if (stats_flags & STATS_UNUSED_FUNC) { + unused_func_str = mputstrn(unused_func_str, "\n", 1); + } } // write the statistics to the specified file @@ -587,29 +1482,83 @@ void TTCN3_Profiler::print_stats() "statistics will not be saved.", stats_filename); return; } - fprintf(file, "%s%s%s%s%s" - , title_str, line_data_str - , (disable_profiler || disable_coverage) ? "" : line_avg_str - , func_data_str, (disable_profiler || disable_coverage) ? "" : func_avg_str); + // by now the strings for all disabled statistics entries should be null + fprintf(file, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" + , title_str + , (NULL != line_func_count_str) ? line_func_count_str : "" + , (NULL != line_data_str) ? line_data_str : "" + , (NULL != line_avg_str) ? line_avg_str : "" + , (NULL != func_data_str) ? func_data_str : "" + , (NULL != func_avg_str) ? func_avg_str : "" + , (NULL != line_time_sorted_mod_str) ? line_time_sorted_mod_str : "" + , (NULL != line_time_sorted_tot_str) ? line_time_sorted_tot_str : "" + , (NULL != func_time_sorted_mod_str) ? func_time_sorted_mod_str : "" + , (NULL != func_time_sorted_tot_str) ? func_time_sorted_tot_str : "" + , (NULL != line_count_sorted_mod_str) ? line_count_sorted_mod_str : "" + , (NULL != line_count_sorted_tot_str) ? line_count_sorted_tot_str : "" + , (NULL != func_count_sorted_mod_str) ? func_count_sorted_mod_str : "" + , (NULL != func_count_sorted_tot_str) ? func_count_sorted_tot_str : "" + , (NULL != line_avg_sorted_mod_str) ? line_avg_sorted_mod_str : "" + , (NULL != line_avg_sorted_tot_str) ? line_avg_sorted_tot_str : "" + , (NULL != func_avg_sorted_mod_str) ? func_avg_sorted_mod_str : "" + , (NULL != func_avg_sorted_tot_str) ? func_avg_sorted_tot_str : "" + , (NULL != line_time_sorted_top10_str) ? line_time_sorted_top10_str : "" + , (NULL != func_time_sorted_top10_str) ? func_time_sorted_top10_str : "" + , (NULL != line_count_sorted_top10_str) ? line_count_sorted_top10_str : "" + , (NULL != func_count_sorted_top10_str) ? func_count_sorted_top10_str : "" + , (NULL != line_avg_sorted_top10_str) ? line_avg_sorted_top10_str : "" + , (NULL != func_avg_sorted_top10_str) ? func_avg_sorted_top10_str : "" + , (NULL != unused_lines_str) ? unused_lines_str : "" + , (NULL != unused_func_str) ? unused_func_str : ""); + fclose(file); + + // free the strings + Free(title_str); + Free(line_func_count_str); + Free(line_data_str); + Free(line_avg_str); + Free(func_data_str); + Free(func_avg_str); + Free(line_time_sorted_mod_str); + Free(line_time_sorted_tot_str); + Free(func_time_sorted_mod_str); + Free(func_time_sorted_tot_str); + Free(line_count_sorted_mod_str); + Free(line_count_sorted_tot_str); + Free(func_count_sorted_mod_str); + Free(func_count_sorted_tot_str); + Free(line_avg_sorted_mod_str); + Free(line_avg_sorted_tot_str); + Free(func_avg_sorted_mod_str); + Free(func_avg_sorted_tot_str); + Free(line_time_sorted_top10_str); + Free(func_time_sorted_top10_str); + Free(line_count_sorted_top10_str); + Free(func_count_sorted_top10_str); + Free(line_avg_sorted_top10_str); + Free(func_avg_sorted_top10_str); + Free(unused_lines_str); + Free(unused_func_str); } void TTCN3_Profiler::reset() { - prev_time = 0.0; + prev_time.tv_sec = 0; + prev_time.tv_usec = 0; prev_file = NULL; prev_line = -1; - prev_stack_len = 0; + prev_stack_len = -1; } -double TTCN3_Profiler::get_time() +timeval TTCN3_Profiler::get_time() { timeval tv; gettimeofday(&tv, NULL); - return tv.tv_sec + tv.tv_usec / 1000000.0; + return tv; } -void TTCN3_Profiler::enter_function(const char* filename, int lineno, const char* function_name) +void TTCN3_Profiler::enter_function(const char* filename, int lineno) { if (disable_profiler && disable_coverage) { return; @@ -619,17 +1568,13 @@ void TTCN3_Profiler::enter_function(const char* filename, int lineno, const char // is measured by using the stack depth. execute_line(filename, lineno); - int element = get_element(filename); - - // store function data - int func = get_function(element, lineno); - if (-1 == func) { - create_function(element, lineno, function_name); - func = profiler_db[element].functions.size() - 1; - } - - if (!disable_coverage) { - ++profiler_db[element].functions[func].exec_count; + if (!stopped) { + int element = get_element(filename); + + // store function data + if (!disable_coverage) { + ++profiler_db[element].functions[get_function(element, lineno)].exec_count; + } } } @@ -639,35 +1584,33 @@ void TTCN3_Profiler::execute_line(const char* filename, int lineno) return; } - if (!disable_profiler) { - double currentTime = get_time(); - - // prev line should not be measured, because it is still running: we are in longer stack level - if (0.0 == prev_time || TTCN3_Stack_Depth::depth() > prev_stack_len) { - // add prev timer to call stack: - TTCN3_Stack_Depth::add_stack(prev_stack_len, prev_file, filename, prev_line, lineno); - } - else { - // if stack level is the same or higher: current line should be measured: - double elapsed = currentTime - prev_time; + if (!disable_profiler && TTCN3_Stack_Depth::depth() > prev_stack_len) { + // this line is in a different function than the last one, don't measure anything + TTCN3_Stack_Depth::add_stack(prev_stack_len, prev_file, filename, prev_line, lineno); + } + + if (!stopped) { + if (!disable_profiler && NULL != prev_file) { + // this line is in the same function as the previous one, measure the time difference + timeval elapsed = subtract_timeval(get_time(), prev_time); - // add the elapsed time to the time of the previous line: + // add the elapsed time to the total time of the previous line add_line_time(elapsed, get_element(prev_file), prev_line); TTCN3_Stack_Depth::update_stack_elapsed(elapsed); } - } - - // several instructions could be in the same line, only count the line once - if (!disable_coverage && (lineno != prev_line || NULL == prev_file || - 0 != strcmp(prev_file, filename))) { - int element = get_element(filename); - - // make sure the line exists in the database - create_lines(element, lineno); - - // increase line execution count - ++profiler_db[element].lines[lineno].exec_count; + + // functions starting at line 0 are: pre_init_module and post_init_module, + // don't include them in the database (as they don't appear in the TTCN-3 code), + // but include any actual code lines they may contain + // also, several instructions could be in the same line, only count the line once + if (0 != lineno && !disable_coverage && (lineno != prev_line || NULL == prev_file || + 0 != strcmp(prev_file, filename))) { + int element = get_element(filename); + + // increase line execution count + ++profiler_db[element].lines[get_line(element, lineno)].exec_count; + } } // store the current location as previous for the next call @@ -702,65 +1645,69 @@ void TTCN3_Profiler::create_function(int element, int lineno, const char* functi { profiler_db_item_t::profiler_function_data_t func_data; func_data.lineno = lineno; - func_data.total_time = 0.0; + func_data.total_time.tv_sec = 0; + func_data.total_time.tv_usec = 0; func_data.exec_count = 0; func_data.name = mcopystr(function_name); profiler_db[element].functions.push_back(func_data); } -void TTCN3_Profiler::create_lines(int element, int lineno) +int TTCN3_Profiler::get_line(int element, int lineno) { - // set 0 for the unknown lines - size_t line_no = lineno; - if (profiler_db[element].lines.size() <= line_no) { - for (size_t i = profiler_db[element].lines.size(); i <= line_no; ++i) { - profiler_db_item_t::profiler_line_data_t line_data; - line_data.total_time = 0.0; - line_data.exec_count = 0; - profiler_db[element].lines.push_back(line_data); + for (size_t i = 0; i < profiler_db[element].lines.size(); ++i) { + if (profiler_db[element].lines[i].lineno == lineno) { + return i; } } + return -1; +} + +void TTCN3_Profiler::create_line(int element, int lineno) +{ + profiler_db_item_t::profiler_line_data_t line_data; + line_data.lineno = lineno; + line_data.total_time.tv_sec = 0; + line_data.total_time.tv_usec = 0; + line_data.exec_count = 0; + profiler_db[element].lines.push_back(line_data); } -void TTCN3_Profiler::add_line_time(double elapsed, int element, int lineno) +void TTCN3_Profiler::add_line_time(timeval elapsed, int element, int lineno) { - if (-1 == lineno) { + if (0 == lineno) { return; } - - // ensure the line data exists - create_lines(element, lineno); - - // increase the time of the line in the current file: - profiler_db[element].lines[lineno].total_time += elapsed; + profiler_db[element].lines[get_line(element, lineno)].total_time = add_timeval( + profiler_db[element].lines[get_line(element, lineno)].total_time, elapsed); } -void TTCN3_Profiler::add_function_time(double elapsed, int element, int lineno) +void TTCN3_Profiler::add_function_time(timeval elapsed, int element, int lineno) { int func = get_function(element, lineno); if (-1 == func) { return; } - profiler_db[element].functions[func].total_time += elapsed; + profiler_db[element].functions[func].total_time = add_timeval( + profiler_db[element].functions[func].total_time, elapsed); } void TTCN3_Profiler::update_last() { - if (0.0 == prev_time) { + if (stopped || (0 == prev_time.tv_sec && 0 == prev_time.tv_usec) || NULL == prev_file) { return; } - - double currentTime = get_time(); - double elapsed = currentTime - prev_time; + + timeval elapsed = subtract_timeval(get_time(), prev_time); int element = get_element(prev_file); - // add the elapsed time to the time of the previous line: + // add the elapsed time to the total time of the previous line add_line_time(elapsed, element, prev_line); TTCN3_Stack_Depth::update_stack_elapsed(elapsed); - // reset measurement: - prev_time = 0.0; + // reset measurement + prev_time.tv_sec = 0; + prev_time.tv_usec = 0; } void TTCN3_Profiler::set_prev(int stack_len, const char* filename, int lineno) @@ -779,6 +1726,8 @@ void TTCN3_Profiler::set_prev(int stack_len, const char* filename, int lineno) int TTCN3_Stack_Depth::current_depth = -1; Vector TTCN3_Stack_Depth::call_stack_timer_db; +boolean TTCN3_Stack_Depth::net_line_times = FALSE; +boolean TTCN3_Stack_Depth::net_func_times = FALSE; TTCN3_Stack_Depth::TTCN3_Stack_Depth() { @@ -801,6 +1750,16 @@ TTCN3_Stack_Depth::~TTCN3_Stack_Depth() --current_depth; } +void TTCN3_Stack_Depth::set_net_line_times(boolean p_net_line_times) +{ + net_line_times = p_net_line_times; +} + +void TTCN3_Stack_Depth::set_net_func_times(boolean p_net_func_times) +{ + net_func_times = p_net_func_times; +} + void TTCN3_Stack_Depth::add_stack(int stack_len, const char* caller_file, const char* func_file, int caller_line, int start_line) { @@ -810,19 +1769,55 @@ void TTCN3_Stack_Depth::add_stack(int stack_len, const char* caller_file, const item.func_file = func_file; item.caller_line = caller_line; item.start_line = start_line; - item.elapsed = 0.0; + item.elapsed.tv_sec = 0; + item.elapsed.tv_usec = 0; + item.first_call = true; + item.recursive_call = false; + + if (!net_line_times || !net_func_times) { + // check if it's a recursive function + for (int i = current_depth - 1; i >= 0 ; --i) { + if (call_stack_timer_db[i].start_line == start_line && + 0 == strcmp(call_stack_timer_db[i].func_file, func_file)) { + item.recursive_call = true; + + // check if the caller is new + if (call_stack_timer_db[i].caller_line == caller_line && + ((NULL == call_stack_timer_db[i].caller_file && NULL == caller_file) || + (NULL != call_stack_timer_db[i].caller_file && NULL != caller_file && + 0 == strcmp(call_stack_timer_db[i].caller_file, caller_file)))) { + item.first_call = false; + break; + } + } + } + } + call_stack_timer_db.push_back(item); } void TTCN3_Stack_Depth::remove_stack() { - // if stack level is the same or higher: measure the time: - double elapsed = call_stack_timer_db[current_depth].elapsed; - - int element = ttcn3_prof.get_element(call_stack_timer_db[current_depth].func_file); - - // add elapsed time to the total execution time of the previous line: - ttcn3_prof.add_function_time(elapsed, element, call_stack_timer_db[current_depth].start_line); + // add the time gathered for this stack level to the appropriate line and function + // except for functions starting at line 0 (pre_init_module and post_init_module) + if (0 != call_stack_timer_db[current_depth].start_line) { + timeval elapsed = call_stack_timer_db[current_depth].elapsed; + if (!net_line_times && NULL != call_stack_timer_db[current_depth].caller_file && + call_stack_timer_db[current_depth].first_call) { + // add the elapsed time to the caller line, if it exists + // (only add it once for recursive functions, at the first call) + ttcn3_prof.add_line_time(elapsed, + ttcn3_prof.get_element(call_stack_timer_db[current_depth].caller_file), + call_stack_timer_db[current_depth].caller_line); + } + if (!net_func_times && !call_stack_timer_db[current_depth].recursive_call) { + // add the elapsed time to the called function, if it's not recursive + // (in case of net function times this has already been done in update_stack_elapsed) + ttcn3_prof.add_function_time(elapsed, + ttcn3_prof.get_element(call_stack_timer_db[current_depth].func_file), + call_stack_timer_db[current_depth].start_line); + } + } ttcn3_prof.set_prev(call_stack_timer_db[current_depth].stack_len, call_stack_timer_db[current_depth].caller_file, @@ -831,9 +1826,21 @@ void TTCN3_Stack_Depth::remove_stack() call_stack_timer_db.erase_at(current_depth); } -void TTCN3_Stack_Depth::update_stack_elapsed(double elapsed) +void TTCN3_Stack_Depth::update_stack_elapsed(timeval elapsed) { - for(int i = 0; i <= current_depth; i++) { - call_stack_timer_db[i].elapsed += elapsed; + // if function times are net times, only add the elapsed time to the current function + if (net_func_times) { + ttcn3_prof.add_function_time(elapsed, + ttcn3_prof.get_element(call_stack_timer_db[current_depth].func_file), + call_stack_timer_db[current_depth].start_line); } -} \ No newline at end of file + if (!net_line_times || !net_func_times) { + // cycle through the stack and add the elapsed time to the entries where + // the function/caller pair appears for the first time (marked by 'first_call') + for(int i = 0; i <= current_depth; ++i) { + if (call_stack_timer_db[i].first_call) { + call_stack_timer_db[i].elapsed = add_timeval(call_stack_timer_db[i].elapsed, elapsed); + } + } + } +} diff --git a/core/Profiler.hh b/core/Profiler.hh index c84bb97..67b4081 100644 --- a/core/Profiler.hh +++ b/core/Profiler.hh @@ -11,6 +11,7 @@ #include "Vector.hh" #include "Types.h" +#include /** This class performs profiling and code coverage on lines and functions in * TTCN-3 code (requires the -z compiler option). @@ -22,8 +23,10 @@ public: struct profiler_db_item_t { /** Database entry for one line */ struct profiler_line_data_t { + /** Line number */ + int lineno; /** The line's total execution time */ - double total_time; + timeval total_time; /** The number of times this line was executed */ int exec_count; }; @@ -34,26 +37,78 @@ public: /** Function starting line */ int lineno; /** The function's total execution time */ - double total_time; + timeval total_time; /** The number of times this function was executed */ int exec_count; }; /** TTCN-3 File name (relative path, owned) */ char* filename; - /** Contains database entries for all the lines in this file (its index is - * the line number, so there may be empty elements) */ + /** Contains database entries for all the lines in this file */ Vector lines; - /** Contains database entries for all the functions in this file (one entry - * for each function) */ + /** Contains database entries for all the functions in this file */ Vector functions; }; + enum profiler_stats_flag_t { + // flags for each statistics entry + STATS_NUMBER_OF_LINES = 0x0000001, + STATS_LINE_DATA_RAW = 0x0000002, + STATS_FUNC_DATA_RAW = 0x0000004, + STATS_LINE_AVG_RAW = 0x0000008, + STATS_FUNC_AVG_RAW = 0x0000010, + STATS_LINE_TIMES_SORTED_BY_MOD = 0x0000020, + STATS_FUNC_TIMES_SORTED_BY_MOD = 0x0000040, + STATS_LINE_TIMES_SORTED_TOTAL = 0x0000080, + STATS_FUNC_TIMES_SORTED_TOTAL = 0x0000100, + STATS_LINE_COUNT_SORTED_BY_MOD = 0x0000200, + STATS_FUNC_COUNT_SORTED_BY_MOD = 0x0000400, + STATS_LINE_COUNT_SORTED_TOTAL = 0x0000800, + STATS_FUNC_COUNT_SORTED_TOTAL = 0x0001000, + STATS_LINE_AVG_SORTED_BY_MOD = 0x0002000, + STATS_FUNC_AVG_SORTED_BY_MOD = 0x0004000, + STATS_LINE_AVG_SORTED_TOTAL = 0x0008000, + STATS_FUNC_AVG_SORTED_TOTAL = 0x0010000, + STATS_TOP10_LINE_TIMES = 0x0020000, + STATS_TOP10_FUNC_TIMES = 0x0040000, + STATS_TOP10_LINE_COUNT = 0x0080000, + STATS_TOP10_FUNC_COUNT = 0x0100000, + STATS_TOP10_LINE_AVG = 0x0200000, + STATS_TOP10_FUNC_AVG = 0x0400000, + STATS_UNUSED_LINES = 0x0800000, + STATS_UNUSED_FUNC = 0x1000000, + // grouped entries + STATS_ALL_RAW_DATA = 0x000001E, + STATS_LINE_DATA_SORTED_BY_MOD = 0x0002220, + STATS_FUNC_DATA_SORTED_BY_MOD = 0x0004440, + STATS_LINE_DATA_SORTED_TOTAL = 0x0008880, + STATS_FUNC_DATA_SORTED_TOTAL = 0x0011100, + STATS_LINE_DATA_SORTED = 0x000AAA0, + STATS_FUNC_DATA_SORTED = 0x0015540, + STATS_ALL_DATA_SORTED = 0x001FFE0, + STATS_TOP10_LINE_DATA = 0x02A0000, + STATS_TOP10_FUNC_DATA = 0x0540000, + STATS_TOP10_ALL_DATA = 0x07E0000, + STATS_UNUSED_DATA = 0x1800000, + STATS_ALL = 0x1FFFFFF + }; + /** Constructor */ TTCN3_Profiler(); - /** Destructor - adds all gathered data to the database file and prints - * statistics if necessary */ + /** Destructor + * In single mode and in the Host Controller's process in parallel mode: + * - imports data gathered on the previous run (if data aggregation is set) + * - imports data gathered by all other processes (only in parallel mode) + * - prints statistics (if necessary) + * Afterwards, in all cases: + * - exports data gathered in this process (including any imported data) + * - frees allocated memory */ ~TTCN3_Profiler(); + /** Reactivates the profiler if it was stopped before, data gathering will resume */ + void start(); + /** Deactivates the profiler, no more data will be gathered until it is reactivated */ + void stop(); + /** Enables or disables profiling - called by the config file parser */ void set_disable_profiler(boolean p_disable_profiler); /** Enables or disables code coverage - called by the config file parser */ @@ -66,14 +121,21 @@ public: void set_stats_filename(const char* p_stats_filename); /** Enables or disables the printing of statistics - called by the config file parser */ void set_disable_stats(boolean p_disable_stats); + /** Disables all statistics entry flags - called by the config file parser */ + void reset_stats_flags(); + /** Enables the specified statistics entry flags - called by the config file parser */ + void add_stats_flags(unsigned int p_flags); /** Returns true if profiling is disabled */ boolean is_profiler_disabled() const; + /** Returns true if the profiler is currently running (not stopped) */ + boolean is_running() const; - /** Deletes the database file if data aggregation is not set */ - void init_data_file(); + /** Stores the component reference of a newly created PTC (in parallel mode only) */ + void add_ptc(component p_comp_ref); + /** Adds the data from the database file to the local database */ - void import_data(); + void import_data(component p_comp_ref = NULL_COMPREF); /** Writes the local database to the database file (overwrites the file) */ void export_data(); @@ -83,9 +145,9 @@ public: /** Resets data related to the previous location and time (the local database is not changed) */ void reset(); /** Returns the current time (in seconds) */ - static double get_time(); + static timeval get_time(); /** Called when a TTCN-3 function starts execution - stores data */ - void enter_function(const char* filename, int lineno, const char* function_name); + void enter_function(const char* filename, int lineno); /** Called when a TTCN-3 code line starts execution - stores data */ void execute_line(const char* filename, int lineno); /** Returns the index of a TTCN-3 file's entry in the local database */ @@ -99,18 +161,22 @@ public: * @param lineno function start line * @param function_name name of the function */ void create_function(int element, int lineno, const char* function_name); - /** Creates TTCN-3 code line entries up to the given line number */ - void create_lines(int element, int lineno); + /** Returns the index of a TTCN-3 code line's entry in the database */ + int get_line(int element, int lineno); + /** Creates a new TTCN-3 code line entry and inserts it into the database */ + void create_line(int element, int lineno); /** Adds elapsed time to the specified TTCN-3 code line's total time */ - void add_line_time(double elapsed, int element, int lineno); + void add_line_time(timeval elapsed, int element, int lineno); /** Adds elapsed time to the specified TTCN-3 function's total time*/ - void add_function_time(double elapsed, int element, int lineno); + void add_function_time(timeval elapsed, int element, int lineno); /** Called when a TTCN-3 function's execution ends - stores data */ void update_last(); /** Stores data related to the previous location */ void set_prev(int stack_len, const char* filename, int lineno); private: + /** If true, the profiler ignores execute_line, enter_function and update_last calls */ + boolean stopped; /** Profiling is disabled if true */ boolean disable_profiler; /** Code coverage is disabled if true */ @@ -124,9 +190,10 @@ private: char* stats_filename; /** Statistics will not be calculated and printed if true */ boolean disable_stats; - + /** Flags that determine which statistics entries are displayed */ + unsigned int stats_flags; /** The time measured at the previous TTCN-3 code line */ - double prev_time; + timeval prev_time; /** Name of the TTCN-3 file, where the last executed line is (not owned) */ const char* prev_file; /** The number of the previously executed line */ @@ -135,6 +202,9 @@ private: Vector profiler_db; /** The stack length at the previously executed line */ int prev_stack_len; + /** Contains the component references of all PTCs (only relevant in the Host + * Controller's process, in parallel mode) */ + Vector ptc_list; }; /** The global TTCN3_Profiler object @@ -151,21 +221,27 @@ extern TTCN3_Profiler ttcn3_prof; * Its instances depict the current call stack. One instance is created at the start * of each TTCN-3 function execution, and it's destroyed at the function's end. */ class TTCN3_Stack_Depth { -public: +public: /** Entry for one function call in the call stack */ struct call_stack_timer_item_t { /** Stack length before the function call */ int stack_len; /** File name, where the calling function is declared (not owned) */ const char* caller_file; - /** File name, where the called function is declared (not owned)*/ + /** File name, where the called function is declared (not owned) */ const char* func_file; /** Calling function's start line */ int caller_line; /** Called function's start line */ int start_line; /** Time elapsed in this function call */ - double elapsed; + timeval elapsed; + /** If true, then this is the first entry of this function and caller pair + * (only used in case of gross line times) */ + boolean first_call; + /** If true, then this function has appeared before in the call stack + * (only used in case of gross function times)*/ + boolean recursive_call; }; /** Constructor - increases the stack depth */ @@ -173,6 +249,11 @@ public: /** Destructor - decreases the stack depth, updates call times in the profiler */ ~TTCN3_Stack_Depth(); + /** Sets whether line times should include function call times - called by the config file parser */ + static void set_net_line_times(boolean p_net_line_times); + /** Sets whether function times should include embedded function times - called by the config file parser */ + static void set_net_func_times(boolean p_net_func_times); + /** Returns the current stack depth */ static int depth() { return current_depth; } /** Inserts a new function call entry into the call stack database */ @@ -181,12 +262,18 @@ public: /** Removes the last entry from the call stack database */ static void remove_stack(); /** Adds the elapsed time to all entries in the call stack database */ - static void update_stack_elapsed(double elapsed); + static void update_stack_elapsed(timeval elapsed); private: /** The current stack depth (starts from 0)*/ static int current_depth; /** The call stack database */ static Vector call_stack_timer_db; + /** If true, line times will not include the execution times of functions called + * in that line */ + static boolean net_line_times; + /** If true, function times will not include the execution times of functions + * called in that function */ + static boolean net_func_times; }; #endif /* PROFILER_HH */ diff --git a/core/RAW.cc b/core/RAW.cc index b316386..72947e8 100644 --- a/core/RAW.cc +++ b/core/RAW.cc @@ -340,7 +340,7 @@ int RAW_encode_enum_type(const TTCN_Typedescriptor_t& p_td, my_raw.ptroffset = p_td.raw->ptroffset; my_raw.unit = p_td.raw->unit; TTCN_Typedescriptor_t my_descr = { p_td.name, 0, &my_raw, NULL, NULL, NULL, - TTCN_Typedescriptor_t::DONTCARE }; + NULL, TTCN_Typedescriptor_t::DONTCARE }; INTEGER i(integer_value); i.RAW_encode(my_descr, myleaf); // myleaf.align=0;//p_td.raw->endianness==ORDER_MSB?min_bits_enum-fl:fl-min_bits_enum; @@ -369,7 +369,7 @@ int RAW_decode_enum_type(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& buff, my_raw.ptroffset = p_td.raw->ptroffset; my_raw.unit = p_td.raw->unit; TTCN_Typedescriptor_t my_descr = { p_td.name, 0, &my_raw, NULL, NULL, NULL, - TTCN_Typedescriptor_t::DONTCARE }; + NULL, TTCN_Typedescriptor_t::DONTCARE }; INTEGER i; /* if(p_td.raw->endianness==ORDER_MSB) buff.increase_pos_bit(fl-min_bits_enum);*/ diff --git a/core/RefdIndex.hh b/core/RefdIndex.hh new file mode 100644 index 0000000..2b2f4a6 --- /dev/null +++ b/core/RefdIndex.hh @@ -0,0 +1,55 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2000-2015 Ericsson Telecom AB +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +/////////////////////////////////////////////////////////////////////////////// + +#ifndef REFDINDEX_HH +#define REFDINDEX_HH + +#ifdef TITAN_RUNTIME_2 + +/** This class contains the functions needed for adding and removing referenced + * indexes to record of/set of types and the optional type (only in RT2). + * By default the functions are empty.*/ +class RefdIndexInterface +{ +public: + virtual ~RefdIndexInterface() {} + virtual void add_refd_index(int) {} + virtual void remove_refd_index(int) {} +}; + +/** References to record of/set of elements through 'out' and 'inout' function + * parameters are handled by this class. + * Usage: create instances of this class before the function call (one instance + * for each referenced index), and place the instances and the function call in + * a block (so the destructor is called immediately after the function call). + * This way the referenced indexes are cleaned up even if the function call ends + * with an exception (DTE) */ +class RefdIndexHandler +{ +public: + RefdIndexHandler(RefdIndexInterface* p_container, int p_index) + { + container = p_container; + index = p_index; + container->add_refd_index(index); + } + + ~RefdIndexHandler() + { + container->remove_refd_index(index); + } + +private: + RefdIndexInterface* container; + int index; +}; + +#endif /* TITAN_RUNTIME_2 */ + +#endif /* REFDINDEX_HH */ + diff --git a/core/Runtime.cc b/core/Runtime.cc index 24a8a9c..25e07bb 100644 --- a/core/Runtime.cc +++ b/core/Runtime.cc @@ -41,6 +41,7 @@ #include "Charstring.hh" #include "Fd_And_Timeout_User.hh" #include +#include "Profiler.hh" namespace API = TitanLoggerApi; @@ -403,6 +404,7 @@ int TTCN_Runtime::hc_main(const char *local_addr, const char *MC_addr, TTCN_Communication::set_local_address(local_addr); TTCN_Communication::set_mc_address(MC_addr, MC_port); TTCN_Communication::connect_mc(); + Module_List::send_versions(); executor_state = HC_IDLE; TTCN_Communication::send_version(); initialize_component_process_tables(); @@ -2303,6 +2305,9 @@ void TTCN_Runtime::process_create_ptc(component component_reference, "state."); return; } + + // let the HC's TTCN-3 Profiler know of this new PTC + ttcn3_prof.add_ptc(component_reference); // clean Emergency log buffer before fork, to avoid duplication TTCN_Logger::ring_buffer_dump(false); diff --git a/core/Single_main.cc b/core/Single_main.cc index e4d7375..0c24306 100644 --- a/core/Single_main.cc +++ b/core/Single_main.cc @@ -22,6 +22,9 @@ #include "Encdec.hh" #include "TitanLoggerApi.hh" #include "TCov.hh" +#ifdef LINUX +#include +#endif #ifdef LICENSE #include "../common/license.h" @@ -32,15 +35,29 @@ const char * stored_argv = "Unidentified program"; static const char segfault[] = ": Segmentation fault occurred\n"; +static const char abortcall[] = ": Abort was called\n"; -void signal_handler(int) +void signal_handler(int signum) { int retval; retval = write(STDERR_FILENO, stored_argv, strlen(stored_argv)); + if(signum==SIGSEGV){ retval = write(STDERR_FILENO, segfault , sizeof(segfault)-1); // sizeof includes \0 + } else { + retval = write(STDERR_FILENO, abortcall , sizeof(abortcall)-1); // sizeof includes \0 + } +#ifdef LINUX + int nptrs; + void *buffer[100]; + nptrs = backtrace(buffer, 100); + backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO); + + fflush(stderr); +#endif (void)retval; TTCN_Logger::close_file(); + signal(SIGABRT, SIG_DFL); abort(); } @@ -65,6 +82,7 @@ int main(int argc, char *argv[]) sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGSEGV, &act, 0); + sigaction(SIGABRT, &act, 0); #ifdef MEMORY_DEBUG debug_new_counter.set_program_name(argv[0]); diff --git a/core/Snapshot.cc b/core/Snapshot.cc index 4877d95..42e32a7 100644 --- a/core/Snapshot.cc +++ b/core/Snapshot.cc @@ -14,6 +14,7 @@ #include #include +#include #include #include #ifdef USE_EPOLL diff --git a/core/TEXT.cc b/core/TEXT.cc index 91ddd72..d0b57c4 100644 --- a/core/TEXT.cc +++ b/core/TEXT.cc @@ -268,6 +268,9 @@ const TTCN_TEXTdescriptor_t BOOLEAN_text_ = { NULL, NULL, NULL, NULL, const TTCN_TEXTdescriptor_t CHARSTRING_text_ = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, { NULL } }; +const TTCN_TEXTdescriptor_t UNIVERSAL_CHARSTRING_text_ = { NULL, NULL, NULL, NULL, + NULL, NULL, NULL, { NULL } }; + const TTCN_TEXTdescriptor_t BITSTRING_text_ = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, { NULL } }; diff --git a/core/TEXT.hh b/core/TEXT.hh index 4d3962d..7a24833 100644 --- a/core/TEXT.hh +++ b/core/TEXT.hh @@ -121,6 +121,7 @@ extern const TTCN_TEXTdescriptor_t CHARSTRING_text_; extern const TTCN_TEXTdescriptor_t BITSTRING_text_; extern const TTCN_TEXTdescriptor_t HEXSTRING_text_; extern const TTCN_TEXTdescriptor_t OCTETSTRING_text_; +extern const TTCN_TEXTdescriptor_t UNIVERSAL_CHARSTRING_text_; /** @} end of TEXT group */ diff --git a/core/TTCN3.hh b/core/TTCN3.hh index 405a340..6fb4305 100644 --- a/core/TTCN3.hh +++ b/core/TTCN3.hh @@ -53,8 +53,10 @@ #ifdef TITAN_RUNTIME_2 #include "RT2/TitanLoggerApiSimple.hh" +#include "RT2/PreGenRecordOf.hh" #else #include "RT1/TitanLoggerApiSimple.hh" +#include "RT1/PreGenRecordOf.hh" #endif #include "Module_list.hh" @@ -70,5 +72,6 @@ #include "JSON.hh" #include "Error.hh" #include "XmlReader.hh" +#include "Profiler.hh" #endif diff --git a/core/Template.hh b/core/Template.hh index 44ccdc4..9b3a0d1 100644 --- a/core/Template.hh +++ b/core/Template.hh @@ -12,6 +12,7 @@ #ifdef TITAN_RUNTIME_2 #include "Struct_of.hh" +#include "RefdIndex.hh" struct TTCN_Typedescriptor_t; struct Erroneous_descriptor_t; #endif @@ -113,7 +114,11 @@ public: #endif }; -class Restricted_Length_Template : public Base_Template { +class Restricted_Length_Template : public Base_Template +#ifdef TITAN_RUNTIME_2 + , public RefdIndexInterface +#endif +{ protected: enum length_restriction_type_t { NO_LENGTH_RESTRICTION = 0, @@ -160,12 +165,6 @@ public: boolean is_omit() const; boolean is_any_or_omit() const; - -#ifdef TITAN_RUNTIME_2 - // Dummy functions, only used in record of/set of value in RT2 - void add_refd_index(int) {} - void remove_refd_index(int) {} -#endif }; #ifndef TITAN_RUNTIME_2 diff --git a/core/Universal_charstring.cc b/core/Universal_charstring.cc index 330f4f2..9b7f534 100644 --- a/core/Universal_charstring.cc +++ b/core/Universal_charstring.cc @@ -19,6 +19,7 @@ #include "Logger.hh" #include "Encdec.hh" #include "Addfunc.hh" // for unichar2int +#include "TEXT.hh" #include #include #include @@ -200,7 +201,7 @@ UNIVERSAL_CHARSTRING::UNIVERSAL_CHARSTRING other_value.must_bound("Initialization of a universal charstring with an " "unbound universal charstring element."); if (charstring) { - cstr = CHARSTRING(other_value.get_uchar().uc_cell); + cstr = CHARSTRING((const char)(other_value.get_uchar().uc_cell)); val_ptr = NULL; } else { init_struct(1); @@ -1068,6 +1069,13 @@ void UNIVERSAL_CHARSTRING::encode(const TTCN_Typedescriptor_t& p_td, TTCN_EncDec_ErrorContext::error_internal ("No RAW descriptor available for type '%s'.", p_td.name); break;} + case TTCN_EncDec::CT_TEXT: { + TTCN_EncDec_ErrorContext ec("While TEXT-encoding type '%s': ", p_td.name); + if(!p_td.text) + TTCN_EncDec_ErrorContext::error_internal + ("No TEXT descriptor available for type '%s'.", p_td.name); + TEXT_encode(p_td,p_buf); + break;} case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); @@ -1117,6 +1125,24 @@ void UNIVERSAL_CHARSTRING::decode(const TTCN_Typedescriptor_t& p_td, TTCN_EncDec_ErrorContext::error_internal ("No RAW descriptor available for type '%s'.", p_td.name); break;} + case TTCN_EncDec::CT_TEXT: { + Limit_Token_List limit; + TTCN_EncDec_ErrorContext ec("While TEXT-decoding type '%s': ", p_td.name); + if(!p_td.text) + TTCN_EncDec_ErrorContext::error_internal + ("No TEXT descriptor available for type '%s'.", p_td.name); + const unsigned char *b=p_buf.get_data(); + if(b[p_buf.get_len()-1]!='\0'){ + p_buf.set_pos(p_buf.get_len()); + p_buf.put_zero(8,ORDER_LSB); + p_buf.rewind(); + } + if(TEXT_decode(p_td,p_buf,limit)<0) + ec.error(TTCN_EncDec::ET_INCOMPL_MSG, + "Can not decode type '%s', because invalid or incomplete" + " message was received" + , p_td.name); + break;} case TTCN_EncDec::CT_XER : { unsigned XER_coding=va_arg(pvar, unsigned); XmlReaderWrap reader(p_buf); @@ -1200,6 +1226,198 @@ UNIVERSAL_CHARSTRING::BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, new_tlv=ASN_BER_V2TLV(new_tlv, p_td, p_coding); return new_tlv; } +int UNIVERSAL_CHARSTRING::TEXT_decode(const TTCN_Typedescriptor_t& p_td, + TTCN_Buffer& buff, Limit_Token_List& limit, boolean no_err, boolean /*first_call*/) +{ + int decoded_length = 0; + int str_len = 0; + clean_up(); + if (p_td.text->begin_decode) { + int tl; + if ((tl = p_td.text->begin_decode->match_begin(buff)) < 0) { + if (no_err) return -1; + TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR, + "The specified token '%s' not found for '%s': ", + (const char*) *(p_td.text->begin_decode), p_td.name); + return 0; + } + decoded_length += tl; + buff.increase_pos(tl); + } + // never return "not enough bits" + // if(buff.get_read_len()<=1 && no_err) return -TTCN_EncDec::ET_LEN_ERR; + + if (p_td.text->select_token) { + int tl; + if ((tl = p_td.text->select_token->match_begin(buff)) < 0) { + if (no_err) return -1; + else tl = 0; + } + str_len = tl; + } + // The length restriction needs some more work +/* else if ( p_td.text->val.parameters + && p_td.text->val.parameters->decoding_params.min_length != -1) { + str_len = p_td.text->val.parameters->decoding_params.min_length; + }*/ + else if (p_td.text->end_decode) { + int tl; + if ((tl = p_td.text->end_decode->match_first(buff)) < 0) { + if (no_err) return -1; + else tl = 0; + } + str_len = tl; + } + else if (limit.has_token()) { + int tl; + if ((tl = limit.match(buff)) < 0) tl = buff.get_read_len() - 1; + str_len = tl; + } + else { + str_len = buff.get_read_len() - 1; + } + +// only utf8 is supported now. + decode_utf8(str_len,buff.get_read_data()); + + decoded_length += str_len; + buff.increase_pos(str_len); + +// Case conversion is an another study +// and it is locale dependent +/* if ( p_td.text->val.parameters + && p_td.text->val.parameters->decoding_params.convert != 0) { + if (p_td.text->val.parameters->decoding_params.convert == 1) { + for (int a = 0; a < str_len; a++) { + val_ptr->chars_ptr[a] = toupper(val_ptr->chars_ptr[a]); + } + } + else { + for (int a = 0; a < str_len; a++) { + val_ptr->chars_ptr[a] = tolower(val_ptr->chars_ptr[a]); + } + } + }*/ + if (p_td.text->end_decode) { + int tl; + if ((tl = p_td.text->end_decode->match_begin(buff)) < 0) { + if (no_err) return -1; + TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR, + "The specified token '%s' not found for '%s': ", + (const char*) *(p_td.text->end_decode), p_td.name); + return 0; + } + decoded_length += tl; + buff.increase_pos(tl); + } + return decoded_length; +} + +int UNIVERSAL_CHARSTRING::TEXT_encode(const TTCN_Typedescriptor_t& p_td, + TTCN_Buffer& buff) const{ + int encoded_length=0; + if(p_td.text->begin_encode){ + buff.put_cs(*p_td.text->begin_encode); + encoded_length+=p_td.text->begin_encode->lengthof(); + } + if(!is_bound()) { + TTCN_EncDec_ErrorContext::error + (TTCN_EncDec::ET_UNBOUND, "Encoding an unbound value."); + if(p_td.text->end_encode){ + buff.put_cs(*p_td.text->end_encode); + encoded_length+=p_td.text->end_encode->lengthof(); + } + return encoded_length; + } + +// The length restriction and case conversion will be added later +// if(p_td.text->val.parameters==NULL){ + + int base_size=buff.get_len(); // strore the current length of the data + // in the buffer + + encode_utf8(buff); + + encoded_length+=buff.get_len()-base_size; // calculate the number of the + // stored octets + +/* } else { + int chars_before=0; + int chars_after=0; + if(val_ptr->n_charsval.parameters->coding_params.min_length){ + switch(p_td.text->val.parameters->coding_params.just){ + case -1: //left + chars_after=p_td.text-> + val.parameters->coding_params.min_length-val_ptr->n_chars; + break; + case 0:{ // center + int pad=p_td.text-> + val.parameters->coding_params.min_length-val_ptr->n_chars; + chars_after=pad/2; + chars_before=pad-chars_after; + break; + } + case 1: // right + default: + chars_before=p_td.text-> + val.parameters->coding_params.min_length-val_ptr->n_chars; + break; + } + } + if(chars_before){ + unsigned char* p=NULL; + size_t len=chars_before; + buff.get_end(p,len); + for(int a=0;aval.parameters->coding_params.convert){ + case -1:{ //lower_case + unsigned char* p=NULL; + size_t len=val_ptr->n_chars; + buff.get_end(p,len); + for(int a=0;an_chars;a++) + p[a]=(unsigned char)tolower(val_ptr->chars_ptr[a]); + buff.increase_length(val_ptr->n_chars); + break; + } + case 0:{ // no conversion + buff.put_cs(*this); + break; + } + case 1: // upper_case + default: + { + unsigned char* p=NULL; + size_t len=val_ptr->n_chars; + buff.get_end(p,len); + for(int a=0;an_chars;a++) + p[a]=(unsigned char)toupper(val_ptr->chars_ptr[a]); + buff.increase_length(val_ptr->n_chars); + break; + } + } + encoded_length+=val_ptr->n_chars; + + if(chars_after){ + unsigned char* p=NULL; + size_t len=chars_after; + buff.get_end(p,len); + for(int a=0;aend_encode){ + buff.put_cs(*p_td.text->end_encode); + encoded_length+=p_td.text->end_encode->lengthof(); + } + return encoded_length; +} void UNIVERSAL_CHARSTRING::encode_utf8(TTCN_Buffer& buf, bool addBOM /*= false*/) const { @@ -2214,7 +2432,9 @@ void UNIVERSAL_CHARSTRING::decode_utf8(int n_octets, // count all octets except the continuing octets (10xxxxxx) if ((octets_ptr[i] & 0xC0) != 0x80) n_uchars++; } - // allocate enough memory + // allocate enough memory, start from clean state + clean_up(); + charstring=false; init_struct(n_uchars); n_uchars = 0; @@ -2676,22 +2896,13 @@ UNIVERSAL_CHARSTRING_ELEMENT& UNIVERSAL_CHARSTRING_ELEMENT::operator= { other_value.must_bound("Assignment of an unbound universal charstring value " "to a universal charstring element."); - if (other_value.val_ptr->n_uchars != 1) + int other_value_size = other_value.charstring ? other_value.cstr.val_ptr->n_chars : + other_value.val_ptr->n_uchars; + if (other_value_size != 1) TTCN_error("Assignment of a universal charstring value with length other " "than 1 to a universal charstring element."); bound_flag = TRUE; - const universal_char& uchar = other_value.val_ptr->uchars_ptr[0]; - if (str_val.charstring) { - if (uchar.is_char()) - str_val.cstr.val_ptr->chars_ptr[uchar_pos] = uchar.uc_cell; - else { - str_val.convert_cstr_to_uni(); - str_val.val_ptr->uchars_ptr[uchar_pos] = uchar; - } - } else { - str_val.copy_value(); - str_val.val_ptr->uchars_ptr[uchar_pos] = uchar; - } + *this = other_value[0]; return *this; } diff --git a/core/Universal_charstring.hh b/core/Universal_charstring.hh index 62ea9fb..5d2e66a 100644 --- a/core/Universal_charstring.hh +++ b/core/Universal_charstring.hh @@ -318,6 +318,10 @@ public: boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); + int TEXT_encode(const TTCN_Typedescriptor_t&, + TTCN_Buffer&) const; + int TEXT_decode(const TTCN_Typedescriptor_t&, TTCN_Buffer&, Limit_Token_List&, + boolean no_err=FALSE, boolean first_call=TRUE); int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t&, XmlReaderWrap& reader, unsigned int, embed_values_dec_struct_t*); /** Decodes UTF-8 into the internal representation (UCS4-BE) diff --git a/core/XER.hh b/core/XER.hh index 604ca04..78262af 100644 --- a/core/XER.hh +++ b/core/XER.hh @@ -19,6 +19,11 @@ class Base_Type; #ifdef TITAN_RUNTIME_2 class Record_Of_Type; class Erroneous_descriptor_t; +#else +namespace PreGenRecordOf { + class PREGEN__RECORD__OF__UNIVERSAL__CHARSTRING; + class PREGEN__RECORD__OF__UNIVERSAL__CHARSTRING__OPTIMIZED; +} #endif class TTCN_Module; @@ -255,6 +260,9 @@ struct XERdescriptor_t * or invalid ("anyElement except ...") namespace URIs. * The unqualified namespace is marked by an empty string ("").*/ const char** ns_uris; + + /** Points to the element type's XER descriptor in case of 'record of' and 'set of' types */ + const XERdescriptor_t* oftype_descr; }; /** Information related to the embedded values in XML encoding @@ -273,11 +281,10 @@ struct embed_values_enc_struct_t /** Erroneous descriptor index for the embedded values (for negative tests) */ int embval_err_descr_idx; #else - /** Stores the array of embedded values as a Base_Type (use get_embedded_value - * to retrieve values - temporarily disabled) */ - const Base_Type* embval_array; - /** Stores the size of the embedded value array */ - int embval_size; + /** Stores the array of embedded values (regular record-of) */ + const PreGenRecordOf::PREGEN__RECORD__OF__UNIVERSAL__CHARSTRING* embval_array_reg; + /** Stores the array of embedded values (optimized record-of) */ + const PreGenRecordOf::PREGEN__RECORD__OF__UNIVERSAL__CHARSTRING__OPTIMIZED* embval_array_opt; #endif /** Stores the index of the next embedded value to be read */ int embval_index; @@ -293,9 +300,10 @@ struct embed_values_dec_struct_t /** Stores the array of embedded values */ Record_Of_Type* embval_array; #else - /** Stores the array of embedded values as a Base_type (use set_embedded_value - * to insert new values - temporarily disabled) */ - Base_Type* embval_array; + /** Stores the array of embedded values (regular record-of) */ + PreGenRecordOf::PREGEN__RECORD__OF__UNIVERSAL__CHARSTRING* embval_array_reg; + /** Stores the array of embedded values (optimized record-of) */ + PreGenRecordOf::PREGEN__RECORD__OF__UNIVERSAL__CHARSTRING__OPTIMIZED* embval_array_opt; #endif /** Stores the number of embedded values that are currently in the array, * and the index where the next one should be inserted */ @@ -414,7 +422,7 @@ void check_namespace_restrictions(const XERdescriptor_t& p_td, const char* p_xml extern const XERdescriptor_t type_name##_xer_ = { \ { xmlname ">\n", xmlname ">\n" }, \ { 2+sizeof(xmlname)-1, 2+sizeof(xmlname)-1 }, \ - 0UL, WHITESPACE_PRESERVE, NULL, NULL, 0, 0, NULL } + 0UL, WHITESPACE_PRESERVE, NULL, NULL, 0, 0, NULL, NULL } // The compiler should fold the two identical strings into one # define XER_STRUCT_COPY(cpy,original) \ diff --git a/core/config_process.l b/core/config_process.l index 4d96260..dafbf2d 100644 --- a/core/config_process.l +++ b/core/config_process.l @@ -35,6 +35,8 @@ #include "../common/dbgnew.hh" +#include "Profiler.hh" + extern string_map_t *config_defines; #define yylval config_process_lval @@ -276,6 +278,25 @@ TTCNSTRINGPARSING_COMPONENT "$#&&&(#TTCNSTRINGPARSING_COMPONENT$#&&^#% " . /* eat unnecessary chars */ +} + +{HEX}+ { + /* numeric statistics filter (check this before checking for NUMBERs) */ + yylval.uint_val = 0; + while(0 != *yytext) { + yylval.uint_val *= 16; + if ('0' <= *yytext && '9' >= *yytext) { + yylval.uint_val += *yytext - '0'; + } + else if ('a' <= *yytext && 'f' >= *yytext) { + yylval.uint_val += *yytext - 'a' + 10; + } + else { + yylval.uint_val += *yytext - 'A' + 10; + } + ++yytext; + } + return ProfilerStatsFlag; } /* Values */ @@ -966,12 +987,170 @@ LOG_ALL { { - [Dd]isable[Pp]rofiler return DisableProfilerKeyword; - [Dd]isable[Cc]overage return DisableCoverageKeyword; - [Dd]ata[Bb]ase[Ff]ile return DatabaseFileKeyword; - [Aa]ggregate[Dd]ata return AggregateDataKeyword; - [Ss]tatistics[Ff]ile return StatisticsFileKeyword; - [Dd]isable[Ss]tatistics return DisableStatisticsKeyword; + [Dd]isable[Pp]rofiler return DisableProfilerKeyword; + [Dd]isable[Cc]overage return DisableCoverageKeyword; + [Dd]ata[Bb]ase[Ff]ile return DatabaseFileKeyword; + [Aa]ggregate[Dd]ata return AggregateDataKeyword; + [Ss]tatistics[Ff]ile return StatisticsFileKeyword; + [Dd]isable[Ss]tatistics return DisableStatisticsKeyword; + [Ss]tatistics[Ff]ilter return StatisticsFilterKeyword; + [Ss]tart[Aa]utomatically return StartAutomaticallyKeyword; + [Nn]et[Ll]ine[Tt]imes return NetLineTimesKeyword; + [Nn]et[Ff]unction[Tt]imes return NetFunctionTimesKeyword; + + /* statistics filters */ + [Nn]umber[Oo]f[Ll]ines { + yylval.uint_val = TTCN3_Profiler::STATS_NUMBER_OF_LINES; + return ProfilerStatsFlag; + } + [Ll]ine[Dd]ata[Rr]aw { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_DATA_RAW; + return ProfilerStatsFlag; + } + [Ff]unc[Dd]ata[Rr]aw { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_DATA_RAW; + return ProfilerStatsFlag; + } + [Ll]ine[Aa]vg[Rr]aw { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_AVG_RAW; + return ProfilerStatsFlag; + } + [Ff]unc[Aa]vg[Rr]aw { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_AVG_RAW; + return ProfilerStatsFlag; + } + [Ll]ine[Tt]imes[Ss]orted[Bb]y[Mm]od { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_TIMES_SORTED_BY_MOD; + return ProfilerStatsFlag; + } + [Ff]unc[Tt]imes[Ss]orted[Bb]y[Mm]od { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_TIMES_SORTED_BY_MOD; + return ProfilerStatsFlag; + } + [Ll]ine[Tt]imes[Ss]orted[Tt]otal { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_TIMES_SORTED_TOTAL; + return ProfilerStatsFlag; + } + [Ff]unc[Tt]imes[Ss]orted[Tt]otal { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_TIMES_SORTED_TOTAL; + return ProfilerStatsFlag; + } + [Ll]ine[Cc]ount[Ss]orted[Bb]y[Mm]od { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_COUNT_SORTED_BY_MOD; + return ProfilerStatsFlag; + } + [Ff]unc[Cc]ount[Ss]orted[Bb]y[Mm]od { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_COUNT_SORTED_BY_MOD; + return ProfilerStatsFlag; + } + [Ll]ine[Cc]ount[Ss]orted[Tt]otal { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_COUNT_SORTED_TOTAL; + return ProfilerStatsFlag; + } + [Ff]unc[Cc]ount[Ss]orted[Tt]otal { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_COUNT_SORTED_TOTAL; + return ProfilerStatsFlag; + } + [Ll]ine[Aa]vg[Ss]orted[Bb]y[Mm]od { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_AVG_SORTED_BY_MOD; + return ProfilerStatsFlag; + } + [Ff]unc[Aa]vg[Ss]orted[Bb]y[Mm]od { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_AVG_SORTED_BY_MOD; + return ProfilerStatsFlag; + } + [Ll]ine[Aa]vg[Ss]orted[Tt]otal { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_AVG_SORTED_TOTAL; + return ProfilerStatsFlag; + } + [Ff]unc[Aa]vg[Ss]orted[Tt]otal { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_AVG_SORTED_TOTAL; + return ProfilerStatsFlag; + } + [Tt]op10[Ll]ine[Tt]imes { + yylval.uint_val = TTCN3_Profiler::STATS_TOP10_LINE_TIMES; + return ProfilerStatsFlag; + } + [Tt]op10[Ff]unc[Tt]imes { + yylval.uint_val = TTCN3_Profiler::STATS_TOP10_FUNC_TIMES; + return ProfilerStatsFlag; + } + [Tt]op10[Ll]ine[Cc]ount { + yylval.uint_val = TTCN3_Profiler::STATS_TOP10_LINE_COUNT; + return ProfilerStatsFlag; + } + [Tt]op10[Ff]unc[Cc]ount { + yylval.uint_val = TTCN3_Profiler::STATS_TOP10_FUNC_COUNT; + return ProfilerStatsFlag; + } + [Tt]op10[Ll]ine[Aa]vg { + yylval.uint_val = TTCN3_Profiler::STATS_TOP10_LINE_AVG; + return ProfilerStatsFlag; + } + [Tt]op10[Ff]unc[Aa]vg { + yylval.uint_val = TTCN3_Profiler::STATS_TOP10_FUNC_AVG; + return ProfilerStatsFlag; + } + [Uu]nused[Ll]ines { + yylval.uint_val = TTCN3_Profiler::STATS_UNUSED_LINES; + return ProfilerStatsFlag; + } + [Uu]nused[Ff]unc { + yylval.uint_val = TTCN3_Profiler::STATS_UNUSED_FUNC; + return ProfilerStatsFlag; + } + [Aa]ll[Rr]aw[Dd]ata { + yylval.uint_val = TTCN3_Profiler::STATS_ALL_RAW_DATA; + return ProfilerStatsFlag; + } + [Ll]ine[Dd]ata[Ss]orted[Bb]y[Mm]od { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_DATA_SORTED_BY_MOD; + return ProfilerStatsFlag; + } + [Ff]unc[Dd]ata[Ss]orted[Bb]y[Mm]od { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_DATA_SORTED_BY_MOD; + return ProfilerStatsFlag; + } + [Ll]ine[Dd]ata[Ss]orted[Tt]otal { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_DATA_SORTED_TOTAL; + return ProfilerStatsFlag; + } + [Ff]unc[Dd]ata[Ss]orted[Tt]otal { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_DATA_SORTED_TOTAL; + return ProfilerStatsFlag; + } + [Ll]ine[Dd]ata[Ss]orted { + yylval.uint_val = TTCN3_Profiler::STATS_LINE_DATA_SORTED; + return ProfilerStatsFlag; + } + [Ff]unc[Dd]ata[Ss]orted { + yylval.uint_val = TTCN3_Profiler::STATS_FUNC_DATA_SORTED; + return ProfilerStatsFlag; + } + [Aa]ll[Dd]ata[Ss]orted { + yylval.uint_val = TTCN3_Profiler::STATS_ALL_DATA_SORTED; + return ProfilerStatsFlag; + } + [Tt]op10[Ll]ine[Dd]ata { + yylval.uint_val = TTCN3_Profiler::STATS_TOP10_LINE_DATA; + return ProfilerStatsFlag; + } + [Tt]op10[Ff]unc[Dd]ata { + yylval.uint_val = TTCN3_Profiler::STATS_TOP10_FUNC_DATA; + return ProfilerStatsFlag; + } + [Tt]op10[Aa]ll[Dd]ata { + yylval.uint_val = TTCN3_Profiler::STATS_TOP10_ALL_DATA; + return ProfilerStatsFlag; + } + [Uu]nused[Dd]ata { + yylval.uint_val = TTCN3_Profiler::STATS_UNUSED_DATA; + return ProfilerStatsFlag; + } + [Aa]ll { + yylval.uint_val = TTCN3_Profiler::STATS_ALL; + return ProfilerStatsFlag; + } } control return ControlKeyword; diff --git a/core/config_process.y b/core/config_process.y index 92c2097..28dce69 100644 --- a/core/config_process.y +++ b/core/config_process.y @@ -219,12 +219,17 @@ string_map_t *config_defines; %token Retry %token Delete %token TtcnStringParsingKeyword -%token DisableProfilerKeyword "DisableProfiler" -%token DisableCoverageKeyword "DisableCoverage" -%token DatabaseFileKeyword "DatabaseFile" -%token AggregateDataKeyword "AggregateData" -%token StatisticsFileKeyword "StatisticsFile" -%token DisableStatisticsKeyword "DisableStatistics" +%token DisableProfilerKeyword "DisableProfiler" +%token DisableCoverageKeyword "DisableCoverage" +%token DatabaseFileKeyword "DatabaseFile" +%token AggregateDataKeyword "AggregateData" +%token StatisticsFileKeyword "StatisticsFile" +%token DisableStatisticsKeyword "DisableStatistics" +%token StatisticsFilterKeyword "StatisticsFilter" +%token StartAutomaticallyKeyword "StartAutomatically" +%token NetLineTimesKeyword "NetLineTimes" +%token NetFunctionTimesKeyword "NetFunctionTimes" +%token ProfilerStatsFlag "profiler statistics filter" %type IntegerValue %type FloatValue @@ -269,6 +274,7 @@ string_map_t *config_defines; %type LengthMatch %type PatternChunk PatternChunkList %type IndexItemIndex LengthBound +%type ProfilerStatsFlags %destructor { Free($$); } ArrayRef @@ -1688,6 +1694,10 @@ ProfilerSetting: | AggregateDataSetting | StatisticsFileSetting | DisableStatisticsSetting +| StatisticsFilterSetting +| StartAutomaticallySetting +| NetLineTimesSetting +| NetFunctionTimesSetting ; DisableProfilerSetting: @@ -1726,6 +1736,46 @@ DisableStatisticsSetting: } ; +StatisticsFilterSetting: + StatisticsFilterKeyword AssignmentChar ProfilerStatsFlags { + ttcn3_prof.reset_stats_flags(); + ttcn3_prof.add_stats_flags($3); + } +| StatisticsFilterKeyword ConcatChar ProfilerStatsFlags { + ttcn3_prof.add_stats_flags($3); + } +; + +ProfilerStatsFlags: + ProfilerStatsFlag { $$ = $1; } +| ProfilerStatsFlag '&' ProfilerStatsFlags { $$ = $1 | $3; } +| ProfilerStatsFlag '|' ProfilerStatsFlags { $$ = $1 | $3; } +; + +StartAutomaticallySetting: + StartAutomaticallyKeyword AssignmentChar BooleanValue { + if ($3) { + ttcn3_prof.start(); + } + else { + ttcn3_prof.stop(); + } + } +; + +NetLineTimesSetting: + NetLineTimesKeyword AssignmentChar BooleanValue { + TTCN3_Stack_Depth::set_net_line_times($3); + } +; + +NetFunctionTimesSetting: + NetFunctionTimesKeyword AssignmentChar BooleanValue { + TTCN3_Stack_Depth::set_net_func_times($3); + } +; + + /**************** [TESTPORT_PARAMETERS] ****************************/ TestportParametersSection: @@ -2207,8 +2257,6 @@ boolean process_config_file(const char *file_name) string_map_free(config_defines); config_defines = NULL; - ttcn3_prof.init_data_file(); - return !error_flag; } diff --git a/core2/Basetype2.cc b/core2/Basetype2.cc index c338947..189fa74 100644 --- a/core2/Basetype2.cc +++ b/core2/Basetype2.cc @@ -856,7 +856,7 @@ int Record_Of_Type::TEXT_encode(const TTCN_Typedescriptor_t& p_td, } return encoded_length; } - const TTCN_Typedescriptor_t* elem_descr = get_elem_descr(); + const TTCN_Typedescriptor_t* elem_descr = p_td.oftype_descr; for(int a=0;aseparator_encode) { buff.put_cs(*p_td.text->separator_encode); @@ -942,9 +942,9 @@ int Record_Of_Type::TEXT_encode_negtest(const Erroneous_descriptor_t* p_err_desc } if (emb_descr) { encoded_length += get_at(a)->TEXT_encode_negtest( - emb_descr,*get_elem_descr(),buff); + emb_descr,*p_td.oftype_descr,buff); } else { - encoded_length += get_at(a)->TEXT_encode(*get_elem_descr(),buff); + encoded_length += get_at(a)->TEXT_encode(*p_td.oftype_descr,buff); } need_separator=true; } @@ -1012,7 +1012,7 @@ int Record_Of_Type::TEXT_decode(const TTCN_Typedescriptor_t& p_td, while(TRUE){ Base_Type* val = create_elem(); pos=buff.get_pos(); - int len = val->TEXT_decode(*get_elem_descr(),buff,limit,TRUE); + int len = val->TEXT_decode(*p_td.oftype_descr,buff,limit,TRUE); if(len==-1 || (len==0 && !limit.has_token())){ buff.set_pos(pos); delete val; @@ -1103,7 +1103,7 @@ ASN_BER_TLV_t* Record_Of_Type::BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, TTCN_EncDec_ErrorContext ec; for(int elem_i=0; elem_iadd_TLV(get_at(elem_i)->BER_encode_TLV(*get_elem_descr(), p_coding)); + new_tlv->add_TLV(get_at(elem_i)->BER_encode_TLV(*p_td.oftype_descr, p_coding)); } if (is_set()) new_tlv->sort_tlvs(); } @@ -1156,10 +1156,10 @@ ASN_BER_TLV_t* Record_Of_Type::BER_encode_TLV_negtest(const Erroneous_descriptor ec.set_msg("Component #%d: ", elem_i); if (emb_descr) { new_tlv->add_TLV(get_at(elem_i)->BER_encode_TLV_negtest( - emb_descr, *get_elem_descr(), p_coding)); + emb_descr, *p_td.oftype_descr, p_coding)); } else { new_tlv->add_TLV(get_at(elem_i)->BER_encode_TLV( - *get_elem_descr(), p_coding)); + *p_td.oftype_descr, p_coding)); } } @@ -1199,7 +1199,7 @@ boolean Record_Of_Type::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, TTCN_EncDec_ErrorContext ec_1("Component #"); TTCN_EncDec_ErrorContext ec_2("0: "); while(BER_decode_constdTLV_next(stripped_tlv, V_pos, L_form, tmp_tlv)) { - get_at(get_nof_elements())->BER_decode_TLV(*get_elem_descr(), tmp_tlv, L_form); + get_at(get_nof_elements())->BER_decode_TLV(*p_td.oftype_descr, tmp_tlv, L_form); ec_2.set_msg("%d: ", val_ptr->n_elements); } return TRUE; @@ -1232,7 +1232,7 @@ int Record_Of_Type::RAW_decode(const TTCN_Typedescriptor_t& p_td, set_size(0); } int start_field = get_nof_elements(); // append at the end - TTCN_Typedescriptor_t const& elem_descr = *get_elem_descr(); + TTCN_Typedescriptor_t const& elem_descr = *p_td.oftype_descr; if (p_td.raw->fieldlength || sel_field != -1) { if (sel_field == -1) sel_field = p_td.raw->fieldlength; for (int a = 0; a < sel_field; a++) { @@ -1250,7 +1250,6 @@ int Record_Of_Type::RAW_decode(const TTCN_Typedescriptor_t& p_td, if (!first_call) return -1; goto finished; } - int ext_bit = rawdec_ebv(); while (limit > 0) { start_of_field = buff.get_pos_bit(); Base_Type* field_bt = get_at(a); // non-const, extend the record-of @@ -1267,12 +1266,11 @@ int Record_Of_Type::RAW_decode(const TTCN_Typedescriptor_t& p_td, decoded_length += decoded_field_length; limit -= decoded_field_length; a++; - if (ext_bit != 1/*XDEFNO*/&& ext_bit != -1/*XDEFDEFAULT*/) { - // ext_bit here may be 2 (XDEFYES) or 3 (XDEFREVERSE). - // (ext_bit != 2) is 0 or 1 + if (EXT_BIT_NO != p_td.raw->extension_bit) { + // (EXT_BIT_YES != p_td.raw->extension_bit) is 0 or 1 // This is the opposite value of what the bit needs to be to signal // the end of decoding, because x-or is the equivalent of != - if ((ext_bit != 2/*XDEFYES*/) ^ buff.get_last_bit()) { + if ((EXT_BIT_YES != p_td.raw->extension_bit) ^ buff.get_last_bit()) { goto finished; } } @@ -1294,7 +1292,7 @@ int Record_Of_Type::RAW_encode(const TTCN_Typedescriptor_t& p_td, RAW_enc_tree& myleaf.rec_of = TRUE; myleaf.body.node.num_of_nodes = encoded_num_of_records; myleaf.body.node.nodes = init_nodes_of_enc_tree(encoded_num_of_records); - TTCN_Typedescriptor_t const& elem_descr = *get_elem_descr(); + TTCN_Typedescriptor_t const& elem_descr = *p_td.oftype_descr; for (int a = 0; a < encoded_num_of_records; a++) { const Base_Type *field_bt = get_at(a); myleaf.body.node.nodes[a] = new RAW_enc_tree(TRUE, &myleaf, &(myleaf.curr_pos), a, elem_descr.raw); @@ -1345,7 +1343,7 @@ int Record_Of_Type::RAW_encode_negtest(const Erroneous_descriptor_t *p_err_descr continue; const Erroneous_values_t *err_vals = p_err_descr->next_field_err_values(i, values_idx); const Erroneous_descriptor_t *emb_descr = p_err_descr->next_field_emb_descr(i, edescr_idx); - TTCN_Typedescriptor_t const& elem_descr = *get_elem_descr(); + TTCN_Typedescriptor_t const& elem_descr = *p_td.oftype_descr; if (err_vals && err_vals->before) { if (err_vals->before->errval == NULL) TTCN_error("internal error: erroneous before value missing"); @@ -1388,11 +1386,11 @@ int Record_Of_Type::RAW_encode_negtest(const Erroneous_descriptor_t *p_err_descr myleaf.body.node.nodes[node_pos] = new RAW_enc_tree(TRUE, &myleaf, &(myleaf.curr_pos), node_pos, elem_descr.raw); encoded_length += get_at(i)->RAW_encode_negtest(emb_descr, - *get_elem_descr(), *myleaf.body.node.nodes[node_pos++]); + *p_td.oftype_descr, *myleaf.body.node.nodes[node_pos++]); } else { myleaf.body.node.nodes[node_pos] = new RAW_enc_tree(TRUE, &myleaf, &(myleaf.curr_pos), node_pos, elem_descr.raw); - encoded_length += get_at(i)->RAW_encode(*get_elem_descr(), + encoded_length += get_at(i)->RAW_encode(*p_td.oftype_descr, *myleaf.body.node.nodes[node_pos++]); } } @@ -1421,7 +1419,7 @@ int Record_Of_Type::RAW_encode_negtest(const Erroneous_descriptor_t *p_err_descr return myleaf.length = encoded_length; } -int Record_Of_Type::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const +int Record_Of_Type::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok) const { if (!is_bound()) { TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, @@ -1432,7 +1430,7 @@ int Record_Of_Type::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_ int enc_len = p_tok.put_next_token(JSON_TOKEN_ARRAY_START, NULL); for(int i = 0; i < get_nof_elements(); ++i) { - int ret_val = get_at(i)->JSON_encode(*get_elem_descr(), p_tok); + int ret_val = get_at(i)->JSON_encode(*p_td.oftype_descr, p_tok); if (0 > ret_val) break; enc_len += ret_val; } @@ -1458,7 +1456,7 @@ int Record_Of_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenize // Read value tokens until we reach some other token size_t buf_pos = p_tok.get_buf_pos(); Base_Type* val = create_elem(); - int ret_val = val->JSON_decode(*get_elem_descr(), p_tok, p_silent); + int ret_val = val->JSON_decode(*p_td.oftype_descr, p_tok, p_silent); if (JSON_ERROR_INVALID_TOKEN == ret_val) { // undo the last action on the buffer p_tok.set_buf_pos(buf_pos); @@ -1634,7 +1632,7 @@ char **Record_Of_Type::collect_ns(const XERdescriptor_t& p_td, size_t& num, bool if (val_ptr) for (int i = 0; i < get_nof_elements(); ++i) { size_t num_new = 0; char **new_namespaces = get_at(i)->collect_ns( - *get_elem_descr()->xer, num_new, def_ns_1); + *p_td.oftype_descr, num_new, def_ns_1); merge_ns(collected_ns, num_collected, new_namespaces, num_new); def_ns = def_ns || def_ns_1; // alas, no ||= } @@ -1786,6 +1784,8 @@ int Record_Of_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, } else { // not ANY-ATTRIBUTES unsigned int sub_flavor = flavor | XER_RECOF | (p_td.xer_bits & (XER_LIST)); + TTCN_EncDec_ErrorContext ec_0("Index "); + TTCN_EncDec_ErrorContext ec_1; for (int i = 0; i < nof_elements; ++i) { if (i > 0 && !own_tag && 0 != emb_val && @@ -1794,8 +1794,9 @@ int Record_Of_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, UNIVERSAL_CHARSTRING_xer_, p_buf, flavor | EMBED_VALUES, indent+1, 0); ++emb_val->embval_index; } + ec_1.set_msg("%d: ", i); if (exer && (p_td.xer_bits & XER_LIST) && i>0) p_buf.put_c(' '); - get_at(i)->XER_encode(*get_elem_descr()->xer, p_buf, + get_at(i)->XER_encode(*p_td.oftype_descr, p_buf, sub_flavor, indent+own_tag, emb_val); } @@ -1824,7 +1825,7 @@ int Record_Of_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, * @param indent indentation level * @return number of bytes generated */ -int Record_Of_Type::encode_element(int i, +int Record_Of_Type::encode_element(int i, const XERdescriptor_t& p_td, const Erroneous_values_t* ev, const Erroneous_descriptor_t* ed, TTCN_Buffer& p_buf, unsigned int sub_flavor, int indent, embed_values_enc_struct_t* emb_val) const { @@ -1869,10 +1870,10 @@ int Record_Of_Type::encode_element(int i, } else { ec.set_msg("Component #%d: ", i); if (ed) { - get_at(i)->XER_encode_negtest(ed, *get_elem_descr()->xer, p_buf, sub_flavor, indent, emb_val); + get_at(i)->XER_encode_negtest(ed, p_td, p_buf, sub_flavor, indent, emb_val); } else { // the "real" encoder - get_at(i)->XER_encode(*get_elem_descr()->xer, p_buf, sub_flavor, indent, emb_val); + get_at(i)->XER_encode(p_td, p_buf, sub_flavor, indent, emb_val); } } @@ -2069,8 +2070,8 @@ int Record_Of_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr ev0_i = emb_val->embval_err->next_field_err_values(emb_val->embval_index, emb_val->embval_err_val_idx); ed0_i = emb_val->embval_err->next_field_emb_descr (emb_val->embval_index, emb_val->embval_err_descr_idx); } - emb_val->embval_array->encode_element(emb_val->embval_index, ev0_i, ed0_i, - p_buf, flavor | EMBED_VALUES, indent + own_tag, 0); + emb_val->embval_array->encode_element(emb_val->embval_index, UNIVERSAL_CHARSTRING_xer_, + ev0_i, ed0_i, p_buf, flavor | EMBED_VALUES, indent + own_tag, 0); ++emb_val->embval_index; } @@ -2079,7 +2080,7 @@ int Record_Of_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr const Erroneous_descriptor_t* emb_descr = p_err_descr->next_field_emb_descr (i, edescr_idx); - encode_element(i, err_vals, emb_descr, p_buf, sub_flavor, indent+own_tag, emb_val); + encode_element(i, *p_td.oftype_descr, err_vals, emb_descr, p_buf, sub_flavor, indent+own_tag, emb_val); // omit_after value -1 becomes "very big" if ((unsigned int)i >= (unsigned int)p_err_descr->omit_after) break; @@ -2146,7 +2147,7 @@ int Record_Of_Type::XER_decode(const XERdescriptor_t& p_td, pos += strlen(str) + 1; // Construct a new XML Reader with the current token. TTCN_Buffer buf2; - const XERdescriptor_t& sub_xer = *get_elem_descr()->xer; + const XERdescriptor_t& sub_xer = *p_td.oftype_descr; buf2.put_c('<'); write_ns_prefix(sub_xer, buf2); @@ -2233,7 +2234,7 @@ int Record_Of_Type::XER_decode(const XERdescriptor_t& p_td, * belong to the embedded type, the record-of has already ended. */ if (!own_tag && !can_start_v( (const char*)reader.LocalName(), (const char*)reader.NamespaceUri(), - *get_elem_descr()->xer, flavor | UNTAGGED)) + p_td, flavor | UNTAGGED)) { for (; success == 1 && reader.Depth() > depth; success = reader.Read()) ; // We should now be back at the same depth as we started. @@ -2241,7 +2242,7 @@ int Record_Of_Type::XER_decode(const XERdescriptor_t& p_td, } ec_1.set_msg("%d: ", get_nof_elements()); /* The call to the non-const get_at() creates the element */ - get_at(get_nof_elements())->XER_decode(*get_elem_descr()->xer, reader, flavor, emb_val); + get_at(get_nof_elements())->XER_decode(*p_td.oftype_descr, reader, flavor, emb_val); if (0 != emb_val && !own_tag && get_nof_elements() > 1) { ++emb_val->embval_index; } @@ -4690,8 +4691,8 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, ev0_0 = ed0->next_field_err_values(0, embed_values_val_idx); ed0_0 = ed0->next_field_emb_descr (0, embed_values_descr_idx); } - sub_len += embed_values->encode_element(0, ev0_0, ed0_0, - p_buf, flavor | EMBED_VALUES, indent+!omit_tag, 0); + sub_len += embed_values->encode_element(0, UNIVERSAL_CHARSTRING_xer_, + ev0_0, ed0_0, p_buf, flavor | EMBED_VALUES, indent+!omit_tag, 0); } } @@ -4844,8 +4845,8 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, ev0_i = ed0->next_field_err_values(emb_val->embval_index, emb_val->embval_err_val_idx); ed0_i = ed0->next_field_emb_descr (emb_val->embval_index, emb_val->embval_err_descr_idx); } - embed_values->encode_element(emb_val->embval_index, ev0_i, ed0_i, - p_buf, flavor | EMBED_VALUES, indent + !omit_tag, 0); + embed_values->encode_element(emb_val->embval_index, UNIVERSAL_CHARSTRING_xer_, + ev0_i, ed0_i, p_buf, flavor | EMBED_VALUES, indent + !omit_tag, 0); ++emb_val->embval_index; } } //for diff --git a/etc/xsd/TXD.xsd b/etc/xsd/TXD.xsd deleted file mode 100644 index e2730e9..0000000 --- a/etc/xsd/TXD.xsd +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - - - - - - - - A choice between describing how to build the project <build> - or providing the location of a pre-built <executable> - These two are mutually exclusive. - - - - - - - Describes the way to build the product from source, - using TPDs. - - - - - - - - - - - - - - - - Override configuration settings in TPDs - - - - - - - - - - - Specifies the location of an already built executable - - - - - - - - - - - - - Describes how to run the test. - There can be at most one "Run" which may contain various runners - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Describes a referenced project - - - - - - - - - - - - - - - - - - - - Optional name of the project. Can be used as reference in the TXD itself. - The TPD is identified by the "path" attribute, below. - - - - - - - This is the filename of the TPD file. Paths are relative to the TXD - itself, or absolute. - - - - - diff --git a/function_test/BER_EncDec/BER_EncDec_TD.fast_script b/function_test/BER_EncDec/BER_EncDec_TD.fast_script index 4510b01..49b8a3e 100644 --- a/function_test/BER_EncDec/BER_EncDec_TD.fast_script +++ b/function_test/BER_EncDec/BER_EncDec_TD.fast_script @@ -9,9 +9,9 @@ :lang eng. .* :docname.Test Description -:docno.8/152 91-CRL 113 200/2 Uen -:rev.A -:date.2012-06-27 +:docno.8/152 91-CRL 113 200/5 Uen +:rev.C +:date.2015-04-27 .* :prep.ETH/XZR Kristof Szabados (+36 1 437 7256) :appr.ETH/XZ (Roland Gecse) diff --git a/function_test/Config_Parser/Logging_1_TD.script b/function_test/Config_Parser/Logging_1_TD.script index 285f4e0..e3a6a6c 100755 --- a/function_test/Config_Parser/Logging_1_TD.script +++ b/function_test/Config_Parser/Logging_1_TD.script @@ -14,9 +14,9 @@ .* Document header information :docname.Test Description -:docno.24/152 91-CRL 113 200/4 Uen -:rev.PA6 -:date.2014-04-01 +:docno.24/152 91-CRL 113 200/5 Uen +:rev.C +:date.2015-04-27 :prep.ETH/RZX Norbert Bartha (ethnba) :appr.ETH/RZX (Csaba Koppany) diff --git a/function_test/Config_Parser/OrderedInclude.script b/function_test/Config_Parser/OrderedInclude.script index 6a80b48..e22683f 100644 --- a/function_test/Config_Parser/OrderedInclude.script +++ b/function_test/Config_Parser/OrderedInclude.script @@ -15,8 +15,8 @@ .* Document header information :docname.Test Description :docno.xx/152 91-CRL 113 200/3 Uen -:rev.A -:date.2013-13-14 +:rev.C +:date.2015-04-27 :prep.ETH/XZR Jeno Balasko :appr.ETH/XZR (Elemer Lelik) diff --git a/function_test/Config_Parser/PreprocessingCfgFiles_TD.script b/function_test/Config_Parser/PreprocessingCfgFiles_TD.script index 6a48c1a..19926d9 100644 --- a/function_test/Config_Parser/PreprocessingCfgFiles_TD.script +++ b/function_test/Config_Parser/PreprocessingCfgFiles_TD.script @@ -14,9 +14,9 @@ .* Document header information :docname.Test Description -:docno.xx/152 91-CRL 113 200/2 Uen -:rev.A -:date.2013-01-16 +:docno.xx/152 91-CRL 113 200/5 Uen +:rev.C +:date.2015-04-27 :prep.ETH/RZX Jeno Balasko (ethbaat) :appr.ETH/RZX (Gyula Koos) diff --git a/function_test/RAW_EncDec/RAW_EncDec_TD.fast_script b/function_test/RAW_EncDec/RAW_EncDec_TD.fast_script index 02c2cdf..fd145b6 100644 --- a/function_test/RAW_EncDec/RAW_EncDec_TD.fast_script +++ b/function_test/RAW_EncDec/RAW_EncDec_TD.fast_script @@ -9,9 +9,9 @@ :lang eng. .* :docname.Test Description -:docno.7/152 91-CRL 113 200/2 Uen +:docno.7/152 91-CRL 113 200/5 Uen :rev.A -:date.2013-02-01 +:date.2015-04-27 .* :prep.ETH/XZR Jeno Balasko (+36 1 437 7760) :appr.ETH/XZ (Gyula Koos) diff --git a/function_test/Semantic_Analyser/ASN_SA_1_TD.script b/function_test/Semantic_Analyser/ASN_SA_1_TD.script index 4e33f50..d3dedc0 100644 --- a/function_test/Semantic_Analyser/ASN_SA_1_TD.script +++ b/function_test/Semantic_Analyser/ASN_SA_1_TD.script @@ -14,9 +14,9 @@ .* Document header information :docname.Test Description -:docno. Uen -:rev.PA1 -:date.2005.02.03. +:docno. 12/15291-CRL200/5 Uen +:rev.A +:date.2015-04-27 :prep.ETH/RZD Endre Szalai (+36 1 437 7796) :appr.ETH/RZ (Zsolt Szendrei) diff --git a/function_test/Semantic_Analyser/ASN_SA_asn1adhoc_TD.script b/function_test/Semantic_Analyser/ASN_SA_asn1adhoc_TD.script index 834ce8d..f4436d6 100644 --- a/function_test/Semantic_Analyser/ASN_SA_asn1adhoc_TD.script +++ b/function_test/Semantic_Analyser/ASN_SA_asn1adhoc_TD.script @@ -14,9 +14,9 @@ .* Document header information :docname.Test Description -:docno. +:docno.20/15291-CRL200/5 Uen :rev. -:date.2005.01.31. +:date.2015-04-27 :prep.ETH/RZD Endre Szalai (+36 1 437 7796) :appr. @@ -33,7 +33,7 @@ :xmp tab=2. REV DATE PREPARED CHANGE __________________________________________________ -- 2005-01-31 ETHESI New document for TITAN R6 +- 2005-01-31 ETHESI New document for TITAN R1.6 :exmp. .*---------------------------------------------------------------------* :h2.Purpose diff --git a/function_test/Semantic_Analyser/TTCN3_SA_10_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_10_TD.script index 89dea16..3d0552c 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_10_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_10_TD.script @@ -14,11 +14,11 @@ .* Document header information :docname.Test Description -:docno.22/152 91-CRL 113 200/3 Uen +:docno.22/152 91-CRL 113 200/5 Uen :rev.A -:date.2013-01-17 +:date.2015-04-27 -:prep.ETH/XZR Krisztian Pandi +:prep.ETH/XZ Jeno Balasko :appr.ETH/XZ (Gyula Koos) :checked.ETHGRY diff --git a/function_test/Semantic_Analyser/TTCN3_SA_11_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_11_TD.script index ce629bd..03373a9 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_11_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_11_TD.script @@ -9,9 +9,9 @@ text. :lang eng. .* :docname.Test Description -:docno. -:rev.PA1 -:date.2011.11.21 +:docno. xy/152 91-CRL 113 200/5 Uen +:rev.A +:date.2015-04-27 .* :prep.ETH/XZR ETHBAAT :subresp.ETHBAAT diff --git a/function_test/Semantic_Analyser/TTCN3_SA_12_TD.script_not_running b/function_test/Semantic_Analyser/TTCN3_SA_12_TD.script_not_running index 6c66e19..fde96ed 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_12_TD.script_not_running +++ b/function_test/Semantic_Analyser/TTCN3_SA_12_TD.script_not_running @@ -8,8 +8,8 @@ .* Document header information :docname.Test Description :docno.xx/152 91-CRL 113 200 Uen -:rev.PA1 -:date.2011-11-16 +:rev.A +:date.2015-04-27 :prep.ETH/RZX Jeno Balasko (ethbaat) :appr.ETH/RZX (Roland Gecse) diff --git a/function_test/Semantic_Analyser/TTCN3_SA_13_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_13_TD.script index 3667858..3011ec2 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_13_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_13_TD.script @@ -9,9 +9,9 @@ text. :lang eng. .* :docname.Test Description -:docno. +:docno.xz/152 91-CRL 113 200 Uen :rev.PA3 -:date.2013-01-16 +:date.2015-04-27 .* :prep.ETH/XZR ETHBAAT :subresp.ETHBAAT diff --git a/function_test/Semantic_Analyser/TTCN3_SA_1_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_1_TD.script index 37e1db1..f4c5b92 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_1_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_1_TD.script @@ -14,11 +14,11 @@ .* Document header information :docname.Test Description -:docno.12/152 91-CRL 113 200/3 Uen +:docno.12/152 91-CRL 113 200/5 Uen :rev.A -:date.2013-01-17 +:date.2015-04-27 -:prep.ETH/XZR Krisztian Pandi +:prep.ETH/XZR Jeno Balasko :appr.ETH/XZ (Gyula Koos) :checked.ETHGRY diff --git a/function_test/Semantic_Analyser/TTCN3_SA_3_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_3_TD.script index e769c18..5ced083 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_3_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_3_TD.script @@ -14,12 +14,12 @@ .* Document header information :docname.Test Description -:docno.14/152 91-CRL 113 200/3 Uen +:docno.14/152 91-CRL 113 200/5 Uen :rev.A -:date.2013-01-17 +:date.2015-04-27 -:prep.ETH/XZR Krisztian Pandi -:appr.ETH/XZ (Gyula Koos) +:prep.ETH/XZ Jeno Balasko +:appr.ETH/XZ (Elemer Lelik) :checked.ETHGRY :title.Test description of the TTCN-3 Semantic Analyzer: Scope Rules diff --git a/function_test/Semantic_Analyser/TTCN3_SA_4_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_4_TD.script index 46eef82..bde23e4 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_4_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_4_TD.script @@ -16,9 +16,9 @@ :docname.Test Description :docno.15/152 91-CRL 113 200/3 Uen :rev.A -:date.2013-01-17 +:date.2015-04-27 -:prep.ETH/XZR Krisztian Pandi +:prep.ETH/XZ Jeno Balasko :appr.ETH/XZ (Gyula Koos) :checked.ETHGRY diff --git a/function_test/Semantic_Analyser/TTCN3_SA_5_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_5_TD.script index 4db626a..86e414e 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_5_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_5_TD.script @@ -14,11 +14,11 @@ .* Document header information :docname.Test Description -:docno.16/152 91-CRL 113 200/3 Uen +:docno.16/152 91-CRL 113 200/5 Uen :rev.A -:date.2013-01-17 +:date.2015-04-27 -:prep.ETH/XZR Krisztian Pandi +:prep.ETH/XZ Jeno Balasko :appr.ETH/XZ (Gyula Koos) :checked.ETHGRY diff --git a/function_test/Semantic_Analyser/TTCN3_SA_6_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_6_TD.script index c6402d6..b860399 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_6_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_6_TD.script @@ -16,9 +16,9 @@ :docname.Test Description :docno.17/152 91-CRL 113 200/3 Uen :rev.A -:date.2013-01-17 +:date.2015-04-27 -:prep.ETH/XZR Krisztian Pandi +:prep.ETH/XZ Jeno Balasko :appr.ETH/XZ (Gyula Koos) :checked.EKRISZA @@ -16537,7 +16537,7 @@ ConsoleMask := WARNING | ERROR | TESTCASE | STATISTICS ModuleA -(?im)Dynamic test case error: Accessing an element in an unbound value of type @ModuleA.t_recof. +(?im)Dynamic test case error: Accessing an element in an unbound value of type @PreGenRecordOf.PREGEN_RECORD_OF_INTEGER. :exmp. @@ -16577,7 +16577,7 @@ ConsoleMask := WARNING | ERROR | TESTCASE | STATISTICS ModuleA -(?im)Dynamic test case error: Index overflow in a value of type @ModuleA.t_recof: The index is 10, but the value has only 2 elements. +(?im)Dynamic test case error: Index overflow in a value of type @PreGenRecordOf.PREGEN_RECORD_OF_INTEGER: The index is 10, but the value has only 2 elements. :exmp. @@ -16617,7 +16617,7 @@ ConsoleMask := WARNING | ERROR | TESTCASE | STATISTICS ModuleA -(?im)Dynamic test case error: Accessing an element in an unbound value of type @ModuleA.t_setof. +(?im)Dynamic test case error: Accessing an element in an unbound value of type @PreGenRecordOf.PREGEN_SET_OF_INTEGER. :exmp. @@ -16657,7 +16657,7 @@ ConsoleMask := WARNING | ERROR | TESTCASE | STATISTICS ModuleA -(?im)Dynamic test case error: Index overflow in a value of type @ModuleA.t_setof: The index is 10, but the value has only 2 elements. +(?im)Dynamic test case error: Index overflow in a value of type @PreGenRecordOf.PREGEN_SET_OF_INTEGER: The index is 10, but the value has only 2 elements. :exmp. diff --git a/function_test/Semantic_Analyser/TTCN3_SA_7_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_7_TD.script index 99987ce..10878cc 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_7_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_7_TD.script @@ -14,9 +14,9 @@ .* Document header information :docname.Test Description -:docno.18/152 91-CRL 113 200/3 Uen +:docno.18/152 91-CRL 113 200/5 Uen :rev.A -:date.2013-01-17 +:date.2015-04-27 :prep.ETH/XZR Krisztian Pandi :appr.ETH/XZ (Gyula Koos) diff --git a/function_test/Semantic_Analyser/TTCN3_SA_9_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_9_TD.script index f136aff..9076fc2 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_9_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_9_TD.script @@ -14,11 +14,11 @@ .* Document header information :docname.Test Description -:docno.20/152 91-CRL 113 200/3 Uen +:docno.xx/152 91-CRL 113 200/5 Uen :rev.A -:date.2013-01-17 +:date.2015-04-27 -:prep.ETH/XZR Krisztian Pandi +:prep.ETH/XZ Jeno Balasko :appr.ETH/XZ (Gyula Koos) :checked.ETHGRY @@ -41,9 +41,10 @@ D 2007-06-08 EJNOSZA Updates for TITAN R7B (expected error messages for E 2008-10-01 EKRISZA Updates for TITAN R7E F 2010-01-18 EKRISZA Updated for TITAN R8C K 2011-10-10 EKRISZA Updated for TITAN R8H -A 2011-12-12 EKRISZA Updated for release -A 2012-06-27 EFERKOV Updated for release -A 2013-01-17 EKRIPND Updated for release +A 2011-12-12 EKRISZA Updated for release +A 2012-06-27 EFERKOV Updated for release +A 2013-01-17 EKRIPND Updated for release +A 2015-04-27 ETHBAAT Updated for release :exmp. .*---------------------------------------------------------------------* diff --git a/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script index db2b40f..b1daa6a 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script @@ -14,11 +14,11 @@ .* Document header information :docname.Test Description -:docno.20/152 91-CRL 113 200/3 Uen +:docno.2x/152 91-CRL 113 200/5 Uen :rev.A -:date.2013-01-17 +:date.2015-04-27 -:prep.ETH/XZR Krisztian Pandi +:prep.ETH/XZ Jeno Balasko :appr.ETH/XZ (Gyula Koos) :checked.ETHGRY @@ -33,7 +33,7 @@ :xmp tab=2. REV DATE PREPARED CHANGE __________________________________________________ -- 2005-02-19 EGBOTAT New document for TITAN R6 +- 2005-02-19 EGBOTAT New document for TITAN R1.6 - 2005-06-30 ETIBHRA Added select-case, alive, interleave tests - 2005-08-16 ETIBHRA Deleted select-case, alive, interleave tests - 2007-12-03 ETHNBA TCs for IsBound are added @@ -3644,22 +3644,19 @@ testcase tc() runs on Empty module bad_arguments { type component empty { } -type record of integer intlist1 -type record of integer intlist2 +type record of integer intlist testcase tc () runs on empty { var integer a := 0 var charstring cs_1 := "My name is JJ" var bitstring bs_1 := '11'B var charstring cs_2 := replace("My name is JJ", -1, 2, "xx") - var intlist1 il1 := { 1, 2, 3 } - var intlist2 il2 := { 4 } + var intlist il1 := { 1, 2, 3 } cs_2 := replace("My name is JJ", 1, 2, '11'B) cs_2 := replace("My name is JJ", 100, 2, "x") cs_2 := replace("My name is JJ", a, 100, "x") cs_2 := replace(cs_1, 1, 2, bs_1) cs_2 := replace(cs_1, 1.0, 2, "xx") - il1 := replace(il1, 1, 1, il2) il1 := replace(il1, 1, 1, cs_1[10]) } } @@ -3670,11 +3667,8 @@ testcase tc () runs on empty (?is)\berror:.+?Fourth operand of operation `replace\(\)' is of type `bitstring', but a value of type `charstring' was expected here - -(?is)\berror:.+?Fourth operand of operation `replace\(\)' is of type `\@bad_arguments.intlist2', but a value of type `\@bad_arguments.intlist1' was expected here - -(?is)\berror:.+?Fourth operand of operation `replace\(\)' is of type `charstring', but a value of type `\@bad_arguments.intlist1' was expected here +(?is)\berror:.+?Fourth operand of operation `replace\(\)' is of type `charstring', but a value of type `\@bad_arguments.intlist' was expected here (?is)\berror:.+?The sum of second operand `index' \(100\) and third operand `len' \(2\) is greater than the length of the first operand \(13\) @@ -4301,31 +4295,6 @@ control { :exmp. -.*---------------------------------------------------------------------* -:h3.Adhoc:: TR 935 - concatenation of incompatible list types -.*---------------------------------------------------------------------* -:xmp tab=0. - - - - -module TR935 { -type record of integer intlist1 -type record of integer intlist2 -control { - var intlist1 il1 := { 1, 2, 3 } - var intlist2 il2 := { 4 } - il1 := il1 & il2 - // Merge this small test-case later. -} -} - - -(?is)\berror: The operands of operation `&' should be of compatible types - - -:exmp. - .*---------------------------------------------------------------------* :h3.Adhoc:: Type Compatibility - Sample tests for structured types .*---------------------------------------------------------------------* @@ -4376,13 +4345,13 @@ ro2 := substr(myrec1 : t_myrecof3, 0, 1) // !OK (?is)\berror: Type mismatch: a value of type `\@Compat1.myrecof1' was expected instead of `integer\[4\]' - + (?is)\berror: The operands of operation `==' should be of compatible types (?is)\berror: Type mismatch: `\@Compat1.myrecof1' and `integer\[4\]' are not compatible: Incompatible record of/SEQUENCE OF subtypes - + (?is)\berror: Type mismatch: `@Compat1.myrecof1' and `@Compat1.myrecof3' are not compatible: Incompatible record of/SEQUENCE OF subtypes @@ -6116,13 +6085,7 @@ module module1 (?is)\berror: \{ \} is not a valid value for type `\@module1.myro1' which has subtype length\(1\) - -(?is)\berror: The operands of operation `==' should be of compatible types - - -(?is)\berror: Type mismatch: a value or template of type `\@module1.myro1' was expected instead of `\@module1.myro2' - - + (?is)\berror: Type mismatch: `\@module1.myro1' and `\@module1.myro2' are not compatible: Incompatible record of/SEQUENCE OF subtypes @@ -6202,13 +6165,7 @@ module module1 (?is)\berror: \{ \} is not a valid value for type `\@module1.myso1' which has subtype length\(1\) - -(?is)\berror: The operands of operation `==' should be of compatible types - - -(?is)\berror: Type mismatch: a value or template of type `\@module1.myso1' was expected instead of `\@module1.myso2' - - + (?is)\berror: Type mismatch: `\@module1.myso1' and `\@module1.myso2' are not compatible: Incompatible set of/SET OF subtypes @@ -8323,10 +8280,10 @@ Temp :exmp. .*---------------------------------------------------------------------* -:h3.Adhoc:: modulepar invalid simple type: component, port, default +:h3.Adhoc:: modulepar invalid simple type: port .*---------------------------------------------------------------------* :xmp tab=0. - + @@ -8343,76 +8300,7 @@ module Temp { type default default_DT; } - -(?is)\berror: - - -(?im)\bnotify\b.+?\bcode\b.+?\bnot\b.+?\bgenerated\b - -:exmp. - -.*------------------------------------------------------------------------------------* -:h3.Adhoc:: modulepar invalid compound type: record, set with component, default -.*------------------------------------------------------------------------------------* -:xmp tab=0. - - - - -module Temp { - modulepar invalidRec tsp_Rec; - modulepar invalidSet tsp_Set; - modulepar invalidUnion tsp_Union; - type record invalidRec { - integer varI1, - default_DT varDT, - charstring varStr - } - type set invalidSet { - integer varI2, - comp_CT varCT1, - charstring varStr - } - type union invalidUnion { - integer varI3, - comp_CT varCT2 - } - type default default_DT; - type component comp_CT { - var integer v_int := 0; - } -} - - -(?is)\berror: - - -(?im)\bnotify\b.+?\bcode\b.+?\bnot\b.+?\bgenerated\b - -:exmp. - -.*------------------------------------------------------------------------------------* -:h3.Adhoc:: modulepar invalid list: record of, set of and array with component, default -.*------------------------------------------------------------------------------------* -:xmp tab=0. - - - - -module Temp { - modulepar ListRec tsp_ListRec; - modulepar ListSet tsp_listSet; - modulepar compArrayType tsp_compArray; - type record of comp_CT ListRec; - type set of default_DT ListSet; - type comp_CT compArrayType[3]; - type default default_DT; - type component comp_CT { - var integer v_int := 0; - } -} - - + (?is)\berror: @@ -8448,7 +8336,7 @@ module Temp { (?im)\bcircular\b.+?\breference\b - + (?is)\berror: diff --git a/function_test/Text_EncDec/TEXT_1_TD.fast_script b/function_test/Text_EncDec/TEXT_1_TD.fast_script index fd201d4..9b83413 100644 --- a/function_test/Text_EncDec/TEXT_1_TD.fast_script +++ b/function_test/Text_EncDec/TEXT_1_TD.fast_script @@ -9,9 +9,9 @@ :lang eng. .* :docname.Test Description -:docno.21/152 91-CRL 113 200/2 Uen +:docno.21/152 91-CRL 113 200/5 Uen :rev.A -:date.2012-06-27 +:date.2015-04-27 .* :prep.ETH/XZR Ferenc Kovacs (+36 1 439 5511) :appr.ETH/XZ (Roland Gecse) diff --git a/function_test/Tools/SAtester b/function_test/Tools/SAtester index 73c46e7..6c2d49b 100755 --- a/function_test/Tools/SAtester +++ b/function_test/Tools/SAtester @@ -78,7 +78,7 @@ proc _compiler {message} { } -proc _executor {message coverage_args rt_2} { +proc _executor {message coverage_args} { global sh_id if {![file exists Makefile]} { @@ -162,12 +162,11 @@ set tc_counter 0 set err_counter 0 set errpostfix "_error" set coverage_args "" -set rt_2 "" set start_date [exec date +"%H:%M:%S"] if {[lindex $argv 0] == "-coverage"} {set argv [lrange $argv 1 end]; set coverage_args "COVERAGE=1"; puts "Coverage mode enabled!"} # RT2 comes after coverage -if {[lindex $argv 0] == "-rt2"} {set argv [lrange $argv 1 end]; set rt_2 "RT2=2"; puts "Function-test runtime enabled!"} +if {[lindex $argv 0] == "-rt2"} {set argv [lrange $argv 1 end]; set env(RT2) yes; puts "Function-test runtime enabled!"} set errorfilename $argv$errpostfix @@ -249,9 +248,9 @@ while {$i <= $tc_counter} { } if {([string length $result_mess] > 3)&&($tc_state != "execute")&&($tc_state != "pure_execute")} {_compiler $result_mess} - if {([string length $Line] > 3)&&($tc_state == "execute")} {_executor $result_mess $coverage_args $rt_2} + if {([string length $Line] > 3)&&($tc_state == "execute")} {_executor $result_mess $coverage_args} if {([string length $Line] > 3)&&($tc_state == "pure_execute")} { - _executor $result_mess $coverage_args $rt_2 + _executor $result_mess $coverage_args } incr i diff --git a/function_test/XER_EncDec/XER_EncDec_TD.script b/function_test/XER_EncDec/XER_EncDec_TD.script index 098c99a..e110cb1 100644 --- a/function_test/XER_EncDec/XER_EncDec_TD.script +++ b/function_test/XER_EncDec/XER_EncDec_TD.script @@ -9,12 +9,12 @@ :lang eng. .* :docname.Test Description -:docno.7/152 91-CRL 113 200/4 Uen +:docno.9/152 91-CRL 113 200/5 Uen :rev.A -:date.2014-04-29 +:date.2015-04-27 .* :prep.ETH/XZ Botond Baranyi -:appr.ETH/XZ (Jeno Balasko) +:appr.ETH/XZ (Elemer Lelik) :checked.ETHBAAT .* :title.Test description - XER coder @@ -828,7 +828,7 @@ control { -Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': While checking anyElement: XML namespace "http://www.somewhere.com" is not in the allowed namespace list. +Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': Index 0: While checking anyElement: XML namespace "http://www.somewhere.com" is not in the allowed namespace list. @@ -875,7 +875,7 @@ control { -Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': While checking anyElement: XML namespace "http://www.somewhereelse.com" is not in the allowed namespace list. +Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': Index 0: While checking anyElement: XML namespace "http://www.somewhereelse.com" is not in the allowed namespace list. @@ -924,7 +924,7 @@ control { -Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': While checking anyElement: XML namespace "http://www.someotherplace.com" is not in the allowed namespace list. +Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': Index 0: While checking anyElement: XML namespace "http://www.someotherplace.com" is not in the allowed namespace list. @@ -1124,7 +1124,7 @@ control { -Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': While checking anyElement: The unqualified XML namespace is in the excluded namespace list. +Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': Index 0: While checking anyElement: The unqualified XML namespace is in the excluded namespace list. @@ -1171,7 +1171,7 @@ control { -Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': While checking anyElement: XML namespace "http://www.somewhere.com" is in the excluded namespace list. +Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': Index 0: While checking anyElement: XML namespace "http://www.somewhere.com" is in the excluded namespace list. @@ -1218,7 +1218,7 @@ control { -Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': While checking anyElement: XML namespace "http://www.somewhereelse.com" is in the excluded namespace list. +Dynamic test case error: While XER-decoding type '@Temp.any_elem_rec_of': Index 0: While checking anyElement: XML namespace "http://www.somewhereelse.com" is in the excluded namespace list. diff --git a/function_test/doc/TTCN3_Executor_TestReport.doc b/function_test/doc/TTCN3_Executor_TestReport.doc index 458f786c0c7725b5e73773bf4e43fdc44ffa0591..860c9b06e00f2cb20da5ba5a7f7624facfee12c2 100644 GIT binary patch delta 69947 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 C&PI{| delta 56432 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 CmHN*B diff --git a/help/Makefile b/help/Makefile index 3c4191b..55bbae0 100644 --- a/help/Makefile +++ b/help/Makefile @@ -26,17 +26,17 @@ exception execute extension external fail false float float2int \ float2str for from function friend get_stringencoding getcall getreply getverdict goto group \ hex2bit hex2int hex2oct hex2str hexstring if ifpresent import in \ inconc infinity inout int2bit int2char int2float int2hex int2oct \ -int2str int2unichar integer interleave ischosen ispresent isvalue kill killed \ +int2str int2unichar integer interleave isbound ischosen ispresent isvalue kill killed \ label language length lengthof log map match message mixed mod \ modifies module modulepar mtc noblock none not not4b nowait null objid \ oct2bit oct2char oct2hex oct2int oct2str oct2unichar octetstring of omit on \ operators optional or or4b out override param pass pattern permutation \ port public private procedure raise read receive record recursive regexp rem remove_bom repeat \ -reply return rnd running runs select self send sender set setverdict \ +replace reply return rnd running runs select self send sender set setverdict \ signature sizeof start stop str2bit str2float str2hex \ -str2int str2oct subset substr superset system template testcase \ -timeout timer to trigger true type unichar2int unichar2oct union universal unmap \ -value valueof var variant verdicttype while with xor xor4b)) +str2int str2oct subset substr superset system template testcase testcasename \ +timeout timer to trigger true type unichar2char unichar2int unichar2oct union universal unmap \ +value valueof var variant verdicttype while with xor xor4b profiler)) IMAGE_FILES := $(addprefix images/, $(addsuffix .jpg, ao left right up)) images/titan_transparent.gif diff --git a/help/info/on.html b/help/info/on.html index 4768cfb..944626b 100644 --- a/help/info/on.html +++ b/help/info/on.html @@ -23,7 +23,7 @@ - +


diff --git a/help/info/operators.html b/help/info/operators.html index e08e10e..66c7482 100644 --- a/help/info/operators.html +++ b/help/info/operators.html @@ -22,8 +22,8 @@ - - + +


diff --git a/help/info/optional.html b/help/info/optional.html index 41ed700..22c3157 100644 --- a/help/info/optional.html +++ b/help/info/optional.html @@ -22,7 +22,7 @@ - + diff --git a/help/info/procedure.html b/help/info/procedure.html index 9c773f9..11a0b81 100644 --- a/help/info/procedure.html +++ b/help/info/procedure.html @@ -23,7 +23,7 @@ - +


diff --git a/help/info/profiler.html b/help/info/profiler.html new file mode 100644 index 0000000..1f5c2bf --- /dev/null +++ b/help/info/profiler.html @@ -0,0 +1,134 @@ + + + + + +profiler + + + + + + +
Titan
+ + + + + + + +
+


+

+
+

@profiler

+
+

The keyword is used to start or stop the profiling or check if the profiling started or not. 

+

By default the profiler is automatically started for each component when the program starts. This can be changed in the configuration file. 

+

Detailed description can be found in the Programmers' Reference Guide.

+ +
+

1. Stopping the profiler

+

2. Starting the profiler

+

3. Checking the profiler running state

+
+ + + +

Related keywords:

+ + +
+

1. Stopping the profiler

+ +
+
+ + + + +
+

@profiler.stop

+
+
+
+ +
+

The profiler can be stopped using the @profiler.stop command. This only affects profiling and code coverage in the current component

+

When stopped the profiler does not measure new data.

+

This command has no effect if the profiler is already stopped.

+ +
+

2. Starting the profiler

+ +
+ + +
+
+ + + + +
+

@profiler.start

+
+
+
+

A stopped profiler can be restarted with the @profiler.start command. This only affects profiling and code coverage in the current component.

+

Similarly, this has no effect if the profiler is already running.

+ +

The execution count of a function is measured at the start of the function, thus if the profiler is stopped when the function is called, its call will not be measured, even if the profiler is restarted during the function’s execution.

+ + +
+

3. Checking the profiler running state

+ + + +
+
+ + + + +
+

@profiler.running

+
+
+
+ +
+

The boolean value @profiler.running stores the state of the profiler in the current component (true if it’s running or false if it’s stopped).

+ +
+

Example:

+ +

function f1(inout integer x) runs on C
+{
+  var boolean stop_prof := not @profiler.running;
+  @profiler.start;
+  x := x + c1;
+  if (stop_prof) {
+    @profiler.stop;
+  }
+}
+
+

+ +

This function is always profiled and returns the profiler to its original state.

+ + + diff --git a/help/info/public.html b/help/info/public.html index c98d49a..7448a81 100644 --- a/help/info/public.html +++ b/help/info/public.html @@ -22,7 +22,7 @@ - + diff --git a/help/info/running.html b/help/info/running.html index 474c7b8..40abdc6 100644 --- a/help/info/running.html +++ b/help/info/running.html @@ -33,9 +33,10 @@

1. Checking components

2. Checking timers

+

3. Starting the profiler


-

1. Checking components

+

1. Checking components


The operation is used to check whether a given parallel test component is running (i.e., has neither timed out nor been stopped). The Boolean value true is returned if the component have been started but not yet terminated or stopped, false otherwise.

@@ -53,6 +54,7 @@ the component have been started but not yet terminated or stopped, false otherwi
  • any
  • component
  • create
  • +
  • @profiler

  • @@ -85,16 +87,16 @@ the component have been started but not yet terminated or stopped, false otherwi
    -

    Examples

    +

    See Examples


    -

    2. Checking  timers

    +

    2. Checking  timers


    The operation is used to check whether a given timer is running (i.e., has neither timed out nor been stopped). The Boolean value true is returned if the timer is running, false otherwise.

    • The operation does not block TTCN-3 program execution, i.e., it reflects the momentarily state of the timer and does not wait for timeout.
    • The keyword any may be used to check whether at least - one timer is runnig.
    • + one timer is running.

    Related keywords:

      @@ -123,16 +125,18 @@ running, false otherwise.

      timer_identifier is the name used to refer to the timer. It must begin with a letter, may contain letters, numbers and underscore characters.

    -
    -

    It is possible to check a member of an timer array.

    -
    +
    +

    It is possible to check a member of a timer array.

    +
    +

    See Example 1c

    +

      timer_identifier[array_index].runnig;

    + face="Courier New" color="#003258" size="5">].running;
    @@ -147,17 +151,19 @@ running, false otherwise.

    array_index points out the timer to be checked.

    -
    +
    +

    Examples

    Example 1a:

    var boolean v_Tbana := vc_metro.running;

    The variable v_Tbana gets the value true if the component with the reference vc_metro is running.


    +

    Example 1b:

    var boolean v_Ubahn := all component.running;

    The variable v_Ubahn will true if all started parallel components are still running.


    -

    Example 1c:

    +

    Example 1c

    var boolean v_metropolitain := any component.running; 

    The variable v_metropolitain is true if at least one parallel component is still running.

    @@ -178,6 +184,6 @@ running, false otherwise.



    BNF definition of component running

    -

    BNF definition of timer runnig

    +

    BNF definition of timer runnnig

    diff --git a/help/info/start.html b/help/info/start.html index 65b655a..dec0f96 100644 --- a/help/info/start.html +++ b/help/info/start.html @@ -34,12 +34,13 @@

    1. Starting a component

    2. Starting a port

    3. Starting a timer

    +

    4. Starting the profiler


    -

    1. Starting a component

    +

    1. Starting a component


    When a parallel test component is created it is not executing any behavior yet. -

    The start operation can be used to execute the required function on the addressedparallel test component.

    +

    The start operation can be used to execute the required function on the addressed parallel test component.

    The function will be executed remotely, thus the start operation does not block execution on the component on which it was invoked.

    Normal parallel test components can only be started once, but alive parallel test components may execute several functions consecutively.

    Some limitations apply to the argument function: @@ -61,6 +62,7 @@

  • killed
  • running
  • stop
  • +
  • @profiler

  • @@ -87,7 +89,7 @@
    -

    2. Starting a port

    +

    2. Starting a port


    The keyword may be used to start a port.

      @@ -129,7 +131,7 @@

    -

    3. Starting a timer

    +

    3. Starting a timer


    The keyword may be used to indicate that a timer should start running.

      @@ -165,9 +167,9 @@ Otherwise it is optional and overwrites the default value. The value is measured in seconds; floating point value must be used.
    -
    +

    It is possible to start a member of an timer array.

    -
    +
    diff --git a/help/info/stop.html b/help/info/stop.html index 8978e33..0bc493c 100644 --- a/help/info/stop.html +++ b/help/info/stop.html @@ -35,9 +35,10 @@

    1. Stopping components

    2. Stopping ports

    3. Stopping timers

    +

    4. Stopping the profiler


    -

    0. Terminating execution

    +

    0. Terminating execution

    The stop statement is used to terminate test execution. Whenever a stop statement is reached, the execution of the underlying testcase is immediately terminatef. The result of execution will be error.


    @@ -55,7 +56,9 @@ error.

    Examples:


    -

    1. Stopping components

    + + +

    1. Stopping components

    • When used in a test case, altstep or function that are executed on a test component, the keyword terminates the relevant test component;
    • when used in the control part of a module or in a function used by the control part of a module, it terminates the execution of the module control part.
    • @@ -68,6 +71,7 @@ error.
    • all
    • component
    • create
    • +
    • @profiler

    @@ -99,9 +103,11 @@ error.
    -

    Examples

    +

    See Examples


    -

    2. Stopping a port

    + + +

    2. Stopping a port


    The keyword may be used to stop a port.

      @@ -141,7 +147,7 @@ error.

    -

    3. Stopping  timers

    +

    3. Stopping  timers


    The keyword may be used to indicate that a timer should stop running.

      @@ -177,9 +183,9 @@ error.

      timer_identifier is the name used to refer to the timer. It must begin with a letter, may contain letters, numbers and underscore characters.

    -
    +

    It is possible to stop a member of an timer array.

    -
    +
    @@ -198,7 +204,7 @@ error.

    timer_identifier is the name used to refer to the timer. It must begin with a letter, may contain letters, numbers and underscore characters.

  • -

    array_index points out the timer to be stoped.

    +

    array_index points out the timer to be stopped.

  • Examples

    diff --git a/help/titan_index.html b/help/titan_index.html index 5e17b13..a35510a 100644 --- a/help/titan_index.html +++ b/help/titan_index.html @@ -89,8 +89,8 @@ - + @@ -268,13 +268,13 @@ + - @@ -304,8 +304,8 @@ - + @@ -349,8 +349,8 @@ - + @@ -384,6 +384,15 @@ + + + + + + + + +
    deactivatedecvalue decode_base64decvalue default disconnect displayprocedure
    @profiler public           
    raise 
    self selectself send sender set 
    unichar2int unichar2charunichar2int unichar2oct union universal   
    @profiler      
    diff --git a/help/titan_main.html b/help/titan_main.html index c866f9d..1c7e9a3 100644 --- a/help/titan_main.html +++ b/help/titan_main.html @@ -57,7 +57,9 @@ U V W - X

    + X + @ +

    diff --git a/loggerplugins/JUnitLogger2/JUnitLogger2.cc b/loggerplugins/JUnitLogger2/JUnitLogger2.cc new file mode 100644 index 0000000..825056e --- /dev/null +++ b/loggerplugins/JUnitLogger2/JUnitLogger2.cc @@ -0,0 +1,346 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2000-2014 Ericsson Telecom AB +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +/////////////////////////////////////////////////////////////////////////////// +#include "JUnitLogger2.hh" + +#include +#include + +#include + +extern "C" +{ + // It's a static plug-in, destruction is done in the destructor. We need + // `extern "C"' for some reason. + ILoggerPlugin *create_junit_logger() { return new JUnitLogger2(); } +} + +extern "C" { + ILoggerPlugin *create_plugin() { return new JUnitLogger2(); } + void destroy_plugin(ILoggerPlugin *plugin) { delete plugin; } +} + +TestSuite::~TestSuite() +{ + for (TestCases::const_iterator it = testcases.begin(); it != testcases.end(); ++it) { + delete (*it); + } +} + +JUnitLogger2::JUnitLogger2() +: filename_stem_(NULL), testsuite_name_(mcopystr("Titan")), filename_(NULL), file_stream_(NULL) +{ + // Overwrite values set by the base class constructor + + fprintf(stderr, "construct junitlogger\n"); + major_version_ = 2; + minor_version_ = 0; + name_ = mcopystr("JUnitLogger"); + help_ = mcopystr("JUnitLogger writes JUnit-compatible XML"); + dte_reason = ""; + //printf("%5lu:constructed\n", (unsigned long)getpid()); +} + +JUnitLogger2::~JUnitLogger2() +{ + //printf("%5lu:desstructed\n", (unsigned long)getpid()); + close_file(); + + Free(name_); + Free(help_); + Free(filename_); + Free(testsuite_name_); + Free(filename_stem_); + name_ = help_ = filename_ = filename_stem_ = NULL; + file_stream_ = NULL; +} + +void JUnitLogger2::init(const char */*options*/) +{ +//printf("%5lu:init\n", (unsigned long)getpid()); + fprintf(stderr, "Initializing `%s' (v%u.%u): %s\n", name_, major_version_, minor_version_, help_); +} + +void JUnitLogger2::fini() +{ + //puts("fini"); + //fprintf(stderr, "JUnitLogger2 finished logging for PID: `%lu'\n", (unsigned long)getpid()); +} + +void JUnitLogger2::set_parameter(const char *parameter_name, const char *parameter_value) { +//puts("set_par"); + if (!strcmp("filename_stem", parameter_name)) { + if (filename_stem_ != NULL) + Free(filename_stem_); + filename_stem_ = mcopystr(parameter_value); + } else if (!strcmp("testsuite_name", parameter_name)) { + if (filename_stem_ != NULL) + Free(testsuite_name_); + testsuite_name_ = mcopystr(parameter_value); + } else { + fprintf(stderr, "Unsupported parameter: `%s' with value: `%s'\n", + parameter_name, parameter_value); + } +} + +void JUnitLogger2::open_file(bool is_first) { + if (is_first) { + if (filename_stem_ == NULL) { + filename_stem_ = mcopystr("junit-xml"); + } + } + + if (file_stream_ != NULL) return; // already open + + if (!TTCN_Runtime::is_single() && !TTCN_Runtime::is_mtc()) return; // don't bother, only MTC has testcases + + filename_ = mprintf("%s-%lu.log", filename_stem_, (unsigned long)getpid()); + + file_stream_ = fopen(filename_, "w"); + if (!file_stream_) { + fprintf(stderr, "%s was unable to open log file `%s', reinitialization " + "may help\n", plugin_name(), filename_); + return; + } + + is_configured_ = true; + time(&(testsuite.start_ts)); + testsuite.ts_name = testsuite_name_; +} + +void JUnitLogger2::close_file() { + if (file_stream_ != NULL) { + time(&(testsuite.end_ts)); + testsuite.write(file_stream_); + fclose(file_stream_); + file_stream_ = NULL; + } + if (filename_) { + Free(filename_); + filename_ = NULL; + } +} + +void JUnitLogger2::log(const TitanLoggerApi::TitanLogEvent& event, + bool /*log_buffered*/, bool /*separate_file*/, + bool /*use_emergency_mask*/) +{ + if (file_stream_ == NULL) return; + + const TitanLoggerApi::LogEventType_choice& choice = event.logEvent().choice(); + + switch (choice.get_selection()) { + case TitanLoggerApi::LogEventType_choice::ALT_testcaseOp: { + const TitanLoggerApi::TestcaseEvent_choice& tcev = choice.testcaseOp().choice(); + + switch (tcev.get_selection()) { + case TitanLoggerApi::TestcaseEvent_choice::ALT_testcaseStarted: { + testcase.tc_name = tcev.testcaseStarted().testcase__name(); + // remember the start time + testcase.tc_start = 1000000LL * (long long)event.timestamp().seconds() + (long long)event.timestamp().microSeconds(); + break; } + + case TitanLoggerApi::TestcaseEvent_choice::ALT_testcaseFinished: { + const TitanLoggerApi::TestcaseType& tct = tcev.testcaseFinished(); + testcase.reason = tct.reason(); + testcase.module_name = tct.name().module__name(); + + const TitanLoggerApi::TimestampType& ts = event.timestamp(); + long long tc_end = 1000000LL * (long long)ts.seconds() + (long long)ts.microSeconds(); + testcase.time = (tc_end - testcase.tc_start) / 1000000.0; + + testcase.setTCVerdict(event); + testcase.dte_reason = dte_reason.data(); + dte_reason = ""; + testsuite.addTestCase(testcase); + testcase.reset(); + break; } + + case TitanLoggerApi::TestcaseEvent_choice::UNBOUND_VALUE: + testcase.verdict = TestCase::Unbound; + break; } // switch testcaseOp().choice.get_selection() + + break; } // testcaseOp + + case TitanLoggerApi::LogEventType_choice::ALT_errorLog: {// A DTE is about to be thrown + const TitanLoggerApi::Categorized& cat = choice.errorLog(); + dte_reason = escape_xml_element(cat.text()); + break; } + + default: break; + } // switch event.logEvent().choice().get_selection() + + fflush(file_stream_); +} + +CHARSTRING JUnitLogger2::escape_xml(const CHARSTRING& xml_str, int escape_chars) { + expstring_t escaped = NULL; + int len = xml_str.lengthof(); + for (int i=0; i': + if (escape_chars>) escaped = mputstr(escaped, ">"); + else escaped = mputc(escaped, c); + break; + case '"': + if (escape_chars") escaped = mputstr(escaped, """); + else escaped = mputc(escaped, c); + break; + case '\'': + if (escape_chars&APOS) escaped = mputstr(escaped, "'"); + else escaped = mputc(escaped, c); + break; + case '&': + if (escape_chars&) escaped = mputstr(escaped, "&"); + else escaped = mputc(escaped, c); + break; + default: + escaped = mputc(escaped, c); + } + } + CHARSTRING ret_val(escaped); + Free(escaped); + return ret_val; +} + +void TestCase::writeTestCase(FILE* file_stream_) const{ + switch(verdict){ + case None: { + fprintf(file_stream_, " \n", module_name.data(), tc_name.data(), time); + fprintf(file_stream_, " no verdict\n"); + fprintf(file_stream_, " \n"); + break; } + case Fail: { + fprintf(file_stream_, " \n", module_name.data(), tc_name.data(), time); + fprintf(file_stream_, " %s\n", reason.data()); + fprintf(file_stream_, "%s\n", stack_trace.data()); + fprintf(file_stream_, " \n"); + fprintf(file_stream_, " \n"); + break; } + case Error: { + fprintf(file_stream_, " \n", module_name.data(), tc_name.data(), time); + fprintf(file_stream_, " %s\n", dte_reason.data()); + fprintf(file_stream_, " \n"); + break; } + default: + fprintf(file_stream_, " \n", module_name.data(), tc_name.data(), time); + break; + } + fflush(file_stream_); +} + +void TestSuite::addTestCase(const TestCase& testcase) { + testcases.push_back(new TestCase(testcase)); + all++; + switch(testcase.verdict) { + case TestCase::Fail: failed++; break; + case TestCase::None: skipped++; break; + case TestCase::Error: error++; break; + case TestCase::Inconc: inconc++; break; + default: break; + } +} + +void TestSuite::write(FILE* file_stream_) { + double difftime_ = difftime(end_ts, start_ts); + fprintf(file_stream_, "\n" + "\n", + ts_name.data(), all, failed, error, skipped, inconc, difftime_); + fflush(file_stream_); + + for (TestCases::const_iterator it = testcases.begin(); it != testcases.end(); ++it) { + (*it)->writeTestCase(file_stream_); + } + + fprintf(file_stream_, "\n"); + fflush(file_stream_); +} + +void TestCase::setTCVerdict(const TitanLoggerApi::TitanLogEvent& event){ + TitanLoggerApi::Verdict tc_verdict = event.logEvent().choice().testcaseOp().choice().testcaseFinished().verdict(); + switch (tc_verdict) { + case TitanLoggerApi::Verdict::UNBOUND_VALUE: + case TitanLoggerApi::Verdict::UNKNOWN_VALUE: + // should not happen + break; + + case TitanLoggerApi::Verdict::v0none: + verdict = TestCase::None; + break; + + case TitanLoggerApi::Verdict::v1pass: + verdict = TestCase::Pass; + break; + + case TitanLoggerApi::Verdict::v2inconc: + verdict = TestCase::Inconc; + break; + + case TitanLoggerApi::Verdict::v3fail: { + verdict = TestCase::Fail; + addStackTrace(event); + break; } + + case TitanLoggerApi::Verdict::v4error: + verdict = TestCase::Error; + break; + } +} + +void TestCase::addStackTrace(const TitanLoggerApi::TitanLogEvent& event){ +// Add a stack trace + const TitanLoggerApi::TitanLogEvent_sourceInfo__list& stack = event.sourceInfo__list(); + + int stack_depth = stack.size_of(); + for (int i=0; i < stack_depth; ++i) { + const TitanLoggerApi::LocationInfo& location = stack[i]; + + stack_trace += " "; + stack_trace += location.filename(); + stack_trace += ":"; + stack_trace += int2str(location.line()); + stack_trace += " "; + stack_trace += location.ent__name(); + stack_trace += " "; + + // print the location type + switch (location.ent__type()) { + case TitanLoggerApi::LocationInfo_ent__type:: UNKNOWN_VALUE: + case TitanLoggerApi::LocationInfo_ent__type:: UNBOUND_VALUE: + // can't happen + break; + case TitanLoggerApi::LocationInfo_ent__type::unknown: + // do nothing + break; + case TitanLoggerApi::LocationInfo_ent__type::controlpart: + stack_trace += "control part"; + break; + case TitanLoggerApi::LocationInfo_ent__type::testcase__: + stack_trace += "testcase"; + break; + case TitanLoggerApi::LocationInfo_ent__type::altstep__: + stack_trace += "altstep"; + break; + case TitanLoggerApi::LocationInfo_ent__type::function__: + stack_trace += "function"; + break; + case TitanLoggerApi::LocationInfo_ent__type::external__function: + stack_trace += "external function"; + break; + case TitanLoggerApi::LocationInfo_ent__type::template__: + stack_trace += "template"; + break; + } + + if(i +#include +#include + +struct TestCase{ + typedef enum { + Pass, + Inconc, + Fail, + Error, + None, + Unbound + } Verdict; + + Verdict verdict; + std::string tc_name; + std::string module_name; + std::string reason; + std::string dte_reason; + std::string stack_trace; + long long tc_start; + double time; + + TestCase():tc_name(""), module_name(""), reason(""), dte_reason(""), stack_trace(""), tc_start(0), time(0.0){} + + void writeTestCase(FILE* file_stream_) const; + void setTCVerdict(const TitanLoggerApi::TitanLogEvent& event); + void addStackTrace(const TitanLoggerApi::TitanLogEvent& event); + void reset() { + tc_name = ""; + module_name = ""; + reason = ""; + dte_reason = ""; + stack_trace = ""; + tc_start = 0; + time = 0.0; + } +}; + + +struct TestSuite { + typedef std::vector TestCases; + +// TitanLoggerApi::TimestampType timestamp; TODO + std::string ts_name; + int all; + int skipped; + int failed; + int error; + int inconc; + TestCases testcases; + time_t start_ts; + time_t end_ts; + + TestSuite():ts_name(""), all(0), skipped(0), failed(0), error(0), inconc(0) {} + ~TestSuite(); + + void addTestCase(const TestCase& element); + void write(FILE* file_stream_); + +}; + +class JUnitLogger2: public ILoggerPlugin +{ +public: + JUnitLogger2(); + virtual ~JUnitLogger2(); + inline bool is_static() { return false; } + void init(const char *options = 0); + void fini(); + + void log(const TitanLoggerApi::TitanLogEvent& event, bool log_buffered, + bool separate_file, bool use_emergency_mask); + void set_parameter(const char *parameter_name, const char *parameter_value); + // do not implement ILoggerPlugin::set_file_name(); + // it gets a filename skeleton and can't expand it. + + virtual void open_file(bool /*is_first*/); + virtual void close_file(); + + enum xml_escape_char_t { LT=0x01, GT=0x02, QUOT=0x04, APOS=0x08, AMP=0x10 }; + CHARSTRING escape_xml(const CHARSTRING& xml_str, int escape_chars); + CHARSTRING escape_xml_attribute(const CHARSTRING& attr_str) { return escape_xml(attr_str, QUOT|AMP); } + CHARSTRING escape_xml_element(const CHARSTRING& elem_str) { return escape_xml(elem_str, LT|AMP); } + CHARSTRING escape_xml_comment(const CHARSTRING& comm_str) { return escape_xml(comm_str, AMP); /* FIXME: --> should be escaped too */ } + +private: + // parameters + char *filename_stem_; + char *testsuite_name_; + // working values + char *filename_; + TestSuite testsuite; + TestCase testcase; + std::string dte_reason; + + FILE *file_stream_; +}; + +#endif // JUnitLogger_HH2 diff --git a/loggerplugins/JUnitLogger2/Makefile b/loggerplugins/JUnitLogger2/Makefile new file mode 100644 index 0000000..98bb575 --- /dev/null +++ b/loggerplugins/JUnitLogger2/Makefile @@ -0,0 +1,96 @@ +############################################################################### +# Copyright (c) 2000-2014 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################### +# Makefile for the JUnitLogger2 plugin. Unfortunately, we'll need four different +# libraries for each plugin... Plugin version information must be +# synchronized with the code. + +TOP := ../.. +include ../../Makefile.cfg + +LIB_DIR := $(TTCN3_DIR)/lib + +MAJOR := 0 +MINOR := 0 + +SOURCES := JUnitLogger2.cc +STATIC_SOURCES := ${SOURCES} +HEADERS := $(SOURCES:.cc=.hh) +OBJECTS := $(SOURCES:.cc=.o) +OBJECTS_RT2 := $(addprefix FT/,$(OBJECTS)) + +SHARED_LIB := libjunitlogger2.so +SHARED_LIB_RT2 := libjunitlogger2-rt2.so +SHARED_LIB_PARALLEL := libjunitlogger2-parallel.so +SHARED_LIB_PARALLEL_RT2 := libjunitlogger2-parallel-rt2.so + +CPPFLAGS += -I../../core -I$(ABS_SRC)/../../common -I$(ABS_SRC)/../../core +# RT2 needs core2 (for RT2/TitanLoggerAPI.hh) in addition to core +CPPFLAGS_RT2 := $(CPPFLAGS) -I$(ABS_SRC)/../../core2 -DTITAN_RUNTIME_2 + +CXXFLAGS += -Werror + +LDFLAGS += -g -L$(ABS_SRC)/../../core -Wl,-soname,$(SHARED_LIB).$(MAJOR) -o $(SHARED_LIB).$(MAJOR).$(MINOR) +LDFLAGS_RT2 += -g -L$(ABS_SRC)/../../core2 -Wl,-soname,$(SHARED_LIB_RT2).$(MAJOR) -o $(SHARED_LIB_RT2).$(MAJOR).$(MINOR) +LDFLAGS_PARALLEL += -g -L$(ABS_SRC)/../../core -Wl,-soname,$(SHARED_LIB_PARALLEL).$(MAJOR) -o $(SHARED_LIB_PARALLEL).$(MAJOR).$(MINOR) +LDFLAGS_PARALLEL_RT2 += -g -L$(ABS_SRC)/../../core2 -Wl,-soname,$(SHARED_LIB_PARALLEL_RT2).$(MAJOR) -o $(SHARED_LIB_PARALLEL_RT2).$(MAJOR).$(MINOR) + +LIBS := -lttcn3-dynamic +LIBS_RT2 := -lttcn3-rt2-dynamic +LIBS_PARALLEL := -lttcn3-parallel-dynamic +LIBS_PARALLEL_RT2 := -lttcn3-rt2-parallel-dynamic + +TARGETS := $(SHARED_LIB) $(SHARED_LIB_PARALLEL) $(SHARED_LIB_RT2) $(SHARED_LIB_PARALLEL_RT2) +# .so with .major appended: +TARGETS_MAJOR := $(addsuffix .$(MAJOR), $(TARGETS)) +# .so with .major.minor appended: +TARGETS_MAJOR_MINOR := $(addsuffix .$(MINOR), $(TARGETS_MAJOR)) + +# OBJECTS_RT2, TARGETS_MAJOR and TARGETS_MAJOR_MINOR are non-standard make variables, +# not taken into account by "clean" in Makefile.genrules +# Delete them as "miscellaneous" files. +TOBECLEANED := $(OBJECTS_RT2) $(TARGETS_MAJOR) $(TARGETS_MAJOR_MINOR) + +all run: $(TARGETS) + +$(SHARED_LIB): $(OBJECTS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $? $(LIBS) -shared + ln -sf $@.$(MAJOR).$(MINOR) $@.$(MAJOR) + ln -sf $@.$(MAJOR) $@ + +$(SHARED_LIB_RT2): $(OBJECTS_RT2) + $(CXX) $(CPPFLAGS_RT2) $(CXXFLAGS) $(LDFLAGS_RT2) $? $(LIBS_RT2) -shared + ln -sf $@.$(MAJOR).$(MINOR) $@.$(MAJOR) + ln -sf $@.$(MAJOR) $@ + +$(SHARED_LIB_PARALLEL): $(OBJECTS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS_PARALLEL) $? $(LIBS_PARALLEL) -shared + ln -sf $@.$(MAJOR).$(MINOR) $@.$(MAJOR) + ln -sf $@.$(MAJOR) $@ + +$(SHARED_LIB_PARALLEL_RT2): $(OBJECTS_RT2) + $(CXX) $(CPPFLAGS_RT2) $(CXXFLAGS) $(LDFLAGS_PARALLEL_RT2) $? $(LIBS_PARALLEL_RT2) -shared + ln -sf $@.$(MAJOR).$(MINOR) $@.$(MAJOR) + ln -sf $@.$(MAJOR) $@ + +$(OBJECTS): $(SOURCES) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $? + +# The `-o $@' stuff is necessary, otherwise the result will be put into the +# current directory. +$(OBJECTS_RT2): $(SOURCES) + mkdir -p FT + $(CXX) $(CPPFLAGS_RT2) $(CXXFLAGS) -c $? -o $@ + +dep: + @echo Doing nothing... + +install: $(SHARED_LIB) $(SHARED_LIB_RT2) $(SHARED_LIB_PARALLEL) $(SHARED_LIB_PARALLEL_RT2) + mkdir -p $(LIB_DIR) + cp $(SHARED_LIB)* $(SHARED_LIB_RT2)* $(SHARED_LIB_PARALLEL)* $(SHARED_LIB_PARALLEL_RT2)* $(LIB_DIR) + +include ../../Makefile.genrules diff --git a/loggerplugins/Makefile b/loggerplugins/Makefile index 0d1dd8b..19b40d5 100644 --- a/loggerplugins/Makefile +++ b/loggerplugins/Makefile @@ -6,7 +6,7 @@ # http://www.eclipse.org/legal/epl-v10.html ############################################################################### DIRS := \ -JUnitLogger TSTLogger +JUnitLogger TSTLogger JUnitLogger2 all run dep clean distclean install: for d in $(DIRS); do $(MAKE) -C $$d $@ || exit 1; done diff --git a/loggerplugins/TSTLogger/TSTLogger.cc b/loggerplugins/TSTLogger/TSTLogger.cc index 5d1514e..c29a273 100644 --- a/loggerplugins/TSTLogger/TSTLogger.cc +++ b/loggerplugins/TSTLogger/TSTLogger.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/mctr2/cli/config_read.l b/mctr2/cli/config_read.l index be8c193..12978bd 100644 --- a/mctr2/cli/config_read.l +++ b/mctr2/cli/config_read.l @@ -323,6 +323,12 @@ IPV6 [0-9A-Fa-f:.]+(%[0-9A-Za-z]+)? /* SC_cstring */ +{HEX}+ { + /* numeric statistics filter (check this before checking NUMBERs) */ + RETURN(ProfilerStatsFlag); +} + + /* Values */ {NUMBER} { @@ -560,12 +566,56 @@ WARNING_UNQUALIFIED RETURN(LoggingBit); { -[Dd]isable[Pp]rofiler return DisableProfilerKeyword; -[Dd]isable[Cc]overage return DisableCoverageKeyword; -[Dd]ata[Bb]ase[Ff]ile return DatabaseFileKeyword; -[Aa]ggregate[Dd]ata return AggregateDataKeyword; -[Ss]tatistics[Ff]ile return StatisticsFileKeyword; -[Dd]isable[Ss]tatistics return DisableStatisticsKeyword; + [Dd]isable[Pp]rofiler RETURN(DisableProfilerKeyword); + [Dd]isable[Cc]overage RETURN(DisableCoverageKeyword); + [Dd]ata[Bb]ase[Ff]ile RETURN(DatabaseFileKeyword); + [Aa]ggregate[Dd]ata RETURN(AggregateDataKeyword); + [Ss]tatistics[Ff]ile RETURN(StatisticsFileKeyword); + [Dd]isable[Ss]tatistics RETURN(DisableStatisticsKeyword); + [Ss]tatistics[Ff]ilter RETURN(StatisticsFilterKeyword); + [Ss]tart[Aa]utomatically RETURN(StartAutomaticallyKeyword); + [Nn]et[Ll]ine[Tt]imes RETURN(NetLineTimesKeyword); + [Nn]et[Ff]unction[Tt]imes RETURN(NetFunctionTimesKeyword); + + /* statistics filters */ + [Nn]umber[Oo]f[Ll]ines | + [Ll]ine[Dd]ata[Rr]aw | + [Ff]unc[Dd]ata[Rr]aw | + [Ll]ine[Aa]vg[Rr]aw | + [Ff]unc[Aa]vg[Rr]aw | + [Ll]ine[Tt]imes[Ss]orted[Bb]y[Mm]od | + [Ff]unc[Tt]imes[Ss]orted[Bb]y[Mm]od | + [Ll]ine[Tt]imes[Ss]orted[Tt]otal | + [Ff]unc[Tt]imes[Ss]orted[Tt]otal | + [Ll]ine[Cc]ount[Ss]orted[Bb]y[Mm]od | + [Ff]unc[Cc]ount[Ss]orted[Bb]y[Mm]od | + [Ll]ine[Cc]ount[Ss]orted[Tt]otal | + [Ff]unc[Cc]ount[Ss]orted[Tt]otal | + [Ll]ine[Aa]vg[Ss]orted[Bb]y[Mm]od | + [Ff]unc[Aa]vg[Ss]orted[Bb]y[Mm]od | + [Ll]ine[Aa]vg[Ss]orted[Tt]otal | + [Ff]unc[Aa]vg[Ss]orted[Tt]otal | + [Tt]op10[Ll]ine[Tt]imes | + [Tt]op10[Ff]unc[Tt]imes | + [Tt]op10[Ll]ine[Cc]ount | + [Tt]op10[Ff]unc[Cc]ount | + [Tt]op10[Ll]ine[Aa]vg | + [Tt]op10[Ff]unc[Aa]vg | + [Uu]nused[Ll]ines | + [Uu]nused[Ff]unc | + [Aa]ll[Rr]aw[Dd]ata | + [Ll]ine[Dd]ata[Ss]orted[Bb]y[Mm]od | + [Ff]unc[Dd]ata[Ss]orted[Bb]y[Mm]od | + [Ll]ine[Dd]ata[Ss]orted[Tt]otal | + [Ff]unc[Dd]ata[Ss]orted[Tt]otal | + [Ll]ine[Dd]ata[Ss]orted | + [Ff]unc[Dd]ata[Ss]orted | + [Aa]ll[Dd]ata[Ss]orted | + [Tt]op10[Ll]ine[Dd]ata | + [Tt]op10[Ff]unc[Dd]ata | + [Tt]op10[Aa]ll[Dd]ata | + [Uu]nused[Dd]ata | + [Aa]ll RETURN(ProfilerStatsFlag); } control RETURN(ControlKeyword); @@ -935,6 +985,7 @@ static boolean whether_update_buffer() case SC_LOGGING: case SC_TESTPORT_PARAMETERS: case SC_EXTERNAL_COMMANDS: + case SC_PROFILER: return TRUE; default: return FALSE; diff --git a/mctr2/cli/config_read.y b/mctr2/cli/config_read.y index 496d4f3..fa787f2 100644 --- a/mctr2/cli/config_read.y +++ b/mctr2/cli/config_read.y @@ -165,12 +165,17 @@ static void yyprint(FILE *file, int type, const YYSTYPE& value); %token Re_try /* Retry clashes with an enum in Qt */ %token Delete -%token DisableProfilerKeyword "DisableProfiler" -%token DisableCoverageKeyword "DisableCoverage" -%token DatabaseFileKeyword "DatabaseFile" -%token AggregateDataKeyword "AggregateData" -%token StatisticsFileKeyword "StatisticsFile" -%token DisableStatisticsKeyword "DisableStatistics" +%token DisableProfilerKeyword "DisableProfiler" +%token DisableCoverageKeyword "DisableCoverage" +%token DatabaseFileKeyword "DatabaseFile" +%token AggregateDataKeyword "AggregateData" +%token StatisticsFileKeyword "StatisticsFile" +%token DisableStatisticsKeyword "DisableStatistics" +%token StatisticsFilterKeyword "StatisticsFilter" +%token StartAutomaticallyKeyword "StartAutomatically" +%token NetLineTimesKeyword "NetLineTimes" +%token NetFunctionTimesKeyword "NetFunctionTimes" +%token ProfilerStatsFlag "profiler statistics flag" %type IntegerValue %type FloatValue KillTimerValue @@ -706,6 +711,10 @@ ProfilerSetting: | AggregateDataSetting | StatisticsFileSetting | DisableStatisticsSetting +| StatisticsFilterSetting +| StartAutomaticallySetting +| NetLineTimesSetting +| NetFunctionTimesSetting ; DisableProfilerSetting: @@ -732,6 +741,29 @@ DisableStatisticsSetting: DisableStatisticsKeyword AssignmentChar BooleanValue ; +StatisticsFilterSetting: + StatisticsFilterKeyword AssignmentChar ProfilerStatsFlags +| StatisticsFilterKeyword ConcatChar ProfilerStatsFlags +; + +ProfilerStatsFlags: + ProfilerStatsFlag +| ProfilerStatsFlag '&' ProfilerStatsFlags +| ProfilerStatsFlag '|' ProfilerStatsFlags +; + +StartAutomaticallySetting: + StartAutomaticallyKeyword AssignmentChar BooleanValue +; + +NetLineTimesSetting: + NetLineTimesKeyword AssignmentChar BooleanValue +; + +NetFunctionTimesSetting: + NetFunctionTimesKeyword AssignmentChar BooleanValue +; + /******************* [TESTPORT_PARAMETERS] section *******************/ TestportParametersSection: diff --git a/mctr2/mctr/MainController.cc b/mctr2/mctr/MainController.cc index 9a7ae8a..e5d0ca0 100644 --- a/mctr2/mctr/MainController.cc +++ b/mctr2/mctr/MainController.cc @@ -121,6 +121,7 @@ void MainController::add_poll_fd(int fd) { if (fd < 0) return; epoll_event event; + memset(&event,0,sizeof(event)); event.events = EPOLLIN; event.data.fd = fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event) < 0) @@ -132,6 +133,7 @@ void MainController::remove_poll_fd(int fd) { if (fd < 0) return; epoll_event event; + memset(&event,0,sizeof(event)); event.events = EPOLLIN; event.data.fd = fd; if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &event) < 0) diff --git a/mctr2/mctr/ttcn3_start b/mctr2/mctr/ttcn3_start index 700b984..960342c 100755 --- a/mctr2/mctr/ttcn3_start +++ b/mctr2/mctr/ttcn3_start @@ -63,11 +63,12 @@ proc wait_mc_prompt {} { proc error_cleanup {error_msg error_retcode} { global mctr_id hc_id + puts "ttcn3_start: error: $error_msg" send -i $mctr_id "exit\r" expect -i $mctr_id eof + expect -i $hc_id eof wait -i $hc_id wait -i $mctr_id - puts "ttcn3_start: error: $error_msg" exit $error_retcode } @@ -245,6 +246,8 @@ expect { } -i $hc_id -re ".*\r" { exp_continue } -i $mctr_id "New HC connected from " { + } -i $hc_id eof { + error_cleanup "Host Controller with id $hc_id stopped unexpectedly" 10 } } diff --git a/regression_test/Makefile b/regression_test/Makefile index 1cf8b9a..4b85e6d 100644 --- a/regression_test/Makefile +++ b/regression_test/Makefile @@ -21,7 +21,7 @@ nonMandatoryPar logFiles logger_control namedActualParameters \ assignmentNotation omitdef anytype RAW implicitMsgEncoding pattern_quadruples \ macros visibility hexstrOper ucharstrOper objidOper CRTR00015758 slider \ XML ipv6 implicitOmit testcase_defparam transparent HQ16404 cfgFile \ -all_from lazyEval tryCatch text2ttcn json junitlogger ttcn2json +all_from lazyEval tryCatch text2ttcn json junitlogger ttcn2json profiler ifdef DYN DIRS += loggerplugin diff --git a/regression_test/XML/EXER-whitepaper/EmbedValues.ttcnpp b/regression_test/XML/EXER-whitepaper/EmbedValues.ttcnpp index fc5cb93..47007d0 100644 --- a/regression_test/XML/EXER-whitepaper/EmbedValues.ttcnpp +++ b/regression_test/XML/EXER-whitepaper/EmbedValues.ttcnpp @@ -219,6 +219,94 @@ testcase decode_emb_array() runs on EMB CHECK_DECODE(exer_dec_emb_outer, str_emb_array_w_holes, Outer, c_emb_array_w_holes); } +// same as before, but the embedded values are stored in an optimized record-of +type record Outer2 { + record of universal charstring embed_values, + integer attr, + octetstring bytes, + RoInner stuff +} with { + variant "name as 'Outer'"; + extension(embed_values) "optimize:memalloc"; + variant "embedValues"; + variant(attr) "attribute"; + variant(bytes) "name as 'Bytes'"; + variant(stuff) "untagged"; +} + +DECLARE_EXER_ENCODERS(Outer2, emb_outer2); + +const Outer2 c_emb_array2 := { + embed_values := { "one", "two", "three", "four", "five", "six" }, + attr := 48, + bytes := 'DEADBEEF'O, + stuff := { { 3, "abc" }, { 4, "def" }, { -6, "red" }, { 118, "blue" } } +} + +const Outer2 c_emb_array_w_holes2 := { + embed_values := { "one", "", "three", "", "five" }, + attr := 48, + bytes := 'DEADBEEF'O, + stuff := { { 3, "abc" }, { 4, "def" }, { -6, "red" }, { 118, "blue" } } +} + +testcase encode_emb_array_opt() runs on EMB +{ + CHECK_METHOD(exer_enc_emb_outer2, c_emb_array2, str_emb_array); + CHECK_METHOD(exer_enc_emb_outer2, c_emb_array_w_holes2, str_emb_array_w_holes); +} + +testcase decode_emb_array_opt() runs on EMB +{ + CHECK_DECODE(exer_dec_emb_outer2, str_emb_array, Outer2, c_emb_array2); + CHECK_DECODE(exer_dec_emb_outer2, str_emb_array_w_holes, Outer2, c_emb_array_w_holes2); +} + +// same as before, but one of the embedded record-ofs is optimized +type record length (1..infinity) of Inner RoInner2 with { extension "optimize:memalloc" }; + +type record Outer3 { + record of universal charstring embed_values, + integer attr, + octetstring bytes, + RoInner2 stuff +} with { + variant "name as 'Outer'"; + extension(embed_values) "optimize:memalloc"; + variant "embedValues"; + variant(attr) "attribute"; + variant(bytes) "name as 'Bytes'"; + variant(stuff) "untagged"; +} + +DECLARE_EXER_ENCODERS(Outer3, emb_outer3); + +const Outer3 c_emb_array3 := { + embed_values := { "one", "two", "three", "four", "five", "six" }, + attr := 48, + bytes := 'DEADBEEF'O, + stuff := { { 3, "abc" }, { 4, "def" }, { -6, "red" }, { 118, "blue" } } +} + +const Outer3 c_emb_array_w_holes3 := { + embed_values := { "one", "", "three", "", "five" }, + attr := 48, + bytes := 'DEADBEEF'O, + stuff := { { 3, "abc" }, { 4, "def" }, { -6, "red" }, { 118, "blue" } } +} + +testcase encode_emb_array_opt2() runs on EMB +{ + CHECK_METHOD(exer_enc_emb_outer3, c_emb_array3, str_emb_array); + CHECK_METHOD(exer_enc_emb_outer3, c_emb_array_w_holes3, str_emb_array_w_holes); +} + +testcase decode_emb_array_opt2() runs on EMB +{ + CHECK_DECODE(exer_dec_emb_outer3, str_emb_array, Outer3, c_emb_array3); + CHECK_DECODE(exer_dec_emb_outer3, str_emb_array_w_holes, Outer3, c_emb_array_w_holes3); +} + control { execute(encode_emb()); execute(decode_emb()); @@ -226,8 +314,12 @@ control { execute(decode_emb_all()); execute(encode_emb_any()); execute(decode_emb_any()); - //execute(encode_emb_array()); - this functionality was temporarily removed in RT1 - //execute(decode_emb_array()); + execute(encode_emb_array()); + execute(decode_emb_array()); + execute(encode_emb_array_opt()); + execute(decode_emb_array_opt()); + execute(encode_emb_array_opt2()); + execute(decode_emb_array_opt2()); } } diff --git a/regression_test/XML/TTCNandXML/Makefile b/regression_test/XML/TTCNandXML/Makefile index 8ae35fd..8fff1eb 100644 --- a/regression_test/XML/TTCNandXML/Makefile +++ b/regression_test/XML/TTCNandXML/Makefile @@ -41,7 +41,7 @@ CPPFLAGS += -D$(PLATFORM) CXXFLAGS += -g -W -Wformat=2 # Flags for the linker: -LDFLAGS += -g -rdynamic +#LDFLAGS += -g -rdynamic WIN32_LIBS += -liconv FREEBSD_LIBS += -liconv diff --git a/regression_test/XML/XER/checkit.pl b/regression_test/XML/XER/checkit.pl index 6c9e7aa..893350c 100755 --- a/regression_test/XML/XER/checkit.pl +++ b/regression_test/XML/XER/checkit.pl @@ -51,6 +51,7 @@ my %versions = ( # built-in modules for the logger 'TitanLoggerApi' => '', 'TitanLoggerControl' => '', +'PreGenRecordOf' => '', ); diff --git a/regression_test/all_from/all_from_subtype.ttcn b/regression_test/all_from/all_from_subtype.ttcn new file mode 100644 index 0000000..421e9c1 --- /dev/null +++ b/regression_test/all_from/all_from_subtype.ttcn @@ -0,0 +1,191 @@ +/****************************************************************************** + * Copyright (c) 2000-2015 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ + +// subtyping and the 'all from' clause +module all_from_subtype { + +import from types all; +import from functions all; + +/* * * * integer * * * */ +template RoI t_RoI1 := { 1, 2, (6..9) }; +template RoI t_RoI2 := { 1, ?, 3 }; +const RoI c_RoI := { 20, 21, 22 }; + +template PosInt t_posint1 := (0, all from t_RoI1); +template PosInt t_posint1_exp := (0, 1, 2, (6..9)); + +template PosInt t_posint2 := (all from c_RoI, 50, 100); +template PosInt t_posint2_exp := (20, 21, 22, 50, 100); + +template PosInt t_posint3 := (10, all from c_RoI, 30, all from t_RoI1); +template PosInt t_posint3_exp := (10, 20, 21, 22, 30, 1, 2, (6..9)); + +template ShortRoI t_sroi1 := { 0, (all from t_RoI1, 10), 20 }; +template ShortRoI t_sroi1_exp := { 0, (1, 2, (6..9), 10), 20 }; + +template ShortRoI t_sroi2 := ( { 1, 2, 3 }, { permutation (all from t_RoI2) } ); +template ShortRoI t_sroi2_exp := ( { 1, 2, 3 }, { permutation (1, ?, 3) } ); + +testcase tc_all_from_subtype_integer() runs on A +{ + if (log2str(t_posint1) != log2str(t_posint1_exp)) { + setverdict(fail, "Expected: ", t_posint1_exp, ", got: ", t_posint1); + } + if (log2str(t_posint2) != log2str(t_posint2_exp)) { + setverdict(fail, "Expected: ", t_posint2_exp, ", got: ", t_posint2); + } + if (log2str(t_posint3) != log2str(t_posint3_exp)) { + setverdict(fail, "Expected: ", t_posint3_exp, ", got: ", t_posint3); + } + if (log2str(t_sroi1) != log2str(t_sroi1_exp)) { + setverdict(fail, "Expected: ", t_sroi1_exp, ", got: ", t_sroi1); + } + if (log2str(t_sroi2) != log2str(t_sroi2_exp)) { + setverdict(fail, "Expected: ", t_sroi2_exp, ", got: ", t_sroi2); + } + setverdict(pass); +} + +/* * * * float * * * */ +template RoF t_RoF := { (-10.0..-2.5), -1.0, 0.0 }; +const RoF c_RoF := { -0.3, -0.2, -0.1 }; + +template NegFloat t_negfloat := (all from t_RoF, -2.0, all from c_RoF, -100.0); +template NegFloat t_negfloat_exp := ((-10.0..-2.5), -1.0, 0.0, -2.0, -0.3, -0.2, -0.1, -100.0); + +template ShortRoF t_srof := { permutation (all from c_RoF) }; +template ShortRoF t_srof_exp := { permutation (-0.3, -0.2, -0.1) }; + +testcase tc_all_from_subtype_float() runs on A +{ + if (log2str(t_negfloat) != log2str(t_negfloat_exp)) { + setverdict(fail, "Expected: ", t_negfloat_exp, ", got: ", t_negfloat); + } + if (log2str(t_srof) != log2str(t_srof_exp)) { + setverdict(fail, "Expected: ", t_srof_exp, ", got: ", t_srof); + } + setverdict(pass); +} + +/* * * * bitstring * * * */ +template RoBS t_RoBS := { '1010'B, ? }; +const RoBS c_RoBS := { '11011000'B, '00110011'B, '10101010'B }; + +template ByteString t_bytestr := ('00000000'B, all from c_RoBS, '11111111'B); +template ByteString t_bytestr_exp := ('00000000'B, '11011000'B, '00110011'B, '10101010'B, '11111111'B); + +template ShortRoBS t_srobs := { '1'B, permutation (all from t_RoBS) }; +template ShortRoBS t_srobs_exp := { '1'B, permutation ('1010'B, ?) }; + +testcase tc_all_from_subtype_bitstring() runs on A +{ + if (log2str(t_bytestr) != log2str(t_bytestr_exp)) { + setverdict(fail, "Expected: ", t_bytestr_exp, ", got: ", t_bytestr); + } + if (log2str(t_srobs) != log2str(t_srobs_exp)) { + setverdict(fail, "Expected: ", t_srobs_exp, ", got: ", t_srobs); + } + setverdict(pass); +} + +/* * * * hexstring * * * */ +template RoHS t_RoHS := { '100'H, 'ABC'H }; +const RoHS c_RoHS := { '19A6'H, '999D'H, '1337'H }; + +template WordString t_wordstr := ('A000'H, 'FFFF'H, all from c_RoHS, '0000'H); +template WordString t_wordstr_exp := ('A000'H, 'FFFF'H, '19A6'H, '999D'H, '1337'H, '0000'H); + +template ShortRoHS t_srohs := { permutation (all from t_RoHS, '180DD'H) }; +template ShortRoHS t_srohs_exp := { permutation ('100'H, 'ABC'H, '180DD'H) }; + +testcase tc_all_from_subtype_hexstring() runs on A +{ + if (log2str(t_wordstr) != log2str(t_wordstr_exp)) { + setverdict(fail, "Expected: ", t_wordstr_exp, ", got: ", t_wordstr); + } + if (log2str(t_srohs) != log2str(t_srohs_exp)) { + setverdict(fail, "Expected: ", t_srohs_exp, ", got: ", t_srohs); + } + setverdict(pass); +} + +/* * * * octetstring * * * */ +template RoOS t_RoOS := { '00'O, 'FF'O }; +const RoOS c_RoOS := { 'E77FB41C'O, 'DEADBEEF'O, 'CDCDCDCD'O }; + +template DWordString t_dwordstr := (all from c_RoOS, '0FFFFFFF'O); +template DWordString t_dwordstr_exp := ('E77FB41C'O, 'DEADBEEF'O, 'CDCDCDCD'O, '0FFFFFFF'O); + +template ShortRoOS t_sroos := { permutation (?, all from t_RoOS) }; +template ShortRoOS t_sroos_exp := { permutation (?, '00'O, 'FF'O) }; + +testcase tc_all_from_subtype_octetstring() runs on A +{ + if (log2str(t_dwordstr) != log2str(t_dwordstr_exp)) { + setverdict(fail, "Expected: ", t_dwordstr_exp, ", got: ", t_dwordstr); + } + if (log2str(t_sroos) != log2str(t_sroos_exp)) { + setverdict(fail, "Expected: ", t_sroos_exp, ", got: ", t_sroos); + } + setverdict(pass); +} + +/* * * * charstring * * * */ +template RoCS t_RoCS := { ("a".."z"), ("0".."9"), ("A".."Z") }; +const RoCS c_RoCS := { "all_from.ttcn", "types.ttcn", "functions.ttcn", "sapc.ttcn" }; + +template TtcnFileName t_ttcnfiles := (all from c_RoCS); +template TtcnFileName t_ttcnfiles_exp := ("all_from.ttcn", "types.ttcn", "functions.ttcn", "sapc.ttcn"); + +template ShortRoCS t_srocs := { permutation (all from t_RoCS) }; +template ShortRoCS t_srocs_exp := { permutation (("a".."z"), ("0".."9"), ("A".."Z")) }; + +testcase tc_all_from_subtype_charstring() runs on A +{ + if (log2str(t_ttcnfiles) != log2str(t_ttcnfiles_exp)) { + setverdict(fail, "Expected: ", t_ttcnfiles_exp, ", got: ", t_ttcnfiles); + } + if (log2str(t_srocs) != log2str(t_srocs_exp)) { + setverdict(fail, "Expected: ", t_srocs_exp, ", got: ", t_srocs); + } + setverdict(pass); +} + +/* * * * universal charstring * * * */ +template RoUCS t_RoUCS := { "abc", ?, "cba" }; +const RoUCS c_RoUCS := { "nothing", "special", "here" }; + +template XsdString t_xsdstr := (pattern "<*>", all from c_RoUCS); +template XsdString t_xsdstr_exp := (pattern "<*>", "nothing", "special", "here"); + +template ShortRoUCS t_sroucs := { all from t_RoUCS }; +template ShortRoUCS t_sroucs_exp := { "abc", ?, "cba" }; + +testcase tc_all_from_subtype_universal_charstring() runs on A +{ + if (log2str(t_xsdstr) != log2str(t_xsdstr_exp)) { + setverdict(fail, "Expected: ", t_xsdstr_exp, ", got: ", t_xsdstr); + } + if (log2str(t_sroucs) != log2str(t_sroucs_exp)) { + setverdict(fail, "Expected: ", t_sroucs_exp, ", got: ", t_sroucs); + } + setverdict(pass); +} + +control { + execute(tc_all_from_subtype_integer()); + execute(tc_all_from_subtype_float()); + execute(tc_all_from_subtype_bitstring()); + execute(tc_all_from_subtype_hexstring()); + execute(tc_all_from_subtype_octetstring()); + execute(tc_all_from_subtype_charstring()); + execute(tc_all_from_subtype_universal_charstring()); +} + +} diff --git a/regression_test/all_from/all_from_with_functions.ttcn b/regression_test/all_from/all_from_with_functions.ttcn index 134f2ec..5aaa17a 100644 --- a/regression_test/all_from/all_from_with_functions.ttcn +++ b/regression_test/all_from/all_from_with_functions.ttcn @@ -11,7 +11,7 @@ module all_from_with_functions { external function f_ext(in template RoI r) return template RoI; -type record of integer RoI; +type record of integer RoI with { encode "JSON" }; type set of integer SoI; type record Rec { @@ -119,10 +119,52 @@ testcase tc_all_from_func_params() runs on CT_Empty { else { setverdict(fail, "Expected: ", c_res_log, ", got: ", vt_res); } } +function f_non_templ(in RoI x) return RoI +{ + return x; +} + +external function f_dec_roi(in octetstring os) return RoI + with { extension "prototype(convert) decode(JSON)" } + +// all from used on regular (non-template) functions +testcase tc_all_from_with_functions2() runs on CT_Empty +{ + var template RoI vt_func_roi := { permutation ( all from f_non_templ( { 1, 4, 7, 10 } ) ) }; + var template integer vt_func_int := ( 0, 1, all from f_non_templ( { 3, 6, 9 } ) ); + + var octetstring v_enc := char2oct("[ 4, 2, 10, 100 ]"); + var template RoI vt_ext_func_roi := { permutation ( all from f_dec_roi(v_enc) ) }; + var template integer vt_ext_func_int := ( 0, 1, all from f_dec_roi(v_enc) ); + + var charstring v_res_log := "{ permutation(1, 4, 7, 10) }"; + if (log2str(vt_func_roi) != v_res_log) { + setverdict(fail, "Expected: ", v_res_log, ", got: ", vt_func_roi); + } + + v_res_log := "(0, 1, 3, 6, 9)"; + if (log2str(vt_func_int) != v_res_log) { + setverdict(fail, "Expected: ", v_res_log, ", got: ", vt_func_int); + } + + v_res_log := "{ permutation(4, 2, 10, 100) }"; + if (log2str(vt_ext_func_roi) != v_res_log) { + setverdict(fail, "Expected: ", v_res_log, ", got: ", vt_ext_func_roi); + } + + v_res_log := "(0, 1, 4, 2, 10, 100)"; + if (log2str(vt_ext_func_int) != v_res_log) { + setverdict(fail, "Expected: ", v_res_log, ", got: ", vt_ext_func_int); + } + + setverdict(pass); +} + control { execute(tc_all_from_with_functions()); execute(tc_all_from_func_params()); + execute(tc_all_from_with_functions2()); } } diff --git a/regression_test/all_from/types.ttcn b/regression_test/all_from/types.ttcn index 862f3de..cc8c2e8 100644 --- a/regression_test/all_from/types.ttcn +++ b/regression_test/all_from/types.ttcn @@ -16,6 +16,7 @@ type component A { type record of integer RoI; type set of integer SoI; +type record of float RoF; type record of SoI RoSoI; type record of RoI RoRoI; type record of RoOS RoRoOS; @@ -23,12 +24,18 @@ type record of SoOS RoSoOS; type set of integer MySetOfType (0 .. 10); +type record of bitstring RoBS; + +type record of hexstring RoHS; + type record of charstring RoCS; type set of charstring CoCS; type record of octetstring RoOS; type set of octetstring SoOS; +type record of universal charstring RoUCS; + type record MyRecord { integer i optional, RoI roi optional, @@ -80,4 +87,41 @@ type record CAI3gCommand { } */ +/* * * * Subtypes * * * */ + +type integer PosInt (0..infinity); + +type float NegFloat (-infinity..0.0); + +type bitstring ByteString length (8); + +type hexstring WordString length (4); + +type octetstring DWordString length (4); + +type charstring TtcnFileName (pattern "*.ttcn"); + +type universal charstring XsdString ( + char(0,0,0,9)..char(0,0,0,9), + char(0,0,0,10)..char(0,0,0,10), + char(0,0,0,12)..char(0,0,0,12), + char(0,0,0,32)..char(0,0,215,255), + char(0,0,224,0)..char(0,0,255,253), + char(0,1,0,0)..char(0,16,255,253) +); + +type record length (0..3) of integer ShortRoI; + +type record length (0..3) of float ShortRoF; + +type record length (0..3) of bitstring ShortRoBS; + +type record length (0..3) of hexstring ShortRoHS; + +type record length (0..3) of octetstring ShortRoOS; + +type record length (0..3) of charstring ShortRoCS; + +type record length (0..3) of universal charstring ShortRoUCS; + } diff --git a/regression_test/boolOper/TboolOper.ttcn b/regression_test/boolOper/TboolOper.ttcn index 602542a..dabf6b6 100644 --- a/regression_test/boolOper/TboolOper.ttcn +++ b/regression_test/boolOper/TboolOper.ttcn @@ -303,6 +303,60 @@ testcase boolIsvalue() runs on boolOper_comptype{ if ( isvalue(vt1) ) { setverdict(fail); } else { setverdict(pass); }; } +type union TestUnion { + integer t, + boolean b +} + +type record TestRecord { + integer t, + boolean b optional +} + +// for TR fix HT60781 +testcase boolShortCircuit() runs on boolOper_comptype { + // create a union variable, make sure the boolean field is not chosen + var TestUnion myUnion := { t := 1 }; + + // reference the boolean field in the 2nd part of a condition using 'and' or 'or' + // only the first part of the condition should be evaluated, since + // evaluating the 2nd part would produce a DTE (because the field isn't chosen) + if (ischosen(myUnion.b) and myUnion.b) { + setverdict(fail, "Error in 'if' condition, field 'b' is not supposed to be chosen"); + } + while (ischosen(myUnion.b) and myUnion.b) { + setverdict(fail, "Error in 'while' condition, field 'b' is not supposed to be chosen"); + } + var integer i; + for (i := 0; ischosen(myUnion.b) and myUnion.b and i < 5; i := i + 1) { + setverdict(fail, "Error in 'for' condition, field 'b' is not supposed to be chosen"); + } + var boolean res := not ischosen(myUnion.b) or myUnion.b; + if (not res) { + setverdict(fail, "Error in boolean assignment, field 'b' is not supposed to be chosen"); + } + + // create a record variable, make sure the boolean field is omitted + var TestRecord myRec := { t := 1, b := omit }; + + // reference the boolean field in the 2nd part of a condition, same as with the union field + // (referencing the boolean field would cause a DTE again, because it is omitted) + if (ispresent(myRec.b) and myRec.b) { + setverdict(fail, "Error in 'if' condition, field 'b' is not supposed to be present"); + } + while (ispresent(myRec.b) and myRec.b) { + setverdict(fail, "Error in 'if' condition, field 'b' is not supposed to be present"); + } + for (i := 0; ispresent(myRec.b) and myRec.b and i < 5; i := i + 1) { + setverdict(fail, "Error in 'for' condition, field 'b' is not supposed to be present"); + } + res := not ispresent(myRec.b) or myRec.b; + if (not res) { + setverdict(fail, "Error in boolean assignment, field 'b' is not supposed to be present"); + } + setverdict(pass); +} + control { const boolean cl_1:=true; var boolean vl_1; @@ -317,6 +371,7 @@ control { execute(boolXor()); execute(boolSubtypes()); execute(boolIsvalue()); + execute(boolShortCircuit()); } } diff --git a/regression_test/cfgFile/module_parameters/assignment/assignment.cfg b/regression_test/cfgFile/module_parameters/assignment/assignment.cfg index cc52824..46e7995 100644 --- a/regression_test/cfgFile/module_parameters/assignment/assignment.cfg +++ b/regression_test/cfgFile/module_parameters/assignment/assignment.cfg @@ -129,10 +129,10 @@ tsp_anytype_float := {float := 42.0} tsp_anytype_MyRec := {MyRec := {field1 := 1, field2 := 2}} // Component -//tsp_component_null := null //modulepar cannot be of type component +tsp_component_null := null // Default -//tsp_default := null //modulepar cannot be of type default +tsp_default := null // Nested array, record of & set of tsp_nested.roi := { 4, 5 }; diff --git a/regression_test/cfgFile/module_parameters/assignment/assignment.ttcn b/regression_test/cfgFile/module_parameters/assignment/assignment.ttcn index 90e757f..69d6842 100644 --- a/regression_test/cfgFile/module_parameters/assignment/assignment.ttcn +++ b/regression_test/cfgFile/module_parameters/assignment/assignment.ttcn @@ -173,10 +173,10 @@ modulepar anytype tsp_anytype_float; modulepar anytype tsp_anytype_MyRec; // Component -//modulepar MyComp_CT tsp_component_null; // modulepar cannot be of type component +modulepar MyComp_CT tsp_component_null; // Default -//modulepar default tsp_default; // modulepar cannot be of type default +modulepar default tsp_default; // Nested array, record of & set of modulepar NestedRec tsp_nested := { { 1, 2, 3 }, { 1, 2, 3 } }; @@ -496,6 +496,16 @@ testcase tc_anytype() runs on MyComp_CT { else { setverdict(fail, "tsp_anytype_MyRec");} } +testcase tc_component() runs on MyComp_CT { + if (tsp_component_null == null) { setverdict(pass); } + else { setverdict(fail, "tsp_component_null");} +} + +testcase tc_default() runs on MyComp_CT { + if (tsp_default == null) { setverdict(pass); } + else { setverdict(fail, "tsp_default");} +} + testcase tc_nested() runs on MyComp_CT { if (tsp_nested == { { 4, 5, 9 }, { 6, 7, 8 } }) { setverdict(pass); } else { setverdict(fail, "tsp_nested = ", tsp_nested); } @@ -558,6 +568,8 @@ control { execute(tc_set_of()); execute(tc_anytype()); execute(tc_array()); + execute(tc_component()); + execute(tc_default()); execute(tc_nested()); execute(tc_nested_templ()); } diff --git a/regression_test/compileonly/Makefile b/regression_test/compileonly/Makefile index f5f02fe..580e20c 100644 --- a/regression_test/compileonly/Makefile +++ b/regression_test/compileonly/Makefile @@ -14,7 +14,7 @@ CODIRS := dynamicTemplate styleGuide topLevelPdu \ centralstorage mfgen-tpd \ openType optionalAssignCompare portConstructor \ isbound namedActualParameters assignmentNotation \ - attribQualif HT48786 + attribQualif HT48786 selectCase all dep clean distclean: for dir in $(CODIRS); do $(MAKE) -C $$dir $@ || exit; done diff --git a/regression_test/compileonly/selectCase/Makefile b/regression_test/compileonly/selectCase/Makefile new file mode 100644 index 0000000..68eabbe --- /dev/null +++ b/regression_test/compileonly/selectCase/Makefile @@ -0,0 +1,41 @@ +############################################################################### +# Copyright (c) 2000-2015 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################### +TOPDIR := ../.. +include $(TOPDIR)/Makefile.regression + +.PHONY: all clean dep + +TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) + +TTCN3_MODULES = selectCase.ttcn + +GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) +GENERATED_HEADERS = $(GENERATED_SOURCES:.cc=.hh) +ifdef CODE_SPLIT +GENERATED_SOURCES := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), .cc _seq.cc _set.cc _seqof.cc _setof.cc _union.cc)) +endif + +OBJECTS = $(GENERATED_SOURCES:.cc=.o) + +TARGET = selectCase$(EXESUFFIX) + +all: $(TARGET) + +$(TARGET): $(GENERATED_SOURCES) $(USER_SOURCES) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ -L$(TTCN3_DIR)/lib -l$(TTCN3_LIB) \ + -L$(OPENSSL_DIR)/lib -lcrypto $($(PLATFORM)_LIBS) + +$(GENERATED_SOURCES) $(GENERATED_HEADERS): $(TTCN3_MODULES) + $(TTCN3_COMPILER) $(COMPILER_FLAGS) $^ + +clean distclean: + $(RM) $(TARGET) $(OBJECTS) $(GENERATED_HEADERS) \ + $(GENERATED_SOURCES) compile *.log + +dep: $(GENERATED_SOURCES) + makedepend $(CPPFLAGS) $(GENERATED_SOURCES) diff --git a/regression_test/compileonly/selectCase/selectCase.ttcn b/regression_test/compileonly/selectCase/selectCase.ttcn new file mode 100644 index 0000000..5d825ea --- /dev/null +++ b/regression_test/compileonly/selectCase/selectCase.ttcn @@ -0,0 +1,76 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2000-2015 Ericsson Telecom AB +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// which accompanies this distribution, and is available at +// http://www.eclipse.org/legal/epl-v10.html +/////////////////////////////////////////////////////////////////////////////// + +module selectCase { + +type record of integer RoI; + +type record Rec { + RoI numz +} + +type record EmptyRec { } + +type record Rec2 { + EmptyRec empty +} + +function f_embeddedEmptyArray() { + var Rec r := { numz := { 1, 2 } }; + + select (r) { + // this condition used to crash the compiler during code generation (artf521346) + case ( { numz := { } } ) { + action("empty"); + } + case else { + action("not empty"); + } + } +} + +function f_emptyArray() { + var RoI a := { 1, 2 }; + + select (a) { + case ( { } ) { + action("empty"); + } + case else { + action("not empty"); + } + } +} + +function f_emptyRecord() { + var EmptyRec er := { }; + + select (er) { + case ( { } ) { + action("empty"); + } + case else { + action("not empty"); + } + } +} + +function f_embeddedEmptyRecord() { + var Rec2 r2 := { empty := { } }; + + select (r2) { + case ( { empty := { } } ) { + action("empty"); + } + case else { + action("not empty"); + } + } +} + +} diff --git a/regression_test/negativeTest/Makefile b/regression_test/negativeTest/Makefile index aa0d37f..5a3b24a 100755 --- a/regression_test/negativeTest/Makefile +++ b/regression_test/negativeTest/Makefile @@ -25,7 +25,7 @@ CXXFLAGS += -Wall -Wextra -Wshadow -g CXXDEPFLAGS := -MM #COMPILER_FLAGS += -LDFLAGS += -rdynamic +#LDFLAGS += -rdynamic TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) diff --git a/regression_test/profiler/Makefile b/regression_test/profiler/Makefile new file mode 100755 index 0000000..58a4580 --- /dev/null +++ b/regression_test/profiler/Makefile @@ -0,0 +1,82 @@ +############################################################################### +# Copyright (c) 2000-2015 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################### +TOPDIR := .. +include $(TOPDIR)/Makefile.regression + +.SUFFIXES: .ttcn .asn .hh .json +.PHONY: all clean dep run + +TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) + +# Tester modules +TTCN3_MODULES = PIPEasp_PortType.ttcn PIPEasp_Types.ttcn PIPEasp_Templates.ttcn Shell.ttcn Testcases.ttcn + +GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) $(ASN1_MODULES:.asn=.cc) +GENERATED_HEADERS = $(GENERATED_SOURCES:.cc=.hh) +ifdef CODE_SPLIT +GENERATED_SOURCES := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), .cc _seq.cc _set.cc _seqof.cc _setof.cc _union.cc)) +endif + +USER_SOURCES = PIPEasp_PT.cc +USER_HEADERS = $(USER_SOURCES:.cc=.hh) + +OBJECTS = $(GENERATED_SOURCES:.cc=.o) $(USER_SOURCES:.cc=.o) + +TARGET = profiler_test$(EXESUFFIX) + +# Tested modules (these are compiled with profiling enabled, and are executed by the tester modules) +PROF_MODULES = prof1.ttcn prof2.ttcn prof3.ttcn + +PROF_COMPILER_FLAGS = $(COMPILER_FLAGS) -z prof_files.txt + +PROF_TTCN3_LIB = ttcn3$(RT2_SUFFIX)-parallel$(DYNAMIC_SUFFIX) + +PROF_GENERATED_SOURCES = $(PROF_MODULES:.ttcn=.cc) +PROF_GENERATED_HEADERS = $(PROF_GENERATED_SOURCES:.cc=.hh) + +PROF_OBJECTS = $(PROF_GENERATED_SOURCES:.cc=.o) + +PROF_TARGET = prof.exe + +TEMP_FILES = $(PROF_GENERATED_SOURCES) $(PROF_GENERATED_HEADERS) $(PROF_OBJECTS) $(PROF_TARGET) data.json prof1.stats empty.stats + +# Rules for tester modules +all: $(TARGET) + +$(TARGET): $(GENERATED_SOURCES) $(USER_SOURCES) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ -L$(TTCN3_DIR)/lib -l$(TTCN3_LIB) -L$(OPENSSL_DIR)/lib -lcrypto $($(PLATFORM)_LIBS) + +$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile + @if [ ! -f $@ ]; then $(RM) compile; $(MAKE) compile; fi + +compile: $(TTCN3_MODULES) + $(filter-out -Nold -E, $(TTCN3_COMPILER)) $(COMPILER_FLAGS) $^ + touch compile + +clean distclean: + -rm -f $(TARGET) $(OBJECTS) $(GENERATED_HEADERS) \ + $(GENERATED_SOURCES) *.log Makefile.bak $(TEMP_FILES) + +dep: $(GENERATED_SOURCES) $(PROF_GENERATED_SOURCES) + makedepend $(CPPFLAGS) $^ + +run: $(TARGET) + ./$^ + +.NOTPARALLEL: + +# Rules for tested modules +$(PROF_TARGET): $(PROF_GENERATED_SOURCES) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ -L$(TTCN3_DIR)/lib -l$(PROF_TTCN3_LIB) -L$(OPENSSL_DIR)/lib -lcrypto $($(PLATFORM)_LIBS) + +$(PROF_GENERATED_SOURCES) $(PROF_GENERATED_HEADERS): prof_compile + @if [ ! -f $@ ]; then $(RM) prof_compile; $(MAKE) prof_compile; fi + +prof_compile: $(PROF_MODULES) + $(filter-out -Nold -E, $(TTCN3_COMPILER)) $(PROF_COMPILER_FLAGS) $^ + touch compile diff --git a/regression_test/profiler/PIPEasp_PT.cc b/regression_test/profiler/PIPEasp_PT.cc new file mode 100644 index 0000000..2b57a16 --- /dev/null +++ b/regression_test/profiler/PIPEasp_PT.cc @@ -0,0 +1,738 @@ +/******************************************************************************* +* Copyright (c) 2000-2014 Ericsson Telecom AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Zoltan Janos Szabo (Ericsson) - initial architecture design and implementation +* Roland Gecse (Ericsson) - initial architecture design +* Akos Cserveni (Ericsson) - Basic AST in compiler, semantic checking +* Gabor Szalai (Ericsson) – RAW and TEXT codecs +* Matyas Forstner (Ericsson) - ASN.1 extension of the compiler and BER/CER/DER codecs +* Kristof Szabados (Ericsson) - Eclipse Designer, Executor, Titanium UIs +* Szabolcs Beres (Ericsson) - Eclipse LogViewer +* Ferenc Kovacs (Ericsson) – log interfaces, big number support, subtype checking +* Csaba Raduly (Ericsson) – ASN.1 additions, XML encoder/decoder +* Adam Delic (Ericsson) – template restrictions, try&catch, support of pre-processor directives in Eclipse +* Krisztian Pandi (Ericsson) – import of imports +* Peter Dimitrov (Ericsson)- maintenance +* Balazs Andor Zalanyi (Ericsson) – code splitting +* Gabor Szalai (Ericsson) – RAW encoding/decoding +* Jeno Attila Balasko (Ericsson) – tests +* Csaba Feher (Ericsson) – epoll support +* Tamas Buti (Ericsson)- maintenance +* Matyas Ormandi (Ericsson) - maintenance +* Botond Baranyi (Ericsson) - JSON encoder +* Arpad Lovassy (Ericsson) - Java Executor API +* Laszlo Baji (Ericsson) - maintenance +* Marton Godar (Ericsson) - xsd2ttcn converter +*******************************************************************************/ +// +// File: PIPEasp_PT.cc +// Description: Source code of PIPE testport implementation +// Rev: +// Prodnr: CNL 113 334 +// Updated: 2008-06-03 +// Contact: http://ttcn.ericsson.se +// + + +#include "PIPEasp_PT.hh" +#include //kill +#include //pipe +#include //errno +#include //isspace +#include //FD_ZERO +#include // sys_errlist +#include //wait +#include //wait + +#ifndef PIPE_BUF_SIZE +#define PIPE_BUF_SIZE 655536 +#endif + +namespace PIPEasp__PortType { + +PIPEasp__PT::PIPEasp__PT(const char *par_port_name) + : PIPEasp__PT_BASE(par_port_name) + , lineMode(true) + , processExecuting(false) + , binaryMode(false) + , disableSend(false) + , processPid(-1) // pid of the process currently executing + , processStdin(-1) // fd of stdin of the process + , processStdout(-1) // fd of stdout of the process + , processStderr(-1) // fd of stderr of the process + , processExitCode(0) // exit code of the process +{ + FD_ZERO(&readfds); + stdout_buffer.clear(); + stderr_buffer.clear(); +} + +PIPEasp__PT::~PIPEasp__PT() +{ +// nothing to do +} + +void PIPEasp__PT::set_parameter(const char * /*parameter_name*/, + const char * /*parameter_value*/) +{ +// no config parameters +} + +void PIPEasp__PT::Event_Handler(const fd_set *read_fds, + const fd_set * /*write_fds*/, const fd_set * /*error_fds*/, + double /*time_since_last_call*/) +{ + log("PIPEasp__PT::Event_Handler called"); + if (processStdout != -1 && FD_ISSET(processStdout, read_fds)) { + if (!processExecuting) { + TTCN_warning("Unexpected message from stdout, no command is executing"); + } else { + log("Incoming stdout message received from process"); + } + + long nBytes; + int r; + + nBytes = PIPE_BUF_SIZE; + unsigned char* buffer; + size_t end_len = nBytes; + stdout_buffer.get_end(buffer, end_len); + r = read(processStdout,buffer,(int)nBytes); + if (r <= 0) { + log("ttcn_pipe_port: read problem on stdout.\n"); + // close the pipe and remove it from event handler + close(processStdout); + FD_CLR(processStdout, &readfds); + Install_Handler(&readfds, NULL, NULL, 0.0); + processStdout = -1; + + // check if stderr is closed: + if (processStderr == -1) { + // child died + log("Child might have died."); + handle_childDeath(); + } + } + else { + log("incoming stdout %ld bytes\n", r); + stdout_buffer.increase_length(r); + sendStdout(); + } + return; + } + if (processStderr != -1 && FD_ISSET(processStderr, read_fds)) { + if (!processExecuting) { + TTCN_warning("Unexpected message from stderr, no command is executing"); + } else { + log("Incoming stderr message received from process"); + } + + long nBytes; + int r; + + nBytes = PIPE_BUF_SIZE; + unsigned char* buffer; + size_t end_len = nBytes; + stderr_buffer.get_end(buffer, end_len); + r = read(processStderr,buffer,(int)nBytes); + if (r <= 0) { + log("ttcn_pipe_port: read problem on stderr.\n"); + // close the pipe and remove it from event handler + close(processStderr); + FD_CLR(processStderr, &readfds); + Install_Handler(&readfds, NULL, NULL, 0.0); + processStderr = -1; + + // check if stdout is closed: + if (processStdout == -1) { + // child died + log("Child might have died."); + handle_childDeath(); + } + } + else { + log("incoming stderr %ld bytes\n", r); + stderr_buffer.increase_length(r); + sendStderr(); + } + return; + } +} + +void PIPEasp__PT::user_map(const char * /*system_port*/) +{ +// nothing to do +} + +void PIPEasp__PT::user_unmap(const char * /*system_port*/) +{ +// nothing to do +} + +void PIPEasp__PT::user_start() +{ +// nothing to do +} + +void PIPEasp__PT::user_stop() +{ +// nothing to do +} + +/************************************* +* Specific outgoing_send functions +*************************************/ +void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PExecute& send_par) { + log("PIPEasp__PT::outgoing_send_PExecute called"); + // disable sendStdout, sendStderr until process exits + if (processExecuting) { + sendError("Pipe Test Port: Command already executing"); + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("PIPE test port (%s): Command already executing. Following ASP is ignored: ", get_name()); + send_par.log(); + TTCN_Logger::end_event(); + return; + } + PIPEasp__Types::ASP__PExecuteBackground message_PExecuteBackground; + // starting command + message_PExecuteBackground.command() = send_par.command(); + outgoing_send(message_PExecuteBackground); + // sending input + PIPEasp__Types::ASP__PStdin message_PStdin; + message_PStdin.stdin_() = send_par.stdin_(); + outgoing_send(message_PStdin); + disableSend = true; + + // closing stdin pipe: + outgoing_send(PIPEasp__Types::ASP__PEndOfInput()); + + log("PIPEasp__PT::outgoing_send_PExecute exited"); +} + +void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PExecuteBinary& send_par) { + log("PIPEasp__PT::outgoing_send_PExecuteBinary called"); + // disable sendStdout, sendStderr until process exits + if (processExecuting) { + sendError("Pipe Test Port: Command already executing"); + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("PIPE test port (%s): Command already executing. Following ASP is ignored: ", get_name()); + send_par.log(); + TTCN_Logger::end_event(); + return; + } + PIPEasp__Types::ASP__PExecuteBackground message_PExecuteBackground; + // starting command + message_PExecuteBackground.command() = send_par.command(); + outgoing_send(message_PExecuteBackground); + // sending input + PIPEasp__Types::ASP__PStdinBinary message_PStdinBinary; + message_PStdinBinary.stdin_() = send_par.stdin_(); + outgoing_send(message_PStdinBinary); + disableSend = true; + + // closing stdin pipe: + outgoing_send(PIPEasp__Types::ASP__PEndOfInput()); + + log("PIPEasp__PT::outgoing_send_PExecuteBinary exited"); +} + +void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PExecuteBackground& send_par) { + log("PIPEasp__PT::outgoing_send_PExecuteBackground called"); + + if (processExecuting) { + log("Process already executing. Cannot start new process."); + sendError("Pipe Test Port: Command already executing"); + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("PIPE test port (%s): Command already executing. Following ASP is ignored: ", get_name()); + send_par.log(); + TTCN_Logger::end_event(); + log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); + return; + } + + // creating pipes for process + int pipesStdin[2]; + int pipesStdout[2]; + int pipesStderr[2]; + + if (pipe(pipesStdin) != 0) { + sendError("Pipe Test Port: Cannot create stdin pipe"); + log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); + return; + } + if (pipe(pipesStdout) != 0) { + sendError("Pipe Test Port: Cannot create stdout pipe"); + log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); + return; + } + if (pipe(pipesStderr) != 0) { + sendError("Pipe Test Port: Cannot create stderr pipe"); + log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); + return; + } + + processStdin = pipesStdin[1]; + processStdout = pipesStdout[0]; + processStderr = pipesStderr[0]; + + processPid = fork(); + if (processPid < 0) { + // + // Error + // + + // close the pipes + close(pipesStdin[0]); + close(pipesStdout[1]); + close(pipesStderr[1]); + + close(processStdin); + close(processStdout); + close(processStderr); + + sendError("Pipe Test Port: Cannot fork"); + } + else if (processPid == 0) { + + // + // Child process + // + + // close the parent end of the pipes + close(processStdin); + close(processStdout); + close(processStderr); + + /*// set these to the other end of the pipe + processStdin = pipesStdin[0]; + processStdout = pipesStdout[1]; + processStderr = pipesStderr[1];*/ + + int r; + // redirect pipeStdin to stdin + r = dup2(pipesStdin[0], 0); + if (r<0) { + TTCN_error("Cannot redirect stdin"); + exit(errno); + } + + // redirect pipeStdout to stdout + r = dup2(pipesStdout[1], 1); + if (r<0) { + TTCN_error("Cannot redirect stdout"); + exit(errno); + } + + // redirect pipeStderr to stderr + r = dup2(pipesStderr[1], 2); + if (r<0) { + TTCN_error("Cannot redirect stderr"); + exit(errno); + } + + processExitCode = execCommand((const char*)send_par.command()); + + // There is a problem executing the command + // Exiting... + + fflush(stdout); + fflush(stderr); + + //closing pipes: + close(pipesStdin[0]); + close(pipesStdout[1]); + close(pipesStderr[1]); + + exit(processExitCode); // end of child process + } + else { + + // + // Parent process + // + + log("Process started with pid: %d", processPid); + // close child end of the pipes + close(pipesStdin[0]); + close(pipesStdout[1]); + close(pipesStderr[1]); + + + processExecuting = true; + + // install handler for the process pipes: + //FD_SET(processStdin, &readfds); + FD_SET(processStdout, &readfds); + FD_SET(processStderr, &readfds); + + Install_Handler(&readfds, NULL, NULL, 0.0); + } + + log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); +} + +void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PStdin& send_par) { + + log("PIPEasp__PT::outgoing_send_PStdin called"); + binaryMode = false; + if (!processExecuting) { + sendError("Pipe Test Port: No command executing"); + return; + } + if (disableSend) { // process was started with PExecute(Binary) + sendError("Pipe Test Port: PStdin is not sent: current process is not started with PExecuteBackground!"); + return; + } + + log("will now write to stdin: '%s'", + (const char*)(send_par.stdin_()+((lineMode)?"\n":""))); + write(processStdin, + (const char*)(send_par.stdin_()+((lineMode)?"\n":"")), + send_par.stdin_().lengthof()+((lineMode)?1:0)); + + log("PIPEasp__PT::outgoing_send_PStdin exited"); +} + +void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PStdinBinary& send_par) { + log("PIPEasp__PT::outgoing_send_PStdinBinary called"); + binaryMode = true; + if (!processExecuting) { + sendError("Pipe Test Port: No command executing"); + return; + } + if (disableSend) { // process was started with PExecute(Binary) + sendError("Pipe Test Port: PStdinBinary is not sent: current process is not started with PExecuteBackground!"); + return; + } + + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("PIPE test port (%s): will now write binary data to stdin: ", get_name()); + send_par.stdin_().log(); + TTCN_Logger::end_event(); + + write(processStdin, + (const char*)(const unsigned char*)(send_par.stdin_()), + send_par.stdin_().lengthof()); + log("PIPEasp__PT::outgoing_send_PStdinBinary exited"); +} + +void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PKill& send_par) { + log("PIPEasp__PT::outgoing_send_PKill called"); + if (!processExecuting) { + // no process is running + log("No process executing."); + sendError("Pipe Test Port: No command executing"); + log("PIPEasp__PT::outgoing_send_PKill exited"); + return; + } + + int signo = (int)send_par.signal(); + if (signo<1 || signo>31) { + // signo out of range; + log("Signo out of range."); + sendError( + "Pipe Test port: Signal number should be " + "between 1 and 31"); + log("PIPEasp__PT::outgoing_send_PKill exited"); + return; + } + // killing process + log("Killing process %d, signo: %d", processPid, signo); + int r = kill(processPid, signo); + log("Kill process returned %d", r); + log("PIPEasp__PT::outgoing_send_PKill exited"); +} + +void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PLineMode& send_par) { + log("PIPEasp__PT::outgoing_send_PLineMode called"); + lineMode = (bool)send_par.lineMode(); + log("LineMode is set to %s", (lineMode)?"TRUE":"FALSE"); + log("PIPEasp__PT::outgoing_send_PLineMode exited"); +} + +void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PEndOfInput& /*send_par*/) { + log("PIPEasp__PT::outgoing_send_PEndOfInput called"); + // close stdin pipe + close(processStdin); + processStdin = -1; + log("stdin closed"); + log("PIPEasp__PT::outgoing_send_PEndOfInput exited"); +} + +/******************************** +* Execute the given command +* returns the exitcode of the process +*********************************/ +int PIPEasp__PT::execCommand(const char* command) { + log("PIPEasp__PT::execCommand called"); + log("Executing command: %s", command); + + // with this it is not possible to access the pid of the process + //return system(command); + + int argc = 0; + char* argv[1024]; + + CHARSTRING temp(0, ""); // empty string + for (int i = 0; command[i] != 0; i++) { + if (isspace(command[i])) { + argv[argc++] = strdup(temp); + log("command argument added: %s", (const char*)temp); + while (command[i] != '0' && isspace(command[i])) i++; + i--; + temp = ""; + } else { + temp = temp + CHARSTRING(1, command+i); + } + } + + if (temp != "") { + argv[argc++] = strdup(temp); + log("command argument added: %s", (const char*)temp); + } + + argv[argc++] = (char*)NULL; + + log("execCommand(%s,%d)\n", argv[0], argc); + execvp(argv[0],argv); + + fprintf(stderr,"Error executing command %s (%d): %s\n", + argv[0], errno, strerror(errno)); + fflush(stderr); +// exit(errno); + return errno; +} + +/*********************************** +* if the the child process died, gets +* the exit code and sends it to TTCN +* should be called when stdout/err are closed +************************************/ +void PIPEasp__PT::handle_childDeath() { + log("Getting process status for pid %d...", processPid); + processExitCode = 0; // reset the exitcode + int pid = wait(&processExitCode); + //waitpid(processPid,&processExitCode, 0); + if (pid!=processPid) { + log("other child died with pid: %d, exit code: %d", pid, processExitCode); + return; + } + + log("Child process exit status is: %d", processExitCode); + // send code to TTCN: + sendExitCode(); + // send result to TTCN + sendResult(); + + // removing fd-s installed for the process: + Uninstall_Handler(); // no handler is needed + FD_ZERO(&readfds); + /* + // equivalent with: + //FD_CLR(processStdin, &readfds); + FD_CLR(processStdout, &readfds); + FD_CLR(processStderr, &readfds); + Install_Handler(&readfds, NULL, NULL, 0.0); + */ + + // closing pipes: + close(processStdin); + //close(processStdout); // already closed + //close(processStderr); // already closed + + processStdin = -1; + //processStdout = -1; + //processStderr = -1; + + processExecuting = false; + disableSend = false; +} + +/*************************** +* Send stdout msg to TTCN +***************************/ +void PIPEasp__PT::sendStdout() { + if (disableSend) return; + + PIPEasp__Types::ASP__PStdout message_PStdout; + PIPEasp__Types::ASP__PStdoutBinary message_PStdoutBinary; + if (lineMode && !binaryMode) { + // send complete lines from buffer + const unsigned char* pos = stdout_buffer.get_read_data(); + for(unsigned int i=0; i +// Prodnr: CNL 113 334 +// Updated: 2008-06-03 +// Contact: http://ttcn.ericsson.se +// + + +#ifndef PIPEasp__PT_HH +#define PIPEasp__PT_HH + +#include "PIPEasp_PortType.hh" + +namespace PIPEasp__PortType { + +class PIPEasp__PT : public PIPEasp__PT_BASE { +public: + PIPEasp__PT(const char *par_port_name = NULL); + ~PIPEasp__PT(); + + void set_parameter(const char *parameter_name, + const char *parameter_value); + + void Event_Handler(const fd_set *read_fds, + const fd_set *write_fds, const fd_set *error_fds, + double time_since_last_call); + +protected: + void user_map(const char *system_port); + void user_unmap(const char *system_port); + + void user_start(); + void user_stop(); + + void outgoing_send(const PIPEasp__Types::ASP__PExecute& send_par); + void outgoing_send(const PIPEasp__Types::ASP__PExecuteBinary& send_par); + void outgoing_send(const PIPEasp__Types::ASP__PExecuteBackground& send_par); + void outgoing_send(const PIPEasp__Types::ASP__PStdin& send_par); + void outgoing_send(const PIPEasp__Types::ASP__PStdinBinary& send_par); + void outgoing_send(const PIPEasp__Types::ASP__PKill& send_par); + void outgoing_send(const PIPEasp__Types::ASP__PLineMode& send_par); + void outgoing_send(const PIPEasp__Types::ASP__PEndOfInput& send_par); +private: + int execCommand(const char* command); + void handle_childDeath(); + void sendStdout(); + void sendStderr(); + void sendExitCode(); + void sendResult(); + void sendError(const char* error_msg); + void log(const char *fmt, ...); + +private: + bool lineMode; // true if lineMode is enabled + bool processExecuting; // true if process is executing: disable new processes + bool binaryMode; // true if result should be returned in as binary data + bool disableSend; // if true sendStdout/err is disabled + + fd_set readfds; // fd set for event handler + int processPid; // pid of the process currently executing + int processStdin; // fd of stdin of the process + int processStdout; // fd of stdout of the process + int processStderr; // fd of stderr of the process + + TTCN_Buffer stdout_buffer; // data sent to stdout + TTCN_Buffer stderr_buffer; // data sent to stderr + int processExitCode; // exit code of the process + +}; + +}//namespace + +#endif diff --git a/regression_test/profiler/PIPEasp_PortType.ttcn b/regression_test/profiler/PIPEasp_PortType.ttcn new file mode 100644 index 0000000..1d43b6f --- /dev/null +++ b/regression_test/profiler/PIPEasp_PortType.ttcn @@ -0,0 +1,46 @@ +/****************************************************************************** + * Copyright (c) 2000-2014 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ +// +// File: PIPEasp_PortType.ttcn +// Reference: Based on SCS PIPE Testport +// Rev: +// Prodnr: CNL 113 334 +// Updated: 2008-06-03 +// Contact: http://ttcn.ericsson.se + +module PIPEasp_PortType +{ + + import from PIPEasp_Types all; +// ************************************************************************* +// * PIPE port type definitions * +// ************************************************************************* + + // system PIPE port type + type port PIPEasp_PT message + { + out ASP_PExecute, + ASP_PExecuteBinary, + ASP_PExecuteBackground, + ASP_PStdin, + ASP_PStdinBinary, + ASP_PKill, + ASP_PLineMode, + ASP_PEndOfInput; + + in ASP_PResult, + ASP_PResultBinary, + ASP_PStdout, + ASP_PStderr, + ASP_PStdoutBinary, + ASP_PStderrBinary, + ASP_PExit, + ASP_PError; + } + +}//eof module diff --git a/regression_test/profiler/PIPEasp_Templates.ttcn b/regression_test/profiler/PIPEasp_Templates.ttcn new file mode 100644 index 0000000..988bd48 --- /dev/null +++ b/regression_test/profiler/PIPEasp_Templates.ttcn @@ -0,0 +1,93 @@ +/****************************************************************************** + * Copyright (c) 2000-2014 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ +module PIPEasp_Templates { + +import from PIPEasp_Types all; + +template ASP_PKill t_PKill(template integer signo) := { + signal := signo +} + +template ASP_PError t_PError(template charstring msg) := { + errorMessage := msg +} + +template ASP_PLineMode t_PLineMode(template boolean p_lineMode) := { + lineMode := p_lineMode +} + +template ASP_PResult t_PResult( + template charstring p_stdout, + template charstring p_stderr, + template integer p_code) := { + stdout := p_stdout, + stderr := p_stderr, + code := p_code +} + +template ASP_PResultBinary t_PResultBinary( + template octetstring p_stdout, + template octetstring p_stderr, + template integer p_code) := { + stdout := p_stdout, + stderr := p_stderr, + code := p_code +} + +template ASP_PStdin t_PStdin( + template charstring p_stdin) := { + stdin := p_stdin +} + +template ASP_PStdinBinary t_PStdinBinary( + template octetstring p_stdinBinary) := { + stdin := p_stdinBinary +} + +template ASP_PStdout t_PStdout( + template charstring p_stdout) := { + stdout := p_stdout +} + +template ASP_PStderr t_PStderr( + template charstring p_stderr) := { + stderr := p_stderr +} + +template ASP_PStdoutBinary t_PStdoutBinary( + template octetstring p_stdout) := { + stdout := p_stdout +} + +template ASP_PStderrBinary t_PStderrBinary( + template octetstring p_stderr) := { + stderr := p_stderr +} + +template ASP_PExecuteBackground t_PExecuteBackground( + template charstring p_command) := { + command := p_command +} + +template ASP_PExit t_PExit(template integer p_code) := { + code := p_code +} + +template ASP_PExecute t_PExecute( + template charstring p_command, template charstring p_stdin) := { + command := p_command, + stdin := p_stdin +} + +template ASP_PExecuteBinary t_PExecuteBinary( + template charstring p_command, template octetstring p_stdin) := { + command := p_command, + stdin := p_stdin +} + +} // end of module diff --git a/regression_test/profiler/PIPEasp_Types.ttcn b/regression_test/profiler/PIPEasp_Types.ttcn new file mode 100644 index 0000000..da8ea94 --- /dev/null +++ b/regression_test/profiler/PIPEasp_Types.ttcn @@ -0,0 +1,180 @@ +/****************************************************************************** + * Copyright (c) 2000-2014 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ +// +// File: PIPEasp_Types.ttcn +// Description: PIPE (ASP) definitions +// Reference: Based on SCS PIPE testport +// Rev: +// Prodnr: CNL 113 334 +// Updated: 2008-06-03 +// Contact: http://ttcn.ericsson.se +// + +module PIPEasp_Types +{//start of the module + +// ************************************************************************* +// * Type Definitions Part * +// ************************************************************************* + +// This ASP can be used to execute the given command with given standard input. +// The PResult ASP is sent as an answer, unless there is already a process +// executing which results in the ASP PError being sent. +// +// This ASP can only be sent from the test suite: $DIRECTION OUT + type record ASP_PExecute { + charstring command, + charstring stdin + }; + +// This ASP is sent as an answer to the PExecute ASP. It provides +// information about the standard output and error of the executed command, +// as well as the exit code of the command. +// +// This ASP can only be received by the test suite: $DIRECTION IN + type record ASP_PResult { + charstring stdout, + charstring stderr, + integer code + }; + +// This ASP is similar to the PExecute ASP, except that binary data is +// sent instead of a string as the contents of standard input. This means that +// the data can be, for instance, the encode form of a PDU. +// +// This ASP can only be sent from the test suite: $DIRECTION OUT + type record ASP_PExecuteBinary { + charstring command, + octetstring stdin + }; + +// This ASP is similar to the PResult ASP, except that the outputs are +// given as binary data. +// +// This ASP can only be received by the test suite: $DIRECTION IN + type record ASP_PResultBinary { + octetstring stdout, + octetstring stderr, + integer code + }; + +// This ASP can be used to start a background process with the command +// given in the parameters. The PStdin, PStdinBinary, PStdout, PStdoutBinary, +// PStderr, and PStderrBinary ASPs can then be used to send and receive input +// and output to and from the process. +// +// This ASP can only be sent by the test suite: $DIRECTION OUT + type record ASP_PExecuteBackground { + charstring command + }; + +// This ASP sends input to the process started with PExecuteBackground. +// After the usage of the PStdin ASP, all outputs are sent back to the +// test suite by the PStdout and PStderr ASPs. +// +// This ASP can only be sent by the test suite: $DIRECTION OUT + type record ASP_PStdin { + charstring stdin + }; + +// This ASP is sent to the test suite when the background process started +// by PExecuteBackground outputs something to its standard output. +// +// This ASP can only be received by the test suite: $DIRECTION IN + type record ASP_PStdout { + charstring stdout + }; + +// This ASP is sent to the test suite when the background process started +// by PExecuteBackground outputs something to its standard error. +// +// This ASP can only be received by the test suite: $DIRECTION IN + type record ASP_PStderr { + charstring stderr + }; + +// This ASP is similar to the PStdin ASP, except that the inputs are in +// binary format. After sending this ASP, all the outputs produced by the +// background process are sent back to the test suite in the PStdoutBinary +// and PStderrBinary ASPs. +// +// This ASP can only be sent by the test suite: $DIRECTION OUT + type record ASP_PStdinBinary { + octetstring stdin + }; + +// This ASP is similar to PStdout, except that it carries binary data. +// +// This ASP can only be received by the test suite: $DIRECTION IN + type record ASP_PStdoutBinary { + octetstring stdout + }; + +// This ASP is similar to PStderr, except that it carries binary data. +// +// This ASP can only be received by the test suite: $DIRECTION IN + type record ASP_PStderrBinary { + octetstring stderr + }; + +// This ASP can be used to send a signal to the process started by +// PExecuteBackground. The parameter value is the signal number. +// +// This ASP can only be sent by the test suite: $DIRECTION OUT + type record ASP_PKill { + integer signal + }; + +// This ASP informs the test suite about the death of the process started +// by PExecuteBackground. The parameter value is the exit code of the process. +// +// This ASP can only be received by the test suite: $DIRECTION IN + type record ASP_PExit { + integer code + }; + +// This ASP determines the meaning of the strings representing the standard +// input, output, and error in the ASPs PExecute, PResult, PStdin, PStdout, +// and PStderr. In the first two ASPs, it determines if a newline is added to +// the end of the inputs and a newline is taken away from the end of the outputs. +// TRUE determines that these changes take place, and FALSE that they do not. +// +// In the three other ASPs, TRUE means that a newline is added to the end of +// each input string, and that the outputs are sent in separate ASPs each +// containing only one line of text (without the newline). +// +// By default, the PIPE test port functions as if the PLineMode ASP would have +// been sent with the parameter values TRUE. +// +// This ASP can only be sent by the test suite: $DIRECTION OUT + type record ASP_PLineMode { + boolean lineMode + }; + +// This ASP is sent to the test suite when the PIPE test port is used +// in a wrong manner. +// +// This ASP can only be received by the test suite: $DIRECTION IN + type record ASP_PError { + charstring errorMessage + }; + +// This ASP can be used to notify the test port that the end of input +// is reached. Makes sense for processes started by PExecuteBackground. +// After this ASP is sent to the background process no more input can be sent +// to its stdin using PStdin(Binary) +// Note, that for processes started by PExecute(Binary) the input is +// closed automatically. +// +// This ASP can only be sent by the test suite: $DIRECTION OUT + type record ASP_PEndOfInput { + }; + +}//end module + + diff --git a/regression_test/profiler/Shell.ttcn b/regression_test/profiler/Shell.ttcn new file mode 100644 index 0000000..0db58a1 --- /dev/null +++ b/regression_test/profiler/Shell.ttcn @@ -0,0 +1,244 @@ +/****************************************************************************** + * Copyright (c) 2000-2014 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ + +module Shell +{ + +import from PIPEasp_Types all; +import from PIPEasp_PortType all; +import from PIPEasp_Templates all; + + +modulepar float tsp_shellCmdTimeout := 20.0; + +type component PIPE_CT { + port PIPEasp_PT PIPE_PCO; + var ASP_PExecute v_ASP_PExecute; + var ASP_PResult v_ASP_PResult; + var ASP_PExecuteBinary v_ASP_PExecuteBinary; + var ASP_PResultBinary v_ASP_PResultBinary; + var ASP_PExecuteBackground v_ASP_PExecuteBackground; + var ASP_PStdin v_ASP_PStdin; + var ASP_PStdout v_ASP_PStdout; + var ASP_PStderr v_ASP_PStderr; + var ASP_PStdinBinary v_ASP_PStdinBinary; + var ASP_PStdoutBinary v_ASP_PStdoutBinary; + var ASP_PStderrBinary v_ASP_PStderrBinary; + var ASP_PKill v_ASP_PKill; + var ASP_PExit v_ASP_PExit; + var ASP_PLineMode v_ASP_PLineMode; + var ASP_PError v_ASP_PError; +} + +type component Shell_CT extends PIPE_CT { + var boolean v_initialized:=false; +} + +type component mtc_CT {} + +//========================================================================= +// Constants +//========================================================================= + +const integer c_shell_successWithoutWarningAndError:=0; +const integer c_shell_success := 0; +const integer c_shell_successWithWarning:=1; //temp until licence is solved +const integer c_shell_error:=256; +const integer c_shell_error_noSuchFileOrDirectory:=512; + +//Expected and accepted diffs: +// Line "Copyright Ericsson AB 2013" - 4 diffs +// Line "XSD to TTCN-3 Translator version:" - 4 diffs +// Line "File" - 4 diffs +// Line "Updated: " - 4 diffs +// Line "module www_" - 4 diffs +// Line "ETSI ES 201 873-9 V4.1.2" - 2 diffs ???? << Fix it ! +// Line "variant \"namespace as" - 4 diffs +// Script counts the strings "\n" thus N different lines mean N-1 numOfDiff +//Possible values: 19,21,23,25 but 21 and 25 should be eliminated! + +const integer c_numOfDiff_headerAndModuleName := 19; +const integer c_numOfDiff_headerModNameAndNamespace := 23; +const integer c_numOfDiff_headerModNameAndImport := 23; + +function f_countDelimiters(in charstring pl_string, in charstring pl_delimiter, inout integer pl_counter) { + pl_counter:=0; + var integer pos:=0; + var integer vl_size:=lengthof(pl_string); + var integer vl_delimsize:=lengthof(pl_delimiter); + while(pos0) { vl_expectedResult:=256; } + var boolean vl_success:=false; + f_shell_command("diff -w " & pl_file1 & " " & pl_file2,"",vl_expectedResult,vl_success); + + if(v_ASP_PResult.code==0) + { + setverdict(pass); + } + else if(v_ASP_PResult.code==256) { + var integer vl_counter:=0; + f_countDelimiters(v_ASP_PResult.stdout,"\n",vl_counter); + log("Counted lines: ",vl_counter, " diffLimit: ", pl_diffLimit) + if(vl_counter>pl_diffLimit) { + setverdict(fail); + } + } else { //e.g 512: No such file or directory + log("Wrong result code: ",v_ASP_PResult.code, " Expected result code: ", vl_expectedResult) + setverdict(fail); + } +}//f_ + + +//********* SHELL Functions *********************** + +//========================================================================= +// f_shell_init +//========================================================================= +function f_shell_init() runs on Shell_CT { + if(v_initialized) { return; } + map(self:PIPE_PCO, system:PIPE_PCO); + v_initialized:=true; +} + +//========================================================================= +// f_shell_cleanup +//========================================================================= +function f_shell_cleanup() runs on Shell_CT { + if(not v_initialized) { return; } + unmap(self:PIPE_PCO, system:PIPE_PCO); + v_initialized:=false; +} +//========================================================================= +// f_setverdictfromBool +//========================================================================= +function f_setverdictfromBool(in boolean pl_result, in boolean pl_expected_result:=true) { + if(pl_result==pl_expected_result) { + setverdict(pass); + }else{ + setverdict(fail); + } + return; +} +//========================================================================= +// f_shell_validateXml +// Compares pl_xmlFileContent (e.g encoding result) against pl_xsdFileName +//========================================================================= +function f_shell_validateXml(in octetstring pl_xmlFileContent, in charstring pl_xsdFileName, in integer pl_expected_result, inout boolean pl_success) +runs on Shell_CT +{ + f_shell_command( "xmllint --noout --schema " & pl_xsdFileName & " - ",oct2char(pl_xmlFileContent), pl_expected_result, pl_success); +} + + +//========================================================================= +// f_shell_command +//========================================================================= +function f_shell_command(in charstring pl_command, in charstring pl_stdin, in integer pl_expected_result, inout boolean pl_success) +runs on Shell_CT +{ + f_shell_init(); + + var integer vl_expectedCode:=-1; + if(pl_expected_result==c_shell_successWithoutWarningAndError or + pl_expected_result==c_shell_successWithWarning) { + vl_expectedCode:=0 + } else { + vl_expectedCode:= pl_expected_result; + } + + log("Running: ", pl_command); + PIPE_PCO.send(t_PExecute(pl_command,pl_stdin)); + + timer t:=tsp_shellCmdTimeout; + t.start; + pl_success:=false; + + alt { + + [] PIPE_PCO.receive(t_PResult(?, ?, ?)) -> value v_ASP_PResult { + log("PResult msg received: ", v_ASP_PResult); + + if(v_ASP_PResult.code==vl_expectedCode ) { + var charstring vl_pattern:=""; + select(pl_expected_result) { + case(c_shell_successWithWarning) { + vl_pattern:="*(Warning|WARNING|warning)*"; + if(regexp(v_ASP_PResult.stderr,vl_pattern,0)!=""){ + log("That is an expected Warning!") + pl_success:=true; + } else { + log("No Warning in the stderr string but expected"); + pl_success:=false; + } + } + case(c_shell_successWithoutWarningAndError) { + vl_pattern:="*(Error|ERROR|error)*"; + if(regexp(v_ASP_PResult.stderr,vl_pattern,0)!=""){ + log("That is an unexpected Error!") + pl_success:=false; + } else { + log("No Error in the stderr string"); + pl_success:=true; + } + vl_pattern:="*(Warning|WARNING)*"; + if(regexp(v_ASP_PResult.stderr,vl_pattern,0)!=""){ + log("That is an unexpected Warning!") + pl_success:=false; + } else { + log("No Warning in the stderr string"); + pl_success:=true; + } + }//case + case(c_shell_error) { + log("Command returned with ERROR as expected"); + pl_success:=true; + } + case(c_shell_error_noSuchFileOrDirectory) { + log("Command returned with No such file or directory as expected"); + pl_success:=true; + } + case else { + log("Other case"); + pl_success:=false; + } + }//select + } else { + log("The result code(", v_ASP_PResult.code, ") is not the expected(", vl_expectedCode, ")"); + pl_success:=false; + }//if + } + [] t.timeout { + pl_success:=false; + } + }//alt + + f_shell_cleanup(); + return; +}//f_shell_command +//========================================================================= +// Name: f_shellCommandWithVerdict +// Description: sets verdict for pass, if the command execution returns with the expected value +//========================================================================= +function f_shellCommandWithVerdict(in charstring pl_command, in charstring pl_stdin, in integer pl_expected_result) runs on Shell_CT { + var boolean vl_success:=false; + f_shell_command(pl_command, pl_stdin, pl_expected_result, vl_success); + f_setverdictfromBool(vl_success) +} + +} // end of module diff --git a/regression_test/profiler/Testcases.ttcn b/regression_test/profiler/Testcases.ttcn new file mode 100644 index 0000000..67765a5 --- /dev/null +++ b/regression_test/profiler/Testcases.ttcn @@ -0,0 +1,74 @@ +/****************************************************************************** + * Copyright (c) 2000-2015 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ + +module Testcases { + +import from Shell all; + +type record of charstring CharstringList; + +function f_test_profiler(in charstring p_target_file, in charstring p_config_file, + in CharstringList p_output_files, in CharstringList p_exp_output_files) runs on Shell_CT +{ + // make the target (the makefile must have a rule for it) + f_shellCommandWithVerdict("make " & p_target_file, "", c_shell_successWithoutWarningAndError); + + if (getverdict == pass) { + // run the executable with the specified configuration file + f_shellCommandWithVerdict("ttcn3_start " & p_target_file & " " & p_config_file, "", + c_shell_successWithoutWarningAndError); + + if (getverdict == pass) { + // compare the output files + var integer i; + for (i := 0; i < sizeof(p_output_files); i := i + 1) { + f_compareFiles(p_output_files[i], p_exp_output_files[i], 0); + if (getverdict != pass) { + action("Output file '" & p_output_files[i] & "' does not match the expected file '" & + p_exp_output_files[i] & "'"); + } + } + } + else { + action("Failed to run target '", p_target_file, "', with configuration file '", p_config_file, "'"); + } + } + else { + action("Failed to make target '", p_target_file, "'"); + } +} + +testcase tc_coverage() runs on Shell_CT +{ + // only code coverage is done in this case, since that is exact, and the results can be checked with + // a simple file comparison + f_test_profiler("prof.exe", "prof1.cfg", { "data.json", "prof1.stats" }, { "data_e.json", "prof1_e.stats" } ); +} + +testcase tc_profiling() runs on Shell_CT +{ + // only profiling is done in this case + // the results cannot be checked, since the call times will vary in each run + f_test_profiler("prof.exe", "prof2.cfg", { }, { } ); +} + +testcase tc_profiling_and_coverage() runs on Shell_CT +{ + // both profiling and code coverage is activated in this case + // although the call times cannot be checked, the statistics filter is set to generate an + // empty statistics file, which can be cheked + f_test_profiler("prof.exe", "prof3.cfg", { "empty.stats" }, { "empty_e.stats" } ); +} + +control { + execute(tc_coverage()); + execute(tc_profiling()); + execute(tc_profiling_and_coverage()); +} + +} diff --git a/regression_test/profiler/data_e.json b/regression_test/profiler/data_e.json new file mode 100644 index 0000000..4a1737e --- /dev/null +++ b/regression_test/profiler/data_e.json @@ -0,0 +1,226 @@ +[ + { + "file" : "prof1.ttcn", + "functions" : [ + { + "name" : "f1", + "start line" : 15, + "execution count" : 3, + "total time" : 0.000000 + }, + { + "name" : "tc1", + "start line" : 19, + "execution count" : 1, + "total time" : 0.000000 + } + ], + "lines" : [ + { + "number" : 13, + "execution count" : 3, + "total time" : 0.000000 + }, + { + "number" : 15, + "execution count" : 3, + "total time" : 0.000000 + }, + { + "number" : 16, + "execution count" : 3, + "total time" : 0.000000 + }, + { + "number" : 19, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 20, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 21, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 22, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 23, + "execution count" : 1, + "total time" : 0.000000 + } + ] + }, + { + "file" : "prof2.ttcn", + "functions" : [ + { + "name" : "f2", + "start line" : 13, + "execution count" : 2, + "total time" : 0.000000 + }, + { + "name" : "t1", + "start line" : 22, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "name" : "tc2", + "start line" : 24, + "execution count" : 1, + "total time" : 0.000000 + } + ], + "lines" : [ + { + "number" : 13, + "execution count" : 2, + "total time" : 0.000000 + }, + { + "number" : 14, + "execution count" : 2, + "total time" : 0.000000 + }, + { + "number" : 18, + "execution count" : 2, + "total time" : 0.000000 + }, + { + "number" : 22, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 24, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 25, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 26, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 27, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 28, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 29, + "execution count" : 1, + "total time" : 0.000000 + } + ] + }, + { + "file" : "prof3.ttcn", + "functions" : [ + { + "name" : "f3", + "start line" : 14, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "name" : "tc3", + "start line" : 21, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "name" : "control", + "start line" : 31, + "execution count" : 1, + "total time" : 0.000000 + } + ], + "lines" : [ + { + "number" : 14, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 16, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 17, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 18, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 21, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 23, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 24, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 25, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 26, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 27, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 28, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 31, + "execution count" : 1, + "total time" : 0.000000 + }, + { + "number" : 32, + "execution count" : 1, + "total time" : 0.000000 + } + ] + } +] diff --git a/regression_test/profiler/empty_e.stats b/regression_test/profiler/empty_e.stats new file mode 100644 index 0000000..bab3ec0 --- /dev/null +++ b/regression_test/profiler/empty_e.stats @@ -0,0 +1,5 @@ +################################################## +## TTCN-3 profiler and code coverage statistics ## +################################################## + + diff --git a/regression_test/profiler/prof1.cfg b/regression_test/profiler/prof1.cfg new file mode 100644 index 0000000..9e2e50f --- /dev/null +++ b/regression_test/profiler/prof1.cfg @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2000-2015 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################### +[EXECUTE] +prof1.tc1 +prof2.tc2 +prof3.control +[PROFILER] +DisableProfiler := true +DisableCoverage := false +DatabaseFile := "data.json" +AggregateData := false +StatisticsFile := "prof1.stats" +DisableStatistics := false +StatisticsFilter := NumberOfLines & AllRawData & UnusedData +[LOGGING] +SourceInfoFormat := Stack +LogEntityName := Yes diff --git a/regression_test/profiler/prof1.ttcn b/regression_test/profiler/prof1.ttcn new file mode 100644 index 0000000..d37cc3e --- /dev/null +++ b/regression_test/profiler/prof1.ttcn @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (c) 2000-2015 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ + +module prof1 { + +type component C {} + +const integer c1 := 7; + +function f1(inout integer x) runs on C { + x := x + c1; +} + +testcase tc1() runs on C { + var integer x := 6; + f1(x); + log(x); + x := x + 1; +} + +control { + execute(tc1()); +} + +} diff --git a/regression_test/profiler/prof1_e.stats b/regression_test/profiler/prof1_e.stats new file mode 100644 index 0000000..ef1d5b0 --- /dev/null +++ b/regression_test/profiler/prof1_e.stats @@ -0,0 +1,84 @@ +################################################## +######### TTCN-3 code coverage statistics ######## +################################################## + + +-------------------------------------- +- Number of code lines and functions - +-------------------------------------- +prof1.ttcn: 10 lines, 3 functions +prof2.ttcn: 13 lines, 4 functions +prof3.ttcn: 13 lines, 3 functions +-------------------------------------- +Total: 36 lines, 10 functions + +------------------------------------------------- +-------- Code line data (execution count) ------- +------------------------------------------------- +3 prof1.ttcn:13 +3 prof1.ttcn:15 [f1] +3 prof1.ttcn:16 +1 prof1.ttcn:19 [tc1] +1 prof1.ttcn:20 +1 prof1.ttcn:21 +1 prof1.ttcn:22 +1 prof1.ttcn:23 +------------------------------------------------- +2 prof2.ttcn:13 [f2] +2 prof2.ttcn:14 +2 prof2.ttcn:18 +1 prof2.ttcn:22 [t1] +1 prof2.ttcn:24 [tc2] +1 prof2.ttcn:25 +1 prof2.ttcn:26 +1 prof2.ttcn:27 +1 prof2.ttcn:28 +1 prof2.ttcn:29 +------------------------------------------------- +1 prof3.ttcn:14 [f3] +1 prof3.ttcn:16 +1 prof3.ttcn:17 +1 prof3.ttcn:18 +1 prof3.ttcn:21 [tc3] +1 prof3.ttcn:23 +1 prof3.ttcn:24 +1 prof3.ttcn:25 +1 prof3.ttcn:26 +1 prof3.ttcn:27 +1 prof3.ttcn:28 +1 prof3.ttcn:31 [control] +1 prof3.ttcn:32 + +------------------------------------------------ +-------- Function data (execution count) ------- +------------------------------------------------ +3 prof1.ttcn:15 [f1] +1 prof1.ttcn:19 [tc1] +------------------------------------------------ +2 prof2.ttcn:13 [f2] +1 prof2.ttcn:22 [t1] +1 prof2.ttcn:24 [tc2] +------------------------------------------------ +1 prof3.ttcn:14 [f3] +1 prof3.ttcn:21 [tc3] +1 prof3.ttcn:31 [control] + +--------------------- +- Unused code lines - +--------------------- +prof1.ttcn:26 [control] +prof1.ttcn:27 +--------------------- +prof2.ttcn:15 +prof2.ttcn:32 [control] +prof2.ttcn:33 +--------------------- + +-------------------- +- Unused functions - +-------------------- +prof1.ttcn:26 [control] +-------------------- +prof2.ttcn:32 [control] +-------------------- + diff --git a/regression_test/profiler/prof2.cfg b/regression_test/profiler/prof2.cfg new file mode 100644 index 0000000..f0c7c0c --- /dev/null +++ b/regression_test/profiler/prof2.cfg @@ -0,0 +1,20 @@ +############################################################################### +# Copyright (c) 2000-2015 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################### +[EXECUTE] +prof1.tc1 +prof2.tc2 +prof3.control +[PROFILER] +DisableProfiler := false +DisableCoverage := true +DatabaseFile := "data.json" +AggregateData := true +DisableStatistics := true +[LOGGING] +SourceInfoFormat := Stack +LogEntityName := Yes diff --git a/regression_test/profiler/prof2.ttcn b/regression_test/profiler/prof2.ttcn new file mode 100644 index 0000000..78f77e8 --- /dev/null +++ b/regression_test/profiler/prof2.ttcn @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) 2000-2015 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ + +module prof2 { + +import from prof1 all; + +function f2(inout integer x) runs on C { + if (x < 0) { + x := x + 1; + } + else { + x := x - 1; + } +} + +template integer t1(in integer x) := (0..x); + +testcase tc2() runs on C { + var integer x := 10; + f1(x); + f2(x); + log(x); + var template integer tx := t1(x); +} + +control { + execute(tc2()); +} + +} diff --git a/regression_test/profiler/prof3.cfg b/regression_test/profiler/prof3.cfg new file mode 100644 index 0000000..20bab99 --- /dev/null +++ b/regression_test/profiler/prof3.cfg @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2000-2015 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################### +[EXECUTE] +prof1.tc1 +prof2.tc2 +prof3.control +[PROFILER] +DisableProfiler := false +DisableCoverage := false +DatabaseFile := "data.json" +AggregateData := false +StatisticsFile := "empty.stats" +DisableStatistics := false +StatisticsFilter := 0 +[LOGGING] +SourceInfoFormat := Stack +LogEntityName := Yes diff --git a/regression_test/profiler/prof3.ttcn b/regression_test/profiler/prof3.ttcn new file mode 100644 index 0000000..00fb287 --- /dev/null +++ b/regression_test/profiler/prof3.ttcn @@ -0,0 +1,35 @@ +/****************************************************************************** + * Copyright (c) 2000-2015 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ + +module prof3 { + +import from prof1 all; +import from prof2 all; + +function f3() runs on C +{ + var integer x := 3; + f1(x); + log(x); +} + +testcase tc3() runs on C +{ + var C otha := C.create("otha"); + otha.start(f3()); + var integer y := 7; + f2(y); + log(y); + otha.done; +} + +control { + execute(tc3()); +} + +} diff --git a/regression_test/profiler/prof_files.txt b/regression_test/profiler/prof_files.txt new file mode 100644 index 0000000..5609b9b --- /dev/null +++ b/regression_test/profiler/prof_files.txt @@ -0,0 +1,3 @@ +prof1.ttcn +prof2.ttcn +prof3.ttcn diff --git a/regression_test/recofOper/Makefile b/regression_test/recofOper/Makefile index e4b9c7a..f4afb60 100644 --- a/regression_test/recofOper/Makefile +++ b/regression_test/recofOper/Makefile @@ -13,7 +13,7 @@ include $(TOPDIR)/Makefile.regression TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) -TTCN3_MODULES = TrecofOper.ttcn +TTCN3_MODULES = TrecofOper.ttcn TrecofCompat.ttcn ifdef RT2 TTCN3_MODULES += TrecofParamRef.ttcn ASN1_MODULES = BerType.asn diff --git a/regression_test/recofOper/TrecofCompat.ttcn b/regression_test/recofOper/TrecofCompat.ttcn new file mode 100644 index 0000000..a3e1a81 --- /dev/null +++ b/regression_test/recofOper/TrecofCompat.ttcn @@ -0,0 +1,262 @@ +/****************************************************************************** + * Copyright (c) 2000-2015 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ + +// This module tests the compatibility between record-ofs and set-ofs of base +// element types +module TrecofCompat { + +type component CT_Empty {} + +// record of +type record of integer RoI1; +type record of integer RoI2; + +type record of boolean RoB1; +type record of boolean RoB2; + +type record of float RoF1; +type record of float RoF2; + +type record of bitstring RoBS1; +type record of bitstring RoBS2; + +type record of hexstring RoHS1; +type record of hexstring RoHS2; + +type record of octetstring RoOS1; +type record of octetstring RoOS2; + +type record of charstring RoCS1; +type record of charstring RoCS2; + +type record of universal charstring RoUS1; +type record of universal charstring RoUS2; + +type record of integer RoI1_opt with { extension "optimize:memalloc" }; +type record of integer RoI2_opt with { extension "optimize:memalloc" }; + +testcase tc_record_of_compat() runs on CT_Empty +{ + var RoI1 v_roi1 := { 1, 2 }; + var RoI2 v_roi2 := v_roi1; + if (not match( { 1, 2 }, v_roi2) or v_roi1 != v_roi2) { setverdict(fail, "record of integer incompatibility"); } + + var RoB1 v_rob1 := { true, false }; + var RoB2 v_rob2 := v_rob1; + if (not match( { true, false }, v_rob2) or v_rob1 != v_rob2) { setverdict(fail, "record of boolean incompatibility"); } + + var RoF1 v_rof1 := { 0.4, 9.6 }; + var RoF2 v_rof2 := v_rof1; + if (not match( { 0.4, 9.6 }, v_rof2) or v_rof1 != v_rof2) { setverdict(fail, "record of float incompatibility"); } + + var RoBS1 v_robs1 := { '1101'B, '10101'B }; + var RoBS2 v_robs2 := v_robs1; + if (not match( { '1101'B, '10101'B }, v_robs2) or v_robs1 != v_robs2) { setverdict(fail, "record of bitstring incompatibility"); } + + var RoHS1 v_rohs1 := { '1AF74'H, 'D000D'H }; + var RoHS2 v_rohs2 := v_rohs1; + if (not match( { '1AF74'H, 'D000D'H }, v_rohs2) or v_rohs1 != v_rohs2) { setverdict(fail, "record of hexstring incompatibility"); } + + var RoOS1 v_roos1 := { 'DEAD'O, '1BC5'O }; + var RoOS2 v_roos2 := v_roos1; + if (not match( { 'DEAD'O, '1BC5'O }, v_roos2) or v_roos1 != v_roos2) { setverdict(fail, "record of octetstring incompatibility"); } + + var RoCS1 v_rocs1 := { "red", "blue" }; + var RoCS2 v_rocs2 := v_rocs1; + if (not match( { "red", "blue" }, v_rocs2) or v_rocs1 != v_rocs2) { setverdict(fail, "record of charstring incompatibility"); } + + var RoUS1 v_rous1 := { "yellow", "green" }; + var RoUS2 v_rous2 := v_rous1; + if (not match( { "yellow", "green" }, v_rous2) or v_rous1 != v_rous2) { setverdict(fail, "record of universal charstring incompatibility"); } + + var RoI1_opt v_roi1_opt := { 1, 2 }; + var RoI2_opt v_roi2_opt := v_roi1_opt; + if (not match( { 1, 2 }, v_roi2_opt) or v_roi1_opt != v_roi2_opt) { setverdict(fail, "record of integer (optimized) incompatibility"); } + + setverdict(pass); +} + +// record of template +testcase tc_record_of_template_compat() runs on CT_Empty +{ + var template RoI1 vt_roi1 := { 1, 2 }; + var template RoI2 vt_roi2 := vt_roi1; + if (not match( { 1, 2 }, vt_roi2) or not match(valueof(vt_roi1), vt_roi2)) + { setverdict(fail, "record of integer template incompatibility"); } + + var template RoB1 vt_rob1 := { true, false }; + var template RoB2 vt_rob2 := vt_rob1; + if (not match( { true, false }, vt_rob2) or not match(valueof(vt_rob1), vt_rob2)) + { setverdict(fail, "record of boolean template incompatibility"); } + + var template RoF1 vt_rof1 := { 0.4, 9.6 }; + var template RoF2 vt_rof2 := vt_rof1; + if (not match( { 0.4, 9.6 }, vt_rof2) or not match(valueof(vt_rof1), vt_rof2)) + { setverdict(fail, "record of float template incompatibility"); } + + var template RoBS1 vt_robs1 := { '1101'B, '10101'B }; + var template RoBS2 vt_robs2 := vt_robs1; + if (not match( { '1101'B, '10101'B }, vt_robs2) or not match(valueof(vt_robs1), vt_robs2)) + { setverdict(fail, "record of bitstring template incompatibility"); } + + var template RoHS1 vt_rohs1 := { '1AF74'H, 'D000D'H }; + var template RoHS2 vt_rohs2 := vt_rohs1; + if (not match( { '1AF74'H, 'D000D'H }, vt_rohs2) or not match(valueof(vt_rohs1), vt_rohs2)) + { setverdict(fail, "record of hexstring template incompatibility"); } + + var template RoOS1 vt_roos1 := { 'DEAD'O, '1BC5'O }; + var template RoOS2 vt_roos2 := vt_roos1; + if (not match( { 'DEAD'O, '1BC5'O }, vt_roos2) or not match(valueof(vt_roos1), vt_roos2)) + { setverdict(fail, "record of octetstring template incompatibility"); } + + var template RoCS1 vt_rocs1 := { "red", "blue" }; + var template RoCS2 vt_rocs2 := vt_rocs1; + if (not match( { "red", "blue" }, vt_rocs2) or not match(valueof(vt_rocs1), vt_rocs2)) + { setverdict(fail, "record of charstring template incompatibility"); } + + var template RoUS1 vt_rous1 := { "yellow", "green" }; + var template RoUS2 vt_rous2 := vt_rous1; + if (not match( { "yellow", "green" }, vt_rous2) or not match(valueof(vt_rous1), vt_rous2)) + { setverdict(fail, "record of universal charstring template incompatibility"); } + + var template RoI1_opt vt_roi1_opt := { 1, 2 }; + var template RoI2_opt vt_roi2_opt := vt_roi1_opt; + if (not match( { 1, 2 }, vt_roi2_opt) or not match(valueof(vt_roi1_opt), vt_roi2_opt)) + { setverdict(fail, "record of integer template (optimized) incompatibility"); } + + setverdict(pass); +} + +// set of +type set of integer SoI1; +type set of integer SoI2; + +type set of boolean SoB1; +type set of boolean SoB2; + +type set of float SoF1; +type set of float SoF2; + +type set of bitstring SoBS1; +type set of bitstring SoBS2; + +type set of hexstring SoHS1; +type set of hexstring SoHS2; + +type set of octetstring SoOS1; +type set of octetstring SoOS2; + +type set of charstring SoCS1; +type set of charstring SoCS2; + +type set of universal charstring SoUS1; +type set of universal charstring SoUS2; + +type set of integer SoI1_opt with { extension "optimize:memalloc" }; +type set of integer SoI2_opt with { extension "optimize:memalloc" }; + +testcase tc_set_of_compat() runs on CT_Empty +{ + var SoI1 v_soi1 := { 1, 2 }; + var SoI2 v_soi2 := v_soi1; + if (not match( { 1, 2 }, v_soi2) or v_soi1 != v_soi2) { setverdict(fail, "set of integer incompatibility"); } + + var SoB1 v_sob1 := { true, false }; + var SoB2 v_sob2 := v_sob1; + if (not match( { true, false }, v_sob2) or v_sob1 != v_sob2) { setverdict(fail, "set of boolean incompatibility"); } + + var SoF1 v_sof1 := { 0.4, 9.6 }; + var SoF2 v_sof2 := v_sof1; + if (not match( { 0.4, 9.6 }, v_sof2) or v_sof1 != v_sof2) { setverdict(fail, "set of float incompatibility"); } + + var SoBS1 v_sobs1 := { '1101'B, '10101'B }; + var SoBS2 v_sobs2 := v_sobs1; + if (not match( { '1101'B, '10101'B }, v_sobs2) or v_sobs1 != v_sobs2) { setverdict(fail, "set of bitstring incompatibility"); } + + var SoHS1 v_sohs1 := { '1AF74'H, 'D000D'H }; + var SoHS2 v_sohs2 := v_sohs1; + if (not match( { '1AF74'H, 'D000D'H }, v_sohs2) or v_sohs1 != v_sohs2) { setverdict(fail, "set of hexstring incompatibility"); } + + var SoOS1 v_soos1 := { 'DEAD'O, '1BC5'O }; + var SoOS2 v_soos2 := v_soos1; + if (not match( { 'DEAD'O, '1BC5'O }, v_soos2) or v_soos1 != v_soos2) { setverdict(fail, "set of octetstring incompatibility"); } + + var SoCS1 v_socs1 := { "red", "blue" }; + var SoCS2 v_socs2 := v_socs1; + if (not match( { "red", "blue" }, v_socs2) or v_socs1 != v_socs2) { setverdict(fail, "set of charstring incompatibility"); } + + var SoUS1 v_sous1 := { "yellow", "green" }; + var SoUS2 v_sous2 := v_sous1; + if (not match( { "yellow", "green" }, v_sous2) or v_sous1 != v_sous2) { setverdict(fail, "set of universal charstring incompatibility"); } + + var SoI1_opt v_soi1_opt := { 1, 2 }; + var SoI2_opt v_soi2_opt := v_soi1_opt; + if (not match( { 1, 2 }, v_soi2_opt) or v_soi1_opt != v_soi2_opt) { setverdict(fail, "set of integer (optimized) incompatibility"); } + + setverdict(pass); +} + +// set of template +testcase tc_set_of_template_compat() runs on CT_Empty +{ + var template SoI1 vt_soi1 := { 1, 2 }; + var template SoI2 vt_soi2 := vt_soi1; + if (not match( { 1, 2 }, vt_soi2) or not match(valueof(vt_soi1), vt_soi2)) + { setverdict(fail, "set of integer template incompatibility"); } + + var template SoB1 vt_sob1 := { true, false }; + var template SoB2 vt_sob2 := vt_sob1; + if (not match( { true, false }, vt_sob2) or not match(valueof(vt_sob1), vt_sob2)) + { setverdict(fail, "set of boolean template incompatibility"); } + + var template SoF1 vt_sof1 := { 0.4, 9.6 }; + var template SoF2 vt_sof2 := vt_sof1; + if (not match( { 0.4, 9.6 }, vt_sof2) or not match(valueof(vt_sof1), vt_sof2)) + { setverdict(fail, "set of float template incompatibility"); } + + var template SoBS1 vt_sobs1 := { '1101'B, '10101'B }; + var template SoBS2 vt_sobs2 := vt_sobs1; + if (not match( { '1101'B, '10101'B }, vt_sobs2) or not match(valueof(vt_sobs1), vt_sobs2)) + { setverdict(fail, "set of bitstring template incompatibility"); } + + var template SoHS1 vt_sohs1 := { '1AF74'H, 'D000D'H }; + var template SoHS2 vt_sohs2 := vt_sohs1; + if (not match( { '1AF74'H, 'D000D'H }, vt_sohs2) or not match(valueof(vt_sohs1), vt_sohs2)) + { setverdict(fail, "set of hexstring template incompatibility"); } + + var template SoOS1 vt_soos1 := { 'DEAD'O, '1BC5'O }; + var template SoOS2 vt_soos2 := vt_soos1; + if (not match( { 'DEAD'O, '1BC5'O }, vt_soos2) or not match(valueof(vt_soos1), vt_soos2)) + { setverdict(fail, "set of octetstring template incompatibility"); } + + var template SoCS1 vt_socs1 := { "red", "blue" }; + var template SoCS2 vt_socs2 := vt_socs1; + if (not match( { "red", "blue" }, vt_socs2) or not match(valueof(vt_socs1), vt_socs2)) + { setverdict(fail, "set of charstring template incompatibility"); } + + var template SoUS1 vt_sous1 := { "yellow", "green" }; + var template SoUS2 vt_sous2 := vt_sous1; + if (not match( { "yellow", "green" }, vt_sous2) or not match(valueof(vt_sous1), vt_sous2)) + { setverdict(fail, "set of universal charstring template incompatibility"); } + + var template SoI1_opt vt_soi1_opt := { 1, 2 }; + var template SoI2_opt vt_soi2_opt := vt_soi1_opt; + if (not match( { 1, 2 }, vt_soi2_opt) or not match(valueof(vt_soi1_opt), vt_soi2_opt)) + { setverdict(fail, "set of integer template (optimized) incompatibility"); } + + setverdict(pass); +} + +control { + execute(tc_record_of_template_compat()); + execute(tc_record_of_compat()); + execute(tc_set_of_template_compat()); + execute(tc_set_of_compat()); +} + +} diff --git a/regression_test/recofOper/TrecofParamRef.ttcn b/regression_test/recofOper/TrecofParamRef.ttcn index 09f4c5a..0485ee9 100644 --- a/regression_test/recofOper/TrecofParamRef.ttcn +++ b/regression_test/recofOper/TrecofParamRef.ttcn @@ -660,6 +660,32 @@ testcase tc_param_ref_emb_lazy() runs on CT_Empty else { setverdict(fail, "@4 got: ", v_roi, ", expected: { 10, , , , , 20 }"); } } +// 19. The function call is interrupted by a DTE, the reference to the element should be cleaned up (HT47424) +function f_dte(in RoI p_roi, inout integer p_val) runs on CT_Empty +{ + var integer bad_index := -1; + if (p_val < p_roi[bad_index]) { + setverdict(fail, "expected DTE in if clause"); + } +} + +testcase tc_param_ref_dte() runs on CT_Empty +{ + var RoI v_roi := { 0, 1, 2, 3 }; + @try { + f_dte(v_roi, v_roi[2]); + setverdict(fail, "expected DTE in function call"); + } + @catch (dummy) {} + v_roi := { }; + var RoI v_copy := v_roi; + var charstring log_exp := "{ }"; + if (log2str(v_roi) == log_exp) { setverdict(pass); } + else { setverdict(fail, "@1 got: ", v_roi, ", expected: ", log_exp); } + if (log2str(v_copy) == log_exp) { setverdict(pass); } + else { setverdict(fail, "@2 got: ", v_copy, ", expected: ", log_exp); } +} + control { execute(tc_param_ref_assign()); execute(tc_param_ref_concat()); @@ -684,6 +710,8 @@ control { execute(tc_param_ref_emb_recof_opt()); execute(tc_param_ref_emb_lazy()); + + execute(tc_param_ref_dte()); } } // end of module diff --git a/regression_test/recofOper/config.cfg b/regression_test/recofOper/config.cfg index eb0d2a5..0cbecad 100644 --- a/regression_test/recofOper/config.cfg +++ b/regression_test/recofOper/config.cfg @@ -12,3 +12,4 @@ FileMask := LOG_ALL ConsoleMask := TTCN_WARNING | TTCN_ERROR | TTCN_TESTCASE | TTCN_STATISTICS [EXECUTE] TrecofOper +TrecofCompat diff --git a/regression_test/recofOper/config_rt2.cfg b/regression_test/recofOper/config_rt2.cfg index 8cd9abc..0c8ed98 100644 --- a/regression_test/recofOper/config_rt2.cfg +++ b/regression_test/recofOper/config_rt2.cfg @@ -12,4 +12,5 @@ FileMask := LOG_ALL ConsoleMask := TTCN_WARNING | TTCN_ERROR | TTCN_TESTCASE | TTCN_STATISTICS [EXECUTE] TrecofOper +TrecofCompat TrecofParamRef diff --git a/regression_test/testcase_defparam/Makefile b/regression_test/testcase_defparam/Makefile index 49f7122..c874dd8 100644 --- a/regression_test/testcase_defparam/Makefile +++ b/regression_test/testcase_defparam/Makefile @@ -32,7 +32,7 @@ CXXDEPFLAGS = -MM CXXFLAGS += -g # Flags for the linker: -LDFLAGS += -g -rdynamic +#LDFLAGS += -g -rdynamic # Flags for the TTCN-3 and ASN.1 compiler: diff --git a/regression_test/ucharstrOper/cstr_content.ttcn b/regression_test/ucharstrOper/cstr_content.ttcn index f93552c..fdc797a 100644 --- a/regression_test/ucharstrOper/cstr_content.ttcn +++ b/regression_test/ucharstrOper/cstr_content.ttcn @@ -367,6 +367,41 @@ testcase tc_unichar_utf8_template() runs on empty { else { setverdict(fail, valueof(t_u1ch), "!=", valueof(t_u1)); } } +// Fixed indexing errors when the string only contained ASCII characters (HT70680) +function f_changeUnichar(in universal charstring pl_char) +return universal charstring +{ + log("lengthof(pl_char): ", lengthof(pl_char)) + log("pl_char: ", pl_char); // garbage here + return pl_char; +} + +function f_modifyUnichar(in universal charstring pl_str) +return universal charstring +{ + var integer vl_size := lengthof(pl_str); + var universal charstring vl_tmp; + + for (var integer vl_i := 0; vl_i < vl_size; vl_i := vl_i + 1) + { + log("pl_str[vl_i]: ", pl_str[vl_i]) + vl_tmp := f_changeUnichar(pl_str[vl_i]); + log("vl_tmp: ", vl_tmp); // garbage here + pl_str[vl_i] := vl_tmp; // segmentation fault here + } + + return pl_str; +} + +testcase tc_indexing_HT70680() runs on empty +{ + // must contain only ASCII characters + var universal charstring v_str := "alma123"; + var universal charstring v_res := f_modifyUnichar(v_str); + if (v_str == v_res) { setverdict(pass); } + else { setverdict(fail, "got: ", v_res, " expected: ", v_str); } +} + control { execute(tc_charstring_content()); @@ -378,6 +413,7 @@ control { //execute(tc_unichar_utf8_mp1()); //execute(tc_unichar_utf8_mp2()); execute(tc_unichar_utf8_template()); + execute(tc_indexing_HT70680()); } } diff --git a/titan_executor_api/doc/Titan_Executor_API_User_Guide.doc b/titan_executor_api/doc/Titan_Executor_API_User_Guide.doc index 62c5615b969dfc39c458f69bc1d57249f37923e2..c3e04d620d7fd6852306e16aeb1d82d124435320 100755 GIT binary patch delta 2626 zcmb8xdr(x@9l-J5*<}|LmUZP}(V&0`id_Zdu?rGe3<6n#D{5jMQkWuIW6(&nVn-3Q z$#l|mlAKAJ_K!|ynwUgEcDZf;NJ}({!8o?TKax~yhE_0YnvR;-PVHo-)9=}JGwExl zxig===W)-u=lssSXYYYq_5-)<;X7<9qO)z4wrYodCLvRAvmI8ab(+25p2j^QHW9g- zvpN2sb3WJI+$%Cd!i&lAM9oQ1j}0b<2!5?alSg`q8vXXZ^ay zhSvLa$m2~Y_m&pxe$QgHlHW9a!gJ-THn_v8N`G5fDszYO{8g!$8*|(2?zJJEH}A>lIXth^VR{;}vU0Ad z?0Dl-6piCOoP+6PM6b!q(xJTBRwys5vg7^EcZ;mWA%t-Oy?RYPm*#V6epqdEQIv{Y zLoNWqp#$wQt>&M5QU!MTLtzu@5n8GC_&twhYLMq&t0U!LRnrRoQ*2)`-263HtepW2h z&bleH5GnD6F$?juH@nl+{*Oib;@U4Q6U%IJ)k*zd`_F}@lv~usgV#$?q5-r#ORlS2 z6Gs!Xcz6n!&Jrv`B?4A%@gG!HJZdIFCK_huW|mdjQ&yxyrL*DEqv>1qk%g(&Wa(Vx zsiL|X%drVvmZ$8xniemr(VmJl*JdiV;QM$=msHGggh@rLrV6LBvl-~t$_3Gw?X7$~ zyNfE*U=Tw%hGE2-Wc%hgY`zq0Y5gv{HC($tA(nY+5j**4_fqe-*b^VdBk(yGI%*)i z0#CSDyxR}18DKa5z0`F8gyVAy74?-z>o13PT?9p!z=<*ZUSVzx?@~D9U875vd}8276R{p@(*qQ=4@9%8A5{4tVq?$c2fO&@w_?D&)8vGij{)+cFe za{QL(zxR3V;?kKbX+IYx2Dd*hmQLQ4V?Hio6(&IDFc+Ec9xmcz#L|=JUCtBdyZ9`! zcHVF*b;j!b^b^&P^JqIoXI1Qr>8u&!7sm;v`7TpFC+B5Cg7PK-n2`6SQQnXfXySuv zLds=K&g!E#{i*-jm-X4rPDg(IGGB3hov+yI3;0)g%U1b(-n#OVdT)uZw4}5ou*$#6 MUuW(8`{TBM0>u_0zyJUM delta 2575 zcmb8xeNdFg9l-J5-Wwns=HM`bA_t-%df|BS4lq_g8BBr|t#3mhh6ss+wmMKL+A3%= zaS|tK>SmJu(@C4RYETb+rvIo+#zbiinP3tfql^=QSelnct?i5*|7gE^=Q(N8&NR=> z=l0p%XZP9t?cQ@w&n~#gwl3yEY z)a#rD71L?prQvSU0BQf70VH*Z+)u|vyC~%7nkABaC*MPU={DW({h=z-iLPntoX&G? zm}Ks4jx}8jV75Nys$_DvU2m%*>v-Jr@y=CC3)eO1<@dZ}H>uYXa<%?+;}h-M^$L&Q zQQ|Ku)1#?#RW;wK+UK3FFMEc*PaDhU9aYx9(%O}$IX_cmvc1iWX39o#)}DK9aSI!h zMVjyk*5j9W0dJufhj18wz-f$P4C6@BCuclj|6SGzos+dMlJ;e_I89H7taRUm%8WH0 zr04^Dj0-TG9Mvmw(sg}KhE<=_r!r&x=1dk@i6;@pB@m5VF3siA+& zi3ji?>ahZ*n;)SQKf`Y9f$91w^x_Z>;|R>{`tXTvnmu>cXPjNdpD}^IAn_h1jTEH9 ztNUly`3V3KHQ$mJjc-~cH)Z4J4Fj?|US-?cTH~oSrMe(*jwjl})XL;&X-i&JB!CC< z$|LE0Ss5;wXC}WtKiA67|3qbulZg$=49Lp>et<<-Z)FyYt8P=2hWoJ)vFb|BAH+kb z!!j&KJsR*Z8qtLHcoe_DPVB-PcoWBP949bIH z%_=0tR>iEs3;xU&Q~N(w?C!PSSR>ZhYpu@47uP|pcYv+9C&W#`GDSB7RqVz?vpw6lfk z)=0IlY^u{1j+0;EjH=iRz5i$H2FQXTSaSkK648{GE zU>?mul%WC}(2kez8@z%);ys+l1zf^aOdy{96hMt#8l;w!E@%wlA4qVp8&QmMEWmoS zVKZLDOZYWT;xxX(b)*rP5)&Zn;MQT~X_>^5!yE_Axqhbo;kd)mQhlxcUTy2BcSiDh zZO7^ECKr!v^kNVnV+`4GJP)w~E3pSp;t0aHh!I@IC?=4~`gpMri?9sK(S)5ijuS{o z;75(_1gVf7PQvKJ6^tT@;kpq*1s+2y%!GOo9e#Ibi50&sN3H(m9KO%kW8?q!SR>tA z-JNIZvciOsAe)^hS7DAL7|j=1J6H6kcL(&mQ`2?bsUCgyRKRkao~pEOaIFekU4z<| zXl*Fj`}c~1$K4WdO*u1Sb9<#mR>@K+ly%bZ>iahRTSvyx58Ns>@(1p#YTw%2;;Y-z z+1$~wU3S-8&%7!`E6lXbVJuy31nriK;Lmtiv27 z%$s5^7(HkUMKz*qVM$T;7!`uF9I1nqVET{g3TujTLjAKgsEaCUwiGoADR(nPv5+1@ zN{0VKs{LmL9puEfQq%>^d1)KA8Ra}IKpC5=D7B|=6KC6!E!QS%CWA1YjWv@&nC5L} zdPKB1!VMNo6zqrdTq(Qx7>0ekvue&fJr;?#s{Qr=Ie&_-Tf`BR~BlZ_OAf=!(q_ zTsw3;GgHBKkhQUyrLmdK&^2MJmxTej{4?Cirf z1}e4E=8U-VD$#Lc$GS5cl;_cw%spifk!cgBF{UcPqGV0HM3n#whhRZk*(ST@sI*%A&aLw^cg)sxUp>XS2f;n z?P^+Cxb3%4s}%0R14dcLfWF5Yqk{k~&{q?|ikL!OXHE$wl8SfWE|3|@pd84I_u(Nl zK{I>Og!qLfz@o~H2 zc2N`)pqF4su~mXjsLZ0QB{z+CRieCHS!4`pp}&rCFde}(57JSjY#tyuBv>R+y(CZ! z+hh;#sJ<^POJYXiB@Pk{+s1$im9*pq8^qHpBzz=vMnFPG!e%MO3~|-qSs0blY)h0$ z2ub*+!ZaS+q=}X#QA7l(*)Zq(63wtg5>FD#U?8y!hn4-7xDsU&TN2mpu!G08YNFXB zyd<=7Ktj8Z$F^yrb@w4Fj4+8RTbiNN^WHK3T3EtoX5wIH8 zz*>lebr1#XVFRSY8Mq3Ca1E}*4Jd+}Pz*{k_-h7z7zqYoD1+W)gp4tmfGL>41egdO zum~1|CwPH3_<%3?LFbqH=l6^6UoFl$la*F{h@U;P2e~c9Tdp1|KC|wxSxQMcNQ0V= zpM0WbA~l{#ca&s2948pbsRY>uBva#El__7KP?leJ?0Xrrk$%LVjftJE$$WGi$lP~S zWpby>FgAMH!*S@?xm;Q75b|X0TWJ*%NfJe21ph$(nlv+H z@<^VuQz5NFB1obqjGQ1+g6U&09Z};4Oc*Rda0JuGVLAyE36d~Cmypkq5lo*@NOMTg zjzKb9glrJhp{UEqUx8f6gM27}&+rALWGPA-WI+z(K>^q>5L{p~c!C#rgAe$EANb3n z#RHHDgakMOC*T6`AQQ6SB4ooQ$blC43}2uP+MxqFp$i=3aG-*z;080n9lq3mseM#m zTYBwE{UegEFC9g)=j+ec)<5EpJztCLd49H5kffhVJ(hapSMtXo7|^uj;JbLbfd;xk z)Vyk8@9EcB(0P~_(}zg(bsT1>o(fYuU51upo;m6;3msJy?Q;-75?~TsL0}oV$@Yx1 zlPr@cI)LXlDT!vwU|&dZNnrUw<*_H@cTQp}j3tR<0FUk3L@Ns;DU2M6+9jT{+Xq@% z7`Rr9B7q}8>)l;oajM>EoMKXYVB1I>kbFdsZ1 z0#-vb#K6z66?VW*h=tv-2jXBa9DoE!f}@ZODR3Op;3SYe%7o$A6CKc%=iod7nQcIJ zbsy}96gUnSAsh0c07wW*;6BvCM`(mL=!7olfv@llD1@n}<8yPvyM}kK-@SNO_4q+U zdB>gN>*XEg9anQR&ksw>Jd$~yOy+-nJ@D(^U-w>ra6R^VEQKDoKu(<5IA6^{K{<$o zPKEz%=IV&UC`)paNbm?OUtE$Fj2E1`@I(CPDGf?Y)%+pqiVF)-QzaAg+d^a14$^ zDx|>)xCi&)9lVEn_y7Y3qCbNU=)wrl1AVXnORxfKu!T_!+fR|>f?O1=hYgSd#~~Xo zK@MDodiVfhifA*C1S2p86POPRU^#?9D1^ZQI0y-F1QH<$3gHh${GHxG<}S3nZ+ZW? z0^he=-sfJ(J)L_2BS=B;U6Jz7CH@o~Xwc8m@yNB%cvt*M$*KgAtEAC_vuVNapl^EL zI1Ld_Flmhbv-V9w*QKNc3n1s>_LBwQD(H}MkOBgJ; zSnI!>@vc*q$d7~?LwYc2Xwt}}L4}P+nkTh?e>w8c1;#mO1WxiVsYokOB04O^RDDWC zhn}*8#w@-%EJnd!nKf0D(epnygAykTo(yY1*#4xgQ~r7R{in?6UvR*I#)x^cOjlw$ zIzT{}HWRlbmDM$jv0lm>PKlAlN}z>Fmtn(T&;o5BU8tS$95vYbFMIjl7I6FGiK4jr z_x3gNn1-fXFC}vj3U}k2B8k}Us4#!;Tj8bR=hxA8M zu?*Uv9Xg;B$jsd^91G9^vY-*54ywSo8ql9<^l`n$xdo-p7@81I4DJ$4x-fj2T&8QXkcMxs)BdnfjfY z`kOQhOTcY6>ctP^tGH68bio8`Y9;@6Uetn3pGRwQCZ99f?0J2wo@ z6mER*2Ne1Z8D`R=9xNkr8*L~@o)T?F(5MTdQq8#6LD8c4LjB>CbTf_&l;~LUqv*vK znX1rCCS&+Xo04cISH~>TNB2u4#@NNlzHM>Tem8N?@LuW_uCK{l+4yCCSqgwMb zjQg?XJ0l#`go88ob|MOyMeC@CxD@}5T%>rxn?(#r_^6B93^+kBvE&^q4n?DkI$cS|83{*DwEX} z*mLLpW^~Fu%V^eA?!n8a+*6NT{M{g}w}xX|GuS)-PTk;FgS{&4Ba+&m_d2%QF#&f% z++M#~u70O2M|)#fVZ(-mJ1yNq9DL$43Tk}Yw!|)6s<36<#oG-hdZ+!)c}#Zkhcy?AS`He{Pq&Rfr(7^B-df{>V$9eFL!K#Z zNJ|Rk_1NuGjT_J{*?qRs%cJ3L@PW%-YnLarP3=s5>T~wkmlr`U>T~{B?J9e}EpUXj zenIJ@13g-c&il7@Yg{V-b1!c^u=T$9s+Z+4Cru5s)H^bcdvEN%H(R$gAuW4tOkfbV zAv4e>=uOSJ%w35u-!y7wj$SMKwC3Bo-x^|SujPMyV#|AMkj7qk=lR~<8*_)&oV)xi zzqhr;Fh#E*KT5pDm-9sb;1K6Wb_Xptc!rjlOkDIw*uKQP37*_6j=|Rq$11}{y|o{9 zI(t;+4~a=s6j7e&n6iF@B4=Ty(Y>|XYma9XwKV;5wz~V|?dlEHH?^GfrKCIb?^`(e zxHO~&4f9ZqoY*=>^JM9Qx6zxT9bzj3&2p-4Ih-$3d-F24%VfvZ<_jEs)!RuD?VhF^ zJha}vp8D2zv0YTvk}Pkxr`fNU#;kXHQIZ?t+EH@w=C+)bIS=jBXKl&sJm9qc`i6s;A!+#vHxj&|{%hX|B1~kt5sEoYbTGs>4O;D5LeZFlJG}j79RdTMjm4I)?7D z3D-+ed=r)zppvS|ZTq<)^2wH`bEMls-|vdIt+8CJmhXL8mkDoEwej1V5p}0%!K8u_ zZR{=8ubN{tK772?GV!cesCL;>Wn0yo1+(?a8vUm&i%L3pE@aNF=a))P1YcBbSjc(* zFoQ8IYIL}BrtaOVTX(mvOYaS{ur1j6s&}rQZDV)t>$lFI7IZdN9Pg}G&S?9PSh+N? zH(aB4?v1)s-rJtswKa9Rwz0A;k!=TF&#}-Ko1Yh6HgJJ)=e*qTn!)Rf!n&_TKJ+VE za^Ye7$7!jpj%T{^6QeUfb;sNE#9T>V$Eo4?xp?31ZmYg2{!!%Nl>G3F?(Rnh$7iV+ zZ2OQK9@xFDzE!;IW#L`tVP@wpAGqbrQ@{5-`}Jst@!e^>Nl~NQc0@e7eDv{|l*dQA z^7F=;-!Tk5bMfubecrwmk@qxfKi_okJ{&n@>BgrE?Tl+Kx!u<6QopcSc52dT%nmy=arzuc3=)E($?Nu8m;wxHVZ{ZG5=d50}q+!~9I*O>dd zRX26MIlHN<@p5;@m9kK+A#Iy>f0-n+YLuQy_WH9H_1khd!AtVumFLeCt8G$kQaqV| zZhpJ()P&PhI@@**%8nbEqw>D)e9$b}ipq%EnA*$_F*&A&&w^t#%QcueEd?H&recnH zW0SA-;fAspTLY6b&TSD3Il5>57@c+Y#DmBZt%{oDVvFRm3l8Heyfn{zEL$OaNydx& z^2nJLkG6J4Cw3g>tjd2n>gfEhjM|W>uM-njUXJ^AugGqA&Gt#==_{*@oz!9)(|6xo z`BPR>m1NCw^L+XG7ZEicpJb&o{8xUP_35i=QRLAP+Bt4j?NeSzw>~{r6}jtCL|jHq zPt3jgi`h3r<94?1yz0^9S)AmTr&uuFN}I(!D$?lhcK^|b%;>6pqd8ggnldutqFv%2 zmi}sQx?@Y-+L9>_jaTM=vvM#ku}xNgH(>Pd8`9_ZCM*#ncKDTleN~WN28ZY+O=jiRlTaJ{B2OkyT++Se)6Hk z3Nb(DulRT=-8gmdZ?lKZxvLk+akV(w$QW85Wm-NeSDec(c$#>@b7j@Yl6)0^4WFqA zSEh6x&YRPdp5|QoG=Os?tK-r7d9guy9Y;pZDBbdG{%whlQ8Nm!E=;&ym!I{*a6)9^ zirdXAlQzfkY<85zEHAw2X`M3XYU``$Go6TzX>@hUj1LPJDcF>LimA;rfAp}F<5Anh zJ~*M_N^|-Rm(qJ}H#4JOt?!JTSl4jM>2&wKGSRZ^R~+o6j*ch5OhoGvJ-TfTH;=Ldyl9JS*;!&?_g9$D-cIk@_($>{d3v)4RN>?vci z55~6Jxh9=Uj>&61$lkO0)FJCdBjzb@uluIIV@^$FdiVLXyOpWY50zB=`Rl(zOMB8xH$G%!<^$K->NF#)x_i{KOE&7SD$cmSar^;3R}het)d|rH; zTKnqTaxL#KR}|W7&U+nB8d9fOe>|zdZffJn3$-OfA~gnG>fPT_Rk`?^$1c!j7tF<3tT3};i7`t6r_$?r2vcU|1^>#OrK zYo6U`*PUe|`FQY$9w)a?3(hc7bvHu-&TMQ>ShwKRwL_1VHc7m_)u^m{V19b?>#w>Q zU-b2_|I(N-C8Xo3_{po!cI?hl@f$zm+As1UE2MH0A5VI?al5Reth&?r!ja8u{hpm{ z8z1s++2iI-vTmEQ6*=lLqikM(O|c5;7`aE*Zg`5@>GpB6LT76%nzc&JCi*~%WXKBF zE9XDOr;W1tY!#v1aHc3amc>YKUnJ3si%pz!@&6-NQaoT1JclEXipb+2^6ZB^=pm07$TJ1<+<-hAAou^tt!8p7 zncO!fH;KvJU~=1+-0K~W4I@{}_OudryFINz z8*wx2X~l7t*cdAyAsz`cfrmR#Iuf{(3Srp#8W@YMCZSWD`=IyWPl^kadX@XWnV+wX z;mpA`z+CtRlA#1zK?1=X0A^qdcHjv?5Dfd_0K`K9kl-uMJt$nwTr0A&Vf>Y;@xKMD zpX*M>_vNuc?EVGh4^lk$>l;}HsaV`VTx<|sc!Po5Tl0kN*s}yU4NBNMOBtr8$ceKT z)zhF8RS8*C)q@Z?jH7JtKpfr07(yTvjzA*Z zg;MB*F3`colV@^dCnT^766nPelrs4u$OwW(Fgdr?#UzlEU^rz%CSsQ`=wq*}z#Dtz z1OKo`f7zk$E3{-(i}g6?u$&8!30ZIpQM(IeKwfUKM57U_`>aJ83F{yVHuNb(N?e2M za07~Es)MF?BJx6m%x4Kgf8fTuka1XaZMKFKpxmI5EOy@md2x> zk{<{m?Ckx!hp^Lg`g;9e`p7EGMEq0dU-LH|UJ@Nz3;x@VKLVXzPll2qU&3DjQ+TV1 zDZeGjoWJe$|2yXYI~`Ma6c%<$(kD4M6#rj!%Kz;VnDoDXeGvBmMG2f@Z7hQ4SKK2~^jLNBXzH|= zHV&G@siI*zl)a4(<*cSl;Y}NEvlN}o8oP`eCrxi2NS*u@(0=mdX``R6Kc(*MPvPMMH(iF#6TzcMZjdY;$T}>`y)8>`WL=%ab&;dJ zdiYisJf+aa81jUH94|?$l9mur!1>t^W7*lelxS~S%m+Qr zhufq~KcpqNH&p0tqm?LkY6^^{+^C^AE1QkdP--Ly7|` zm5vmBl)8izfuXJ=C1=9q-jhGra8mD(lJkSt*kdiE`Y>}X=JYACcmukMP1=V{B}*o$5BH-1&7p(1p@#Hm&RvWq!TW@i1n(vsjH$)k&&G7My6{?R2qt1j`2*PxQlY_wt`u_Etu{!1HSEu_K8cB75)GH7<489iV?ygmIufxMJ% ziwUE^4!E!FX)75Q?jAcVZ0L^GN9RM1^>P2h)G)EjStW(aq+%6}2z1S4w+qhBA^iOm! Wx67GcPw(Nb8AE2w{xXJ^7W*Fvh5$hT delta 11163 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 diff --git a/usrguide/apiguide.doc b/usrguide/apiguide.doc index 6d9e0e61f2044c2b981cb6ec4afec09665d603e6..0d52c28e306b8280cf08f1bdb59e80c2cfd13305 100644 GIT binary patch delta 29549 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 Uot2esO-)NlO%lhwYnjIXA4P^>TmS$7 delta 34302 zcmciL2YeLO+W7I=*=#le0tqA}A%pK0jQbZ7GN-xqxkdpszcDBr!5bu58_kS;bzB_Z~IdkTm=bWA0v~~Qw65}_N zoEcxIL4c(F3zeis?3*Y(&CbqN57wew8+DM5y2wC1)JG;<3B!YCn%j%PA=1Zlu0T~uxb^papQK)w~|z>iL*mM$%1M>^#7_>Q4%g$3n}9-n4YVm)>HrG ztmJR^MYAL|9Ac8D%gWFTrbdn{BeYo2f!eub&7HRG@hcbY?R?00HSh6*1sF(}BprL% zB-PVSaX;>*W8v(*!dT+je#}<=7d^}*9U=igkpT7Ik`gAVvqdXUl_axtWrS}8)otEd z?y5X&X`$_@y*x_;UpOVn#?{X+m87hEYQ~&30-NRW&xX4#=i-1uf!Sr~h?P{AbXEw8 zQs?n;;5PXu$5&gd9W52?X?A-`LPE*nrf^emq2evl8`N)AKeKqZHiLU6CU}CyJNG55 z%-Sv&v1*5G&K@Dp`Sz>iFJ4tUZdcn$sFD!e{FUA>ztXSw$XuGVJ2}U5exlQqzl?9+ ze>}uR(bY-S>ezyv zKUR)#Itqk^Xy>MCLv)^t@QyIexvfAYPYY?z+XXyVw8cB4L*upM?6(N@9#3$N3iZ^t zB{)Cz9k)4;gqF+izKYGJUB%{1FW|Y1&F-ua<{3Quo5Q@#B|05pNuJ9js>j2%CX&yGF*u$OaYSSe4XBxg)P@5#x|jDlr7$CI5yeaBOr?-wlT=}U^%7rSm&ZK=+y z1-)ZPb;cI*wwLCtU&z~Dn*X>x-Z{TeQSCbHZ!1*7=I*53y_yoM*n?Z8w}18muqSvf zpXy8xiS{&Mb0&nxYTdJYQkAI8`r5nb>~`na@QR+gcIW5eCA7)2C#pF~3RY%zH&t{7 zMR?}jp6Dzd;TeHF$(a?A<~cP26-vrJ)c zqbX`7PeZBB7YkSN^w+b1lKoR_Pjl`lT-g&&(}tVk4=2VuV?%c5aULBs(!#cRa-zQ6#}rKSg&u)j6Vw_uN$HLf?Lxb61hlp87nG zyvLJx9>sXpZc_ZDdNFU*i!r(C#mJl93$mvrBqqlv#w&qq<(gsMl4r#vs5y%C*BQ1} zj`!8^tQupTBWvX-yGl zz3%)JR;=!P*Lpe2*LEsPQWvZ0k~4j6dzMZjYsWwC1Z9~^Zs@I(;8{P3LT(b2VjJY9 zp`LLkc=DH|KBJ<%<4;iLZ;%`N>Ui=;o$dNMg*VELy?srvD}QW|eVt8EW^L46#IwMX zSYWzqxXSqj&GIg`7U8szSye2MB{C8J#S8I zp3Ei-Q*2Yd-X_=gUBi=FR!Wqv8;M`bO?}OHQk!CEX3f`fGhZD~YK?WOZkJp6`kJb| z`L({UYqrbHeGPb)Y^u!_wnHA4*Kz;m)$>=+pFV%}$iW{De*NW&FTY+mXV$b?)256X zJY{gVQEk+>HWB9jbℑ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 diff --git a/usrguide/referenceguide.doc b/usrguide/referenceguide.doc index 4bc7ce3308253a4c88c9c24b94c0ebee8361d7cd..9a9bf7e6f6ad68b8e2657249c7fad57c192a7a18 100644 GIT binary patch delta 271401 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%0D?9zAADT9CKrNNEe`YO7d%5cU%YZ=tsMyp%j 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 ack7+~wBmZt4TP0vQdvV{-)(T(brlcuq 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'HDTt~v9003I+a~*=s`ts z9L5VXd^f*z_i$;Qce&?8O>mMp$Q1}VS(6jBHP`^I=J?O7&eP10K|gbU)>rx)_auiS zT-&hQ-8^tXmfBwOzm|QEyMEwuroWe#^MJdMHgb!sA=(kGDotvlD#OT*OL;+9>fZ%u*RBiO^7thWY6Ylp0X z&G!))@ttLiv09DqEMtt?PhgrgFkV|{4O~j#oV}J2CThj@T1MzkR)2F~EXy*@9LVK* zS(b|gx&u|(w5ZeWVp{%vrfI}-%Y_wEKx?+oT`?p*v0Sicl!dgF``kI6j-lp3cX(-| zhFq+Qw_Oo(S3Fi@iHc}>_q%hLMoW!98Eq5#hpeMmeH~5MZ<;yAqep*bj^={7EZjY7 zw13qX(8?ch=L#8joOb&FbJF90X-?vpLpGEG+Cpn|%0Z$}Sfk_h=&T1V<31wM^$uFb zov25Tv_`Y`ifEh7(eW&$e@d8UMqf>=sDKtz*6qF zMo*V$*I~=J15257*fMU%5u%4$qXSF1+8SN+5Ya!GqZ5KlS@?))+}zug=r%`8bCM8T z%E{K~=0}O%ZH*2rQt!BF+*N{0Ino?mMawC3ve_CPSjrpL=nW@`E_K2(?!Z#Ma>6txRkY$K ziJoJP4lLzy2G`~r`^$} zaVJW=@e?RB;b10;B>aogTB=u6)-ITbiP8qhFjfAGVWPFBXH3)K{`EeJ)c4M~^MuTh z-2B~U4djQhfcDG}mcV$e(hrs~@-tFE8*L3t)D~LG10X$|x*O!ae?F~)11&RHhyUzoMlz(nnkHPF8>MbDeYD2FUH z&YQ;QKV&JOO|=F_YwN6m{)KsL4UE-_U9gPNzc8s6ER&Acrdb313v=EYn5aFm2KpDK z$wku`<(Q@4Mbo7H$1DZ3udIR5+68N%e_<+KvWziSYkJ8tM*qURXAO+kwpj!H3-ion z%NP^2N|!BT^e@b4bD$ikEH(%Fk5Skjt%1>6_A90_#_9V^$1A2u%i)RF8t7k`gVsPw zKx?3XVX9xXj4@H`bk*H8WXF_B0f(--YkK8=y~q%4C`P-;63Z!L64yOy=nB{6dIy?t z`XJ6X)&0gwlgy*u|pTWhjXkw zoO+JkubX+8xyHp~y08;0J*xepb3f$r6UIN$l`rT}qH<$h@0T1(Tx+j$&*3gRHg3_K zyWmjbdNHTpcy6AL_wvWpRX2)rEzy}fT4FSJtwe3^Mv3O!g%T~f!zs=t=x%TiQ_Sq9 z+xZ5sPDb@fx~lK+u6W#^ubaM#FKi$mH^ja2N51tTrhcQ#b%}Q^N{1)Kp$zy&f&`TFbQ#AMEbpow>>mK&wjRugH zb%>b(`)G=50T~8xpA?0-A1V?8TGA9RaO+=m4;V{RWF4Z5q$%nMFMoz}3r@@q*gcG= zx{;H+a-u@OyWF7@s{;0n;IVyN324mSJJBm(B=rx(XDp-`!>bO&Zf@X;%V;Zq9tRX0 zPrV()2ehCm5+>+c(iHsyR!wAPLTse{gLimreMXq}&)1$JnKE&?$_rn;Xf zgG58hA@Lq%keJv>mrNNXnocNF1RI5{)T`L_^9T;aZ?uLK)3i*iWJq6`x6rWn5OMzsgr49G;8BT5F;peZi(&^@Fn zIHP6DcVuyh`|AA zG({nb9FZWT{An5RHsz049&ns8NJLQnh@^n|ls{r~zzND9aVOvv${#T-;9bff@huB0 zrcnlo;}kny`Exr!-k~DO1k|M|QUdBx?uae{qiKo_6U|n=!^?3%IYi0A73pX$CgTR~ z;|XPoCywi}aqR!&Xjz5zco@$=qE!M{p>YF`kTsD)39+b--Pniwc!=dyxaN)$&r@LG zB+jB}RSGJ!LI-rN#_bfuRp*cb^J=jFe_Vr-4?bM2#jPqVtwSM$>-ZhF@dxhXF|twm zg(Dvd;vi07MLiY-z3a2YDA|CL7FAIj`Cs7v3<{$d8hZKD0-ewsH5$?rFQW@K;&U9q zd5n3HgC8uX*xiUEirczqh}QT9hp@Ie!y!WpQVlQO!LF8M4hL`+-bbyu2iAroEo4F# zONAm$^@h9Ivp%D2NE$$0O|Nz|8>oIx%we?##^t&E(@*`4d?DE}H4{P7}MV|pKgF%L@-*_Tve|3GSvVA|_kgGbnKW*CRx;I0DB;0hXy zqap}e;AOlto>lNJyEHWcBT*LRrm;Izprs-zBMLEyMK!#Qsn~+;_yd38*)(380C`)< zo7jS{kZC&aGC);SLn``V0M_6fGO|~=Pz&{?MSiZcyF5>{j!sV>bOoCyCXC?QGo#P>_we4B~6D$6!xws?4Bl9r_`GjWh{6 za1;gESc~Hle!~Jb)>Zh^%SQJPWWzd&hppK9*=91cZRA4FSJ{XltFH=gbHSxQ~R^K-Z}i5v5|<$`|}vVAOKS6|9)6BJm+?hEf5?^BH!Syr;U zAr)`n$5q_$LB9`_8iQ|f2-7}f?(xD$Y)4qWnq3*G8#({Ly3J$>yFX{Q#g*+Gydd@n zWdgRI<$MO7U%0*Y3ma&T+x-6H>O;x_w0p$eBz&2{p}xjlY6Cw)62|~9p(oa3c3~>= zqDCbLujh8C=qQJ3grzZ5DulDDLuJR+Iu6yiu0!p7!J&2`nPZ5TQK5-L#WwLe)YcYE z2nRT*_!XNvI@A_?(8;0J!P%J+A>mafhJAe;>LAYacc_cVGuWXDqWBPpDvc9Esa=fm zuRGM6m^6->$jHY*N)(nZW(HC4bB6KqXXh41glBegB!eYXjeH;b4^V9xWe+hR%ARzn zc>H#OGp~zG=n^w`nJSi77!D1tQ#TqPV;ySz?oi#Z{Vq$6r4JoyCA?uyH4dc;P))f! ze?Bcr-Anw%(Nf+B+DkjtSLjj3sZx;`?^HFAFVV^Ggi{qya;nmZL|N>v?o@jbRoAKF z@Kb%K`W;gmI@MI1p%(B@xQ3rGlcTY<_@SB8tA3=VPje2%aD>X%$IUKw` zdWgInwpGU8!>O>18Y7&l4!*}3R2t<}@mMy_saE5{c+NpFg~Pm6*g~buZ8$vLsZQV| zPGiG-FD+EY+)5?PJ-9{f;=l1=6Z=2+|4M#Nn$RCpuzNd8in}|Q5j=r&r&A5V2t0=K zYif|gg*JE@`*0Y=_Bd4pntkh3t+2xTol|`b?I0<^)U!^$;^kDYU1Opcb;GINg!_S0 zWk*X6Q2Sy9)?n&0oVQ|c4h}{!JtyBtgF6@Bv&4DaL1Jz`35666Y)7Ii2ezZprWn;a zo8bmWxS13Acn#G%7;O#f|R4x5PI<{{p7zV&nkaSikc;iniNulVm=mN1CHV@f)yvqmE=qT!3q--XkUSq z*ot#_j3-i)LTX4z&4{)L){K}&`+5W`L`X%5Or?y95K;l63xX9Oq~gOD2v&TM3J-Zo zGj2$Q2dU`L7r}ZCQomt0yuk_%Qn8^}BufgZ*dP@eh9Ov?K`JsFL9il&RA4BJKm`VW zy@l~~2kR|JeTB0K)>n{v3ULV5Q;_-zQ_E7g1}i8?#e{1JR!ork2+0W6N0535^AN0u zAoUOKB3S=G>K!yfu-<{xH&}sSeFLdyAkU8ks~Jf3g0>a-oeI`3ka`8{5v*4r^$9Xn zH0l#bJ%TO>)+3Pm17ASu4@mU^sWy;@^XFi-0jVy~7s2WRQcXY(KXS5(mV*Bf#7m33 zw(WoS5TqpAxb-k(Yhb&#I}`~XhR8l4ha!1Hk45Ur@rZxt(8lER|7el&?@JV~zmC;^sz~|wB?>#8)RFoR6)FF|MDbE=NEN65Op)^MOB8Rgiqij7 zkzzih`M0Hs_y72eCRmK5JDbr@W;jvNPgd-koO0R!!~doJUViKUU(SGAKcjQ|*5vnG zZxsGa80WAYXn63W9C7epHs43xJwAu8drwauhx7OBzVWYm9yoksdwUu=d`DjMoN{Pu z`g)SI-}-tYw4AA)NME&7Png43x1VRO!*{8_XPCp+VW4Mgh7$6VQy21|15c72W29;P z=g`I$_T(<>WS7+cyPkm)B6*;c>S&zzt7OitsTNINXJIL{I0_$0+s#i2DE>B*cgSFGMY_;&)A zq%bqZQ!Sr9cKMgA(c=d&obp6GdE}TmJuJU=a-?TR&Tv(i+G-6{CDl%~R}m^w+cC;h zpimi=RW(%IRVv>cj8L^yit2+w>NVc?IXx`gcXN~{mvd%+Px72Gp32_2q$LN_knFq- znQ9s&cOSroZ{fx*u!t&*;7l|*%Tu{%M$*hovjNR4G+WWkO0zS~Y&1D3Q_s-kF*7Rt zDS1BBKh3utj9xO6rhPNUQ@TKYTI;rIP^n$}h{(Eqy7&EgU__(teR{oCMk_GZ6PZ|x zQ)41z%uV_Y?3>c3Vz+*S`}+II5;W|ddM~0@N}rTLuid57-(Qv@S{u&Lb)*;nCCi_z z$%U@Jx69#gKl{mry{{ZLwaYr60%^*6l%}lV46M1uj!*h~(*8StW-bYfn3Lv7?v>2q zasut2aaz@@kTmp1MofUDc`|Z>%LFPP7DCdw9I}9`A=%o5yx0m!?=DDE&TAXeJSB3; zwkC5dTcb25jMHwWdAc|zXw9d4N_dxX#1=;HGc;xDQu$M+?&3&IR&rUIvXbLz%1UlX zQ&w(Anld+|Y0A{zqbXDWh^DOEy)?7aJV8_D_A*Ubng=vxBgtFYKljh7cv|w%qZZ9@ znk{I`;`E>?i#^a6KEpHH5niV}*J@Y*S%&^xN0Vj^%{!YXMo-N2eCtSh+P*zgoGRx3 z_wv#&rbw{Dp#Q;i29rU9A*IrXBw9iu(uZ)Z$uyRN=|kczA$ih=aIM!gmS@t3NP!SK zyPotRF_sXgKcr~rLPuLd9y+x#vpvzKm?%rkpEfb9lEB;)^*3*&i;1OjtU2Zvn;0X* z`gpF|#26{oW6s;e7&+EsPT9m5N!DYI+Qb-H)?@bD#29JTV|Lrb7pXXueVt7H#(>&`j18riAJnJ!iY+{T& z>oGlSVvIcNF`aEoHAiVvIcNF%4{Dj6CZxwQORHJQwok zIVoKXZ(MqsXFVp~CdSCK9#h#S#>lfCQ`RQN$g>_((k8~pvmR5_CdSCK9+TfD#>lfC zlglQ?$g>`k)h5QsvmWEJi81nA(4S|OE{1o_J>62Y=XkGW?PW8_(n zxoHz)%7YnBUujSIT-VmO-wM)!I;l%VuE=N#%#2S3FbK%v)U#mnCD>3N}HHqo`W$oGss#29(jV=mgn7fwTUtEtjBD&i81o5$E>%BG4ia(d}I@2 zlfClWG%VoE;&VvIcNF?DQWj6CZx)oo&oJnJ!uHZew?^_Xaz7$eVmOnI9a zBhPwFDVrE0&-%GcM7kK`d@za2Sh77AG{wjR#Z^>reu6Q1Y+{1*6O4JrCMGyPNrB@` zPr4Z6_$L@cB?T$x15a55pLwpa-IJ0fra}~3fLt^!tQ8;YDJ0kHo?aKNrG3BMQ|Z6B z=(=u)C#Fz-hOoUROEtBW9iBLO6$>Ah?A3M9pnjFcX|3`%m0`+ zF?Jwt9nlG$kpka@Bc4`{F!^Wg>`_ntu&<=&Uq?OL13kAM^AryJv$WOVqNVmw+UiSN z;p5x`7<1ec>1eNgc-+%=`j|R%PI&rc>O8mLUAdn7iZRy&Fs-c6w2PIm)UKHdl#eo>opP+m zn_i`tDO$R#t0;;O6csfem6M z*=JL5HKm{~WqD%9scuC5_z*H3Ws2JU2M-H124F($m%L5-CzauT`7#-H-t-i z>1)ZbLKA3sSt^!l%MAW5{RTf!NxuD|nS7-;wt=~t;7IYk0LCAL0=b?W92KO_3 z@6ubES7!LbMc45IFayyzXA-hz=vSi%DQIIDrHS?xdf0yEOycxus!I?e;^W+|^2N|u zE`)p`6Y`!U`efxxrE1%iUMhuU6w@r_Srt{egqZp9;|O6ILVA8rNFQ?}Xclzx z2i*jk2wH2>u>f*!U{1e-s&IN9AwH)1JVIQER4No1l57@G#R!?5s+NR;1JL1*Com~k z4~--w4s^~WLl3tht%WVc2Uc96>FD~{ON40o)B{qKp|g94*tkF3N+rL8UvF;}?CO@T z)hB7Sh96niR%$Wbu+cLzK`EyuMn_Wrq=Y1o>>002nLKU0hhJoNM*l~LKiV(yxtz(* zYm-c3qKi6Gs-eKMlezenXOy=pk*p4s;$c|RF4%C}v#mN=YO-xltydQ>RXinfbRK5b z8pe1An+IFu)xp%NZKm}{udZgnHr`R@VzPIFX(FA0d0SLm;@#a-ok*_^WjN*=V(xR< zd$6fbnqjGrrO)#|9n2C-d`!#IDfUT8NcJ!+(?=R=eA=oS>Jrsq)2;gJ454kir~~K> zS#6{Jl=*dvU9=vL&K&>zjOm8n-jV9mx@3c=uW1!J!{N5+=AO(q+FaE7K4cQs+6ou> zn#`{=R9J-@e0Ao2@qW?jrs(uyQ?v=G9z55VMjHzJ+L{|w^;7h=`tS7XXddEMKZ_QA z{w53S(hXPrOe*UQll{A^W9dz%NU^bn-cae^T^&nrpaG__^oA}0DW*=zrX5bQDxfzk zvPgctC18=nhYX>iUyp3(?W&dv!|#NtCBs9X&rnK+2|H(eU0L#|NjC25Xr@X`*m?H@ zO`nX696tU@TIMq7(Lub+Q}jhmYJ5^E=TFgYG*jO56n%usbTlocE;&g4K~7`Iys9nN7as-wdZ6124gr`*?Id~as=UP zEic||PDeAV&NtLm-9?S?UfBpuXfG#KR8hT$DysN7d`7j)_wJ5%;X@|SAhS^&XKjA# z)S-5@avaKRV)GiDZPL=Zz3k5=zd3>a+u6qI!n(DwUs$B0BMi-QCBnsqfj$fTiEFAW z+1R?dmE?;v|JRpbjt@!dU>47EG^yD*&70Q7X=n_;{t~@sf4&3ri#(fC)*7E8)OO4K z&CjDQd@XBfEa!EbPKc{AFfW}(g9f(Xd9muK77bdmK$y+O$=4@RPx`zmMyuK__ijl$ z)e-#EcFR0}?F{p0C(~eO-*R5C%~r$^n?U}5IlsYP%8~+=^UIBs>Axq~EqSi*pD&rJ z?Up60hML#5rCzqH;<;1*`%!!mzNgs6VI_)BrFZ>I%eFndT$)B>JuFVe6X9d#!1QOE z@n;@B)6af>>vh1^G)mxVHcaq+)2Mf>MJLAyXY1OsaT@h=F)OU@%nP`!uwA}&dewz5 z2Po~9{j?oV9BEtgD0BbE*p_U)pK0DM&LNnW{+$N3yhd9?$wr7$^XA!Zin#d*?D$l> zmey-K3eSD*zwe2;LH4RCp73hXsyMq@TFUd=Y!5i?fRBEuZfw(2eW;j za*O{yn=TCh^J$Cb(4he)O%?4()J8?S1g%=*l5_e5B1a#U4{?st{>MMU(uQywgFl1ofsX04%LLm+1LG$T6Z;Pc>tMf1B<4(Uj_gO%1aLpp>)63XY-&BocJfVp&VDrxi7&4l;{=H2ZTtLQm#fQM!pAiPp&A+)jjed{v%r84}tWwbwyE8dMG z;9gD#@SJj*mR$D@AwL1v>aNut{2p1!+L9G(-+E*2TW`FzR^?o)n^^bcMAh$+^Hck2 zXFd*V_|Io9Y%lHW-<+mAcP|~p51gbSe9&DQOQX2^KDvu*4pN_#+x2JmpV=WCP)Q$g zHOU`wgNda!nDZs_66{Kl@QX63NLYj$_t9d0?jDU6lM9oGa9}o5O7Q`hz~>;1D2Lq`;M0$ zFWp*teDm?o8a_PLu(V-*!~9eE^YiDwK26;ezU3J0;D$|SK~M99W3)H_qmqUzdmeU} zF2kN5!Gb$i(Oj-MPQwP@xmy2IeNFw*ilcif3gA|D%dN5eO5AprgcJluah$*~jQuiL~co$8n@IKhUt4+m~*i zzI5b3`H=%hF3D?MZpGYDX<>gAgt&xY-(60P! zHI3zMPSV$f3c)mu4>&`YbIm!L*!^1FDI6VCjL$h z?azIx>8pH0HGQ0RFFp%B6VK6gTyvg=B{kL|ovLg+)wpNJo>L%d`Wm#d@e?GlckF4b zTVB_=pm6~%N_=W9!fstHc4B@tRDG-lcDq_b{rJGUw3FDFU`$dcjB#G*e4EC0JNuhM zI$VBu^WoKp-?OAblvX26;YZ48G+%p?c65U;tngjKd)}p5zMz_RXjh{BIUWL@Sv~g*{(#Zuc`UT&-fE@PL}WLp-T?;1BXZd&u+JM)ng!OM-1Qx+J z?1gF5?qN-HA7D+|;ylwt_hLCx;I_AfWLD{ zAXS$x97Ot8$!8)yU3h=~`;*@veL)$zLqMK9`$xjdLZIXPP-zygj*&WYk02?N&kmB> z@mC{|4GNNiXiRZCT(ZMLq$ykzCS~_*sBfrkI8k0(URw$Z@@?&g+R|cV8$J{zC846E zcM6p0tQo%J0;yTm2Q6e(aps-7pUaZj}|KxQRS7<(u+JKTzZP{ z3Xwv2ZMfvY&&EjJI32m|#mLc8=Z?l-jrG+=kxl^O?xen=etX5XihARxMeivM)y6p- zKUAdgw_>COF+!{`UbGU!brI4M+OaqiX6qa+&E}d8Qg7|gM}IzA@qNW-MN2A{nDU~E zg(y|LjJoqM6Ufg=PEfbb*mSYxV)e=D%6+>l zw^wf6z4heQ%8ix(SozMIN?Q4yVAihHn=(q$rip|Q*Qg7@A@q#P~5q}7FH+!JeE&pF7pO<|8$ueXm zsxPW}l*^0jI(d))2;z5XYcmktXIV8aR6M&V65xi|>dbk&M z#FcErs6Ui%iSuUNxA{6Iej7jsw4)@f9wyeNr@G=nFlO8k>E--sBPp2<%m7{mih)mo zGGI5b2Pg-A2krt!AZ8RL9RNL$2BZTI0lB~!;BP=4FadZGSOP2sRskOX9|9i%yGK#3 ze?n@TfA{(?XOEvfc=q@&*MGUb4^Z+QAZStZZ+=1bbEUf4!c?2^`?I~B{M`17Wjk=k zYCjcRXPf)v+Zr@8OFX|+AIT7lsl^67>|SW83x7bpo&CfnE@t^l8)@EbH)YRzuFRJF zUBy1^k%P0PUud}5_BG(u16P3SfY^&IeAsXtWa+2Ag+C?1r$su<|~jK@QHr zXaSVK-KR@2E!x$PF#m-1O7r2rSCx(@^qohje@ox++Cb%O;tf%tzr=7T@kswL@r%lq7W>_}EF57N5i>TTS8nv%Y9{*&U)cP-Q%f4~Y zNHDB(t=wrlm8jXNrgPR-Wm!kyQ_F0JaI9XpZxvNLt)~{XYGy4KuFX8pmD|lDsy4dn zoGoi++03WoE4JI&LuJ^^Qnk-+7E!h9?_f_I7YsW+QXOrkgJU>sx{f$mwpo_mxueRm z)9FT;!PnfZtD_(?n(x`DTfy6yz~03oSI3Auipkdz+@>G(4t^*0DPb(fGvy!mvl6(u=s zaWx909|#zs)`uV`F_I#V*BJ0-4ZlcrSRl*vxQyae;5rWvV%>Su2^Qzt2E%ysj2~D~R67)d z0W6Ay0^vY=01G6MK(xFyi2cKb-j_#&vVK%s;OElx;QazWrsOW~iLzbpuW)ShCVn@J zh4ZUnY*Ky~4A~7B4g4M01XKgpfZu>XY+X1I0b~M0fNWqUFbkLstOvFNek0!3_>GwU z;Qe`iBeWuq@_!Ie;1{CgBYsf$IZEzt&f7v%ZBX;~HS(2kc8bE2$|Bej8`szJ6`fcp zpB~A4TbV*XUlGsz_$QI9y^UNdr=1~p5pwq2C>C#X-cm^l&yQunJSWOQa4H1tdTx%# zc;${_KRJ%4=R;#ysH}@-jN0`d9K#Cj7;U>@z@`|s+J>u>KkmRbOST*y-+=|ouXJKQ zw&UselFn?rom^5^jMuIU%d+E^b-^Al>cV{NxP!ZbySodEv*Thhp|XEhHrIZpkGna{ z&NJNh0swfd%m+acq!{pq?L#!@Pas?dH|<*W&Fa(94(O*&)g0K{n<0 zjQt>ij5cz?PQvVA)g-?#Uu456EJjTm2zS3G0^hX3z6w8O)u3l*wlE=X#@rYF|Dr zgRSE`d$X6-3=LXUu2&{nQDrvWA_lV%d3;}%Ewvf=HX(2AAY|1K4doF-nZNw> zP@Js)2c^09Ft+v)Tb=)^t`mp^Xplt>wu~5i`$VKRnkRGo;ZzU{#k9OuCr4=ZF;Ed3$Dts zJfp?=@S!B0bixVM5Eq{uH$v>WIc{>smuv`)^o6kP=WGTg0^+mdL`I-^^re;mX9Md@ zz5U6fB!>*Z>%SRDIdZ#=>=NZZc!_sq2}`7PJgJ0r%NG#^^AQG$_nruDEfm8H0`)+B z94Ow+AX7l`0uWga+6J@;6!C$41`2;A-+;nr$u3ZD&;y{t7*(L~VR8mkM4^kYe0$J1 zV8pcXJg$5KyGYvbaQf|NM$6W;q7L(Dk4Jpx=SwrHj^N zFADg{pPZDFcC&TVr6=*{XZEo4aO-zQJxPIpP#%p6eV3o#!&2--k{v`AJBuVah%9gx zK@2iY6rj)oM-d%KcMzH7ERyCRGTm83?;tYCSw!a`lIJXv>L4=KSwtK$)pY8LMmvjG zt*eSW;Vfdct}2r4EMm2;Dw5?aVzq9dqElZ-kyIP&svTE~oJFkGRYf{Fi&(9zibOh#SgosyggA>>t*eUoJBwJYtBQCzi&(82q*&Ko5wW?m z)AFK2EIzcw@PzMHbr3*o@~UKGBE_rPYIGBq7x591P8?zcH@wg-FRNq|UA9%RLBSc~ ze_KW%(mVl-1V#Z*0#5-?1ET#I&}V_?fLver~He^40*;C=7L`?5As>RG9%65Gp@3HI-1|Q$|m<;Uh{(@ z<@gUJVihCFe)0nzW{n^RQR+(`L+v~{g;F2TGEznMk<;Wb@+$u2HJ0vWKbU;;8XM=@ wAvHOvkG^keMto*UMtZ!qUvf%(A6;T*d{V!Rq|9Vp-$(nV_mO8cvIWxr0?h#regFUf delta 14561 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 HEt38R{-<|` -- 2.34.1