diff --git a/compiler2/main.cc b/compiler2/main.cc index c09b9d0efa8689816aefced84b539a47899beea1..d9326ce42d9076b1a4657d09c3677198cc21d3a4 100644 --- a/compiler2/main.cc +++ b/compiler2/main.cc @@ -98,7 +98,8 @@ boolean generate_skeleton = FALSE, force_overwrite = FALSE, implicit_json_encoding = FALSE, json_refs_for_all_types = TRUE, force_gen_seof = FALSE, omit_in_value_list = FALSE, warnings_for_bad_variants = FALSE, debugger_active = FALSE, - legacy_unbound_union_fields = FALSE, split_to_slices = FALSE; + legacy_unbound_union_fields = FALSE, split_to_slices = FALSE, + legacy_untagged_union; // Default code splitting mode is set to 'no splitting'. CodeGenHelper::split_type code_splitting_mode = CodeGenHelper::SPLIT_NONE; @@ -387,7 +388,7 @@ static boolean is_valid_asn1_filename(const char* file_name) static void usage() { fprintf(stderr, "\n" - "usage: %s [-abcdEfgijlLMnOpqrRsStuwxXyY] [-J file] [-K file] [-z file] [-V verb_level]\n" + "usage: %s [-abcdEfgijlLMnNOpqrRsStuwxXyY] [-J file] [-K file] [-z file] [-V verb_level]\n" " [-o dir] [-U none|type|'number'] [-P modulename.top_level_pdu_name] [-Q number] ...\n" " [-T] module.ttcn [-A] module.asn ...\n" " or %s -v\n" @@ -410,6 +411,7 @@ static void usage() " -L: add source line info for logging\n" " -M: allow 'omit' in template value lists (legacy behavior)\n" " -n: activate debugger (generates extra code for debugging)\n" + " -N: ignore UNTAGGED encoding instruction on top level unions (legacy behaviour)\n" " -o dir: output files will be placed into dir\n" " -p: parse only (no semantic check or code generation)\n" " -P pduname: define top-level pdu\n" @@ -487,7 +489,7 @@ int main(int argc, char *argv[]) s0flag = false, Cflag = false, yflag = false, Uflag = false, Qflag = false, Sflag = false, Kflag = false, jflag = false, zflag = false, Fflag = false, Mflag = false, Eflag = false, nflag = false, Bflag = false, errflag = false, - print_usage = false, ttcn2json = false; + print_usage = false, ttcn2json = false, Nflag = false; CodeGenHelper cgh; @@ -581,7 +583,7 @@ int main(int argc, char *argv[]) if (!ttcn2json) { for ( ; ; ) { - int c = getopt(argc, argv, "aA:bBcC:dEfFgijJ:K:lLMno:pP:qQ:rRsStT:uU:vV:wxXyYz:0-"); + int c = getopt(argc, argv, "aA:bBcC:dEfFgijJ:K:lLMnNo:pP:qQ:rRsStT:uU:vV:wxXyYz:0-"); if (c == -1) break; switch (c) { case 'a': @@ -759,6 +761,10 @@ int main(int argc, char *argv[]) SET_FLAG(n); debugger_active = TRUE; break; + case 'N': + SET_FLAG(N); + legacy_untagged_union = TRUE; + break; case 'B': SET_FLAG(B); legacy_unbound_union_fields = TRUE; diff --git a/compiler2/main.hh b/compiler2/main.hh index f486fec3966af99b825f83b6df55d33884f39069..06710f2799a33752afb6cfd024230c02992ef8fe 100644 --- a/compiler2/main.hh +++ b/compiler2/main.hh @@ -51,7 +51,7 @@ extern boolean generate_skeleton, force_overwrite, include_line_info, check_subtype, suppress_context, enable_set_bound_out_param, display_up_to_date, implicit_json_encoding, json_refs_for_all_types, force_gen_seof, omit_in_value_list, warnings_for_bad_variants, debugger_active, - legacy_unbound_union_fields, split_to_slices; + legacy_unbound_union_fields, split_to_slices, legacy_untagged_union; extern const char *expected_platform; diff --git a/compiler2/record.c b/compiler2/record.c index 27bd00cfa5138f2823d75126511dfab3b2111824..0ee6d5268b8fbad0094d20558a5e142f52acb362 100644 --- a/compiler2/record.c +++ b/compiler2/record.c @@ -2290,7 +2290,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) ); if (i > start_at + num_attributes) { // First field's embed value is already processed src = mputprintf(src, - "if (e_xer && (p_td.xer_bits & UNTAGGED && !(p_td.xer_bits & EMBED_VALUES) && 0 != emb_val_parent\n" + "if (e_xer && ((p_td.xer_bits & UNTAGGED) && !(p_td.xer_bits & EMBED_VALUES) && 0 != emb_val_parent\n" " %s%s%s)) {\n" " if (0 != emb_val_parent->embval_array_reg) {\n" " if (emb_val_parent->embval_index < emb_val_parent->embval_array_reg->size_of()) {\n" @@ -3000,7 +3000,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) , sdef->elements[i].dispname); src = mputprintf(src, - " if (p_td.xer_bits & UNTAGGED && 0 != emb_val_parent) {\n" + " if ((p_td.xer_bits & UNTAGGED) && 0 != emb_val_parent) {\n" " if (p_reader.NodeType() == XML_READER_TYPE_TEXT) {\n" " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" " if (0 != emb_val_parent->embval_array_reg) {\n" diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 7b4bcdea7a95e687a3a0de39ed4d8d28b17cf491..58ea606b37c5abc2291e9ba39a8492acdfd3108f 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -6806,9 +6806,9 @@ namespace Ttcn { if (Common::Type::CT_XER == encoding_type) { Type* last = input_type->get_type_refd_last(); if (last->is_untagged() && - last->get_typetype() != Type::T_CHOICE_A && + ((last->get_typetype() != Type::T_CHOICE_A && last->get_typetype() != Type::T_CHOICE_T && - last->get_typetype() != Type::T_ANYTYPE) { + last->get_typetype() != Type::T_ANYTYPE) || legacy_untagged_union == TRUE)) { // "untagged" on the (toplevel) input type will have no effect, // unless it is union or anytype warning("UNTAGGED encoding attribute is ignored on top-level type"); diff --git a/compiler2/union.c b/compiler2/union.c index 21fe71e1b02ce62da60004171059b3953d807359..05e835e1579930e95bb585784ab56bd9926c1bac 100644 --- a/compiler2/union.c +++ b/compiler2/union.c @@ -1520,11 +1520,15 @@ void defUnionClass(struct_def const *sdef, output_struct *output) " if (is_exer(p_flavor)) flavor_1 &= ~XER_RECOF;\n" " if (!(p_flavor & XER_LIST)) flavor_2 |= FROM_UNION_USETYPE;\n" " boolean omit_tag = begin_xml(p_td, p_buf, flavor_1, p_indent, FALSE, " - "(collector_fn)&%s::collect_ns%s, flavor_2 | THIS_UNION);\n" - // Top level union can be untagged, so don't increase the indentation - " int p_indent_tmp = (is_exer(p_flavor) && p_indent == 0 && (p_td.xer_bits & UNTAGGED)) ? p_indent : p_indent + (!p_indent || !omit_tag);\n" + "(collector_fn)&%s::collect_ns%s, flavor_2%s);\n" , sdef->name - , sdef->xerUseTypeAttr ? ", type_atr" : ", 0"); + , sdef->xerUseTypeAttr ? ", type_atr" : ", 0" + , legacy_untagged_union == FALSE ? " | THIS_UNION" : ""); + if (legacy_untagged_union == FALSE) { + // Top level union can be untagged, so don't increase the indentation + src = mputstr(src, + " int p_indent_tmp = (is_exer(p_flavor) && p_indent == 0 && (p_td.xer_bits & UNTAGGED)) ? p_indent : p_indent + (!p_indent || !omit_tag);\n"); + } src = mputprintf(src, " unsigned int flavor_0 = (p_flavor & XER_MASK)%s;\n" " switch (union_selection) {\n" @@ -1533,11 +1537,12 @@ void defUnionClass(struct_def const *sdef, output_struct *output) src = mputprintf(src, " case %s_%s:\n" " ec_1.set_msg(\"%s': \");\n" " field_%s->XER_encode(%s_xer_, p_buf, flavor_0, " - "flavor_2, p_indent_tmp, 0);\n" + "flavor_2, p_indent%s, 0);\n" " break;\n", selection_prefix, sdef->elements[i].name, sdef->elements[i].dispname, - sdef->elements[i].name, sdef->elements[i].typegen); + sdef->elements[i].name, sdef->elements[i].typegen, + legacy_untagged_union == FALSE ? "_tmp" : " + (!p_indent || !omit_tag)"); } src = mputprintf(src, " case %s:\n" " (void)flavor_0;\n" /* warning reduction for empty union */ @@ -1547,10 +1552,11 @@ void defUnionClass(struct_def const *sdef, output_struct *output) if (sdef->xerUseTypeAttr) { src = mputstr(src, " if (p_buf.get_data()[p_buf.get_len()-1] != '\\n') flavor_1 |= SIMPLE_TYPE;\n"); } - src = mputstr(src, - " end_xml(p_td, p_buf, flavor_1, p_indent, 0, flavor_2 | THIS_UNION);\n" + src = mputprintf(src, + " end_xml(p_td, p_buf, flavor_1, p_indent, 0, flavor_2%s);\n" " return (int)p_buf.get_len() - encoded_length;\n" - "}\n\n"); + "}\n\n" + , legacy_untagged_union == FALSE ? " | THIS_UNION" : ""); if (use_runtime_2) { def = mputstr(def, @@ -1741,6 +1747,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output) " int rd_ok=1, xml_depth=-1;\n" "%s%s" " unsigned long xerbits = p_td.xer_bits;\n" + "%s" " if (xerbits & USE_TYPE_ATTR) p_flavor &= ~XER_RECOF;\n" " boolean own_tag = !(e_xer && ((xerbits & (ANY_ELEMENT | UNTAGGED)) " "|| (p_flavor & (USE_NIL|(e_xer ? XER_LIST : XER_RECOF)))));\n" @@ -1756,6 +1763,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output) , name , sdef->xerUseTypeAttr ? " const char * typeatr = 0;\n" : "" , sdef->xerUseUnion ? " boolean attribute = (p_td.xer_bits & XER_ATTRIBUTE) ? TRUE : FALSE;\n" : "" + , legacy_untagged_union ? " if (p_flavor & XER_TOPLEVEL) xerbits &= ~UNTAGGED;\n" : "" , sdef->xerUseUnion ? "if (!attribute) " : "" , sdef->xerUseUnion ? " || (p_flavor & USE_TYPE_ATTR)" : "" , sdef->xerUseUnion ? "if (!(p_flavor & USE_TYPE_ATTR)) " : "" diff --git a/regression_test/XML/LegacyUntaggedUnion/LegacyUntaggedUnion.ttcnpp b/regression_test/XML/LegacyUntaggedUnion/LegacyUntaggedUnion.ttcnpp new file mode 100644 index 0000000000000000000000000000000000000000..0379bb5238a83a522842468f81574d944c0e0cb7 --- /dev/null +++ b/regression_test/XML/LegacyUntaggedUnion/LegacyUntaggedUnion.ttcnpp @@ -0,0 +1,79 @@ +/****************************************************************************** + * Copyright (c) 2000-2017 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: + * Szabo, Bence Janos + * + ******************************************************************************/ +module LegacyUntaggedUnion { +modulepar boolean Untagged_verbose := false; +#define verbose Untagged_verbose +#include "../macros.ttcnin" + + type component EmptyCT { + + } + + type union MyUnion { + integer i, + charstring cs + } with { + variant "untagged"; + } + + DECLARE_XER_ENCODERS(MyUnion, myunion); + DECLARE_EXER_ENCODERS(MyUnion, myunion); + + const MyUnion c_mu := { i := 5 }; + + const universal charstring c_b_mu := "<MyUnion>\n\t<i>5</i>\n</MyUnion>\n\n"; + const universal charstring c_e_mu := "<MyUnion>\n\t<i>5</i>\n</MyUnion>\n\n"; + + testcase tc_legacy_union_untagged() runs on EmptyCT { + CHECK_METHOD(bxer_enc_myunion, c_mu, c_b_mu); + CHECK_METHOD(exer_enc_myunion, c_mu, c_e_mu); + + CHECK_DECODE(bxer_dec_myunion, c_b_mu, MyUnion, c_mu); + CHECK_DECODE(exer_dec_myunion, c_e_mu, MyUnion, c_mu); + } + + + + type union MyRecord { + MyUnion mu + } with { + variant (mu) "untagged"; + } + + DECLARE_XER_ENCODERS(MyRecord, myrec); + DECLARE_EXER_ENCODERS(MyRecord, myrec); + + const MyRecord c_mr := { mu := { i := 5 } }; + + const universal charstring c_b_mr := "<MyRecord>\n\t<mu>\n\t\t<i>5</i>\n\t</mu>\n</MyRecord>\n\n"; + const universal charstring c_e_mr := "<MyRecord>\n\t<i>5</i>\n</MyRecord>\n\n"; + + + // This should be unaffected from the legacy switch + testcase tc_legacy_union_in_record_untagged() runs on EmptyCT { + CHECK_METHOD(bxer_enc_myrec, c_mr, c_b_mr); + CHECK_METHOD(exer_enc_myrec, c_mr, c_e_mr); + + CHECK_DECODE(bxer_dec_myrec, c_b_mr, MyRecord, c_mr); + CHECK_DECODE(exer_dec_myrec, c_e_mr, MyRecord, c_mr); + } + + + + control { + execute(tc_legacy_union_untagged()); + execute(tc_legacy_union_in_record_untagged()); + } + +} with { + encode "XML"; +} \ No newline at end of file diff --git a/regression_test/XML/LegacyUntaggedUnion/Makefile b/regression_test/XML/LegacyUntaggedUnion/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3a212e46467f3580ef9827a27916042acc136143 --- /dev/null +++ b/regression_test/XML/LegacyUntaggedUnion/Makefile @@ -0,0 +1,196 @@ +############################################################################## +# Copyright (c) 2000-2017 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: +# Szabo, Bence Janos +# +############################################################################## + + +TOPDIR := ../.. +include ../../Makefile.regression + +ORIG ?= . + +ifdef SRCDIR +ORIGSRC := $(ABS_SRC) +else +ORIGSRC := $(ORIG) +endif + +CPP := cpp + +# Flags for the C++ preprocessor (and makedepend as well): +#CPPFLAGS += + +# Flags for preprocessing TTCN-3 files: +#CPPFLAGS_TTCN3 += + +# Flags for the C++ compiler: +CXXFLAGS += -g -fmessage-length=0 + +# Flags for the linker: +LDFLAGS += -g + +WIN32_LIBS += -liconv +INTERIX_LIBS += -L/usr/local/lib -liconv +FREEBSD_LIBS += -liconv + +# Local flags for Titan (can be overridden from the environment or commandline) +TTCNFLAGS := -b -r -x -N + +# Flags for the TTCN-3 and ASN.1 compiler +# (common flags already set in Makefile.regression) +COMPILER_FLAGS += $(TTCNFLAGS) -a + +# $(sort ) also eliminates duplicates +COMPILER_FLAGS := $(sort $(COMPILER_FLAGS)) + +# Execution mode: (either ttcn3 or ttcn3-parallel) +TTCN3_LIB := ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) + +## +## + +# TTCN-3 modules of this project: +TTCN3_MODULES = converter.ttcn +# UTF8.ttcn + +# TTCN-3 modules to preprocess: +TTCN3_PP_MODULES := $(wildcard $(ORIGSRC)/*.ttcnpp) + + +# Files to include in TTCN-3 preprocessed modules: +TTCN3_INCLUDES = $(TOP_SRC)/XML/macros.ttcnin + +# TTCN-3 source files generated by the C preprocessor: +PREPROCESSED_TTCN3_MODULES := $(notdir $(TTCN3_PP_MODULES:.ttcnpp=.ttcn)) + + +# C++ source & header files generated from the TTCN-3 & ASN.1 modules of +# this project: +GENERATED_SOURCES := $(TTCN3_MODULES:.ttcn=.cc) $(PREPROCESSED_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)) +else ifdef SPLIT_TO_SLICES +POSTFIXES := $(foreach file, $(SPLIT_TO_SLICES), $(addsuffix $(file), _part_)) +POSTFIXES := $(foreach file, $(POSTFIXES), $(addprefix $(file), .cc)) +GENERATED_SOURCES2 := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), $(POSTFIXES))) +GENERATED_SOURCES += $(GENERATED_SOURCES2) +endif + +# C/C++ Source & header files of Test Ports, external functions and +# other modules: +USER_SOURCES := iconver.cc +USER_HEADERS := $(USER_SOURCES:.cc=.hh) + +# Object files of this project that are needed for the executable test suite: +OBJECTS := $(GENERATED_SOURCES:.cc=.o) $(USER_SOURCES:.cc=.o) + +# The name of the executable test suite: +TARGET := LegacyUnionUntagged$(RT2_SUFFIX)$(EXESUFFIX) + +# +# Rules for building the executable... +# + +all: $(TARGET) + +objects: $(OBJECTS) ; + +ifeq ($(findstring dynamic,$(TTCN3_LIB)),) +# not dynamic +CORELIB_BINARY := $(TTCN3_DIR)/lib/lib$(TTCN3_LIB).a +else +CORELIB_BINARY := $(TTCN3_DIR)/lib/lib$(TTCN3_LIB).so +endif + +# libttcn3.a appears twice; this should be harmless +$(TARGET): $(OBJECTS) $(CORELIB_BINARY) + $(CXX) $(LDFLAGS) -o $@ $(OBJECTS) \ + -L$(TTCN3_DIR)/lib -l$(TTCN3_LIB) \ + -L$(OPENSSL_DIR)/lib -lcrypto $($(PLATFORM)_LIBS) \ + || $(TTCN3_DIR)/bin/titanver $(OBJECTS) + +%.o: %.cc + @echo '(C++)' $<; $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< + +%.d: %.cc + @echo '(dep)' $<; $(CXX) -MM -MP $(CPPFLAGS) $(CXXFLAGS) $< >$@ + +# The preprocessing step +%.ttcn: %.ttcnpp $(TTCN3_INCLUDES) + $(CPP) -x c -nostdinc $(CPPFLAGS_TTCN3) $< $@ + +preprocess: $(PREPROCESSED_TTCN3_MODULES) ; + +$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile + @if [ ! -f $@ ]; then $(RM) compile; $(MAKE) compile; fi + +check: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES) + $(TTCN3_COMPILER) -s $(COMPILER_FLAGS) $^ + +compile:: $(firstword $(TTCN3_COMPILER)) + @if [ -f $@ ]; then $(RM) compile; $(MAKE) compile; fi +# if [ -f $(GENERATED_SOURCES) ]; then rm -f $(GENERATED_SOURCES); $(MAKE) $(GENERATED_SOURCES); fi + +compile:: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES) +# "modulepar boolean verbose" makes this unusable with old names + $(TTCN3_COMPILER) $(COMPILER_FLAGS) $^ - $? + touch $@ + +clean celan clena: + -$(RM) $(TARGET) $(OBJECTS) $(GENERATED_HEADERS) \ + $(GENERATED_SOURCES) $(PREPROCESSED_TTCN3_MODULES) compile \ + tags *.log + +distclean: clean + -$(RM) $(DEPFILES) + +# +# Add your rules here if necessary... +# + +.SUFFIXES: .asn .ttcn .ttcnpp + +RUN := $(shell which colortitan 2>/dev/null) +ifeq ($(firstword $(RUN)),no) +# stupid /bin/which on Solaris writes errors to stdout instead of stderr +RUN := +endif + +run: $(TARGET) + $(RUN) ./$^ + +debug: + $(MAKE) run RUN='gdb --args' + +vpath %.cc $(TOP_SRC)/iconv +vpath %.ttcn $(TOP_SRC)/iconv + + +dep: ; + +DEPFILES := $(OBJECTS:.o=.d) + +ifeq (,$(findstring n,$(MAKEFLAGS))) +ifeq (,$(filter clean distclean preprocess,$(MAKECMDGOALS))) +-include $(DEPFILES) +endif +endif + +# Only ttcnpp files contain tests +TESTS := $(PREPROCESSED_TTCN3_MODULES:.ttcn=) + +# Ability to run one control part +$(TESTS): $(TARGET) + $(RUN) ./$^ + +ifdef SRCDIR +$(foreach src, $(USER_SOURCES), $(eval vpath $(src) $(ABS_SRC))) +endif diff --git a/regression_test/XML/Makefile b/regression_test/XML/Makefile index a3eb1e51391cb83ae83eafc6699bb1301d4c1fe5..f2506c080c5b34897e3d7b485cbf82ddba94807a 100644 --- a/regression_test/XML/Makefile +++ b/regression_test/XML/Makefile @@ -30,7 +30,7 @@ endif XDIRS := $(wildcard $(SHADOWED)) xsdConverter \ HM60295 HN15589 HQ30408 HR49727 HU13380 $(RT2_ONLY) \ XmlWorkflow tpdValidTest AbstractBlock UseNilLong AttributeFormDefault \ -RecordOmit XSDBaseType +RecordOmit XSDBaseType LegacyUntaggedUnion # List of fake targets: .PHONY: all dep clean run $(XDIRS) $(addsuffix /, $(XDIRS)) profile diff --git a/usrguide/referenceguide.doc b/usrguide/referenceguide.doc index e498fb6d296e76bfbe9784d71c15063c12e60b77..c103a2285c6f0be226f1be38a92e768712de65f7 100644 Binary files a/usrguide/referenceguide.doc and b/usrguide/referenceguide.doc differ