From: erititan Date: Mon, 16 Mar 2015 09:45:12 +0000 (+0100) Subject: Sync with 5.2.0 X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=af7104877b9819f9e11f3ca6109eda961e971478;p=deliverable%2Ftitan.core.git Sync with 5.2.0 --- diff --git a/Install/.gitignore b/Install/.gitignore index 2460008..3d75889 100644 --- a/Install/.gitignore +++ b/Install/.gitignore @@ -1 +1 @@ -!Makefile +!Makefile \ No newline at end of file diff --git a/README.cygwin b/README.cygwin index 43be04a..4b683ee 100644 --- a/README.cygwin +++ b/README.cygwin @@ -1,3 +1,11 @@ +****************************************************************************** +* 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 +****************************************************************************** + Cygwin setup - If Cygwin is installed already, refresh your Cygwin installation Titan is always build for the newest Cygwin version available. diff --git a/README.linux b/README.linux index 0666677..9becb31 100644 --- a/README.linux +++ b/README.linux @@ -1,113 +1,118 @@ -Build and install Titan on Linux - -1.Install required libraries: -(examples are given for Ubuntu 12.04/14.04; for other Linuxes, pls. use the relevant library installation method) - -sudo apt-get install g++ expect libssl-dev libxml2-dev libncurses5-dev flex bison -xutils-dev is needed by makedepend: -sudo apt-get install xutils-dev -The following packages may be needed for titan_eclipse/automatic_build: -sudo apt-get install ant xsltproc - -2.Clone the titan directory from git into /home//titan - -git clone https://github.com/eclipse/titan.core titan - -3. Configure the build - -cd titan -check that MakefileFOSS.cfg is present and has the following content: -cat MakefileFOSS.cfg - -# Configurations for the Free Open Source Software version -LICENSING := no -USAGE_STATS := no - - -Several build options are possible; for details on options , please read through the Makefile.cfg. -Options can be overridden by the content of a file named Makefile.personal which can be used to -adapt to local installation directories, change config options etc. -Below, a small number of typical scenarios are presented. - -1) JNI disabled - -The JNI interface is used by the Eclipse Titan Executor or by the Java Executor API. -If you don't need them , Titan can be compiled without JNI. - -Create ~/titan/Makefile.personal to override settings in Makefile.cfg with the following content: -(replace paths with values relevant to your installation) - -TTCN3_DIR := /home//titan/Install -OPENSSL_DIR := /usr -#JDKDIR := /usr/lib/jvm/java-7-openjdk-amd64 -XMLDIR := /usr -JNI := no -GEN_PDF := no - - - - -2) JNI enabled - -install JDK into /home//jdk - -Create ~/titan/Makefile.personal to override settings in Makefile.cfg with the following content: -(replace paths with values relevant to your installation) - -TTCN3_DIR := /home//titan/Install -OPENSSL_DIR := /usr -JDKDIR := /usr/lib/jvm/java-7-openjdk-amd64 -XMLDIR := /usr -JNI := yes -GEN_PDF := no - - - -3. Run make - -make - -4. Run make install - -make install - -This will install Titan into /home//titan/Install - -5. Optionally , run function/regression tests - -set environment variable TTCN3_DIR to /home//titan/Install - -(setenv TTCN3_DIR /home//titan/Install for csh, -export TTCN3_DIR=/home//titan/Install for bash ) - - - -cd /home//titan/function_test - -in the following Makefiles - -XER_EncDec/Makefile -Text_EncDec/Makefile -RAW_EncDec/Makefile - -edit the value of XMLDIR to match your installation values - -run the tests - -make - -( or make |& tee outputfile if you want to save the output for verification) - -cd /home//titan/regression_test -make run - -( or make run |& tee outputfile if you want to save the output for verification) - -These tests might run for half an hour (regr.tests) to two hours (func.tests) - -6. Optionally , copy Titan into its' final directory. -From here on, you can continue with the Titan installation guide, see /Install/docs, to set environment variables etc. - - - - +****************************************************************************** +* 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 +****************************************************************************** + +Build and install Titan on Linux + +1.Install required libraries: +(examples are given for Ubuntu 12.04/14.04; for other Linuxes, pls. use the relevant library installation method) + +sudo apt-get install g++ expect libssl-dev libxml2-dev libncurses5-dev flex bison +xutils-dev is needed by makedepend: +sudo apt-get install xutils-dev +The following packages may be needed for titan_eclipse/automatic_build: +sudo apt-get install ant xsltproc + +2.Clone the titan directory from git into /home//titan + +git clone https://github.com/eclipse/titan.core titan + +3. Configure the build + +cd titan +check that MakefileFOSS.cfg is present and has the following content: +cat MakefileFOSS.cfg + +# Configurations for the Free Open Source Software version +LICENSING := no +USAGE_STATS := no + + +Several build options are possible; for details on options , please read through the Makefile.cfg. +Options can be overridden by the content of a file named Makefile.personal which can be used to +adapt to local installation directories, change config options etc. +Below, a small number of typical scenarios are presented. + +1) JNI disabled + +The JNI interface is used by the Eclipse Titan Executor or by the Java Executor API. +If you don't need them , Titan can be compiled without JNI. + +Create ~/titan/Makefile.personal to override settings in Makefile.cfg with the following content: +(replace paths with values relevant to your installation) + +TTCN3_DIR := /home//titan/Install +OPENSSL_DIR := /usr +#JDKDIR := /usr/lib/jvm/java-7-openjdk-amd64 +XMLDIR := /usr +JNI := no +GEN_PDF := no + + + + +2) JNI enabled + +install JDK into /home//jdk + +Create ~/titan/Makefile.personal to override settings in Makefile.cfg with the following content: +(replace paths with values relevant to your installation) + +TTCN3_DIR := /home//titan/Install +OPENSSL_DIR := /usr +JDKDIR := /usr/lib/jvm/java-7-openjdk-amd64 +XMLDIR := /usr +JNI := yes +GEN_PDF := no + + + +3. Run make + +make + +4. Run make install + +make install + +This will install Titan into /home//titan/Install + +5. Optionally , run function/regression tests + +set environment variable TTCN3_DIR to /home//titan/Install + +(setenv TTCN3_DIR /home//titan/Install for csh, +export TTCN3_DIR=/home//titan/Install for bash ) + + + +cd /home//titan/function_test + +in the following Makefiles + +XER_EncDec/Makefile +Text_EncDec/Makefile +RAW_EncDec/Makefile + +edit the value of XMLDIR to match your installation values + +run the tests + +make + +( or make |& tee outputfile if you want to save the output for verification) + +cd /home//titan/regression_test +make run + +( or make run |& tee outputfile if you want to save the output for verification) + +These tests might run for half an hour (regr.tests) to two hours (func.tests) + +6. Optionally , copy Titan into its' final directory. +From here on, you can continue with the Titan installation guide, see /Install/docs, to set environment variables etc. + diff --git a/README.md b/README.md index b920dec..8dfedb8 100644 --- a/README.md +++ b/README.md @@ -20,26 +20,26 @@ http://polarsys.org/sites/default/files/custom_uploads/TITAN%20Datasheet%20A4%20 ##Binaries and SHA512 checksums for a number of Linux platforms can be downloaded from: -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.1.0-sles10.tgz -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.1.0-sles10.tgz.sha512 -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.1.2-sled10.2.tgz -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.1.2-sled10.2.tgz.sha512 -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.3-SLED11.1.tgz -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.3-SLED11.1.tgz.sha512 -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.1.2-rhel5.tgz -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.1.2-rhel5.tgz.sha512 -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-SLED11.1.tgz -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-SLED11.1.tgz.sha512 -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-sled11.0.tgz -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-sled11.0.tgz.sha512 -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-sles11.1.tgz -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-sles11.1.tgz.sha512 -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.4.5-rhel6.tgz -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.4.5-rhel6.tgz.sha512 -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.6-ubuntu12.04.tgz -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.6-ubuntu12.04.tgz.sha512 -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.8-ubuntu14.04.tgz -* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.8-ubuntu14.04.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux32-gcc4.1.0-sles10.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux32-gcc4.1.0-sles10.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux32-gcc4.1.2-sled10.2.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux32-gcc4.1.2-sled10.2.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux32-gcc4.3-SLED11.1.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux32-gcc4.3-SLED11.1.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.1.2-rhel5.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.1.2-rhel5.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.3-SLED11.1.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.3-SLED11.1.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.3-sled11.0.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.3-sled11.0.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.3-sles11.1.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.3-sles11.1.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.4.5-rhel6.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.4.5-rhel6.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.6-ubuntu12.04.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.6-ubuntu12.04.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.8-ubuntu14.04.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.2.pl0-linux64-gcc4.8-ubuntu14.04.tgz.sha512 # Related products: diff --git a/README.md~ b/README.md~ new file mode 100644 index 0000000..b920dec --- /dev/null +++ b/README.md~ @@ -0,0 +1,79 @@ +# titan.core + +TTCN-3 is a standardized, modular language specifically designed for testing. +Eclipse Titan offers a free and open source (FOSS) compiler both for TTCN-3 and for +ASN.1 (Abstract Syntax Notation One). + +# Standards page (also including downloadable code): + +* http://www.ttcn-3.org/ + +# Main project page: + +* https://projects.eclipse.org/projects/tools.titan + +##Introductory video of a presentation about Titan held at EclipseCon 2014: +* https://www.youtube.com/watch?v=2knzZuwzn-Y. + +##Titan Datasheet on polarsys.org: +http://polarsys.org/sites/default/files/custom_uploads/TITAN%20Datasheet%20A4%202.1.pdf + +##Binaries and SHA512 checksums for a number of Linux platforms can be downloaded from: + +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.1.0-sles10.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.1.0-sles10.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.1.2-sled10.2.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.1.2-sled10.2.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.3-SLED11.1.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux32-gcc4.3-SLED11.1.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.1.2-rhel5.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.1.2-rhel5.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-SLED11.1.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-SLED11.1.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-sled11.0.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-sled11.0.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-sles11.1.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.3-sles11.1.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.4.5-rhel6.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.4.5-rhel6.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.6-ubuntu12.04.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.6-ubuntu12.04.tgz.sha512 +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.8-ubuntu14.04.tgz +* https://www.eclipse.org/downloads/download.php?file=/titan/ttcn3-5.1.pl0-linux64-gcc4.8-ubuntu14.04.tgz.sha512 + + +# Related products: + +## Test Ports: + +* https://github.com/eclipse/titan.TestPorts.Common_Components.Abstract_Socket +* https://github.com/eclipse/titan.TestPorts.HTTPmsg +* https://github.com/eclipse/titan.TestPorts.LANL2asp +* https://github.com/eclipse/titan.TestPorts.PCAPasp +* https://github.com/eclipse/titan.TestPorts.PIPEasp +* https://github.com/eclipse/titan.TestPorts.SCTPasp +* https://github.com/eclipse/titan.TestPorts.SIPmsg +* https://github.com/eclipse/titan.TestPorts.SQLasp +* https://github.com/eclipse/titan.TestPorts.TCPasp +* https://github.com/eclipse/titan.TestPorts.TELNETasp +* https://github.com/eclipse/titan.TestPorts.UDPasp + + +## Protocol Modules: + +* https://github.com/eclipse/titan.ProtocolModules.COMMON +* https://github.com/eclipse/titan.ProtocolModules.DHCP +* https://github.com/eclipse/titan.ProtocolModules.DHCPv6 +* https://github.com/eclipse/titan.ProtocolModules.DIAMETER_ProtocolModule_Generator +* https://github.com/eclipse/titan.ProtocolModules.DNS +* https://github.com/eclipse/titan.ProtocolModules.ICMP +* https://github.com/eclipse/titan.ProtocolModules.ICMPv6 +* https://github.com/eclipse/titan.ProtocolModules.IP +* https://github.com/eclipse/titan.ProtocolModules.RTP +* https://github.com/eclipse/titan.ProtocolModules.RTSP +* https://github.com/eclipse/titan.ProtocolModules.SMPP +* https://github.com/eclipse/titan.ProtocolModules.SMTP +* https://github.com/eclipse/titan.ProtocolModules.SNMP +* https://github.com/eclipse/titan.ProtocolModules.TCP +* https://github.com/eclipse/titan.ProtocolModules.UDP +* https://github.com/eclipse/titan.ProtocolModules.XMPP diff --git a/README.mingw b/README.mingw new file mode 100644 index 0000000..6169d87 --- /dev/null +++ b/README.mingw @@ -0,0 +1,48 @@ +****************************************************************************** +* 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 +****************************************************************************** + +MinGW setup + + (A) Download the MinGW installer from the MinGW site: + http://www.mingw.org/ + + (B) Follow the install steps found on the MinGW getting started page: + http://www.mingw.org/wiki/getting_started + Select the mingw-gcc-v3 packages because Titan only compiles + with older gcc. If you select the gcc4 packages, then the make process + stops immediately with some error messages. Select the msys packages too. + + (C) Check the PATH system variable: + System -> Advanced system settings -> Environment Variables -> Path + The MinGW installation path must be present to use the installed + executables and files. For example: + echo %PATH% + C:\MinGW\bin;C:\MinGW\usr\bin... + + (D) Working environment: + Use the \msys\\msys.bat file to start a shell. + Download and extract the Titan source files and folders to a directory, + and create a Makefile.personal in the top directory. Please check the + installation guide and set all the needed variables like TTCN3_DIR. The + MinGW compilation needs a few extra changes in the Makefile.cfg also. Set + the PLATFORM and MINGW values: + PLATFORM := WIN32 + MINGW := -DMINGW -mno-cygwin + + (E) Compile Titan: + cd titan + make -j + make install + The compiled files will be placed into the ./Install directory. + + (F) If the build process stops with a Windows error message saying that some files + are missing, search for the indicated Cygwin package and download it from the Cygwin page. + You can search fast and easily with the Cygwin Package Search tool: + https://cygwin.com/cgi-bin2/package-grep.cgi + Extract the downloaded package into the MinGW installation directory, and + restart the build process. diff --git a/common/config_preproc_la.l b/common/config_preproc_la.l index 316b634..1699f33 100644 --- a/common/config_preproc_la.l +++ b/common/config_preproc_la.l @@ -142,6 +142,7 @@ MACRO_REFERENCE_INT \$"{"{WS}{TTCN3IDENTIFIER}{WS}(","{WS}integer{WS})?"}" } "["{WS}LOGGING{WS}"]" BEGIN(INITIAL); +"["{WS}PROFILER{WS}"]" BEGIN(INITIAL); "["{WS}EXECUTE{WS}"]" BEGIN(INITIAL); "["{WS}EXTERNAL_COMMANDS{WS}"]" BEGIN(INITIAL); "["{WS}GROUPS{WS}"]" BEGIN(INITIAL); diff --git a/common/version.h b/common/version.h index b6472c0..a72a783 100644 --- a/common/version.h +++ b/common/version.h @@ -10,7 +10,7 @@ /* Version numbers */ #define TTCN3_MAJOR 5 -#define TTCN3_MINOR 1 +#define TTCN3_MINOR 2 #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 50100 +#define TTCN3_VERSION 50200 /* 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 3f45141..4cfcad2 100644 --- a/compiler2/AST.cc +++ b/compiler2/AST.cc @@ -263,17 +263,10 @@ namespace Common { return versions; } - void Modules::add_types_to_json_schema(JSON_Tokenizer& json) + void Modules::generate_json_schema(JSON_Tokenizer& json, map& json_refs) { for(size_t i = 0; i < mods_v.size(); ++i) { - mods_v[i]->add_types_to_json_schema(json); - } - } - - void Modules::add_func_to_json_schema(map& json_refs) - { - for(size_t i = 0; i < mods_v.size(); ++i) { - mods_v[i]->add_func_to_json_schema(json_refs); + mods_v[i]->generate_json_schema(json, json_refs); } } @@ -807,6 +800,12 @@ namespace Common { mputprintf(effective_module_functions, "%s\"%s\"", (effective_module_functions ? ", " : ""), get_modid().get_dispname().c_str()); } + if (profiler_enabled && MOD_TTCN == get_moduletype()) { + 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()); + } } output->source.static_function_bodies = mputstr(output->source.static_function_bodies, output->functions.pre_init); @@ -844,6 +843,12 @@ namespace Common { mputprintf(effective_module_functions, "%s\"%s\"", (effective_module_functions ? ", " : ""), get_modid().get_dispname().c_str()); } + if (profiler_enabled && MOD_TTCN == get_moduletype()) { + 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()); + } } output->source.static_function_bodies = mputstr(output->source.static_function_bodies, output->functions.post_init); diff --git a/compiler2/AST.hh b/compiler2/AST.hh index 693559c..ddb99c2 100644 --- a/compiler2/AST.hh +++ b/compiler2/AST.hh @@ -116,14 +116,15 @@ namespace Common { void generate_code(CodeGenHelper& cgh); void dump(unsigned level=1) const; - /** Generates JSON schema segments for the types defined in the modules - * and adds them to the JSON schema parameter. */ - void add_types_to_json_schema(JSON_Tokenizer& json); - - /** Generates JSON schemas containing references to the types defined in the - * modules. Information related to the types' JSON encoding and decoding - * functions is also inserted after the references. */ - void add_func_to_json_schema(map& json_refs); + /** Generates JSON schema segments for the types defined in the modules, + * and references to these types. Information related to the types' + * JSON encoding and decoding functions is also inserted after the references. + * + * @param json JSON document containing the main schema, schema segments for + * the types will be inserted here + * @param json_refs map of JSON documents containing the references and function + * info related to each type */ + void generate_json_schema(JSON_Tokenizer& json, map& json_refs); }; /** @@ -391,15 +392,15 @@ namespace Common { void generate_code(CodeGenHelper& cgh); virtual void dump(unsigned level) const; - /** Generates JSON schema segments for the types defined in the module - * and adds them to the JSON schema parameter. */ - virtual void add_types_to_json_schema(JSON_Tokenizer&) = 0; - - /** Generates JSON schemas containing references to the types that have JSON - * encoding and/or decoding functions declared in the module. Information - * related to these functions is also inserted after the references - * (only for TTCN-3 modules). */ - virtual void add_func_to_json_schema(map&) = 0; + /** Generates JSON schema segments for the types defined in the modules, + * and references to these types. Information related to the types' + * JSON encoding and decoding functions is also inserted after the references. + * + * @param json JSON document containing the main schema, schema segments for + * the types will be inserted here + * @param json_refs map of JSON documents containing the references and function + * info related to each type */ + virtual void generate_json_schema(JSON_Tokenizer& json, map& json_refs) = 0; }; /** diff --git a/compiler2/CompilerError.cc b/compiler2/CompilerError.cc index 88b5acc..2b438fa 100644 --- a/compiler2/CompilerError.cc +++ b/compiler2/CompilerError.cc @@ -298,7 +298,7 @@ namespace Common { if (++error_count >= max_errors) { fputs("Maximum number of errors reached, aborting.\n", stderr); fflush(stderr); - abort(); + exit(EXIT_FAILURE); } } diff --git a/compiler2/Makefile b/compiler2/Makefile index e5a1833..61ef64f 100644 --- a/compiler2/Makefile +++ b/compiler2/Makefile @@ -68,7 +68,7 @@ main.cc Real.cc Setting.cc SigParam.cc string.cc subtype.cc Stopwatch.cc \ Type.cc Type_chk.cc Type_codegen.cc TypeCompat.cc \ Typestuff.cc ustring.cc Value.cc Valuestuff.cc XerAttributes.cc subtypestuff.cc CodeGenHelper.cc -MFGEN_SOURCES := makefile.c xpather.cc +MFGEN_SOURCES := makefile.c xpather.cc ProjectGenHelper.cc TCOV2LCOV_SOURCES := tcov2lcov.cc diff --git a/compiler2/ProjectGenHelper.cc b/compiler2/ProjectGenHelper.cc new file mode 100644 index 0000000..991449e --- /dev/null +++ b/compiler2/ProjectGenHelper.cc @@ -0,0 +1,744 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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 "ProjectGenHelper.hh" +#include "../common/memory.h" + +#include "error.h" +#include +#include +#include +#include + +const std::string ProjectDescriptor::emptyString = std::string(); + +ProjectDescriptor::ProjectDescriptor(const char * name) : + projectName(std::string(name)), + tpdFileName(), + targetExecutableName(), + projectAbsTpdDir(), + projectAbsWorkingDir(), + projectWorkingDir(), + library(false), + dynamicLinked(false), + referencedProjects(), + refProjWorkingDirs(), + libSearchPaths(), + linkerLibraries(), + ttcn3ModuleNames(), + asn1ModuleNames(), + userSources(), + userHeaders(), + ttcnPP(), + initialized(false) +{} + +void ProjectDescriptor::cleanUp() +{ + referencedProjects.clear(); + refProjWorkingDirs.clear(), + libSearchPaths.clear(); + linkerLibraries.clear(); + ttcn3ModuleNames.clear(); + asn1ModuleNames.clear(); + userSources.clear(); + userHeaders.clear(); + ttcnPP.clear(); +} + +bool ProjectDescriptor::isInitialized() +{ + if (!projectName.empty() && + !targetExecutableName.empty() && + !projectAbsTpdDir.empty() && + !projectAbsWorkingDir.empty() && + !projectWorkingDir.empty()) + initialized = true; + return initialized; +} + +void ProjectDescriptor::setTPDFileName(const char* name) +{ + const char SEPARATOR = '/'; + std::string fileName(name); + size_t refProjPos = fileName.find_last_of(SEPARATOR); + if (std::string::npos == refProjPos) { + tpdFileName = fileName; + } + else { + tpdFileName = fileName.substr(refProjPos + 1); + } +} + +void ProjectDescriptor::setProjectAbsWorkingDir(const char* name) +{ + if (!name) { + ERROR("No path was given to the working directory. Check if 'r' flag is set "); + return; + } + projectAbsWorkingDir = std::string(name); + ProjectGenHelper::Instance().setRootDirOS(name); +} + +void ProjectDescriptor::addToReferencedProjects(const char* refProjName) +{ + std::vector::iterator it; + for (it = referencedProjects.begin(); it != referencedProjects.end(); ++it) { + if (*it == std::string(refProjName)) return; + } + referencedProjects.push_back(std::string(refProjName)); +} + +void ProjectDescriptor::addToRefProjWorkingDirs(const std::string& subProjDir) +{ + std::vector::iterator it; + for (it = refProjWorkingDirs.begin(); it != refProjWorkingDirs.end(); ++it) { + if (*it == subProjDir) return; + } + refProjWorkingDirs.push_back(subProjDir); +} + +bool ProjectDescriptor::hasLinkerLibTo(const std::string& refProjName) const +{ + ProjectDescriptor* refProj = ProjectGenHelper::Instance().getTargetOfProject(refProjName.c_str()); + for (size_t i = 0; i < referencedProjects.size(); ++i){ + if (refProj && refProj->library) return true; + } + return false; +} + +bool ProjectDescriptor::hasLinkerLib(const char* libName) const +{ + std::string linkerLibName(libName); + std::vector::const_iterator it; + for (it = linkerLibraries.begin(); it != linkerLibraries.end(); ++it) { + if (*it == linkerLibName) return true; + } + return false; +} + +void ProjectDescriptor::addToLibSearchPaths(const char* libSearchPath) +{ + std::string searchPath(libSearchPath); + std::vector::iterator it; + for (it = libSearchPaths.begin(); it != libSearchPaths.end(); ++it) { + if (*it == searchPath) return; + } + libSearchPaths.push_back(libSearchPath); +} + +void ProjectDescriptor::addToLinkerLibs(const char* linkerLibs) +{ + std::string llibs(linkerLibs); + std::vector::iterator it; + for (it = linkerLibraries.begin(); it != linkerLibraries.end(); ++it) { + if (*it == llibs) return; + } + linkerLibraries.push_back(linkerLibs); +} + +size_t ProjectDescriptor::getLibSearchPathIndex(const std::string& subProjName) const +{ + + for (size_t i = 0; i < libSearchPaths.size(); ++i) { + if (std::string::npos != libSearchPaths[i].find(subProjName)) + return i; + } + return std::numeric_limits::max(); +} + +const char* ProjectDescriptor::getLibSearchPath(const std::string& subProjName) const +{ + for (size_t i = 0; i < libSearchPaths.size(); ++i) { + if (std::string::npos != libSearchPaths[i].find(subProjName)) + return libSearchPaths[i].c_str(); + } + return NULL; +} + +bool ProjectDescriptor::hasTtcn3ModuleName(const char* moduleName) const +{ + std::string modName(moduleName); + std::vector::const_iterator it; + for (it = ttcn3ModuleNames.begin(); it != ttcn3ModuleNames.end(); ++it) { + if (*it == modName) return true; + } + return false; +} + +bool ProjectDescriptor::hasAsn1ModuleName(const char* moduleName) const +{ + std::string modName(moduleName); + std::vector::const_iterator it; + for (it = asn1ModuleNames.begin(); it != asn1ModuleNames.end(); ++it) { + if (*it == modName) return true; + } + return false; +} + +bool ProjectDescriptor::hasUserSource(const char* userSourceName) const +{ + std::string sourceName(userSourceName); + std::vector::const_iterator it; + for (it = userSources.begin(); it != userSources.end(); ++it) { + if (*it == sourceName) return true; + } + return false; +} + +bool ProjectDescriptor::hasUserHeader(const char* userHeaderName) const +{ + std::string headerName(userHeaderName); + std::vector::const_iterator it; + for (it = userHeaders.begin(); it != userHeaders.end(); ++it) { + if (*it == headerName) return true; + } + return false; +} + +bool ProjectDescriptor::hasTtcn3PP(const char* ttcnPPName) const +{ + std::string ttcnPPFile(ttcnPPName); + std::vector::const_iterator it; + for (it = ttcnPP.begin(); it != ttcnPP.end(); ++it) { + if (*it == ttcnPPFile) return true; + } + return false; +} + +std::string ProjectDescriptor::setRelativePathTo(const std::string& absPathTo) +{ + if (projectAbsWorkingDir.empty()) return std::string(); + const char SEPARATOR = '/'; + if (projectAbsWorkingDir.at(0) != SEPARATOR || absPathTo.at(0) != SEPARATOR) + ERROR("Expecting absolute path to generate LinkerLibSearchPath "); + size_t length = projectAbsWorkingDir.size() > absPathTo.size() ? absPathTo.size() : projectAbsWorkingDir.size(); + size_t lastSlash = 0; + size_t i; + for(i = 0; i < length && projectAbsWorkingDir.at(i) == absPathTo.at(i); ++i) { + if (projectAbsWorkingDir.at(i) == SEPARATOR && absPathTo.at(i) == SEPARATOR) { + lastSlash = i; // the same path until now... + } + } + if (length == i) { // got subdirectory + if (projectAbsWorkingDir == absPathTo) { + return std::string("."); // the same pathes were given + } + else if ((projectAbsWorkingDir.size() > absPathTo.size() && projectAbsWorkingDir.at(length) == SEPARATOR) || + (projectAbsWorkingDir.size() < absPathTo.size() && absPathTo.at(length) == SEPARATOR)) + lastSlash = length; + } + + size_t slashCount = 0; + for (size_t i = lastSlash; i < projectAbsWorkingDir.size(); ++i) { + if (projectAbsWorkingDir.at(i) == SEPARATOR) + ++slashCount; + } + + std::string relPath; + const std::string upDir("../"); + for (size_t i = 0; i < slashCount; ++i) + relPath.append(upDir); + + std::string pathTo = absPathTo.substr(lastSlash+1); // we left the heading slash + relPath.append(pathTo); + return std::string(relPath); +} + +void ProjectDescriptor::print() +{ + fprintf( stderr, "project name %s and it is %s initialized\n", projectName.c_str(), isInitialized() ? "" : "not"); + fprintf( stderr, " target executable name %s\n",targetExecutableName.c_str()); + fprintf( stderr, " project abs TPD dir %s\n", projectAbsTpdDir.c_str()); + fprintf( stderr, " project abs working dir %s\n", projectAbsWorkingDir.c_str()); + fprintf( stderr, " project working dir %s\n", projectWorkingDir.c_str()); + fprintf( stderr, " project is %s\n", library ? "Library" : "Executable"); + fprintf( stderr, " project linking is %s\n", dynamicLinked ? "dynamic" : "static"); + std::vector::iterator it; + for (it = referencedProjects.begin(); it != referencedProjects.end(); ++it) { + fprintf( stderr, " Referenced project %s\n",(*it).c_str()); + } + for (it = refProjWorkingDirs.begin(); it != refProjWorkingDirs.end(); ++it) { + fprintf( stderr, " Working dir of referenced project %s\n",(*it).c_str()); + } + for (it = linkerLibraries.begin(); it != linkerLibraries.end(); ++it) { + fprintf( stderr, " Linker library %s\n", (*it).c_str()); + } + for (it = libSearchPaths.begin(); it != libSearchPaths.end(); ++it) { + fprintf( stderr, " Linker lib search path %s\n", (*it).c_str()); + } + for (it = ttcn3ModuleNames.begin(); it != ttcn3ModuleNames.end(); ++it) { + fprintf( stderr, " TTCN3 Module Name: %s\n", (*it).c_str()); + } + for (it = asn1ModuleNames.begin(); it != asn1ModuleNames.end(); ++it) { + fprintf( stderr, " ASN1 Module Name: %s\n", (*it).c_str()); + } + for (it = userSources.begin(); it != userSources.end(); ++it) { + fprintf( stderr, " Source Name: %s\n", (*it).c_str()); + } + for (it = userHeaders.begin(); it != userHeaders.end(); ++it) { + fprintf( stderr, " Header Name: %s\n", (*it).c_str()); + } + for (it = ttcnPP.begin(); it != ttcnPP.end(); ++it) { + fprintf( stderr, " TTCN PP Name: %s\n", (*it).c_str()); + } + fprintf( stderr, "\n"); +} + +ProjectGenHelper& ProjectGenHelper::Instance() +{ + static ProjectGenHelper singleton; + return singleton; +} + +const std::string ProjectGenHelper::emptyString = std::string(); + +ProjectGenHelper::ProjectGenHelper() : + nameOfTopLevelProject(), + rootDirOS(), + relPathToRootDirOS(), + Zflag(false), + Wflag(false), + Hflag(false), + projs(), + checkedProjs() +{} + +void ProjectGenHelper::addTarget(const char* projName) +{ + if (!Zflag) return; + if (projs.end() != projs.find(std::string(projName))) return; // we have it + ProjectDescriptor newLib(projName); + projs.insert(std::pair (std::string(projName), newLib)); +} + +void ProjectGenHelper::setToplevelProjectName(const char* name) +{ + if (!nameOfTopLevelProject.empty()) return; + nameOfTopLevelProject = std::string(name); +} + +void ProjectGenHelper::setRootDirOS( const char* name) +{ + if (rootDirOS.empty()) { + rootDirOS = std::string(name); + } + else { //compare the 2 string and get the common part + const char* root = rootDirOS.c_str(); + const char* head = root; + for (; *root++ == *name++; ) ; + size_t length = root - head - 1; //minus the non-matching + if (rootDirOS.size() > length) { + rootDirOS.resize(length); + } + } +} + +const std::string& ProjectGenHelper::getRootDirOS(const char* name) +{ + ProjectDescriptor* proj = getProject(name); + if (!proj) return emptyString; + relPathToRootDirOS = proj->setRelativePathTo(rootDirOS); + return relPathToRootDirOS; +} + +ProjectDescriptor* ProjectGenHelper::getTargetOfProject(const char* projName) +{ + if (!Zflag) return NULL; + if (projs.end() == projs.find(std::string(projName))) return NULL; + return getProject(projName); +} + +const ProjectDescriptor* ProjectGenHelper::getTargetOfProject(const char* projName) const +{ + if (!Zflag) return NULL; + if (projs.end() == projs.find(std::string(projName))) return NULL; + return getProject(projName); +} + +ProjectDescriptor* ProjectGenHelper::getProjectDescriptor(const char* targetName) +{ + if (!Zflag) return NULL; + for (std::map::iterator it = projs.begin(); it != projs.end(); ++it) { + if ((it->second).getTargetExecName() == std::string(targetName)) + return &(it->second); + } + return NULL; +} + +std::map::const_iterator ProjectGenHelper::getHead() const +{ + return projs.begin(); +} + +std::map::const_iterator ProjectGenHelper::getEnd() const +{ + return projs.end(); +} + +void ProjectGenHelper::addTtcn3ModuleToProject(const char* projName, const char* moduleName) +{ + if (!Zflag) return; + if (projs.end() == projs.find(std::string(projName))) return; + ProjectDescriptor* proj = getProject(projName); + if (proj && !proj->hasTtcn3ModuleName(moduleName)) { + proj->addTtcn3ModuleName(moduleName); + } +} + +void ProjectGenHelper::addAsn1ModuleToProject(const char* projName, const char* moduleName) +{ + if (!Zflag) return; + if (projs.end() == projs.find(std::string(projName))) return; + ProjectDescriptor* proj = getProject(projName); + if (proj &&!proj->hasAsn1ModuleName(moduleName)) { + proj->addAsn1ModuleName(moduleName); + } +} + +void ProjectGenHelper::addUserSourceToProject(const char* projName, const char* userSourceName) +{ + if (!Zflag) return; + if (projs.end() == projs.find(std::string(projName))) return; + ProjectDescriptor* proj = getProject(projName); + if (proj && !proj->hasUserSource(userSourceName)) { + proj->addUserSource(userSourceName); + } +} + +void ProjectGenHelper::addUserHeaderToProject(const char* projName, const char* userHeaderName) +{ + if (!Zflag) return; + if (projs.end() == projs.find(std::string(projName))) return; + ProjectDescriptor* proj = getProject(projName); + if (proj && !proj->hasUserHeader(userHeaderName)) { + proj->addUserHeader(userHeaderName); + } +} + +void ProjectGenHelper::addTtcnPPToProject(const char* projName, const char* ttcnPPName) +{ + if (!Zflag) return; + if (projs.end() == projs.find(std::string(projName))) return; + ProjectDescriptor* proj = getProject(projName); + if (proj && !proj->hasTtcn3PP(ttcnPPName)) { + proj->addTtcn3PP(ttcnPPName); + } +} + +void ProjectGenHelper::generateRefProjectWorkingDirsTo(const char* projName) +{ + if (!Zflag) return; + std::map::iterator iter = projs.find(projName); + if (projs.end() == iter) { + ERROR("Project \"%s\" is not found in the project hierarchy ", projName); + return; + } + if (nameOfTopLevelProject != (iter->second).getProjectName()) { + ERROR("Project \"%s\" is not the on the top-level ", projName); + return; + } + ProjectDescriptor* proj = &(iter->second); // the Top level project + + for (size_t i = 0; i < proj->numOfReferencedProjects(); ++i) { + const std::string& refProjName = proj->getReferencedProject(i); + ProjectDescriptor* refProj = getTargetOfProject(refProjName.c_str()); + if (!refProj) return; // for sure... + const std::string& absWorkingDir = refProj->getProjectAbsWorkingDir(); + if (!absWorkingDir.empty()) { + std::string relPath = proj->setRelativePathTo(absWorkingDir); + proj->addToRefProjWorkingDirs(relPath); + } + } +} + +size_t ProjectGenHelper::numOfLibs() const +{ + if (!Zflag) return 0; + size_t num = 0; + for (std::map::const_iterator it = projs.begin(); it != projs.end(); ++it) { + if ((it->second).isLibrary()) { + ++num; + } + } + return num; +} + +struct CompareStr +{ + bool operator () (const char* lhs, const char* rhs) { + int ret = strcmp(lhs, rhs); + return (0 > ret); + } +}; + +void ProjectGenHelper::getExternalLibs(std::vector& extLibs) +{ + if (!Zflag) return; + std::map libs; + for (std::map::iterator it = projs.begin(); it != projs.end(); ++it) { + if ((it->second).numOfLinkerLibs() > 0) { + for (size_t i = 0; i < (it->second).numOfLinkerLibs(); ++i) { + const char* key = (it->second).getLinkerLib(i); + const char* value = (it->second).getProjectName().c_str(); + libs.insert(std::pair(key,value)); // filter duplicates + } + } + } + std::map::iterator it; + for (it = libs.begin(); it != libs.end(); ++it) { + extLibs.push_back(it->first); + } +} + +void ProjectGenHelper::getExternalLibSearchPathes(std::vector& extLibPathes) +{ + if (!Zflag) return; + std::map libPathes; + for (std::map::iterator it = projs.begin(); it != projs.end(); ++it) { + if ((it->second).numOfLibSearchPaths() > 0) { + for (size_t i = 0; i < (it->second).numOfLibSearchPaths(); ++i) { + const char* key = (it->second).getLibSearchPath(i); + const char* value = (it->second).getProjectName().c_str(); + libPathes.insert(std::pair(key,value)); // filter duplicates + } + } + } + std::map::iterator it; + for (it = libPathes.begin(); it != libPathes.end(); ++it) { + extLibPathes.push_back(it->first); + } +} + +bool ProjectGenHelper::hasReferencedProject() +{ + if (!Zflag) return false; + ProjectDescriptor* topLevel = getTargetOfProject(nameOfTopLevelProject.c_str()); + if (topLevel && topLevel->numOfReferencedProjects()) return true; + return false; +} + +bool ProjectGenHelper::isTtcn3ModuleInLibrary(const char* moduleName) const +{ + if (!Zflag) return false; + for (std::map::const_iterator it = projs.begin(); it != projs.end(); ++it) { + if ((it->second).hasTtcn3ModuleName(moduleName) && (it->second).isLibrary()) return true; + } + return false; +} + +bool ProjectGenHelper::isAsn1ModuleInLibrary(const char* moduleName) const +{ + if (!Zflag) return false; + for (std::map::const_iterator it = projs.begin(); it != projs.end(); ++it) { + if ((it->second).hasAsn1ModuleName(moduleName) && (it->second).isLibrary()) return true; + } + return false; +} + +bool ProjectGenHelper::isSourceFileInLibrary(const char* fileName) const +{ + if (!Zflag || NULL == fileName) return false; + for (std::map::const_iterator it = projs.begin(); it != projs.end(); ++it) { + if ((it->second).hasUserSource(fileName) && (it->second).isLibrary()) return true; + } + return false; +} + +bool ProjectGenHelper::isHeaderFileInLibrary(const char* fileName) const +{ + if (!Zflag || NULL == fileName) return false; + + for (std::map::const_iterator it = projs.begin(); it != projs.end(); ++it) { + if ((it->second).hasUserHeader(fileName) && (it->second).isLibrary()) return true; + } + return false; +} + +bool ProjectGenHelper::isTtcnPPFileInLibrary(const char* fileName) const +{ + if (!Zflag || NULL == fileName) return false; + + for (std::map::const_iterator it = projs.begin(); it != projs.end(); ++it) { + if ((it->second).hasTtcn3PP(fileName) && (it->second).isLibrary()) return true; + } + return false; +} + +bool ProjectGenHelper::isCPPSourceFile(const char* fileName) const +{ + std::string fnStr(fileName); + size_t pos = fnStr.find_last_of('.'); + if (std::string::npos == pos) return false; + const std::string EXT_CC("cc"); + const std::string EXT_CPP("cpp"); + int length = 0; + if (std::string::npos != fnStr.find (EXT_CC, pos + 1)) + length = EXT_CC.size(); + else if (std::string::npos != fnStr.find (EXT_CPP, pos + 1)) + length = EXT_CPP.size(); + + if (length && fnStr.size() == pos + length + 1) + return true; + else + return false; +} + +bool ProjectGenHelper::isCPPHeaderFile(const char* fileName) const +{ + std::string fnStr(fileName); + size_t pos = fnStr.find_last_of('.'); + if (std::string::npos == pos) return false; + const std::string EXT_HPP("hpp"); + const std::string EXT_HH("hh"); + const std::string EXT_H("h"); + int length = 0; + if (std::string::npos != fnStr.find (EXT_HH, pos + 1)) + length = EXT_HH.size(); + else if (std::string::npos != fnStr.find (EXT_HPP, pos + 1)) + length = EXT_HPP.size(); + else if (std::string::npos != fnStr.find (EXT_H, pos + 1)) + length = EXT_H.size(); + + if (length && fnStr.size() == pos + length + 1) + return true; + else + return false; +} + +bool ProjectGenHelper::isTtcnPPFile(const char* fileName) const +{ + std::string fnStr(fileName); + size_t pos = fnStr.find_last_of('.'); + if (std::string::npos == pos) return false; + const std::string EXT_TTCNPP("ttcnpp"); + int length = 0; + if (std::string::npos != fnStr.find (EXT_TTCNPP, pos + 1)) + length = EXT_TTCNPP.size(); + + if (length && fnStr.size() == pos + length + 1) + return true; + else + return false; +} + +void ProjectGenHelper::print() +{ + if (!Zflag) return; + fprintf(stderr, "Top Level project : %s\n", nameOfTopLevelProject.c_str()); + for (std::map::iterator it = projs.begin(); it != projs.end(); ++it) { + (it->second).print(); + } +} + +bool ProjectGenHelper::sanityCheck() +{ + if (!Zflag) return true; + bool ret = true; +// if toplevel is a dynamic linked executable (not library) all executable shall set to the same linking method + { + ProjectDescriptor* topLevel = getTargetOfProject(nameOfTopLevelProject.c_str()); + bool isDynamicLinked = topLevel->getLinkingStrategy(); + if (!topLevel->isLibrary() && isDynamicLinked) { // dynamic linked executable + for (std::map::iterator it = projs.begin(); it != projs.end(); ++it) { + if (!(it->second).isLibrary()) { //if exectubale + if (isDynamicLinked != (it->second).getLinkingStrategy()) { + ERROR("project \"%s\" is set to %s linking. Sub project \"%s\" is set to %s linking. " + "All sub-level executable shall be set to the %s's type.", + nameOfTopLevelProject.c_str(), + isDynamicLinked ? "dynamic" : "static", + ((it->second).getProjectName()).c_str(), + isDynamicLinked ? "static" : "dynamic", + nameOfTopLevelProject.c_str()); + ret = false; + } + } + } + } + } + +// under a dynamic linked library every project shall be linked dynamic library too. + { + checkedProjs.clear(); + bool found = false; // search for executable under dynamic linked library + char* execName = NULL; + for (std::map::reverse_iterator rit = projs.rbegin(); rit != projs.rend(); ++rit) { + if ((rit->second).isLibrary() && (rit->second).getLinkingStrategy()) { //dynamic library + ProjectDescriptor& proj = rit->second; + found = DynamicLibraryChecker(&proj, found, &execName); + if (found) { + ERROR("Project \"%s\" is dynamic linked library. Sub project \"%s\" is executable.\n" + "in TPD file, %s's all sub-level defaultTarget shall be set library too.", + proj.getProjectName().c_str(), execName, proj.getProjectName().c_str()); + ret = false; + break; + } + } + } + } + + return ret; +} + +ProjectDescriptor* ProjectGenHelper::getProject(const char* projName) +{ + if (!projName) return NULL; + for (std::map::iterator it = projs.begin(); it != projs.end(); ++it) { + if (it->first == std::string(projName)) { + return &(it->second); + } + } + return NULL; +} + +const ProjectDescriptor* ProjectGenHelper::getProject(const char* projName) const +{ + if (!projName) return NULL; + for (std::map::const_iterator it = projs.begin(); it != projs.end(); ++it) { + if (it->first == std::string(projName)) { + return &(it->second); + } + } + return NULL; +} + + +void ProjectGenHelper::cleanUp() +{ + if (!Zflag) return; + checkedProjs.clear(); + for (std::map::iterator it = projs.begin(); it != projs.end(); ++it) { + (it->second).cleanUp(); + } +} + +bool ProjectGenHelper::DynamicLibraryChecker(const ProjectDescriptor* desc, + bool& found, + char** executableName) +{ + if (found || !desc) return true; + for (size_t i = 0; i < desc->numOfReferencedProjects(); ++i) { + char* refProjName = const_cast (desc->getReferencedProject(i).c_str()); + const ProjectDescriptor* subProj = getTargetOfProject(refProjName); + if (0 == checkedProjs.count(subProj->getProjectName())) { + if (subProj->isLibrary()) { + found = DynamicLibraryChecker(subProj, found, executableName); + } + else { // search for executable under dynamic linked library + found = true; + *executableName = refProjName; + break; + } + } + } + // it is checked, no such executable was found. Store it not to iterate again + if (!found) + checkedProjs.insert(std::pair + (desc->getProjectName(), desc)); + return found; +} + diff --git a/compiler2/ProjectGenHelper.hh b/compiler2/ProjectGenHelper.hh new file mode 100644 index 0000000..638633b --- /dev/null +++ b/compiler2/ProjectGenHelper.hh @@ -0,0 +1,157 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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 +/////////////////////////////////////////////////////////////////////////////// +#ifndef _LIB_GEN_HELPER_HH +#define _LIB_GEN_HELPER_HH +#include +#include +#include +#include +class ProjectGenHelper; +class ProjectDescriptor { +public: + explicit ProjectDescriptor(const char* name); + ~ProjectDescriptor() { cleanUp(); }; + + const std::string& getProjectName() const { return projectName; } + void setTPDFileName( const char* name); + const std::string& getTPDFileName() const { return tpdFileName; } + void setTargetExecName(const char* name) { targetExecutableName = std::string(name); } + const std::string& getTargetExecName() const { return targetExecutableName; } + void setProjectAbsTpdDir(const char* name) { projectAbsTpdDir = std::string(name); } + const std::string& getProjectAbsTpdDir() const { return projectAbsTpdDir; } + void setProjectAbsWorkingDir(const char* name); + void setProjectWorkingDir(const char* name) { projectWorkingDir = std::string(name); } + const std::string& getProjectAbsWorkingDir() const { return projectAbsWorkingDir; } + const std::string& getProjectWorkingDir() const { return projectWorkingDir; } + void setLinkingStrategy(bool strategy) { dynamicLinked = strategy; } + bool getLinkingStrategy() const { return dynamicLinked; } + void setLibrary(bool isLib) { library = isLib; } + bool isLibrary() const { return library; } + bool isInitialized(); + void addToReferencedProjects(const char* refProjName); + void addToRefProjWorkingDirs(const std::string& subProjDir); + bool hasLinkerLibTo(const std::string& refProjName) const; + bool hasLinkerLib(const char* libName) const; // Linker Lib got from TPD + void addToLibSearchPaths(const char* libSearchPath); + void addToLinkerLibs(const char* linkerLibs); + void print(); + void cleanUp(); + size_t numOfReferencedProjects() const { return referencedProjects.size(); }; + size_t numOfRefProjWorkingDirs() const { return refProjWorkingDirs.size(); }; + size_t numOfLibSearchPaths() const { return libSearchPaths.size(); }; + size_t numOfLinkerLibs() const { return linkerLibraries.size(); }; + const std::string& getReferencedProject(size_t index) const + { return index < referencedProjects.size() ? referencedProjects[index] : emptyString; }; + const std::string& getRefProjWorkingDir(size_t index) const + { return index < refProjWorkingDirs.size() ? refProjWorkingDirs[index] : emptyString; }; + const char* getLibSearchPath(const std::string& subProjName) const; + const char* getLibSearchPath(size_t index) const { return libSearchPaths[index].c_str(); }; + const char* getLinkerLib(const std::string& subProjName) const; + const char* getLinkerLib(size_t index) const { return linkerLibraries[index].c_str(); }; + size_t getLibSearchPathIndex(const std::string& subProjName) const; + void setLibSearchPath(size_t index, const std::string& relPath) { libSearchPaths[index] = relPath; }; + void addTtcn3ModuleName(const char* name) { ttcn3ModuleNames.push_back(name); }; + bool hasTtcn3ModuleName(const char* moduleName) const; + void addAsn1ModuleName(const char* name) { asn1ModuleNames.push_back(name); }; + bool hasAsn1ModuleName(const char* moduleName) const; + void addUserSource(const char* name) { userSources.push_back(name); }; + bool hasUserSource(const char* userSourceName) const; + void addUserHeader(const char* name) { userHeaders.push_back(name); }; + bool hasUserHeader(const char* userHeaderName) const; + void addTtcn3PP(const char* name) { ttcnPP.push_back(name); }; + bool hasTtcn3PP(const char* ttcnPPName) const; + std::string setRelativePathTo(const std::string& absPathTo); + +private: + static const std::string emptyString; + std::string projectName; + std::string tpdFileName; + std::string targetExecutableName; //Library or Executable(only the top level) + std::string projectAbsTpdDir; + std::string projectAbsWorkingDir; + std::string projectWorkingDir; + bool library; + bool dynamicLinked; + std::vector referencedProjects; + std::vector refProjWorkingDirs; + std::vector libSearchPaths; + std::vector linkerLibraries; + std::vector ttcn3ModuleNames; + std::vector asn1ModuleNames; + std::vector userSources; // *.cc ; *.cpp + std::vector userHeaders; // *.hh ; *.h ; *.hpp + std::vector ttcnPP; // *.ttcnpp + bool initialized; +}; + +class ProjectGenHelper { +public: + static ProjectGenHelper &Instance(); + ~ProjectGenHelper() { cleanUp(); }; + void setZflag(bool flag) { Zflag = flag; }; + bool getZflag() const { return Zflag; }; + void setWflag(bool flag) { Wflag = flag; }; + bool getWflag() const { return Wflag; }; + void setHflag(bool flag) { Hflag = flag; }; + bool getHflag() const { return Hflag; }; + void setToplevelProjectName(const char* name); + const std::string& getToplevelProjectName() const { return nameOfTopLevelProject; }; + void setRootDirOS(const char* name); + const std::string& getRootDirOS(const char* name); + void addTarget(const char* projName); + void generateRefProjectWorkingDirsTo(const char* projName); + void addTtcn3ModuleToProject(const char* projName, const char* moduleName); + void addAsn1ModuleToProject(const char* projName, const char* moduleName); + void addUserSourceToProject(const char* projName, const char* userSourceName); + void addUserHeaderToProject(const char* projName, const char* userHeaderName); + void addTtcnPPToProject(const char* projName, const char* ttcnPPName); + bool isTtcn3ModuleInLibrary(const char* moduleName) const; + bool isAsn1ModuleInLibrary(const char* moduleName) const; + bool isSourceFileInLibrary(const char* fileName) const; + bool isHeaderFileInLibrary(const char* fileName) const; + bool isTtcnPPFileInLibrary(const char* fileName) const; + ProjectDescriptor* getTargetOfProject(const char* projName); + const ProjectDescriptor* getTargetOfProject(const char* projName) const; + ProjectDescriptor* getProjectDescriptor(const char* targetName); //target_executable_name + std::map::const_iterator getHead() const; + std::map::const_iterator getEnd() const; + size_t numOfLibs() const; + void getExternalLibs(std::vector& extLibs); + void getExternalLibSearchPathes(std::vector& extLibPathes); + bool hasReferencedProject(); + size_t numOfProjects() const { return projs.size();}; + bool isCPPSourceFile(const char* fileName) const; + bool isCPPHeaderFile(const char* fileName) const; + bool isTtcnPPFile(const char* fileName) const; + void print(); + bool sanityCheck(); // tests if the structure generated from TPDs is consistent + void cleanUp(); + +private: + ProjectGenHelper(); + ProjectGenHelper(const ProjectGenHelper &rhs); + ProjectGenHelper &operator=(const ProjectGenHelper &rhs); + ProjectDescriptor* getProject(const char* projName); + const ProjectDescriptor* getProject(const char* projName) const; + bool DynamicLibraryChecker(const ProjectDescriptor* desc, + bool& found, + char** executableName); +private: + static ProjectGenHelper& intance; + static const std::string emptyString; + std::string nameOfTopLevelProject; + std::string rootDirOS; // make archive needs the top dir on OS level + std::string relPathToRootDirOS; + bool Zflag; // the makefilegen switch wether to use this option at all + bool Wflag; // prefix woring directory + bool Hflag; // hierarchical make structure + std::map projs; + std::map checkedProjs; +}; + +#endif // _LIB_GEN_HELPER_HH diff --git a/compiler2/Setting.cc b/compiler2/Setting.cc index 64c02b6..1dae00b 100644 --- a/compiler2/Setting.cc +++ b/compiler2/Setting.cc @@ -232,6 +232,12 @@ namespace Common { mputprintf(effective_module_functions, "%s\"%s\"", (effective_module_functions ? ", " : ""), entityname); } + if (profiler_enabled) { + str = mputprintf(str, + "TTCN3_Stack_Depth stack_depth;\n" + "ttcn3_prof.enter_function(\"%s\", %d, \"%s\");\n", + filename, yyloc.first_line, entityname); + } } return str; } @@ -242,6 +248,10 @@ namespace Common { if (include_location_info && !transparency) { str = mputprintf(str, "current_location.update_lineno(%d);\n", yyloc.first_line); + if (profiler_enabled) { + str = mputprintf(str, "ttcn3_prof.execute_line(\"%s\", %d);\n", + get_filename(), yyloc.first_line); + } if (tcov_file_name && in_tcov_files(get_filename())) { effective_module_lines = mputprintf(effective_module_lines, "%s%d", @@ -544,9 +554,9 @@ namespace Common { else return false; } - Type *Scope::get_mtc_system_comptype(bool is_system, bool is_connecting) + Type *Scope::get_mtc_system_comptype(bool is_system) { - if (parent_scope) return parent_scope->get_mtc_system_comptype(is_system, is_connecting); + if (parent_scope) return parent_scope->get_mtc_system_comptype(is_system); else return 0; } diff --git a/compiler2/Setting.hh b/compiler2/Setting.hh index 7ddf074..82f1bfc 100644 --- a/compiler2/Setting.hh +++ b/compiler2/Setting.hh @@ -592,10 +592,9 @@ public: virtual bool has_ass_withId(const Identifier& p_id); virtual bool is_valid_moduleid(const Identifier& p_id); /** Returns the TTCN-3 component type that is associated with - * keywords 'mtc' or 'system'. Returns NULL outside testcase definitions - * (unless it's a 'map' or 'connect' statement block) or if the component type - * cannot be determined. */ - virtual Type *get_mtc_system_comptype(bool is_system, bool is_connecting); + * keywords 'mtc' or 'system'. Returns NULL if the component type + * cannot be determined (i.e. outside testcase definitions). */ + virtual Type *get_mtc_system_comptype(bool is_system); /** Checks the 'runs on' clause of definition \a p_ass that it can * be called from this scope unit. Parameters \a p_loc and \a * p_what are used in error messages. \a p_what contains "call" or diff --git a/compiler2/Type.cc b/compiler2/Type.cc index 2f59ba7..2a9683d 100644 --- a/compiler2/Type.cc +++ b/compiler2/Type.cc @@ -573,6 +573,7 @@ namespace Common { ownertype = OT_UNKNOWN; owner = 0; chk_finished = false; + pard_type_instance = false; } void Type::clean_up() @@ -5204,8 +5205,8 @@ end_ext: bool Type::hasEncodeAttr(const MessageEncodingType_t encoding_type) { - if (CT_JSON == encoding_type && - (is_asn1() || (is_ref() && get_type_refd()->is_asn1()))) { + if (CT_JSON == encoding_type && (implicit_json_encoding + || is_asn1() || (is_ref() && get_type_refd()->is_asn1()))) { // ASN.1 types automatically support JSON encoding return true; } @@ -5573,10 +5574,15 @@ end_ext: case T_UNIVERSALSTRING: case T_BMPSTRING: case T_VERDICT: + case T_NULL: + case T_OID: + case T_ROID: + case T_ANY: // these basic types support JSON encoding by default return json_mem.remember(t, ANSWER_YES); case T_SEQ_T: case T_SEQ_A: + case T_OPENTYPE: case T_SET_T: case T_SET_A: case T_CHOICE_T: @@ -5645,7 +5651,7 @@ end_ext: case T_ENUM_T: case T_ENUM_A: break; // check for an encode attribute - default: + default: return json_mem.remember(t, ANSWER_NO); } // switch return json_mem.remember(t, hasEncodeAttr(CT_JSON) ? ANSWER_YES : ANSWER_NO); @@ -6815,10 +6821,6 @@ end_ext: string Type::get_dispname() const { - if (T_REFD == typetype) { - // cannot calculate the display name for referenced types this way - FATAL_ERROR("Type::get_dispname()"); - } string dispname = genname; size_t pos = 0; while(pos < dispname.size()) { diff --git a/compiler2/Type.hh b/compiler2/Type.hh index f15b4e5..55737c9 100644 --- a/compiler2/Type.hh +++ b/compiler2/Type.hh @@ -380,6 +380,11 @@ namespace Common { /** True if chk() has finished running. * Prevents force_raw() from running chk_raw(), chk_text() or chk_json() on unchecked types. */ bool chk_finished; + + /** Signifies that this type is an instance of an ASN.1 parameterized type. + * It will not have its own segment and reference generated in the JSON schema, + * its schema segment will be generated as an embedded type's would. */ + bool pard_type_instance; /** Copy constructor, for the use of Type::clone() only. */ Type(const Type& p); @@ -786,6 +791,7 @@ namespace Common { * If \a v is correct and it is or refers to a constant the constant value * is returned for further checking. Otherwise the return value is NULL. */ Value *chk_range_boundary(Value *v, const char *which, const Location& loc); + void chk_range_boundary_infinity(Value *v, bool is_upper); void chk_this_template_builtin(Template *t); void chk_this_template_Int_Real(Template *t); void chk_this_template_Enum(Template *t); @@ -1128,6 +1134,9 @@ namespace Common { bool is_untagged() const; + inline boolean is_pard_type_instance() { return pard_type_instance; } + inline void set_pard_type_instance() { pard_type_instance = true; } + /** Calculates the type's display name from the genname (replaces double * underscore characters with single ones) */ string get_dispname() const; @@ -1152,6 +1161,10 @@ namespace Common { /** Generates the JSON schema segment that would validate a union type or * an anytype and inserts it into the main schema. */ void generate_json_schema_union(JSON_Tokenizer& json); + + /** Generates a reference to this type's schema segment and inserts it into + * the given schema. */ + void generate_json_schema_ref(JSON_Tokenizer& json); }; /** @} end of AST_Type group */ diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 7aee9f7..d3861eb 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -639,8 +639,8 @@ void Type::chk_xer_any_attributes() for (size_t x = 0; x < parent_type->get_nof_comps(); ++x) { CompField * cf = parent_type->get_comp_byIndex(x); if (cf->get_type() != this) continue; - if (cf->has_default() || cf->get_is_optional()) { - error("The field with ANY-ATTRIBUTES cannot be OPTIONAL or DEFAULT"); + if (cf->has_default()) { + error("The field with ANY-ATTRIBUTES cannot have DEFAULT"); } } break; @@ -5613,6 +5613,37 @@ void Type::chk_this_template_Str(Template *t) } } +void Type::chk_range_boundary_infinity(Value *v, bool is_upper) +{ + if (v) { + v->set_my_governor(this); + { + Error_Context cntxt2(v, "In %s boundary", is_upper ? "upper" : "lower"); + chk_this_value_ref(v); + Value *v_last = v->get_value_refd_last(0, EXPECTED_STATIC_VALUE); + if (v_last->get_valuetype() == Value::V_OMIT) { + v->error("`omit' value is not allowed in this context"); + v->set_valuetype(Value::V_ERROR); + return; + } + if (sub_type != NULL) { + if (is_upper) { + if (!sub_type->get_root()->is_upper_limit_infinity()) { + v->error("Infinity is not a valid value for type '%s' which has subtype %s", + asString(), sub_type->to_string().c_str()); + } + } + else { + if (!sub_type->get_root()->is_lower_limit_infinity()) { + v->error("Infinity is not a valid value for type '%s' which has subtype %s", + asString(), sub_type->to_string().c_str()); + } + } + } + } + } +} + Value *Type::chk_range_boundary(Value *v, const char *which, const Location& loc) { @@ -5693,6 +5724,12 @@ void Type::chk_this_template_Int_Real(Template *t) FATAL_ERROR("Type::chk_this_template_Int_Real()"); } } + if (v_lower && !v_upper) { + chk_range_boundary_infinity(v_lower, true); + } + if (!v_lower && v_upper) { + chk_range_boundary_infinity(v_upper, false); + } break;} default: t->error("%s cannot be used for type `%s'", t->get_templatetype_str(), diff --git a/compiler2/Type_codegen.cc b/compiler2/Type_codegen.cc index 6e9679c..b6baffb 100644 --- a/compiler2/Type_codegen.cc +++ b/compiler2/Type_codegen.cc @@ -243,6 +243,7 @@ void Type::generate_code_typedescriptor(output_struct *target) case OT_TYPE_DEF: case OT_COMP_FIELD: case OT_RECORD_OF: + case OT_REF_SPEC: force_xer = has_encoding(CT_XER); // && (is_ref() || (xerattrib && !xerattrib->empty())); break; default: @@ -362,10 +363,20 @@ void Type::generate_code_typedescriptor(output_struct *target) case T_UNIVERSALSTRING: case T_BMPSTRING: case T_VERDICT: + case T_NULL: + case T_OID: + case T_ROID: + case T_ANY: // use predefined JSON descriptors instead of null pointers for basic types target->source.global_vars = mputprintf(target->source.global_vars, "&%s_json_, ", gennamejsondescriptor.c_str()); break; + case T_ENUM_T: + case T_ENUM_A: + // use a predefined JSON descriptor for enumerated types + target->source.global_vars = mputstr(target->source.global_vars, + "&ENUMERATED_json_, "); + break; default: target->source.global_vars = mputstr(target->source.global_vars, "NULL, "); @@ -389,24 +400,14 @@ void Type::generate_code_typedescriptor(output_struct *target) "const TTCN_Typedescriptor_t& %s_descr_ = %s_descr_;\n", gennameown_str, gennametypedescriptor.c_str()); } - else { - /* In general, we avoid generating a XER descriptor for - * "artificial" types. */ - - if (ownertype==OT_REF_SPEC) { - // A XER descriptor without a TTCN descriptor to own it - generate_code_xerdescriptor(target); - } #ifndef NDEBUG - else - target->source.global_vars = mputprintf(target->source.global_vars, - "// %s_xer_ elided\n", gennameown_str); - + else { target->source.global_vars = mputprintf( target->source.global_vars, "// %s_descr_ not needed, use %s_descr_\n", gennameown_str, gennametypedescriptor.c_str()); -#endif } // if(needs_alias()) +#endif + } // if (gennameown == gennametypedescriptor) } @@ -2617,10 +2618,10 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val // stored if this is a field of a union with the "as value" coding instruction if (ownertype == OT_COMP_FIELD) { CompField* cf = static_cast(owner); - if(as_value || (cf->get_type()->jsonattrib != NULL - && cf->get_type()->jsonattrib->alias != NULL)) { + if (as_value || (cf->get_type()->jsonattrib != NULL + && cf->get_type()->jsonattrib->alias != NULL)) { json.put_next_token(JSON_TOKEN_NAME, "originalName"); - char* field_str = mprintf("\"%s\"", cf->get_name().get_dispname().c_str()); + char* field_str = mprintf("\"%s\"", cf->get_name().get_ttcnname().c_str()); json.put_next_token(JSON_TOKEN_STRING, field_str); Free(field_str); } @@ -2635,18 +2636,20 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val Free(alias_str); } } - + // get the type at the end of the reference chain Type* last = get_type_refd_last(); // if the type has its own definition and it's embedded in another type, then // its schema already exists, only add a reference to it - if (embedded && (last->ownertype == OT_TYPE_DEF /* TTCN-3 type definition */ + // exception: instances of ASN.1 parameterized types, always embed their schemas + if (embedded && (!is_ref() || !get_type_refd()->pard_type_instance) && + (last->ownertype == OT_TYPE_DEF /* TTCN-3 type definition */ || last->ownertype == OT_TYPE_ASS /* ASN.1 type assignment */ )) { json.put_next_token(JSON_TOKEN_NAME, "$ref"); char* ref_str = mprintf("\"#/definitions/%s/%s\"", - last->my_scope->get_scope_mod()->get_modid().get_dispname().c_str(), - last->get_dispname().c_str()); + last->my_scope->get_scope_mod()->get_modid().get_ttcnname().c_str(), + (is_ref() && last->pard_type_instance) ? get_type_refd()->get_dispname().c_str() : last->get_dispname().c_str()); json.put_next_token(JSON_TOKEN_STRING, ref_str); Free(ref_str); } else { @@ -2685,15 +2688,17 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val case T_BSTR_A: case T_HSTR: case T_OSTR: + case T_ANY: // use the JSON string type and add a pattern to only allow bits or hex digits json.put_next_token(JSON_TOKEN_NAME, "type"); json.put_next_token(JSON_TOKEN_STRING, "\"string\""); json.put_next_token(JSON_TOKEN_NAME, "subType"); - json.put_next_token(JSON_TOKEN_STRING, (last->typetype == T_OSTR) ? "\"octetstring\"" : + json.put_next_token(JSON_TOKEN_STRING, + (last->typetype == T_OSTR || last->typetype == T_ANY) ? "\"octetstring\"" : ((last->typetype == T_HSTR) ? "\"hexstring\"" : "\"bitstring\"")); json.put_next_token(JSON_TOKEN_NAME, "pattern"); json.put_next_token(JSON_TOKEN_STRING, - (last->typetype == T_OSTR) ? "\"^([0-9A-Fa-f][0-9A-Fa-f])*$\"" : + (last->typetype == T_OSTR || last->typetype == T_ANY) ? "\"^([0-9A-Fa-f][0-9A-Fa-f])*$\"" : ((last->typetype == T_HSTR) ? "\"^[0-9A-Fa-f]*$\"" : "\"^[01]*$\"")); break; case T_CSTR: @@ -2723,6 +2728,15 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val json.put_next_token(JSON_TOKEN_NAME, "subType"); json.put_next_token(JSON_TOKEN_STRING, "\"universal charstring\""); break; + case T_OID: + case T_ROID: + json.put_next_token(JSON_TOKEN_NAME, "type"); + json.put_next_token(JSON_TOKEN_STRING, "\"string\""); + json.put_next_token(JSON_TOKEN_NAME, "subType"); + json.put_next_token(JSON_TOKEN_STRING, "\"objid\""); + json.put_next_token(JSON_TOKEN_NAME, "pattern"); + json.put_next_token(JSON_TOKEN_STRING, "\"^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$\""); + break; case T_VERDICT: // enumerate the possible values json.put_next_token(JSON_TOKEN_NAME, "enum"); @@ -2739,8 +2753,8 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val // enumerate the possible values json.put_next_token(JSON_TOKEN_NAME, "enum"); json.put_next_token(JSON_TOKEN_ARRAY_START); - for (size_t i = 0; i < u.enums.eis->get_nof_eis(); ++i) { - char* enum_str = mprintf("\"%s\"", get_ei_byIndex(i)->get_name().get_dispname().c_str()); + for (size_t i = 0; i < last->u.enums.eis->get_nof_eis(); ++i) { + char* enum_str = mprintf("\"%s\"", last->get_ei_byIndex(i)->get_name().get_ttcnname().c_str()); json.put_next_token(JSON_TOKEN_STRING, enum_str); Free(enum_str); } @@ -2748,13 +2762,18 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val // list the numeric values for the enumerated items json.put_next_token(JSON_TOKEN_NAME, "numericValues"); json.put_next_token(JSON_TOKEN_ARRAY_START); - for (size_t i = 0; i < u.enums.eis->get_nof_eis(); ++i) { - char* num_val_str = mprintf("%lli", get_ei_byIndex(i)->get_value()->get_val_Int()->get_val()); + for (size_t i = 0; i < last->u.enums.eis->get_nof_eis(); ++i) { + char* num_val_str = mprintf("%lli", last->get_ei_byIndex(i)->get_value()->get_val_Int()->get_val()); json.put_next_token(JSON_TOKEN_NUMBER, num_val_str); Free(num_val_str); } json.put_next_token(JSON_TOKEN_ARRAY_END); break; + case T_NULL: + // use the JSON null value for the ASN.1 NULL type + json.put_next_token(JSON_TOKEN_NAME, "type"); + json.put_next_token(JSON_TOKEN_STRING, "\"null\""); + break; case T_SEQOF: case T_SETOF: case T_ARRAY: @@ -2769,6 +2788,7 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val case T_CHOICE_T: case T_CHOICE_A: case T_ANYTYPE: + case T_OPENTYPE: last->generate_json_schema_union(json); break; default: @@ -2862,17 +2882,20 @@ void Type::generate_json_schema_record(JSON_Tokenizer& json) // use the field's alias if it has one json.put_next_token(JSON_TOKEN_NAME, (field->jsonattrib != NULL && field->jsonattrib->alias != NULL) ? - field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_dispname().c_str()); + field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_ttcnname().c_str()); // optional fields can also get the JSON null value if (get_comp_byIndex(i)->get_is_optional()) { - json.put_next_token(JSON_TOKEN_OBJECT_START); - json.put_next_token(JSON_TOKEN_NAME, "anyOf"); - json.put_next_token(JSON_TOKEN_ARRAY_START); - json.put_next_token(JSON_TOKEN_OBJECT_START); - json.put_next_token(JSON_TOKEN_NAME, "type"); - json.put_next_token(JSON_TOKEN_STRING, "\"null\""); - json.put_next_token(JSON_TOKEN_OBJECT_END); + // special case: ASN NULL type, since it uses the JSON literal "null" as a value + if (T_NULL != field->get_type_refd_last()->typetype) { + json.put_next_token(JSON_TOKEN_OBJECT_START); + json.put_next_token(JSON_TOKEN_NAME, "anyOf"); + json.put_next_token(JSON_TOKEN_ARRAY_START); + json.put_next_token(JSON_TOKEN_OBJECT_START); + json.put_next_token(JSON_TOKEN_NAME, "type"); + json.put_next_token(JSON_TOKEN_STRING, "\"null\""); + json.put_next_token(JSON_TOKEN_OBJECT_END); + } } else if (!has_non_optional) { has_non_optional = true; } @@ -2882,7 +2905,8 @@ void Type::generate_json_schema_record(JSON_Tokenizer& json) // for optional fields: specify the presence of the "omit as null" coding instruction // and close structures - if (get_comp_byIndex(i)->get_is_optional()) { + if (get_comp_byIndex(i)->get_is_optional() && + T_NULL != field->get_type_refd_last()->typetype) { json.put_next_token(JSON_TOKEN_ARRAY_END); json.put_next_token(JSON_TOKEN_NAME, "omitAsNull"); json.put_next_token((field->jsonattrib != NULL && field->jsonattrib->omit_as_null) ? @@ -2907,7 +2931,7 @@ void Type::generate_json_schema_record(JSON_Tokenizer& json) // use the field's alias if it has one char* field_str = mprintf("\"%s\"", (field->jsonattrib != NULL && field->jsonattrib->alias != NULL) ? - field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_dispname().c_str()); + field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_ttcnname().c_str()); json.put_next_token(JSON_TOKEN_STRING, field_str); Free(field_str); } @@ -2924,7 +2948,7 @@ void Type::generate_json_schema_record(JSON_Tokenizer& json) // use the field's alias if it has one char* field_str = mprintf("\"%s\"", (field->jsonattrib != NULL && field->jsonattrib->alias != NULL) ? - field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_dispname().c_str()); + field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_ttcnname().c_str()); json.put_next_token(JSON_TOKEN_STRING, field_str); Free(field_str); } @@ -2959,7 +2983,7 @@ void Type::generate_json_schema_union(JSON_Tokenizer& json) // use the alternative's alias if it has one json.put_next_token(JSON_TOKEN_NAME, (field->jsonattrib != NULL && field->jsonattrib->alias != NULL) ? - field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_dispname().c_str()); + field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_ttcnname().c_str()); // let the alternative's type insert its schema field->generate_json_schema(json, true, false); @@ -2977,7 +3001,7 @@ void Type::generate_json_schema_union(JSON_Tokenizer& json) // use the alternative's alias here as well char* field_str = mprintf("\"%s\"", (field->jsonattrib != NULL && field->jsonattrib->alias != NULL) ? - field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_dispname().c_str()); + field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_ttcnname().c_str()); json.put_next_token(JSON_TOKEN_STRING, field_str); Free(field_str); @@ -2991,6 +3015,23 @@ void Type::generate_json_schema_union(JSON_Tokenizer& json) json.put_next_token(JSON_TOKEN_ARRAY_END); } +void Type::generate_json_schema_ref(JSON_Tokenizer& json) +{ + // start the object containing the reference + json.put_next_token(JSON_TOKEN_OBJECT_START); + + // insert the reference + json.put_next_token(JSON_TOKEN_NAME, "$ref"); + char* ref_str = mprintf("\"#/definitions/%s/%s\"", + my_scope->get_scope_mod()->get_modid().get_ttcnname().c_str(), + get_dispname().c_str()); + json.put_next_token(JSON_TOKEN_STRING, ref_str); + Free(ref_str); + + // the object will be closed later, as it may contain other properties +} + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ } // namespace Common diff --git a/compiler2/Value.cc b/compiler2/Value.cc index 4f51aa3..a1c1c8a 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -3178,10 +3178,10 @@ namespace Common { case OPTYPE_CONCAT: return get_expr_governor_v1v2(exp_val); case OPTYPE_COMP_MTC: - if (my_scope) return my_scope->get_mtc_system_comptype(false, false); + if (my_scope) return my_scope->get_mtc_system_comptype(false); else return 0; case OPTYPE_COMP_SYSTEM: - if (my_scope) return my_scope->get_mtc_system_comptype(true, false); + if (my_scope) return my_scope->get_mtc_system_comptype(true); else return 0; case OPTYPE_COMP_SELF: if (my_scope) { @@ -3234,18 +3234,6 @@ namespace Common { if(valuetype != V_INVOKE) FATAL_ERROR("Value::get_invoked_type()"); return u.invoke.v->get_expr_governor(exp_val); } - - Type* Value::get_component_governor() - { - if (V_EXPR == valuetype && OPTYPE_COMP_MTC == u.expr.v_optype) { - if (my_scope) { - return my_scope->get_mtc_system_comptype(false, true); - } else { - return 0; - } - } - return get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE); - } const char* Value::get_opname() const { @@ -4048,10 +4036,10 @@ namespace Common { Type *t_comptype; switch (u.expr.v_optype) { case OPTYPE_COMP_MTC: - t_comptype = my_scope->get_mtc_system_comptype(false, false); + t_comptype = my_scope->get_mtc_system_comptype(false); break; case OPTYPE_COMP_SYSTEM: - t_comptype = my_scope->get_mtc_system_comptype(true, false); + t_comptype = my_scope->get_mtc_system_comptype(true); break; case OPTYPE_COMP_SELF: { Ttcn::RunsOnScope *t_ros = my_scope->get_scope_runs_on(); @@ -10009,13 +9997,14 @@ error: string Value::create_stringRepr() { + // note: cannot call is_asn1() when only parsing (scopes are not properly set) switch (valuetype) { case V_ERROR: return string(""); case V_NULL: return string("NULL"); case V_BOOL: - if (is_asn1()) { + if (!parse_only && is_asn1()) { if (u.val_bool) return string("TRUE"); else return string("FALSE"); } @@ -10066,7 +10055,7 @@ error: case V_OID: case V_ROID: { string ret_val; - if (!is_asn1()) ret_val += "objid "; + if (parse_only || !is_asn1()) ret_val += "objid "; ret_val += "{ "; for (size_t i = 0; i < u.oid_comps->size(); i++) { if (i>0) ret_val += ' '; @@ -10075,7 +10064,7 @@ error: ret_val += " }"; return ret_val; } case V_CHOICE: - if (is_asn1()) { + if (!parse_only && is_asn1()) { string ret_val(u.choice.alt_name->get_dispname()); ret_val += " : "; ret_val += u.choice.alt_value->get_stringRepr(); @@ -10109,7 +10098,7 @@ error: case V_SEQ: case V_SET: { string ret_val("{ "); - bool asn1_flag = is_asn1(); + bool asn1_flag = !parse_only && is_asn1(); for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); i++) { if (i > 0) ret_val += ", "; NamedValue *nv = u.val_nvs->get_nv_byIndex(i); diff --git a/compiler2/Value.hh b/compiler2/Value.hh index 47eedeb..cfd3f79 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -479,11 +479,6 @@ namespace Common { Type* get_expr_governor_last(); /** get the type invoked */ Type *get_invoked_type(Type::expected_value_t exp_val); - - /** An alternative version of get_expr_governor for components. This will - * return the MTC component type in function and altstep scopes as well. - * Calls get_expr_governor in all other cases. */ - Type* get_component_governor(); private: const char* get_opname() const; /** Used to determine whether the reference points to value or diff --git a/compiler2/asn1/AST_asn1.cc b/compiler2/asn1/AST_asn1.cc index d286ad3..6e83b0b 100644 --- a/compiler2/asn1/AST_asn1.cc +++ b/compiler2/asn1/AST_asn1.cc @@ -513,21 +513,34 @@ namespace Asn { asss->add_ass(p_ass); } - void Module::add_types_to_json_schema(JSON_Tokenizer& json) + void Module::generate_json_schema(JSON_Tokenizer& json, map& json_refs) { // add a new property for this module - json.put_next_token(JSON_TOKEN_NAME, modid->get_dispname().c_str()); + json.put_next_token(JSON_TOKEN_NAME, modid->get_ttcnname().c_str()); // add type definitions into an object json.put_next_token(JSON_TOKEN_OBJECT_START); - // pass the JSON tokenizer onto each type definition + // cycle through all type assignments, insert schema segments and references + // when needed for (size_t i = 0; i < asss->get_nof_asss(); ++i) { Common::Assignment* ass = asss->get_ass_byIndex(i); if (Common::Assignment::A_TYPE == ass->get_asstype()) { - Type* t = ass->get_Type(); - if (t->has_encoding(Type::CT_JSON)) { - t->generate_json_schema(json, false, false); + Asn::Assignment* asn_ass = dynamic_cast(ass); + // skip parameterized types and their instances + if (NULL == asn_ass || NULL == asn_ass->get_ass_pard()) { + Type* t = ass->get_Type(); + if (!t->is_pard_type_instance() && t->has_encoding(Type::CT_JSON)) { + // insert type's schema segment + t->generate_json_schema(json, false, false); + + if (json_refs_for_all_types && !json_refs.has_key(t)) { + // create JSON schema reference for the type + JSON_Tokenizer* json_ref = new JSON_Tokenizer; + json_refs.add(t, json_ref); + t->generate_json_schema_ref(*json_ref); + } + } } } } @@ -1193,6 +1206,14 @@ namespace Asn { classify_ass(refch); return asstype != A_ERROR ? ass->is_asstype(p_asstype, refch) : false; } + + Ass_pard* Ass_Undef::get_ass_pard() const + { + if (NULL != ass) { + return ass->get_ass_pard(); + } + return ass_pard; + } bool Ass_Undef::_error_if_pard() { diff --git a/compiler2/asn1/AST_asn1.hh b/compiler2/asn1/AST_asn1.hh index 180d0d1..43eba03 100644 --- a/compiler2/asn1/AST_asn1.hh +++ b/compiler2/asn1/AST_asn1.hh @@ -129,7 +129,7 @@ namespace Asn { virtual void set_right_scope(Scope *p_scope) =0; void set_dontgen() {dontgen=true;} /** Returns 0 if assignment is not parameterized! */ - Ass_pard* get_ass_pard() const { return ass_pard; } + virtual Ass_pard* get_ass_pard() const { return ass_pard; } /** Returns 0 if this assignment is not parameterized! */ Assignment* new_instance(Common::Module *p_mod); virtual Type* get_Type(); @@ -244,12 +244,13 @@ namespace Asn { void add_ass(Assignment *p_ass); TagDefault::tagdef_t get_tagdef() const { return tagdef; } - /** Generates JSON schema segments for the types defined in the module - * and adds them to the JSON schema parameter. */ - virtual void add_types_to_json_schema(JSON_Tokenizer&); - - /** Does nothing. ASN.1 modules can't contain functions. */ - virtual void add_func_to_json_schema(map&) {} + /** Generates JSON schema segments for the types defined in the modules, + * and references to these types. + * + * @param json JSON document containing the main schema, schema segments for + * the types will be inserted here + * @param json_refs map of JSON documents containing the references to each type */ + virtual void generate_json_schema(JSON_Tokenizer& json, map& json_refs); }; /** @@ -442,6 +443,7 @@ namespace Asn { virtual void set_my_scope(Scope *p_scope); virtual void set_right_scope(Scope *p_scope); virtual bool is_asstype(asstype_t p_asstype, ReferenceChain* refch=0); + virtual Ass_pard* get_ass_pard() const; virtual Setting* get_Setting(); virtual Type* get_Type(); virtual Value* get_Value(); diff --git a/compiler2/asn1/Ref.cc b/compiler2/asn1/Ref.cc index b933ea1..0c7b52f 100644 --- a/compiler2/asn1/Ref.cc +++ b/compiler2/asn1/Ref.cc @@ -190,7 +190,11 @@ namespace Asn { new_ass->set_location(*this); new_ass->set_dontgen(); new_ass->chk(); - + + if (Common::Assignment::A_TYPE == new_ass->get_asstype()) { + new_ass->get_Type()->set_pard_type_instance(); + } + ref_ds=new Ref_defd_simple(new Identifier(my_mod->get_modid()), new Identifier(new_ass_id)); ref_ds->set_fullname(get_fullname()); diff --git a/compiler2/compiler.1 b/compiler2/compiler.1 index 762b4f0..a3416e4 100644 --- a/compiler2/compiler.1 +++ b/compiler2/compiler.1 @@ -26,8 +26,20 @@ or .br .B compiler .B \-v +.br +or +.br +.B compiler \-\-ttcn2json +.RB "[\| " \-jf " \|]" +.RB "[\| " \-T " \|]" +module.ttcn ... +.RB "[\| " \-A " \|]" +module.asn ... +.RB "[\| " \- +schema.json +.RB " \|]" .SH DESCRIPTION -This manual page is a quick reference for the TTCN-3 and ASN.1 to C++ +This manual page is a quick reference for the TTCN-3 and ASN.1 to C++ (or JSON schema) compiler of the TTCN-3 Test Executor. It only summarizes the meaning of all command line options. For more details please consult the .B Programmer's Technical Reference for TITAN TTCN-3 Test Executor. @@ -298,6 +310,29 @@ in the list before the dash. If the single dash is not present in the command line the compiler will generate code for .I all modules. +.TP +.B \-\-ttcn2json +Generates a JSON schema from the types defined in the specified TTCN-3 and ASN.1 modules. +Must always be the first compiler option. From the previously listed options only +.B \-T +and +.B \-A +can be used, instead the JSON schema generator has options of its own: +.TP +.B \-j +Only types that have JSON coding enabled are included in the schema. +.TP +.B \-f +The schema only validates types that have a JSON encoding or decoding method declared. +.TP +.BI \- " file" +The single dash character as command line argument specifies the name of the generated +JSON schema file. If it is not present, then the schema file name is generated from +the name of the first input file (by replacing its suffix with +.I \.json +or appending +.I \.json +to the end of the file). .SH EXIT STATUS The compiler exits with a status of zero when no errors were encountered during its operation. A status of one will be returned if syntax or diff --git a/compiler2/encdec.c b/compiler2/encdec.c index 2dc6e66..4d5362d 100644 --- a/compiler2/encdec.c +++ b/compiler2/encdec.c @@ -50,8 +50,10 @@ void def_encdec(const char *p_classname, #ifndef NDEBUG "// written by %s in " __FILE__ " at %d\n" #endif - "int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int) const;\n" - "int XER_decode(const XERdescriptor_t&, XmlReaderWrap&, unsigned int);\n" + "int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int, " + "embed_values_enc_struct_t*) const;\n" + "int XER_decode(const XERdescriptor_t&, XmlReaderWrap&, unsigned int, " + "embed_values_dec_struct_t*);\n" "static boolean can_start(const char *name, const char *uri, " "XERdescriptor_t const& xd, unsigned int);\n" "%s" @@ -114,7 +116,7 @@ void def_encdec(const char *p_classname, /* Do not use %s_xer_ here. It supplies the XER descriptor of oldtype * even if encoding newtype for: * type newtype oldtype; */ - " XER_encode(*(p_td.xer),p_buf, XER_coding, 0);\n" + " XER_encode(*(p_td.xer),p_buf, XER_coding, 0, 0);\n" " p_buf.put_c('\\n');\n" /* make sure it has a newline */ " break;}\n" " case TTCN_EncDec::CT_JSON: {\n" @@ -215,7 +217,7 @@ void def_encdec(const char *p_classname, " for (int rd_ok=reader.Read(); rd_ok==1; rd_ok=reader.Read()) {\n" " if (reader.NodeType() == XML_READER_TYPE_ELEMENT) break;\n" " }\n" - " XER_decode(*(p_td.xer), reader, XER_coding | XER_TOPLEVEL);\n" + " XER_decode(*(p_td.xer), reader, XER_coding | XER_TOPLEVEL, 0);\n" " size_t bytes = reader.ByteConsumed();\n" " p_buf.set_pos(bytes);\n" " break;}\n" diff --git a/compiler2/enum.c b/compiler2/enum.c index 67133e2..15ad0b5 100644 --- a/compiler2/enum.c +++ b/compiler2/enum.c @@ -605,7 +605,7 @@ void defEnumClass(const enum_def *edef, output_struct *output) src = mputprintf(src, "int %s::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf," - " unsigned int p_flavor, int p_indent) const\n" + " unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const\n" "{\n" " int encoded_length=(int)p_buf.get_len();\n" " const boolean e_xer = is_exer(p_flavor);\n" @@ -643,7 +643,7 @@ void defEnumClass(const enum_def *edef, output_struct *output) "// written by %s in " __FILE__ " at %d\n" #endif "int %s::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader," - " unsigned int p_flavor)\n" + " unsigned int p_flavor, embed_values_dec_struct_t*)\n" "{\n" " int rd_ok = 1, type;\n" diff --git a/compiler2/main.cc b/compiler2/main.cc index 9f50d8e..fd58f1a 100644 --- a/compiler2/main.cc +++ b/compiler2/main.cc @@ -66,7 +66,9 @@ boolean generate_skeleton = FALSE, force_overwrite = FALSE, semantic_check_only = FALSE, output_only_linenum = FALSE, default_as_optional = FALSE, enable_set_bound_out_param = FALSE, use_runtime_2 = FALSE, gcc_compat = FALSE, asn1_xer = FALSE, - check_subtype = TRUE, suppress_context = FALSE, display_up_to_date = 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; // Default code splitting mode is set to 'no splitting'. CodeGenHelper::split_type code_splitting_mode = CodeGenHelper::SPLIT_NONE; @@ -356,7 +358,7 @@ static void usage() " [-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 [-T] module.ttcn [-A] module.asn ... - schema.json\n" + " or %s --ttcn2json [-jf] ... [-T] module.ttcn [-A] module.asn ... [- schema.json]\n" "\n" "OPTIONS:\n" " -a: force XER in ASN.1 files\n" @@ -366,10 +368,13 @@ static void usage() " -f: force overwriting of output files\n" " -g: emulate GCC error/warning message format\n" " -i: use only line numbers in error/warning messages\n" + " -j: disable JSON encoder/decoder functions\n" " -l: include source line info in C++ code\n" " -L: add source line info for logging\n" " -K file: enable selective code coverage\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" " -q: suppress all messages (quiet mode)\n" " -Qn: quit after n errors\n" " -r: disable RAW encoder/decoder functions\n" @@ -379,19 +384,20 @@ static void usage() " -t: generate Test Port skeleton\n" " -u: duplicate underscores in file names\n" " -U none|type: select code splitting mode for the generated C++ code\n" + " -V verb_level: set verbosity level bitmask (decimal)\n" " -w: suppress warnings\n" " -x: disable TEXT encoder/decoder functions\n" " -X: disable XER encoder/decoder functions\n" - " -j: disable JSON encoder/decoder functions\n" " -y: disable subtype checking\n" - " -V verb_level: set verbosity level bitmask (decimal)\n" - " -o dir: output files will be placed into dir\n" " -Y: Enforces legacy behaviour of the \"out\" function parameters (see refguide)\n" - " -P pduname: define top-level pdu\n" + //" -z: enable profiling and code coverage for TTCN-3 files\n" - not open to the public yet " -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" - " --ttcn2json: generate JSON schema from input modules\n", argv0, argv0, argv0); + " --ttcn2json: generate JSON schema from input modules\n" + "JSON schema generator options:\n" + " -j: only include types with JSON encoding\n" + " -f: only generate references to types with JSON encoding/decoding functions\n", argv0, argv0, argv0); } #define SET_FLAG(x) if (x##flag) {\ @@ -441,7 +447,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, + Sflag = false, Kflag = false, jflag = false, zflag = false, errflag = false, print_usage = false, ttcn2json = false; CodeGenHelper cgh; @@ -457,6 +463,7 @@ int main(int argc, char *argv[]) if (0 == strcmp(argv[1], "--ttcn2json")) { ttcn2json = true; display_up_to_date = TRUE; + implicit_json_encoding = TRUE; for (int i = 2; i < argc; ++i) { // A dash (-) is used to separate the schema file name from the input files if (0 == strcmp(argv[i], "-")) { @@ -487,6 +494,16 @@ int main(int argc, char *argv[]) } add_module(n_modules, module_list, argv[i], Module::MOD_TTCN); } + else if (0 == strcmp(argv[i], "-j")) { + implicit_json_encoding = FALSE; + } + else if (0 == strcmp(argv[i], "-f")) { + json_refs_for_all_types = FALSE; + } + else if (0 == strcmp(argv[i], "-fj") || 0 == strcmp(argv[i], "-jf")) { + implicit_json_encoding = FALSE; + json_refs_for_all_types = FALSE; + } else if (argv[i][0] == '-') { ERROR("Invalid option `%s' after option `--ttcn2json'", argv[i]); print_usage = true; @@ -523,7 +540,7 @@ int main(int argc, char *argv[]) if (!ttcn2json) { for ( ; ; ) { - int c = getopt(argc, argv, "aA:C:K:LP:T:V:bcdfgilo:YpqQ:rRs0StuU:vwxXjy-"); + int c = getopt(argc, argv, "aA:C:K:LP:T:V:bcdfgilo:YpqQ:rRs0StuU:vwxXjyz-"); if (c == -1) break; switch (c) { case 'a': @@ -678,6 +695,10 @@ int main(int argc, char *argv[]) SET_FLAG(y); check_subtype = FALSE; break; + case 'z': + SET_FLAG(z); + profiler_enabled = TRUE; + break; case 'Q': { long max_errs; @@ -704,7 +725,7 @@ int main(int argc, char *argv[]) case '-': if (!strcmp(argv[optind], "--ttcn2json")) { - ERROR("Option `--ttcn2json' does not allow the use of other options"); + ERROR("Option `--ttcn2json' is only allowed as the first option"); } else { ERROR("Invalid option: `%s'", argv[optind]); } @@ -722,7 +743,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) { + Uflag || yflag || Kflag || jflag || zflag) { errflag = true; print_usage = true; } @@ -738,6 +759,10 @@ int main(int argc, char *argv[]) ERROR("Source line information `-L' is necessary for code coverage `-K'."); errflag = true; } + if (zflag && !Lflag) { + ERROR("Source line information `-L' is necessary for profiling `-z'."); + errflag = true; + } if (iflag && gflag) { WARNING("Option `-g' overrides `-i'."); iflag = false; // -g gives more information diff --git a/compiler2/main.hh b/compiler2/main.hh index 0beb371..18ec896 100644 --- a/compiler2/main.hh +++ b/compiler2/main.hh @@ -33,7 +33,8 @@ extern unsigned int nof_notupdated_files; 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; + check_subtype, suppress_context, enable_set_bound_out_param, display_up_to_date, + implicit_json_encoding, json_refs_for_all_types, profiler_enabled; extern const char *expected_platform; diff --git a/compiler2/makefile.c b/compiler2/makefile.c index 746d126..4252d22 100644 --- a/compiler2/makefile.c +++ b/compiler2/makefile.c @@ -13,7 +13,7 @@ #include #include #if defined SOLARIS || defined SOLARIS8 -# include +#include #endif #include "../common/memory.h" @@ -32,7 +32,8 @@ static const char *program_name = NULL; static unsigned int error_count = 0; static boolean suppress_warnings = FALSE; - +void free_string2_list(struct string2_list* act_elem); +void free_string_list(struct string_list* act_elem); void ERROR(const char *fmt, ...) { va_list parameters; @@ -163,6 +164,7 @@ struct base_dir_struct { /** data structure that describes the information needed for the Makefile */ struct makefile_struct { + char *project_name; size_t nTTCN3Modules; struct module_struct *TTCN3Modules; @@ -206,11 +208,15 @@ struct makefile_struct { boolean coverage; char *tcov_file_name; boolean library; + boolean linkingStrategy; + boolean hierarchical; struct string_list* sub_project_dirs; /* not owned */ struct string_list* ttcn3_prep_includes; /* not owned */ struct string_list* ttcn3_prep_defines; /* not owned */ + struct string_list* ttcn3_prep_undefines; /* not owned */ struct string_list* prep_includes; /* not owned */ struct string_list* prep_defines; /* not owned */ + struct string_list* prep_undefines; /* not owned */ boolean codesplittpd; boolean quietly; boolean disablesubtypecheck; @@ -246,6 +252,7 @@ struct makefile_struct { /** Initializes structure \a makefile with empty lists and default settings. */ static void init_makefile_struct(struct makefile_struct *makefile) { + makefile->project_name = NULL; makefile->nTTCN3Modules = 0; makefile->TTCN3Modules = NULL; makefile->preprocess = FALSE; @@ -283,6 +290,8 @@ static void init_makefile_struct(struct makefile_struct *makefile) makefile->coverage = FALSE; makefile->tcov_file_name = NULL; makefile->library = FALSE; + makefile->linkingStrategy = FALSE; + makefile->hierarchical = FALSE; makefile->sub_project_dirs = NULL; makefile->ttcn3_prep_includes = NULL; makefile->prep_includes = NULL; @@ -303,6 +312,7 @@ static void init_makefile_struct(struct makefile_struct *makefile) /** Deallocates all memory associated with structure \a makefile. */ static void free_makefile_struct(const struct makefile_struct *makefile) { + Free(makefile->project_name); size_t i; for (i = 0; i < makefile->nTTCN3Modules; i++) { Free(makefile->TTCN3Modules[i].dir_name); @@ -348,6 +358,7 @@ static void dump_makefile_struct(const struct makefile_struct *makefile, { size_t i; DEBUG(level, "Data used for Makefile generation:"); + DEBUG(level + 1, "TTCN-3 project name: %s", makefile->project_name); DEBUG(level + 1, "TTCN-3 modules: (%u pcs.)", makefile->nTTCN3Modules); for (i = 0; i < makefile->nTTCN3Modules; i++) { const struct module_struct *module = makefile->TTCN3Modules + i; @@ -406,12 +417,12 @@ static void dump_makefile_struct(const struct makefile_struct *makefile, if (user->header_name != NULL) { DEBUG(level + 3, "Header file: %s", user->header_name); DEBUG(level + 3, "Header file has .hh or .hpp suffix: %s", - user->has_hh_suffix ? "yes" : "no"); + user->has_hh_suffix ? "yes" : "no"); } if (user->source_name != NULL) { DEBUG(level + 3, "Source file: %s", user->source_name); DEBUG(level + 3, "Source file has .cc or .cpp suffix: %s", - user->has_cc_suffix ? "yes" : "no"); + user->has_cc_suffix ? "yes" : "no"); DEBUG(level + 3, "Object file: %s.o", user->file_prefix); } } @@ -437,7 +448,7 @@ static void dump_makefile_struct(const struct makefile_struct *makefile, const struct base_dir_struct *base_dir = makefile->BaseDirs + i; DEBUG(level + 2, "Directory: %s", base_dir->dir_name); DEBUG(level + 3, "Has TTCN-3/ASN.1 modules: %s", - base_dir->has_modules ? "yes" : "no"); + base_dir->has_modules ? "yes" : "no"); } } DEBUG(level + 1, "Working directory: %s", @@ -914,7 +925,7 @@ static void add_path_to_list(size_t *list_size, char ***list_ptr, for (i = 0; i < *list_size; i++) { if (!strcmp(canonized_path_name, (*list_ptr)[i])) { if (report_warning) WARNING("File `%s' was given more than once for the " - "Makefile.", path_name); + "Makefile.", path_name); Free(canonized_path_name); return; } @@ -934,28 +945,32 @@ static void add_user_file(struct makefile_struct *makefile, const char *suffix = get_suffix(path_name); if (suffix != NULL) { if (!strcmp(suffix, "ttcn") || !strcmp(suffix, "ttcn3") || - !strcmp(suffix, "3mp") || !strcmp(suffix, "ttcnpp")) { + !strcmp(suffix, "3mp") || !strcmp(suffix, "ttcnpp")) { /* The file content was already checked. Since it doesn't look like * a valid TTCN-3 file, these suffixes are suspect */ WARNING("File `%s' does not contain a valid TTCN-3 module. " - "It will be added to the Makefile as other file.", path_name); - } else if (!strcmp(suffix, "ttcnin")) { + "It will be added to the Makefile as other file.", path_name); + } + else if (!strcmp(suffix, "ttcnin")) { /* this is a TTCN-3 include file */ if (makefile->preprocess) { - add_path_to_list(&makefile->nTTCN3IncludeFiles, - &makefile->TTCN3IncludeFiles, path_name, makefile->working_dir, TRUE); - return; - } else { - WARNING("The suffix of file `%s' indicates that it is a TTCN-3 " - "include file, but TTCN-3 preprocessing is not enabled. The file " - "will be added to the Makefile as other file.", path_name); + add_path_to_list(&makefile->nTTCN3IncludeFiles, + &makefile->TTCN3IncludeFiles, path_name, makefile->working_dir, TRUE); + return; + } + else { + WARNING("The suffix of file `%s' indicates that it is a TTCN-3 " + "include file, but TTCN-3 preprocessing is not enabled. The file " + "will be added to the Makefile as other file.", path_name); } - } else if (!strcmp(suffix, "asn") || !strcmp(suffix, "asn1")) { + } + else if (!strcmp(suffix, "asn") || !strcmp(suffix, "asn1")) { /* The file content was already checked. Since it doesn't look like * a valid ASN.1 file, these suffixes are suspect */ WARNING("File `%s' does not contain a valid ASN.1 module. " - "It will be added to the Makefile as other file.", path_name); - } else if (!strcmp(suffix, "cc") || !strcmp(suffix, "c") || !strcmp(suffix, "cpp")) { + "It will be added to the Makefile as other file.", path_name); + } + else if (!strcmp(suffix, "cc") || !strcmp(suffix, "c") || !strcmp(suffix, "cpp")) { /* this is a source file */ char *dir_name = get_dir_name(path_name, makefile->working_dir); char *file_name = get_file_from_path(path_name); @@ -963,48 +978,49 @@ static void add_user_file(struct makefile_struct *makefile, struct user_struct *user; size_t i; for (i = 0; i < makefile->nUserFiles; i++) { - user = makefile->UserFiles + i; - if (!strcmp(file_prefix, user->file_prefix)) { - if (user->source_name != NULL) { - /* the source file is already present */ - if (is_same_file(dir_name, file_name, - user->dir_name, user->source_name)) { - WARNING("File `%s' was given more than once for the Makefile.", - path_name); - } else { - char *path_name1 = compose_path_name(user->dir_name, - user->source_name); - char *path_name2 = compose_path_name(dir_name, file_name); - ERROR("C/C++ source files `%s' and `%s' cannot be used together " - "in the same Makefile.", path_name1, path_name2); - Free(path_name1); - Free(path_name2); - } - } else { - /* a header file with the same prefix is already present */ - if (is_same_directory(dir_name, user->dir_name)) { - user->source_name = file_name; - file_name = NULL; - if (!strcmp(suffix, "cc") || !strcmp(suffix, "cpp")) user->has_cc_suffix = TRUE; - } else { - char *path_name1 = compose_path_name(dir_name, file_name); - char *path_name2 = compose_path_name(user->dir_name, - user->header_name); - ERROR("C/C++ source file `%s' cannot be used together with " - "header file `%s' in the same Makefile.", path_name1, - path_name2); - Free(path_name1); - Free(path_name2); - } - } - Free(dir_name); - Free(file_name); - Free(file_prefix); - return; - } + user = makefile->UserFiles + i; + if (!strcmp(file_prefix, user->file_prefix)) { + if (user->source_name != NULL) { + /* the source file is already present */ + if (is_same_file(dir_name, file_name, + user->dir_name, user->source_name)) { + WARNING("File `%s' was given more than once for the Makefile.", path_name); + } + else { + char *path_name1 = compose_path_name(user->dir_name, user->source_name); + char *path_name2 = compose_path_name(dir_name, file_name); + ERROR("C/C++ source files `%s' and `%s' cannot be used together " + "in the same Makefile.", path_name1, path_name2); + Free(path_name1); + Free(path_name2); + } + } + else { + /* a header file with the same prefix is already present */ + if (is_same_directory(dir_name, user->dir_name)) { + user->source_name = file_name; + file_name = NULL; + if (!strcmp(suffix, "cc") || !strcmp(suffix, "cpp")) + user->has_cc_suffix = TRUE; + } + else { + char *path_name1 = compose_path_name(dir_name, file_name); + char *path_name2 = compose_path_name(user->dir_name, user->header_name); + ERROR("C/C++ source file `%s' cannot be used together with " + "header file `%s' in the same Makefile.", path_name1, + path_name2); + Free(path_name1); + Free(path_name2); + } + } + Free(dir_name); + Free(file_name); + Free(file_prefix); + return; + } } makefile->UserFiles = (struct user_struct*)Realloc(makefile->UserFiles, - (makefile->nUserFiles + 1) * sizeof(*makefile->UserFiles)); + (makefile->nUserFiles + 1) * sizeof(*makefile->UserFiles)); user = makefile->UserFiles + makefile->nUserFiles; makefile->nUserFiles++; user->dir_name = dir_name; @@ -1015,7 +1031,8 @@ static void add_user_file(struct makefile_struct *makefile, if (!strcmp(suffix, "cc") || !strcmp(suffix, "cpp")) user->has_cc_suffix = TRUE; else user->has_cc_suffix = FALSE; return; - } else if (!strcmp(suffix, "hh") || !strcmp(suffix, "h")) { + } + else if (!strcmp(suffix, "hh") || !strcmp(suffix, "h")) { /* this is a header file */ char *dir_name = get_dir_name(path_name, makefile->working_dir); char *file_name = get_file_from_path(path_name); @@ -1023,48 +1040,47 @@ static void add_user_file(struct makefile_struct *makefile, struct user_struct *user; size_t i; for (i = 0; i < makefile->nUserFiles; i++) { - user = makefile->UserFiles + i; - if (!strcmp(file_prefix, user->file_prefix)) { - if (user->header_name != NULL) { - /* the header file is already present */ - if (is_same_file(dir_name, file_name, - user->dir_name, user->header_name)) { - WARNING("File `%s' was given more than once for the Makefile.", - path_name); - } else { - char *path_name1 = compose_path_name(user->dir_name, - user->header_name); - char *path_name2 = compose_path_name(dir_name, file_name); - ERROR("C/C++ header files `%s' and `%s' cannot be used together " - "in the same Makefile.", path_name1, path_name2); - Free(path_name1); - Free(path_name2); - } - } else { - /* a source file with the same prefix is already present */ - if (is_same_directory(dir_name, user->dir_name)) { - user->header_name = file_name; - file_name = NULL; - if (!strcmp(suffix, "hh") || !strcmp(suffix, "hpp")) user->has_hh_suffix = TRUE; - } else { - char *path_name1 = compose_path_name(dir_name, file_name); - char *path_name2 = compose_path_name(user->dir_name, - user->source_name); - ERROR("C/C++ header file `%s' cannot be used together with " - "source file `%s' in the same Makefile.", path_name1, - path_name2); - Free(path_name1); - Free(path_name2); - } - } - Free(dir_name); - Free(file_name); - Free(file_prefix); - return; - } + user = makefile->UserFiles + i; + if (!strcmp(file_prefix, user->file_prefix)) { + if (user->header_name != NULL) { + /* the header file is already present */ + if (is_same_file(dir_name, file_name, user->dir_name, user->header_name)) { + WARNING("File `%s' was given more than once for the Makefile.", path_name); + } + else { + char *path_name1 = compose_path_name(user->dir_name, user->header_name); + char *path_name2 = compose_path_name(dir_name, file_name); + ERROR("C/C++ header files `%s' and `%s' cannot be used together " + "in the same Makefile.", path_name1, path_name2); + Free(path_name1); + Free(path_name2); + } + } + else { + /* a source file with the same prefix is already present */ + if (is_same_directory(dir_name, user->dir_name)) { + user->header_name = file_name; + file_name = NULL; + if (!strcmp(suffix, "hh") || !strcmp(suffix, "hpp")) + user->has_hh_suffix = TRUE; + } + else { + char *path_name1 = compose_path_name(dir_name, file_name); + char *path_name2 = compose_path_name(user->dir_name, user->source_name); + ERROR("C/C++ header file `%s' cannot be used together with " + "source file `%s' in the same Makefile.", path_name1, path_name2); + Free(path_name1); + Free(path_name2); + } + } + Free(dir_name); + Free(file_name); + Free(file_prefix); + return; + } } makefile->UserFiles = (struct user_struct*)Realloc(makefile->UserFiles, - (makefile->nUserFiles + 1) * sizeof(*makefile->UserFiles)); + (makefile->nUserFiles + 1) * sizeof(*makefile->UserFiles)); user = makefile->UserFiles + makefile->nUserFiles; makefile->nUserFiles++; user->dir_name = dir_name; @@ -1176,31 +1192,34 @@ static void complete_user_files(const struct makefile_struct *makefile) static const char * const suffix_list[] = { "hh", "h", "hpp", NULL }; const char * const *suffix_ptr; for (suffix_ptr = suffix_list; *suffix_ptr != NULL; suffix_ptr++) { - char *file_name = mprintf("%s.%s", user->file_prefix, *suffix_ptr); - char *path_name = compose_path_name(user->dir_name, file_name); - if (get_path_status(path_name) == PS_FILE) { - Free(path_name); - user->header_name = file_name; - if (!strcmp(*suffix_ptr, "hh") || !strcmp(*suffix_ptr, "hpp")) user->has_hh_suffix = TRUE; - break; - } - Free(file_name); - Free(path_name); + char *file_name = mprintf("%s.%s", user->file_prefix, *suffix_ptr); + char *path_name = compose_path_name(user->dir_name, file_name); + if (get_path_status(path_name) == PS_FILE) { + Free(path_name); + user->header_name = file_name; + if (!strcmp(*suffix_ptr, "hh") || !strcmp(*suffix_ptr, "hpp")) + user->has_hh_suffix = TRUE; + break; + } + Free(file_name); + Free(path_name); } - } else if (user->source_name == NULL) { + } + else if (user->source_name == NULL) { static const char * const suffix_list[] = { "cc", "c", "cpp", NULL }; const char * const *suffix_ptr; for (suffix_ptr = suffix_list; *suffix_ptr != NULL; suffix_ptr++) { - char *file_name = mprintf("%s.%s", user->file_prefix, *suffix_ptr); - char *path_name = compose_path_name(user->dir_name, file_name); - if (get_path_status(path_name) == PS_FILE) { - Free(path_name); - user->source_name = file_name; - if (!strcmp(*suffix_ptr, "cc") || !strcmp(*suffix_ptr, "cpp")) user->has_cc_suffix = TRUE; - break; - } - Free(file_name); - Free(path_name); + char *file_name = mprintf("%s.%s", user->file_prefix, *suffix_ptr); + char *path_name = compose_path_name(user->dir_name, file_name); + if (get_path_status(path_name) == PS_FILE) { + Free(path_name); + user->source_name = file_name; + if (!strcmp(*suffix_ptr, "cc") || !strcmp(*suffix_ptr, "cpp")) + user->has_cc_suffix = TRUE; + break; + } + Free(file_name); + Free(path_name); } } } @@ -1434,16 +1453,17 @@ static void check_naming_convention(struct makefile_struct *makefile) for (i = 0; i < makefile->nTTCN3Modules; i++) { const struct module_struct *module = makefile->TTCN3Modules + i; if (module->dir_name != NULL) { - if (!module->is_regular) makefile->BaseTTCN3ModulesRegular = FALSE; - } else { - if (!module->is_regular) makefile->TTCN3ModulesRegular = FALSE; + if (!module->is_regular) makefile->BaseTTCN3ModulesRegular = FALSE; + } + else { + if (!module->is_regular) makefile->TTCN3ModulesRegular = FALSE; } if (!makefile->TTCN3ModulesRegular && !makefile->BaseTTCN3ModulesRegular) - break; + break; } /* ttcnpp files are ttcn files */ if ((makefile->TTCN3ModulesRegular || makefile->BaseTTCN3ModulesRegular) && - makefile->preprocess) { + makefile->preprocess) { for (i = 0; i < makefile->nTTCN3PPModules; i++) { const struct module_struct *module = makefile->TTCN3PPModules + i; if (module->dir_name != NULL) { @@ -1458,29 +1478,31 @@ static void check_naming_convention(struct makefile_struct *makefile) for (i = 0; i < makefile->nASN1Modules; i++) { const struct module_struct *module = makefile->ASN1Modules + i; if (module->dir_name != NULL) { - if (!module->is_regular) makefile->BaseASN1ModulesRegular = FALSE; - } else { - if (!module->is_regular) makefile->ASN1ModulesRegular = FALSE; + if (!module->is_regular) makefile->BaseASN1ModulesRegular = FALSE; + } + else { + if (!module->is_regular) makefile->ASN1ModulesRegular = FALSE; } if (!makefile->ASN1ModulesRegular && !makefile->BaseASN1ModulesRegular) - break; + break; } for (i = 0; i < makefile->nUserFiles; i++) { const struct user_struct *user = makefile->UserFiles + i; if (user->dir_name != NULL) { - if (!user->has_cc_suffix) - makefile->BaseUserSourcesRegular = FALSE; - if (!user->has_cc_suffix || !user->has_hh_suffix) - makefile->BaseUserHeadersRegular = FALSE; - } else { - if (!user->has_cc_suffix) - makefile->UserSourcesRegular = FALSE; - if (!user->has_cc_suffix || !user->has_hh_suffix) - makefile->UserHeadersRegular = FALSE; + if (!user->has_cc_suffix) + makefile->BaseUserSourcesRegular = FALSE; + if (!user->has_cc_suffix || !user->has_hh_suffix) + makefile->BaseUserHeadersRegular = FALSE; + } + else { + if (!user->has_cc_suffix) + makefile->UserSourcesRegular = FALSE; + if (!user->has_cc_suffix || !user->has_hh_suffix) + makefile->UserHeadersRegular = FALSE; } if (!makefile->UserHeadersRegular && !makefile->UserSourcesRegular && - !makefile->BaseUserHeadersRegular && - !makefile->BaseUserSourcesRegular) break; + !makefile->BaseUserHeadersRegular && + !makefile->BaseUserSourcesRegular) break; } } else { /* this project (Makefile) will-be stand-alone */ @@ -1488,8 +1510,8 @@ static void check_naming_convention(struct makefile_struct *makefile) for (i = 0; i < makefile->nTTCN3Modules; i++) { const struct module_struct *module = makefile->TTCN3Modules + i; if (!module->is_regular || module->dir_name != NULL) { - makefile->TTCN3ModulesRegular = FALSE; - break; + makefile->TTCN3ModulesRegular = FALSE; + break; } } if (makefile->TTCN3ModulesRegular && makefile->preprocess) { @@ -1504,18 +1526,18 @@ static void check_naming_convention(struct makefile_struct *makefile) for (i = 0; i < makefile->nASN1Modules; i++) { const struct module_struct *module = makefile->ASN1Modules + i; if (!module->is_regular || module->dir_name != NULL) { - makefile->ASN1ModulesRegular = FALSE; - break; + makefile->ASN1ModulesRegular = FALSE; + break; } } for (i = 0; i < makefile->nUserFiles; i++) { const struct user_struct *user = makefile->UserFiles + i; if (!user->has_cc_suffix) - makefile->UserSourcesRegular = FALSE; + makefile->UserSourcesRegular = FALSE; if (!user->has_cc_suffix || !user->has_hh_suffix) - makefile->UserHeadersRegular = FALSE; + makefile->UserHeadersRegular = FALSE; if (!makefile->UserHeadersRegular && !makefile->UserSourcesRegular) - break; + break; } } } @@ -1639,8 +1661,13 @@ static void fprint_extra_targets(FILE* fp, struct string2_list* target_placement /** Prints the Makefile based on structure \a makefile. */ static void print_makefile(struct makefile_struct *makefile) { - boolean add_refd_prjs = makefile->sub_project_dirs && makefile->sub_project_dirs->str; - + boolean add_refd_prjs = FALSE; + if (makefile->linkingStrategy && makefile->hierarchical) { + add_refd_prjs = hasSubProject(makefile->project_name); + } + else { + add_refd_prjs = makefile->sub_project_dirs && makefile->sub_project_dirs->str; + } NOTIFY("Generating Makefile skeleton..."); if (makefile->force_overwrite || @@ -1673,7 +1700,7 @@ static void print_makefile(struct makefile_struct *makefile) fp = fopen(makefile->output_file, "w"); if (fp == NULL){ ERROR("Cannot open output file `%s' for writing: %s", - makefile->output_file, strerror(errno)); + makefile->output_file, strerror(errno)); return; } user_info = get_user_info(); @@ -1685,15 +1712,21 @@ static void print_makefile(struct makefile_struct *makefile) "# - make, make all Builds the %s.\n" "# - make archive Archives all source files.\n" "# - make check Checks the semantics of TTCN-3 and ASN.1 " - "modules.\n" - "# - make clean Removes all generated files.\n" + "modules.\n" + "%s" // clean: + "%s" //clean-all "# - make compile Translates TTCN-3 and ASN.1 modules to C++.\n" "# - make dep Creates/updates dependency list.\n" "# - make executable Builds the executable test suite.\n" "# - make library Builds the library archive.\n" "# - make objects Builds the object files without linking the " "executable.\n", user_info, - makefile->library ? "library archive." : "executable test suite"); + makefile->library ? "library archive." : "executable test suite", + (makefile->linkingStrategy && makefile->hierarchical) ? + "# - make clean Removes generated files from project.\n" : + "# - make clean Removes all generated files.\n", + (makefile->linkingStrategy && makefile->hierarchical) ? + "# - make clean-all Removes all generated files from the project hierarchy.\n" : ""); Free(user_info); if (makefile->dynamic) fprintf(fp, "# - make shared_objects Builds the shared object files " @@ -1702,14 +1735,14 @@ static void print_makefile(struct makefile_struct *makefile) fputs("# - make preprocess Preprocess TTCN-3 files.\n", fp); if (makefile->central_storage) { fputs("# WARNING! This Makefile uses pre-compiled files from the " - "following directories:\n", fp); + "following directories:\n", fp); for (i = 0; i < makefile->nBaseDirs; i++) fprintf(fp, "# %s\n", makefile->BaseDirs[i].dir_name); fputs("# The executable tests will be consistent only if all directories " - "use\n" - "# the same platform and the same version of TTCN-3 Test Executor " - "and\n" - "# C++ compiler with the same command line switches.\n\n", fp); + "use\n" + "# the same platform and the same version of TTCN-3 Test Executor " + "and\n" + "# C++ compiler with the same command line switches.\n\n", fp); } if (makefile->gnu_make) { fputs("# WARNING! This Makefile can be used with GNU make only.\n" @@ -1720,8 +1753,10 @@ static void print_makefile(struct makefile_struct *makefile) ".PHONY: all shared_objects executable library objects check clean dep archive", fp); if (makefile->preprocess) fputs(" preprocess", fp); if (add_refd_prjs) { - fputs("\\\n referenced-all referenced-shared_objects referenced-executable referenced-library referenced-objects referenced-check" - "\\\n referenced-clean referenced-archive", fp); + fprintf(fp, "\\\n referenced-all referenced-shared_objects referenced-executable referenced-library referenced-objects referenced-check" + "\\\n referenced-clean%s", + (makefile->linkingStrategy && makefile->hierarchical) ? + "-all" : ""); } fprint_extra_targets(fp, makefile->target_placement_list, "PHONY"); @@ -1731,10 +1766,31 @@ static void print_makefile(struct makefile_struct *makefile) fputs("\n\n", fp); } + if (makefile->linkingStrategy) { + const char* tpd_name = getTPDFileName(makefile->project_name); + if (tpd_name) { + fputs("# Titan Project Descriptor file what this Makefile is generated from.\n", fp); + fprintf(fp, "TPD = %s\n\n", tpd_name); + } + const char* root_dir = getPathToRootDir(makefile->project_name); + if (root_dir) { + fputs("# Relative path to top directory at OS level.\n", fp); + fprintf(fp, "ROOT_DIR = %s\n\n", root_dir); + } + } + if (add_refd_prjs) { - struct string_list* act_elem = makefile->sub_project_dirs; - fputs("# This is the top level makefile of a Makefile hierarchy generated from\n" - "# a Titan Project Descriptor hierarchy. List of referenced project\n" + struct string_list* act_elem = NULL; + struct string_list* head = NULL; + if (makefile->linkingStrategy && makefile->hierarchical) {// pair with free_string_list + head = act_elem = getRefWorkingDirs(makefile->project_name); + } + else { + act_elem = makefile->sub_project_dirs; + } + if (!makefile->linkingStrategy) + fputs("# This is the top level makefile of a Makefile hierarchy generated from\n", fp); + fputs("# Titan Project Descriptor hierarchy. List of referenced project\n" "# working directories (ordered by dependencies):\n", fp); while (act_elem) { if (act_elem->str) { @@ -1742,8 +1798,16 @@ static void print_makefile(struct makefile_struct *makefile) } act_elem = act_elem->next; } + if (makefile->linkingStrategy && makefile->hierarchical) { // pair with getRefWorkingDirs + free_string_list(head); + } fputs("REFERENCED_PROJECT_DIRS = ", fp); - act_elem = makefile->sub_project_dirs; + if (makefile->linkingStrategy && makefile->hierarchical) { + head = act_elem = getRefWorkingDirs(makefile->project_name); // pair with free_string_list + } + else { + act_elem = makefile->sub_project_dirs; + } while (act_elem) { if (act_elem->str) { fprintf(fp, "%s ", act_elem->str); @@ -1751,6 +1815,9 @@ static void print_makefile(struct makefile_struct *makefile) act_elem = act_elem->next; } fputs("\n\n", fp); + if (makefile->linkingStrategy && makefile->hierarchical) {// pair with getRefWorkingDirs + free_string_list(head); + } } fprintf(fp, "#\n" @@ -1819,6 +1886,16 @@ static void print_makefile(struct makefile_struct *makefile) } } + if (makefile->prep_undefines) { + struct string_list* act_elem = makefile->prep_undefines; + while (act_elem) { + if (act_elem->str) { + fprintf(fp, " -U%s", act_elem->str); + } + act_elem = act_elem->next; + } + } + fputs("\n\n", fp); if (makefile->gcc_dep) { @@ -1853,6 +1930,15 @@ static void print_makefile(struct makefile_struct *makefile) act_elem = act_elem->next; } } + if (makefile->ttcn3_prep_undefines) { + struct string_list* act_elem = makefile->ttcn3_prep_undefines; + while (act_elem) { + if (act_elem->str) { + fprintf(fp, " -U%s", act_elem->str); + } + act_elem = act_elem->next; + } + } fputs("\n\n", fp); } @@ -1937,7 +2023,7 @@ static void print_makefile(struct makefile_struct *makefile) fprint_extra_targets(fp, makefile->target_placement_list, "TTCN3_MODULES"); if (makefile->preprocess) { fputs("\n\n" - "# TTCN-3 modules to preprocess:\n" + "# TTCN-3 modules to preprocess:\n" "TTCN3_PP_MODULES =", fp); for (i = 0; i < makefile->nTTCN3PPModules; i++) { const struct module_struct *module = makefile->TTCN3PPModules + i; @@ -1948,21 +2034,58 @@ static void print_makefile(struct makefile_struct *makefile) } if (makefile->central_storage) { fputs("\n\n" - "# TTCN-3 modules used from central project(s):\n" - "BASE_TTCN3_MODULES =", fp); - for (i = 0; i < makefile->nTTCN3Modules; i++) { - const struct module_struct *module = makefile->TTCN3Modules + i; - /* Central storage used AND file is not in the current directory => - * it goes into BASE_TTCN3_MODULES */ - if (module->dir_name != NULL) print_file_name(fp, module); + "# TTCN-3 modules used from central project(s):\n" + "BASE_TTCN3_MODULES =", fp); + if (!makefile->linkingStrategy) { + for (i = 0; i < makefile->nTTCN3Modules; i++) { + const struct module_struct *module = makefile->TTCN3Modules + i; + /* Central storage used AND file is not in the current directory => it goes into BASE_TTCN3_MODULES */ + if (module->dir_name != NULL) print_file_name(fp, module); + } + if (makefile->preprocess) { + fputs("\n\n" + "# TTCN-3 modules to preprocess used from central project(s):\n" + "BASE_TTCN3_PP_MODULES =", fp); + for (i = 0; i < makefile->nTTCN3PPModules; i++) { + const struct module_struct *module = makefile->TTCN3PPModules + i; + if (module->dir_name != NULL && !isTtcnPPFileInLibrary(module->file_name)) + print_file_name(fp, module); + } + } } - if (makefile->preprocess) { + else { // new linking strategy + for (i = 0; i < makefile->nTTCN3Modules; i++) { + const struct module_struct *module = makefile->TTCN3Modules + i; + /* Central storage used AND file is not in the current directory => it goes into BASE_TTCN3_MODULES */ + if (module->dir_name != NULL && !isTtcn3ModuleInLibrary(module->module_name)) + print_file_name(fp, module); + } fputs("\n\n" - "# TTCN-3 modules to preprocess used from central project(s):\n" - "BASE_TTCN3_PP_MODULES =", fp); - for (i = 0; i < makefile->nTTCN3PPModules; i++) { - const struct module_struct *module = makefile->TTCN3PPModules + i; - if (module->dir_name != NULL) print_file_name(fp, module); + "# TTCN-3 library linked modules used from central project(s):\n" + "BASE2_TTCN3_MODULES =", fp); + for (i = 0; i < makefile->nTTCN3Modules; i++) { + const struct module_struct *module = makefile->TTCN3Modules + i; + /* Central storage used AND file is not in the current directory => it goes into BASE_TTCN3_MODULES */ + if (module->dir_name != NULL && isTtcn3ModuleInLibrary(module->module_name)) + print_file_name(fp, module); + } + if (makefile->preprocess) { + fputs("\n\n" + "# TTCN-3 modules to preprocess used from central project(s):\n" + "BASE_TTCN3_PP_MODULES =", fp); + for (i = 0; i < makefile->nTTCN3PPModules; i++) { + const struct module_struct *module = makefile->TTCN3PPModules + i; + if (module->dir_name != NULL && !isTtcnPPFileInLibrary(module->file_name)) + print_file_name(fp, module); + } + fputs("\n\n" + "# TTCN-3 library linked modules to preprocess used from central project(s):\n" + "BASE2_TTCN3_PP_MODULES =", fp); + for (i = 0; i < makefile->nTTCN3PPModules; i++) { + const struct module_struct *module = makefile->TTCN3PPModules + i; + if (module->dir_name != NULL && isTtcnPPFileInLibrary(module->file_name)) + print_file_name(fp, module); + } } } } @@ -1971,7 +2094,7 @@ static void print_makefile(struct makefile_struct *makefile) "# Files to include in TTCN-3 preprocessed modules:\n" "TTCN3_INCLUDES =", fp); for (i = 0; i < makefile->nTTCN3IncludeFiles; i++) - fprintf(fp, " %s", makefile->TTCN3IncludeFiles[i]); + fprintf(fp, " %s", makefile->TTCN3IncludeFiles[i]); fprint_extra_targets(fp, makefile->target_placement_list, "TTCN3_INCLUDES"); } fputs("\n\n" @@ -1980,16 +2103,33 @@ static void print_makefile(struct makefile_struct *makefile) for (i = 0; i < makefile->nASN1Modules; i++) { const struct module_struct *module = makefile->ASN1Modules + i; if (module->dir_name == NULL || !makefile->central_storage) - print_file_name(fp, module); + print_file_name(fp, module); } fprint_extra_targets(fp, makefile->target_placement_list, "ASN1_MODULES"); if (makefile->central_storage) { fputs("\n\n" - "# ASN.1 modules used from central project(s):\n" - "BASE_ASN1_MODULES =", fp); - for (i = 0; i < makefile->nASN1Modules; i++) { - const struct module_struct *module = makefile->ASN1Modules + i; - if (module->dir_name != NULL) print_file_name(fp, module); + "# ASN.1 modules used from central project(s):\n" + "BASE_ASN1_MODULES =", fp); + if (!makefile->linkingStrategy) { + for (i = 0; i < makefile->nASN1Modules; i++) { + const struct module_struct *module = makefile->ASN1Modules + i; + if (module->dir_name != NULL) print_file_name(fp, module); + } + } + else { + for (i = 0; i < makefile->nASN1Modules; i++) { + const struct module_struct *module = makefile->ASN1Modules + i; + if (module->dir_name != NULL && !isAsn1ModuleInLibrary(module->module_name)) + print_file_name(fp, module); + } + fputs("\n\n" + "# ASN.1 library linked modules used from central project(s):\n" + "BASE2_ASN1_MODULES =", fp); + for (i = 0; i < makefile->nASN1Modules; i++) { + const struct module_struct *module = makefile->ASN1Modules + i; + if (module->dir_name != NULL && isAsn1ModuleInLibrary(module->module_name)) + print_file_name(fp, module); + } } } if (makefile->preprocess) { @@ -1998,17 +2138,34 @@ static void print_makefile(struct makefile_struct *makefile) "PREPROCESSED_TTCN3_MODULES =", fp); for (i = 0; i < makefile->nTTCN3PPModules; i++) { const struct module_struct *module = makefile->TTCN3PPModules + i; - if (module->dir_name == NULL || !makefile->central_storage) - print_preprocessed_file_name(fp, module); + if (module->dir_name == NULL || !makefile->central_storage) + print_preprocessed_file_name(fp, module); } if (makefile->central_storage) { fputs("\n\n" "# TTCN-3 files generated by the CPP used from central project(s):\n" "BASE_PREPROCESSED_TTCN3_MODULES =", fp); - for (i = 0; i < makefile->nTTCN3PPModules; i++) { - const struct module_struct *module = makefile->TTCN3PPModules + i; - if (module->dir_name != NULL) - print_preprocessed_file_name(fp, module); + if (!makefile->linkingStrategy) { + for (i = 0; i < makefile->nTTCN3PPModules; i++) { + const struct module_struct *module = makefile->TTCN3PPModules + i; + if (module->dir_name != NULL) + print_preprocessed_file_name(fp, module); + } + } + else { // new linking strategy + for (i = 0; i < makefile->nTTCN3PPModules; i++) { + const struct module_struct *module = makefile->TTCN3PPModules + i; + if (module->dir_name != NULL && !isTtcnPPFileInLibrary(module->file_name)) + print_preprocessed_file_name(fp, module); + } + fputs("\n\n" + "# TTCN-3 library linked files generated by the CPP used from central project(s):\n" + "BASE2_PREPROCESSED_TTCN3_MODULES =", fp); + for (i = 0; i < makefile->nTTCN3PPModules; i++) { + const struct module_struct *module = makefile->TTCN3PPModules + i; + if (module->dir_name != NULL && isTtcnPPFileInLibrary(module->file_name)) + print_preprocessed_file_name(fp, module); + } } } } @@ -2080,11 +2237,12 @@ static void print_makefile(struct makefile_struct *makefile) fputs("\nGENERATED_HEADERS =", fp); if (makefile->gnu_make) { fputs(" $(GENERATED_SOURCES:.cc=.hh)", fp); - } else { + } + else { for (i = 0; i < makefile->nTTCN3Modules; i++) { - const struct module_struct *module = makefile->TTCN3Modules + i; - if (module->dir_name == NULL || !makefile->central_storage) - print_generated_file_name(fp, module, FALSE, ".hh"); + const struct module_struct *module = makefile->TTCN3Modules + i; + if (module->dir_name == NULL || !makefile->central_storage) + print_generated_file_name(fp, module, FALSE, ".hh"); } if (makefile->preprocess) { for (i = 0; i < makefile->nTTCN3PPModules; i++) { @@ -2094,9 +2252,9 @@ static void print_makefile(struct makefile_struct *makefile) } } for (i = 0; i < makefile->nASN1Modules; i++) { - const struct module_struct *module = makefile->ASN1Modules + i; - if (module->dir_name == NULL || !makefile->central_storage) - print_generated_file_name(fp, module, FALSE, ".hh"); + const struct module_struct *module = makefile->ASN1Modules + i; + if (module->dir_name == NULL || !makefile->central_storage) + print_generated_file_name(fp, module, FALSE, ".hh"); } } if (makefile->central_storage) { @@ -2168,36 +2326,74 @@ static void print_makefile(struct makefile_struct *makefile) } fputs("\nBASE_GENERATED_HEADERS =", fp); if (makefile->gnu_make) { - fputs(" $(BASE_GENERATED_SOURCES:.cc=.hh)", fp); + fputs(" $(BASE_GENERATED_SOURCES:.cc=.hh)", fp); } else { - for (i = 0; i < makefile->nTTCN3Modules; i++) { - const struct module_struct *module = makefile->TTCN3Modules + i; - if (module->dir_name != NULL) - print_generated_file_name(fp, module, TRUE, ".hh"); - } - if (makefile->preprocess) { - for (i = 0; i < makefile->nTTCN3PPModules; i++) { - const struct module_struct *module = makefile->TTCN3PPModules + i; - if (module->dir_name != NULL) - print_generated_file_name(fp, module, TRUE, ".hh"); - } - } - for (i = 0; i < makefile->nASN1Modules; i++) { - const struct module_struct *module = makefile->ASN1Modules + i; - if (module->dir_name != NULL) - print_generated_file_name(fp, module, TRUE, ".hh"); - } + for (i = 0; i < makefile->nTTCN3Modules; i++) { + const struct module_struct *module = makefile->TTCN3Modules + i; + if (module->dir_name != NULL) + print_generated_file_name(fp, module, TRUE, ".hh"); + } + if (makefile->preprocess) { + for (i = 0; i < makefile->nTTCN3PPModules; i++) { + const struct module_struct *module = makefile->TTCN3PPModules + i; + if (module->dir_name != NULL) + print_generated_file_name(fp, module, TRUE, ".hh"); + } + } + for (i = 0; i < makefile->nASN1Modules; i++) { + const struct module_struct *module = makefile->ASN1Modules + i; + if (module->dir_name != NULL) + print_generated_file_name(fp, module, TRUE, ".hh"); + } + } + } + + if (makefile->linkingStrategy) { + fputs("\n\n" + "# C++ source & header files generated from the TTCN-3 " + " library linked modules of\n" + "# central project(s):\n" + "BASE2_GENERATED_SOURCES =", fp); + if (makefile->gnu_make && makefile->BaseTTCN3ModulesRegular) { + fputs(" $(BASE2_TTCN3_MODULES:.ttcn=.cc)", fp); + fputs(" $(BASE2_ASN1_MODULES:.asn=.cc)", fp); + if (makefile->preprocess) + fputs(" $(BASE2_TTCN3_PP_MODULES:.ttcnpp=.cc)", fp); + } + else { + for (i = 0; i < makefile->nTTCN3Modules; i++) { + const struct module_struct *module = makefile->TTCN3Modules + i; + if (module->dir_name != NULL && isTtcn3ModuleInLibrary(module->module_name)) { + print_generated_file_name(fp, module, TRUE, ".cc"); + } + } + if (makefile->preprocess) { + for (i = 0; i < makefile->nTTCN3PPModules; i++) { + const struct module_struct *module = makefile->TTCN3PPModules + i; + if (module->dir_name != NULL && isTtcnPPFileInLibrary(module->file_name)) { + print_generated_file_name(fp, module, TRUE, ".cc"); + } + } + } } + + fputs("\nBASE2_GENERATED_HEADERS =", fp); + if (makefile->gnu_make) { + fputs(" $(BASE2_GENERATED_SOURCES:.cc=.hh)", fp); + } + else + ERROR("the usage of 'Z' flag requires GNU make"); } + fputs("\n\n" "# C/C++ Source & header files of Test Ports, external functions " - "and\n" - "# other modules:\n" + "and\n" + "# other modules:\n" "USER_SOURCES =", fp); for (i = 0; i < makefile->nUserFiles; i++) { const struct user_struct *user = makefile->UserFiles + i; if (user->dir_name == NULL || !makefile->central_storage) - print_source_name(fp, user); + print_source_name(fp, user); } fprint_extra_targets(fp, makefile->target_placement_list, "USER_SOURCES"); fputs("\nUSER_HEADERS =", fp); @@ -2205,35 +2401,80 @@ static void print_makefile(struct makefile_struct *makefile) fputs(" $(USER_SOURCES:.cc=.hh)", fp); } else { for (i = 0; i < makefile->nUserFiles; i++) { - const struct user_struct *user = makefile->UserFiles + i; - if (user->dir_name == NULL || !makefile->central_storage) - print_header_name(fp, user); + const struct user_struct *user = makefile->UserFiles + i; + if (user->dir_name == NULL || !makefile->central_storage) + print_header_name(fp, user); } } fprint_extra_targets(fp, makefile->target_placement_list, "USER_HEADERS"); if (makefile->central_storage) { fputs("\n\n" "# C/C++ Source & header files of Test Ports, external functions " - "and\n" - "# other modules used from central project(s):\n" + "and\n" + "# other modules used from central project(s):\n" "BASE_USER_SOURCES =", fp); - for (i = 0; i < makefile->nUserFiles; i++) { - const struct user_struct *user = makefile->UserFiles + i; - if (user->dir_name != NULL) - print_source_name(fp, user); + if (!makefile->linkingStrategy) { + for (i = 0; i < makefile->nUserFiles; i++) { + const struct user_struct *user = makefile->UserFiles + i; + if (user->dir_name != NULL) { + print_source_name(fp, user); + } + } + fputs("\nBASE_USER_HEADERS =", fp); + if (makefile->gnu_make && makefile->BaseUserHeadersRegular) { + fputs(" $(BASE_USER_SOURCES:.cc=.hh)", fp); + } + else { + for (i = 0; i < makefile->nUserFiles; i++) { + const struct user_struct *user = makefile->UserFiles + i; + if (user->dir_name != NULL) + print_header_name(fp, user); + } + } } - fputs("\nBASE_USER_HEADERS =", fp); - if (makefile->gnu_make && makefile->BaseUserHeadersRegular) { - fputs(" $(BASE_USER_SOURCES:.cc=.hh)", fp); - } else { - for (i = 0; i < makefile->nUserFiles; i++) { - const struct user_struct *user = makefile->UserFiles + i; - if (user->dir_name != NULL) - print_header_name(fp, user); - } + else { + for (i = 0; i < makefile->nUserFiles; i++) { + const struct user_struct *user = makefile->UserFiles + i; + if (user->dir_name != NULL && !isSourceFileInLibrary(user->source_name)) { + print_source_name(fp, user); + } + } + fputs("\nBASE_USER_HEADERS =", fp); + if (makefile->gnu_make && makefile->BaseUserHeadersRegular) { + fputs(" $(BASE_USER_SOURCES:.cc=.hh)", fp); + } + else { + for (i = 0; i < makefile->nUserFiles; i++) { + const struct user_struct *user = makefile->UserFiles + i; + if (user->dir_name != NULL && !isHeaderFileInLibrary(user->header_name)) + print_header_name(fp, user); + } + } + + fputs("\n\n" + "# C/C++ Source & header files of Test Ports, external functions " + "and\n" + "# other modules used from library linked central project(s):\n" + "BASE2_USER_SOURCES =", fp); + for (i = 0; i < makefile->nUserFiles; i++) { + const struct user_struct *user = makefile->UserFiles + i; + if (user->dir_name != NULL && isSourceFileInLibrary(user->source_name)) { + print_source_name(fp, user); + } + } + fputs("\nBASE2_USER_HEADERS =", fp); + if (makefile->gnu_make && makefile->BaseUserHeadersRegular) { + fputs(" $(BASE2_USER_SOURCES:.cc=.hh)", fp); + } + else { + for (i = 0; i < makefile->nUserFiles; i++) { + const struct user_struct *user = makefile->UserFiles + i; + if (user->dir_name != NULL && isHeaderFileInLibrary(user->header_name)) + print_header_name(fp, user); + } + } } } - if (makefile->dynamic) { fputs("\n\n" "# Shared object files of this project:\n" @@ -2299,7 +2540,7 @@ static void print_makefile(struct makefile_struct *makefile) fputs("\n\n" "# Object files of this project that are needed for the executable " - "test suite:\n" + "test suite:\n" "OBJECTS = $(GENERATED_OBJECTS) $(USER_OBJECTS)\n\n" /* never := */ "GENERATED_OBJECTS =", fp); if (makefile->gnu_make) { @@ -2376,77 +2617,170 @@ static void print_makefile(struct makefile_struct *makefile) fputs("\n\n" "# Shared object files of central project(s):\n" "BASE_SHARED_OBJECTS =", fp); + if (!makefile->linkingStrategy) { + if (makefile->gnu_make) { + fputs(" $(BASE_GENERATED_SOURCES:.cc=.so)", fp); + } + else { + for (i = 0; i < makefile->nTTCN3Modules; i++) { + const struct module_struct *module = makefile->TTCN3Modules + i; + if (module->dir_name != NULL) + print_generated_file_name(fp, module, TRUE, ".so"); + } + if (makefile->preprocess) { + for (i = 0; i < makefile->nTTCN3PPModules; i++) { + const struct module_struct *module = + makefile->TTCN3PPModules + i; + if (module->dir_name != NULL) + print_generated_file_name(fp, module, TRUE, ".so"); + } + } + for (i = 0; i < makefile->nASN1Modules; i++) { + const struct module_struct *module = makefile->ASN1Modules + i; + if (module->dir_name != NULL) + print_generated_file_name(fp, module, TRUE, ".so"); + } + } + if (makefile->gnu_make && makefile->BaseUserSourcesRegular) { + fputs(" $(BASE_USER_SOURCES:.cc=.so)", fp); + } + else { + for (i = 0; i < makefile->nUserFiles; i++) { + const struct user_struct *user = makefile->UserFiles + i; + if (user->dir_name != NULL) + print_shared_object_name(fp, user); + } + } + } + else { // new linkingStrategy + if (makefile->gnu_make) { + fputs(" $(BASE_GENERATED_SOURCES:.cc=.so)", fp); + } + else + ERROR("the usage of 'Z' flag requires GNU make"); + + if (makefile->gnu_make && makefile->BaseUserSourcesRegular) { + fputs(" $(BASE_USER_SOURCES:.cc=.so)", fp); + } + else { + for (i = 0; i < makefile->nUserFiles; i++) { + const struct user_struct *user = makefile->UserFiles + i; + if (user->dir_name != NULL && !isSourceFileInLibrary(user->source_name)) + print_shared_object_name(fp, user); + } + } + } + } /* if dynamic */ + fputs("\n\n" + "# Object files of central project(s) that are needed for the " + "executable test suite:\n" + "BASE_OBJECTS =", fp); + if (!makefile->linkingStrategy) { if (makefile->gnu_make) { - fputs(" $(BASE_GENERATED_SOURCES:.cc=.so)", fp); - } else { + fputs(" $(BASE_GENERATED_SOURCES:.cc=.o)", fp); + } + else { for (i = 0; i < makefile->nTTCN3Modules; i++) { const struct module_struct *module = makefile->TTCN3Modules + i; if (module->dir_name != NULL) - print_generated_file_name(fp, module, TRUE, ".so"); + print_generated_file_name(fp, module, TRUE, ".o"); } if (makefile->preprocess) { for (i = 0; i < makefile->nTTCN3PPModules; i++) { - const struct module_struct *module = - makefile->TTCN3PPModules + i; + const struct module_struct *module = makefile->TTCN3PPModules + i; if (module->dir_name != NULL) - print_generated_file_name(fp, module, TRUE, ".so"); + print_generated_file_name(fp, module, TRUE, ".o"); } } for (i = 0; i < makefile->nASN1Modules; i++) { const struct module_struct *module = makefile->ASN1Modules + i; if (module->dir_name != NULL) - print_generated_file_name(fp, module, TRUE, ".so"); + print_generated_file_name(fp, module, TRUE, ".o"); } } if (makefile->gnu_make && makefile->BaseUserSourcesRegular) { - fputs(" $(BASE_USER_SOURCES:.cc=.so)", fp); - } else { + fputs(" $(BASE_USER_SOURCES:.cc=.o)", fp); + } + else { for (i = 0; i < makefile->nUserFiles; i++) { const struct user_struct *user = makefile->UserFiles + i; if (user->dir_name != NULL) - print_shared_object_name(fp, user); + print_object_name(fp, user); } } - } /* if dynamic */ - fputs("\n\n" - "# Object files of central project(s) that are needed for the " - "executable test suite:\n" - "BASE_OBJECTS =", fp); - if (makefile->gnu_make) { - fputs(" $(BASE_GENERATED_SOURCES:.cc=.o)", fp); - } else { - for (i = 0; i < makefile->nTTCN3Modules; i++) { - const struct module_struct *module = makefile->TTCN3Modules + i; - if (module->dir_name != NULL) - print_generated_file_name(fp, module, TRUE, ".o"); + } + else { // new linkingStrategy + if (makefile->gnu_make) { + fputs(" $(BASE_GENERATED_SOURCES:.cc=.o)", fp); } - if (makefile->preprocess) { - for (i = 0; i < makefile->nTTCN3PPModules; i++) { - const struct module_struct *module = makefile->TTCN3PPModules + i; - if (module->dir_name != NULL) - print_generated_file_name(fp, module, TRUE, ".o"); - } + else + ERROR("the usage of 'Z' flag requires GNU make"); + + if (makefile->gnu_make && makefile->BaseUserSourcesRegular) { + fputs(" $(BASE_USER_SOURCES:.cc=.o)", fp); } - for (i = 0; i < makefile->nASN1Modules; i++) { - const struct module_struct *module = makefile->ASN1Modules + i; - if (module->dir_name != NULL) - print_generated_file_name(fp, module, TRUE, ".o"); + else { + for (i = 0; i < makefile->nUserFiles; i++) { + const struct user_struct *user = makefile->UserFiles + i; + if (user->dir_name != NULL && !isSourceFileInLibrary(user->source_name)) + print_object_name(fp, user); + } } } + } + if (makefile->linkingStrategy) { + fputs("\n\n" + "# Object files of library linked central project(s) that are needed for the " + "executable test suite:\n" + "BASE2_OBJECTS =", fp); + if (makefile->gnu_make) { + if (makefile->dynamic) + fputs(" $(BASE2_GENERATED_SOURCES:.cc=.so)", fp); + else + fputs(" $(BASE2_GENERATED_SOURCES:.cc=.o)", fp); + } + else ERROR("the usage of 'Z' flag requires GNU make"); + if (makefile->gnu_make && makefile->BaseUserSourcesRegular) { - fputs(" $(BASE_USER_SOURCES:.cc=.o)", fp); - } else { + if (makefile->dynamic) + fputs(" $(BASE2_USER_SOURCES:.cc=.so)", fp); + else + fputs(" $(BASE2_USER_SOURCES:.cc=.o)", fp); + } + else { for (i = 0; i < makefile->nUserFiles; i++) { const struct user_struct *user = makefile->UserFiles + i; - if (user->dir_name != NULL) - print_object_name(fp, user); + if (user->dir_name != NULL && isSourceFileInLibrary(user->source_name)) { + if (makefile->dynamic) + print_shared_object_name(fp, user); + else + print_object_name(fp, user); + } + } + } + if (makefile->hierarchical) { + fputs("\n\n" + "#Libraries of referenced project(s) that are needed for the " + "executable or library target:\n" + "BASE2_LIBRARY =", fp); + struct string2_list* head = getLinkerLibs(makefile->project_name); + struct string2_list* act_elem = head; + while (act_elem) { + if (act_elem->str2) { + fputs(" ", fp); + fprintf(fp, "%s/lib%s.%s", act_elem->str1, act_elem->str2, + isDynamicLibrary(act_elem->str2) ? "so" : "a"); + } + act_elem = act_elem->next; } + free_string2_list(head); } } + fputs("\n\n" - "# Other files of the project (Makefile, configuration files, etc.)\n" - "# that will be added to the archived source files:\n" - "OTHER_FILES =", fp); + "# Other files of the project (Makefile, configuration files, etc.)\n" + "# that will be added to the archived source files:\n" + "OTHER_FILES =", fp); for (i = 0; i < makefile->nOtherFiles; i++) fprintf(fp, " %s", makefile->OtherFiles[i]); fprint_extra_targets(fp, makefile->target_placement_list, "OTHER_FILES"); @@ -2465,19 +2799,35 @@ static void print_makefile(struct makefile_struct *makefile) fputs(".exe", fp); } #endif - fputs("\n", fp); - + fputs("\n\n", fp); + if (makefile->linkingStrategy) { +#ifndef WIN32 + fputs("DYNAMIC_LIBRARY = lib$(EXECUTABLE).so\n", fp); + fputs("STATIC_LIBRARY = lib$(EXECUTABLE).a\n", fp); +#else + char* name_prefix = cut_suffix(makefile->ets_name); + fprintf(fp, "DYNAMIC_LIBRARY = lib%s.so\n", name_prefix); + fprintf(fp, "STATIC_LIBRARY = lib%s.a\n", name_prefix); + Free(name_prefix); +#endif + } /* LIBRARY variable */ ets_suffix = get_suffix(makefile->ets_name); if (ets_suffix != NULL && !strcmp(ets_suffix, "exe")) { char* name_prefix = cut_suffix(makefile->ets_name); - fprintf(fp, "\n\nLIBRARY = %s%s\n", name_prefix ? name_prefix : "library", - makefile->dynamic ? "_lib.so" : ".a"); - Free(name_prefix); - } else { - fprintf(fp, "\n\nLIBRARY = %s%s\n", makefile->ets_name, - makefile->dynamic ? "_lib.so" : ".a"); + fprintf(fp, "\n\nLIBRARY = %s%s%s\n", "lib", name_prefix ? name_prefix : "library", + makefile->dynamic ? ".so" : ".a"); + Free(name_prefix); } + else { +#ifndef WIN32 + fprintf(fp, "\n\nLIBRARY = lib$(EXECUTABLE)%s\n", + makefile->dynamic ? ".so" : ".a"); +#else + fprintf(fp, "\n\nLIBRARY = lib%s%s\n", + makefile->ets_name, makefile->dynamic ? ".so" : ".a"); +#endif + } } else { fputs("\n\n" @@ -2485,10 +2835,20 @@ static void print_makefile(struct makefile_struct *makefile) "EXECUTABLE =\n" "LIBRARY =\n", fp); } - - fprintf(fp, "\n" + if (!makefile->linkingStrategy || !buildObjects(makefile->project_name, add_refd_prjs)) { + fprintf(fp, "\n" "TARGET = $(%s)", makefile->library ? "LIBRARY" : "EXECUTABLE"); - + } + else { + if (makefile->dynamic) { + fputs("\n" + "TARGET = $(SHARED_OBJECTS)", fp); + } + else { + fputs("\n" + "TARGET = $(OBJECTS)", fp); + } + } fputs("\n\n" "#\n" "# Do not modify these unless you know what you are doing...\n" @@ -2583,8 +2943,10 @@ static void print_makefile(struct makefile_struct *makefile) /* There is no need to create the .so for all the source files */ fputs("$(EXECUTABLE): $(LIBRARY)\n" "\tif $(CXX) $(LDFLAGS) -o $@ $(LIBRARY)", fp); - } else { - fprintf(fp, "$(EXECUTABLE): %s", makefile->dynamic ? "$(SHARED_OBJECTS)" : "$(OBJECTS)"); + } + else { + fprintf(fp, "$(EXECUTABLE): %s", makefile->dynamic ? "$(SHARED_OBJECTS)" : "$(OBJECTS)"); + if (!makefile->linkingStrategy) { // use the old linking method if (makefile->central_storage) { if (makefile->dynamic) { fputs(" $(BASE_SHARED_OBJECTS)", fp); @@ -2592,19 +2954,39 @@ static void print_makefile(struct makefile_struct *makefile) fputs(" $(BASE_OBJECTS)", fp); } } - fputs("\n" - "\tif $(CXX) $(LDFLAGS) -o $@ ", fp); /* start writing the link step */ - if (makefile->gnu_make) fputs("$^", fp); - else { + } + else { + if (!makefile->library) { if (makefile->dynamic) { - fputs("$(SHARED_OBJECTS)", fp); + fputs(" $(BASE_SHARED_OBJECTS)", fp); + } + else { + fputs(" $(BASE_OBJECTS)", fp); + } + if (makefile->hierarchical) { + fputs(" $(BASE2_LIBRARY)", fp); + } + } + } + fprintf(fp, "\n" + "\tif $(CXX) $(LDFLAGS) -o $@ %s", +#if defined (SOLARIS) || defined (SOLARIS8) + ""); +#else + makefile->dynamic ? "-Wl,--no-as-needed " : ""); /* start writing the link step */ +#endif + if (makefile->gnu_make) fputs("$^", fp); + else { + if (makefile->dynamic) { + fputs("$(SHARED_OBJECTS)", fp); if (makefile->central_storage) - fputs(" $(BASE_SHARED_OBJECTS)", fp); - } else { - fputs("$(OBJECTS)", fp); + fputs(" $(BASE_SHARED_OBJECTS)", fp); + } + else { + fputs("$(OBJECTS)", fp); if (makefile->central_storage) - fputs(" $(BASE_OBJECTS)", fp); - } + fputs(" $(BASE_OBJECTS)", fp); + } } } @@ -2622,27 +3004,65 @@ static void print_makefile(struct makefile_struct *makefile) "\t-L$(TTCN3_DIR)/lib -l$(TTCN3_LIB)" " \\\n" "\t-L$(OPENSSL_DIR)/lib -lcrypto"); - if (makefile->linkerlibraries) { - struct string_list* act_elem = makefile->linkerlibraries; - while (act_elem) { - if (act_elem->str) { - fprintf(fp, " -l%s", act_elem->str); + if (!makefile->linkingStrategy) { + if (makefile->linkerlibraries) { + struct string_list* act_elem = makefile->linkerlibraries; + while (act_elem) { + if (act_elem->str) { + fprintf(fp, " -l%s", act_elem->str); + } + act_elem = act_elem->next; } - act_elem = act_elem->next; } - } - if (makefile->linkerlibsearchpath) { - struct string_list* act_elem = makefile->linkerlibsearchpath; - while (act_elem) { - if (act_elem->str) { - fprintf(fp, " -L%s", act_elem->str); + if (makefile->linkerlibsearchpath) { + struct string_list* act_elem = makefile->linkerlibsearchpath; + while (act_elem) { + if (act_elem->str) { + fprintf(fp, " -L%s", act_elem->str); + } + act_elem = act_elem->next; } - act_elem = act_elem->next; } + fprintf(fp, " \\\n" + "\t-L$(XMLDIR)/lib $($(PLATFORM)_LIBS); \\\n" + "\tthen : ; else $(TTCN3_DIR)/bin/titanver $(OBJECTS); exit 1; fi\n"); + } + else { // new linking strategy + fputs (" \\\n", fp); + if (makefile->linkerlibraries && !makefile->library) { + struct string2_list* head = getLinkerLibs(makefile->project_name); + struct string2_list* act_elem = head; + while (act_elem) { + if (act_elem->str1 && act_elem->str2) { + fprintf(fp, "\t-L%s -Wl,-rpath=%s -l%s \\\n", act_elem->str1, act_elem->str1, act_elem->str2); + } + act_elem = act_elem->next; + } + free_string2_list(head); + + struct string_list* act_head = getExternalLibPathes(makefile->project_name); + struct string_list* act_ext_elem = act_head; + while (act_ext_elem) { + if (act_ext_elem->str) { + fprintf(fp, "\t-L%s \\\n", act_ext_elem->str); + } + act_ext_elem = act_ext_elem->next; + } + free_string_list(act_head); + act_head = getExternalLibs(makefile->project_name); + act_ext_elem = act_head; + while (act_ext_elem) { + if (act_ext_elem->str) { + fprintf(fp, "\t-l%s \\\n", act_ext_elem->str); + } + act_ext_elem = act_ext_elem->next; + } + free_string_list(act_head); + } + fprintf(fp, + "\t-L$(XMLDIR)/lib $($(PLATFORM)_LIBS); \\\n" + "\tthen : ; else $(TTCN3_DIR)/bin/titanver $(OBJECTS); exit 1; fi\n"); } - fprintf(fp, " \\\n" - "\t-L$(XMLDIR)/lib $($(PLATFORM)_LIBS); \\\n" - "\tthen : ; else $(TTCN3_DIR)/bin/titanver $(OBJECTS); exit 1; fi\n"); /* If the compiler will not be run because there are no TTCN(PP) or ASN.1 * files, create the "compile" marker file which is checked by the * superior makefile if using this project as central storage */ @@ -2651,21 +3071,115 @@ static void print_makefile(struct makefile_struct *makefile) /* target $(LIBRARY) */ if (makefile->dynamic) { - fputs("\n" - "$(LIBRARY): $(OBJECTS)\n" - "\t$(CXX) -shared -o $@ $(OBJECTS)", fp); - if (makefile->central_storage) { - fputs(" $(BASE_SHARED_OBJECTS)", fp); + fprintf(fp, "\n" + "$(LIBRARY): $(OBJECTS)%s\n" + "\t$(CXX) -shared -o $@ $(OBJECTS)", + makefile->hierarchical ? " $(BASE2_LIBRARY)" : ""); + if (makefile->central_storage && !makefile->linkingStrategy) { + fputs(" $(BASE_SHARED_OBJECTS) ;\n" + "\tln -s $@ $(subst lib, ,$@) > /dev/null 2>&1 ;", fp); } - } else { - fputs("\n" - "$(LIBRARY): $(OBJECTS)\n" - "\t$(AR) -r $(ARFLAGS) $(LIBRARY) $(OBJECTS)", fp); - if (makefile->central_storage) { + if (makefile->linkingStrategy) { + struct string2_list* head = getLinkerLibs(makefile->project_name); + struct string2_list* act_elem = head; + // If the project is Executable on Top Level the linker can link the *.a and *.so together + while (act_elem && !isTopLevelExecutable(makefile->project_name)) { + if (act_elem->str1 && act_elem->str2 && isDynamicLibrary(act_elem->str2)) { + fputs(" \\\n", fp); + fprintf(fp, "\t-L%s -Wl,-rpath=%s -l%s", act_elem->str1, act_elem->str1, act_elem->str2); + } + else { + const char* mainLibName = getLibFromProject(makefile->project_name); + ERROR("Library archive 'lib%s.a' cannot be linked to dynamic library 'lib%s.so' " + "in project '%s' ", + act_elem->str2, mainLibName ? mainLibName : "", makefile->project_name); + free_string2_list(head); + exit(EXIT_FAILURE); + } + act_elem = act_elem->next; + } + free_string2_list(head); + struct string_list* act_head = getExternalLibPathes(makefile->project_name); + struct string_list* act_ext_elem = act_head; + while (act_ext_elem) { + if (act_ext_elem->str) { + fputs(" \\\n", fp); + fprintf(fp, "\t-L%s", act_ext_elem->str); + } + act_ext_elem = act_ext_elem->next; + } + free_string_list(act_head); + act_head = getExternalLibs(makefile->project_name); + act_ext_elem = act_head; + while (act_ext_elem) { + if (act_ext_elem->str) { + fputs(" \\\n", fp); + fprintf(fp, "\t-l%s", act_ext_elem->str); + } + act_ext_elem = act_ext_elem->next; + } + free_string_list(act_head); + } + } + else { // static linking + fprintf(fp, "\n" + "$(LIBRARY): $(OBJECTS)%s\n" + "\t$(AR) -r%s $(ARFLAGS) $(LIBRARY) $(OBJECTS)", + makefile->hierarchical ? " $(BASE2_LIBRARY)" : "", + makefile->linkingStrategy ? "cT" : ""); + if (makefile->central_storage && !makefile->linkingStrategy) { fputs(" $(BASE_OBJECTS)", fp); } + if (makefile->linkingStrategy) { + if ( makefile->library) { + struct string2_list* head = getLinkerLibs(makefile->project_name); + struct string2_list* act_elem = head; + while (act_elem) { + if (act_elem->str2 && !isDynamicLibrary(act_elem->str2)) { + fputs(" \\\n", fp); + fprintf(fp, "\t%s/lib%s.a", act_elem->str1, act_elem->str2); + } + else { + const char* mainLibName = getLibFromProject(makefile->project_name); + if (act_elem->str2) { + ERROR("Dynamic library 'lib%s.so' cannot be linked to static library 'lib%s.a' " + "in project '%s' ", + act_elem->str2, mainLibName ? mainLibName : "", makefile->project_name); + exit(EXIT_FAILURE); + } + else { + struct string_list* ext_libs = getExternalLibs(makefile->project_name); + if (ext_libs && ext_libs->str) { + ERROR("Third party dynamic library '%s' cannot be linked to static library 'lib%s.a' " + "in project '%s' ", ext_libs->str, + mainLibName ? mainLibName : "", makefile->project_name); + free_string_list(ext_libs); + exit(EXIT_FAILURE); + } + free_string_list(ext_libs); + } + } + act_elem = act_elem->next; + } + free_string2_list(head); + + struct string_list* act_head = getExternalLibs(makefile->project_name); + struct string_list* act_ext_elem = act_head; + while (act_ext_elem) { + if (act_ext_elem->str && hasExternalLibrary(act_ext_elem->str, makefile->project_name)) { + fputs(" \\\n", fp); + fprintf(fp, "\tlib%s.a", act_ext_elem->str); + ERROR("linking static 3d party or sytem library 'lib%s.a' to " + "project library 'lib%s.a' is not supported ", + act_ext_elem->str, makefile->ets_name); + exit(EXIT_FAILURE); + } + act_ext_elem = act_ext_elem->next; + } + free_string_list(act_head); + } + } } - fputs("\n\n.cc.o .c.o:\n" "\t$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $@ $<\n\n", fp); @@ -2698,7 +3212,9 @@ static void print_makefile(struct makefile_struct *makefile) if (makefile->central_storage) { boolean is_first = TRUE; - fputs("$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile-all compile ", fp); + fprintf(fp, "$(GENERATED_SOURCES) $(GENERATED_HEADERS):%s compile-all compile ", + makefile->hierarchical ? " update" : ""); + if (add_refd_prjs) fputs("referenced-dep", fp); /* These extra compile dependencies for the generated .cc are here to * check if all the referenced projects are up to date. @@ -2707,175 +3223,260 @@ static void print_makefile(struct makefile_struct *makefile) */ if (!add_refd_prjs) for (i = 0; i < makefile->nBaseDirs; i++) { const struct base_dir_struct *base_dir = makefile->BaseDirs + i; - if (base_dir->has_modules) { - if (is_first) { - fputs(" \\\n", fp); - is_first = FALSE; - } else putc(' ', fp); - fprintf(fp, "%s/compile", base_dir->dir_name); - } + if (base_dir->has_modules) { + if (is_first) { + fputs(" \\\n", fp); + is_first = FALSE; + } + else putc(' ', fp); + fprintf(fp, "%s/compile", base_dir->dir_name); + } } - if (makefile->preprocess) { - fprintf(fp, "\n" - "\t@if [ ! -f $@ ]; then %s compile-all; $(MAKE) compile-all; fi\n" - "\n" - "check:%s $(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" - "\t$(PREPROCESSED_TTCN3_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) " - "\\\n" - "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)\n" - "\t$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) ", rm_command, add_refd_prjs?" referenced-check":""); - if (makefile->gnu_make) { - if (add_refd_prjs) // referenced-check cannot be compiled it is not a ttcn modul - fputs("$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" - "\t$(PREPROCESSED_TTCN3_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) " - "\\\n" - "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)\n", fp); - else - fputs("$^", fp); - } - else { - fputs("\\\n" - "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" - "\t$(PREPROCESSED_TTCN3_MODULES) " - "$(BASE_PREPROCESSED_TTCN3_MODULES) \\\n" - "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)", fp); - } - fputs("\n\n" - "compile: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) " - "$(ASN1_MODULES)\n" - "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n" - "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" - "\t$(PREPROCESSED_TTCN3_MODULES) " - "$(BASE_PREPROCESSED_TTCN3_MODULES) \\\n" - "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) - $?\n" - "\ttouch $@\n" - "\n" - "compile-all: $(BASE_TTCN3_MODULES) " - "$(BASE_PREPROCESSED_TTCN3_MODULES) \\\n" - "$(BASE_ASN1_MODULES)\n" - "\t$(MAKE) preprocess\n" - "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n" - "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" - "\t$(PREPROCESSED_TTCN3_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) " - "\\\n" - "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) \\\n" - "\t- $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES)\n" - "\ttouch $@ compile\n\n", fp); - } else { - fprintf(fp, "\n" - "\t@if [ ! -f $@ ]; then %s compile-all; $(MAKE) compile-all; fi\n" - "\n" - "check:%s $(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" - "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)\n" - "\t$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) ", rm_command, add_refd_prjs?" referenced-check":""); - if (makefile->gnu_make) { - if (add_refd_prjs) // referenced-check cannot be compiled it is not a ttcn modul - fputs("$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" - "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)\n", fp); - else - fputs("$^", fp); - } - else { - fputs("\\\n" - "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" - "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)", fp); - } - fputs("\n\n" - "compile: $(TTCN3_MODULES) $(ASN1_MODULES)\n" - "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n" - "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" - "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) \\\n" - "\t- $?\n" - "\ttouch $@\n" - "\n" - "compile-all: $(BASE_TTCN3_MODULES) $(BASE_ASN1_MODULES)\n" - "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n" - "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" - "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) \\\n" - "\t- $(TTCN3_MODULES) $(ASN1_MODULES)\n" - "\ttouch $@ compile\n\n", fp); - } - for (i = 0; i < makefile->nBaseDirs; i++) { - const struct base_dir_struct *base_dir = makefile->BaseDirs + i; - if (base_dir->has_modules) { - size_t j; - fprintf(fp, "%s/compile:", base_dir->dir_name); - for (j = 0; j < makefile->nTTCN3Modules; j++) { - const struct module_struct *module = makefile->TTCN3Modules + j; - if (module->dir_name != NULL && - !strcmp(base_dir->dir_name, module->dir_name)) - print_file_name(fp, module); - } - for (j = 0; j < makefile->nTTCN3PPModules; j++) { - const struct module_struct *module = makefile->TTCN3PPModules + j; - if (module->dir_name != NULL && - !strcmp(base_dir->dir_name, module->dir_name)) - print_file_name(fp, module); - } - for (j = 0; j < makefile->nASN1Modules; j++) { - const struct module_struct *module = makefile->ASN1Modules + j; - if (module->dir_name != NULL && - !strcmp(base_dir->dir_name, module->dir_name)) - print_file_name(fp, module); - } - fprintf(fp, "\n" - "\t@echo 'Central directory %s is not up-to-date!'\n" - "\t@exit 2\n\n", base_dir->dir_name); - } + fprintf(fp, "\n" + "\t@if [ ! -f $@ ]; then %s compile-all; $(MAKE) compile-all; fi\n" + "\n" + "check:%s $(TTCN3_MODULES) $(BASE_TTCN3_MODULES) %s\\\n" + "\t$(PREPROCESSED_TTCN3_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) " + "%s\\\n" + "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) %s\n" + "\t$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) ", + rm_command, add_refd_prjs?" referenced-check":"", + makefile->linkingStrategy ? "$(BASE2_TTCN3_MODULES) ":"", + makefile->linkingStrategy ? "$(BASE2_PREPROCESSED_TTCN3_MODULES) ":"", + makefile->linkingStrategy ? "$(BASE2_ASN1_MODULES) ":""); + if (makefile->gnu_make) { + if (add_refd_prjs) // referenced-check cannot be compiled it is not a ttcn modul + fprintf(fp, "$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) %s\\\n" + "\t$(PREPROCESSED_TTCN3_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) " + "%s\\\n" + "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) %s\n", + makefile->linkingStrategy ? "$(BASE2_TTCN3_MODULES) ":"", + makefile->linkingStrategy ? "$(BASE2_PREPROCESSED_TTCN3_MODULES) ":"", + makefile->linkingStrategy ? "$(BASE2_ASN1_MODULES) ":""); + else + fputs("$^", fp); + } + else { + fputs("\\\n" + "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" + "\t$(PREPROCESSED_TTCN3_MODULES) " + "$(BASE_PREPROCESSED_TTCN3_MODULES) \\\n" + "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)", fp); + } + if (makefile->linkingStrategy && makefile->hierarchical) { + fputs("\n\n" + "update: $(BASE_TTCN3_MODULES) $(BASE_ASN1_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) \\\n" + "\t$(BASE2_TTCN3_MODULES) $(BASE2_ASN1_MODULES) $(BASE2_PREPROCESSED_TTCN3_MODULES)\n" + "ifneq ($(wildcard $(GENERATED_SOURCES)), ) \n" + "ifeq ($(wildcard $?), ) \n" + "\ttouch compile-all; \n" + "\ttouch update; \n" + "endif\n" + "endif",fp); + } + fprintf(fp, "\n\n" + "compile: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) " + "$(ASN1_MODULES)\n" + "\t@echo \"compiling \"'$(patsubst %%.tpd, %%, $(TPD))';\n" + "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n" + "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) %s\\\n" + "\t$(PREPROCESSED_TTCN3_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) %s\\\n" + "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) %s - $?\n" + "\ttouch $@\n\n", + makefile->linkingStrategy ? "$(BASE2_TTCN3_MODULES) ":"", + makefile->linkingStrategy ? "$(BASE2_PREPROCESSED_TTCN3_MODULES) ":"", + makefile->linkingStrategy ? "$(BASE2_ASN1_MODULES)":""); + fprintf (fp, + "compile-all: $(BASE_TTCN3_MODULES) $(BASE_ASN1_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) " + "%s" + "\t$(MAKE) preprocess\n" + "\t@echo \"compiling all \"'$(patsubst %%.tpd, %%, $(TPD))';\n" + "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n" + "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) %s\\\n" + "\t$(PREPROCESSED_TTCN3_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) %s" + "\\\n" + "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) %s\\\n" + "\t- $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES)\n" + "\ttouch $@ compile\n\n", + makefile->linkingStrategy ? "\\\n\t$(BASE2_TTCN3_MODULES) $(BASE2_ASN1_MODULES) " + "$(BASE2_PREPROCESSED_TTCN3_MODULES) \n":"\n", + makefile->linkingStrategy ? "$(BASE2_TTCN3_MODULES) ":"", + makefile->linkingStrategy ? "$(BASE2_PREPROCESSED_TTCN3_MODULES) ":"", + makefile->linkingStrategy ? "$(BASE2_ASN1_MODULES) ":""); + } + else { + fprintf(fp, "\n" + "\t@if [ ! -f $@ ]; then %s compile-all; $(MAKE) compile-all; fi\n", rm_command); + fprintf(fp, "\n" + "check:%s $(TTCN3_MODULES) $(BASE_TTCN3_MODULES) %s\\\n" + "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) %s\n" + "\t$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) ", + add_refd_prjs?" referenced-check":"", + makefile->linkingStrategy ? "$(BASE2_TTCN3_MODULES) ":"", + makefile->linkingStrategy ? "$(BASE2_ASN1_MODULES) ":""); + if (makefile->gnu_make) { + if (add_refd_prjs) // referenced-check cannot be compiled it is not a ttcn modul + fprintf(fp, "$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) %s\\\n" + "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) %s\n", + makefile->linkingStrategy ? "$(BASE2_TTCN3_MODULES) ":"", + makefile->linkingStrategy ? "$(BASE2_ASN1_MODULES) ":""); + else + fputs("$^", fp); } - } else { /* not central storage */ + else { + fputs("\\\n" + "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n" + "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)", fp); + } + + if (makefile->linkingStrategy && makefile->hierarchical) { + fputs("\n\n" + "update: $(BASE_TTCN3_MODULES) $(BASE_ASN1_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) \\\n" + "\t$(BASE2_TTCN3_MODULES) $(BASE2_ASN1_MODULES) $(BASE2_PREPROCESSED_TTCN3_MODULES)\n" + "ifneq ($(wildcard $(GENERATED_SOURCES)), ) \n" + "ifeq ($(wildcard $?), ) \n" + "\ttouch compile-all; \n" + "\ttouch update; \n" + "endif\n" + "endif",fp); + } + + fprintf(fp, "\n\n" + "compile: $(TTCN3_MODULES) $(ASN1_MODULES)\n" + "\t@echo \"compiling \"'$(patsubst %%.tpd, %%, $(TPD))';\n" + "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n" + "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) %s\\\n" + "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) %s\\\n" + "\t- $?\n" + "\ttouch $@\n\n", + makefile->linkingStrategy ? "$(BASE2_TTCN3_MODULES) " : "", + makefile->linkingStrategy ? "$(BASE2_ASN1_MODULES) " : ""); + fprintf(fp, + "compile-all: $(BASE_TTCN3_MODULES) $(BASE_ASN1_MODULES) %s\n", + makefile->linkingStrategy ? "$(BASE2_TTCN3_MODULES) $(BASE2_ASN1_MODULES)" : ""); + fputs("\t@echo \"compiling all \"'$(patsubst %.tpd, %, $(TPD))';\n", fp); + fprintf(fp,"\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n" + "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) %s\\\n" + "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) %s\\\n" + "\t- $(TTCN3_MODULES) $(ASN1_MODULES)\n" + "\ttouch $@ compile\n\n", + makefile->linkingStrategy ? "$(BASE2_TTCN3_MODULES) " : "", + makefile->linkingStrategy ? "$(BASE2_ASN1_MODULES) " : ""); + } + if (!makefile->hierarchical) + for (i = 0; i < makefile->nBaseDirs; i++) { + const struct base_dir_struct *base_dir = makefile->BaseDirs + i; + if (base_dir->has_modules) { + size_t j; + fprintf(fp, "%s/compile:", base_dir->dir_name); + for (j = 0; j < makefile->nTTCN3Modules; j++) { + const struct module_struct *module = makefile->TTCN3Modules + j; + if (module->dir_name != NULL && + !strcmp(base_dir->dir_name, module->dir_name)) + print_file_name(fp, module); + } + for (j = 0; j < makefile->nTTCN3PPModules; j++) { + const struct module_struct *module = makefile->TTCN3PPModules + j; + if (module->dir_name != NULL && + !strcmp(base_dir->dir_name, module->dir_name)) + print_file_name(fp, module); + } + for (j = 0; j < makefile->nASN1Modules; j++) { + const struct module_struct *module = makefile->ASN1Modules + j; + if (module->dir_name != NULL && + !strcmp(base_dir->dir_name, module->dir_name)) + print_file_name(fp, module); + } + fprintf(fp, "\n" + "\t@echo 'Central directory %s is not up-to-date!'\n" + "\t@exit 2\n\n", base_dir->dir_name); + } + } + } + else { /* not central storage */ fprintf(fp, "$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile\n" - "\t@if [ ! -f $@ ]; then %s compile; $(MAKE) compile; fi\n\n" - "check: $(TTCN3_MODULES) ", rm_command); + "\t@if [ ! -f $@ ]; then %s compile; $(MAKE) compile; fi\n\n" + "check: $(TTCN3_MODULES) ", rm_command); if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp); fputs("$(ASN1_MODULES)\n" - "\t$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) ", fp); + "\t$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) ", fp); if (makefile->gnu_make) fputs("$^", fp); else { - fputs("\\\n" - "\t$(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES)", - fp); + fputs("\\\n" + "\t$(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES)", + fp); } fputs("\n\n" - "compile: $(TTCN3_MODULES) ", fp); + "compile: $(TTCN3_MODULES) ", fp); if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp); fputs("$(ASN1_MODULES)\n" - "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) ", fp); + "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) ", fp); if (makefile->gnu_make) fputs("$^", fp); else { - fputs("\\\n" - "\t$(TTCN3_MODULES) ", fp); - if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp); - fputs("$(ASN1_MODULES)", fp); + fputs("\\\n" + "\t$(TTCN3_MODULES) ", fp); + if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp); + fputs("$(ASN1_MODULES)", fp); } fputs(" - $?\n" - "\ttouch $@\n" - "\n", fp); - } - fprintf(fp, "clean:%s\n" - "\t-%s $(EXECUTABLE) $(LIBRARY) $(OBJECTS) $(GENERATED_HEADERS) \\\n" - "\t$(GENERATED_SOURCES) ", add_refd_prjs?" referenced-clean":"", rm_command); - if (makefile->dynamic) fputs("$(SHARED_OBJECTS) ", fp); - if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp); - fputs("compile", fp); - if (makefile->central_storage) fputs(" compile-all", fp); - if (makefile->gcc_dep) fputs(" $(DEPFILES)", fp); - fprintf(fp, " \\\n" - "\ttags *.log%s", - add_refd_prjs?" referenced*":""); - + "\ttouch $@\n" + "\n", fp); + } +// clean: + if (makefile->linkingStrategy) { + fprintf(fp, "clean:%s\n", (add_refd_prjs && !makefile->hierarchical) ? + " referenced-clean" : ""); + if (makefile->dynamic && (makefile->central_storage || makefile->linkingStrategy)) { + fprintf(fp,"\tfind . -type l -name \"*.so\" -exec unlink {} \\;\n"); + } + fprintf(fp, "\t%s $(EXECUTABLE) $(DYNAMIC_LIBRARY) $(STATIC_LIBRARY) " + "$(OBJECTS) $(GENERATED_HEADERS) \\\n" + "\t$(GENERATED_SOURCES) ", rm_command); + if (makefile->dynamic) fputs("$(SHARED_OBJECTS) ", fp); + if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp); + fputs("compile", fp); + if (makefile->central_storage) fputs(" compile-all", fp); + if (makefile->gcc_dep) fputs(" $(DEPFILES)", fp); + fprintf(fp, " \\\n" + "\ttags *.log%s%s\n\n", + add_refd_prjs?" referenced*":"", + makefile->hierarchical ? " update":""); + } + else { + fprintf(fp, "clean:%s\n" + "\t-%s $(EXECUTABLE) $(LIBRARY) $(OBJECTS) $(GENERATED_HEADERS) \\\n" + "\t$(GENERATED_SOURCES) ", add_refd_prjs?" referenced-clean":"", rm_command); + if (makefile->dynamic) fputs("$(SHARED_OBJECTS) ", fp); + if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp); + fputs("compile", fp); + if (makefile->central_storage) fputs(" compile-all", fp); + if (makefile->gcc_dep) fputs(" $(DEPFILES)", fp); + fprintf(fp, " \\\n" + "\ttags *.log%s", + add_refd_prjs?" referenced*":""); + } + +// clean-all: + if (makefile->linkingStrategy && makefile->hierarchical) + fprintf(fp, "clean-all: %s clean\n", add_refd_prjs ? "referenced-clean-all":""); + +// dep: fputs("\n\ndep: $(GENERATED_SOURCES) $(USER_SOURCES)",fp); - if (add_refd_prjs) fprintf(fp, "\n\t%s referenced-dep", rm_command); + if (add_refd_prjs) { + fprintf(fp, "\n\t%s referenced-dep", rm_command); + } else fputs(" ;",fp); - + if (makefile->gcc_dep) { fprintf(fp, " \n\n" "ifeq ($(findstring n,$(MAKEFLAGS)),)\n" - "ifeq ($(filter clean check compile archive diag%s,$(MAKECMDGOALS)),)\n" + "ifeq ($(filter clean%s check compile archive diag%s,$(MAKECMDGOALS)),)\n" "-include $(DEPFILES)\n" "endif\n" - "endif", (makefile->preprocess ? " preprocess" : "")); + "endif", + (makefile->linkingStrategy && makefile->hierarchical) ? " clean-all" : "", + (makefile->preprocess ? " preprocess" : "")); /* Don't include .d files when cleaning etc.; make will try to build them * and this involves running the Titan compiler. Same for preprocess. * The check target would be pointless if running the compiler @@ -2887,36 +3488,50 @@ static void print_makefile(struct makefile_struct *makefile) if (makefile->gnu_make) fputs("$^", fp); else fputs("$(GENERATED_SOURCES) $(USER_SOURCES)", fp); } - fprintf(fp, "\n\n" - "archive:%s\n" - "\tmkdir -p $(ARCHIVE_DIR)\n" - "\ttar -cvhf - ", add_refd_prjs?" referenced-archive":""); - if (makefile->central_storage) { - fputs("$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n", fp); - if (makefile->preprocess) { - fputs("\t$(TTCN3_PP_MODULES) $(BASE_TTCN3_PP_MODULES) " - "$(TTCN3_INCLUDES)\\\n", fp); + + if (makefile->linkingStrategy) { + fputs("\n\n" + "archive:\n" + "\t@perl $(TTCN3_DIR)/bin/ttcn3_archive.pl\n\n", fp); + } + else { + fputs("\n\n" + "archive:\n" + "\tmkdir -p $(ARCHIVE_DIR)\n" + "\ttar -cvhf - ", fp); + if (makefile->central_storage) { + fprintf(fp, "$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) %s\\\n", + makefile->linkingStrategy ? "$(BASE2_TTCN3_MODULES) " : ""); + if (makefile->preprocess) { + fprintf(fp, "\t$(TTCN3_PP_MODULES) $(BASE_TTCN3_PP_MODULES) " + "%s $(TTCN3_INCLUDES) \\\n", + makefile->linkingStrategy ? "$(BASE2_TTCN3_PP_MODULES)" : ""); + } + fprintf(fp, "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) %s\\\n" + "\t$(USER_HEADERS) $(BASE_USER_HEADERS) %s\\\n" + "\t$(USER_SOURCES) $(BASE_USER_SOURCES) %s", + makefile->linkingStrategy ? "$(BASE2_ASN1_MODULES) " : "", + makefile->linkingStrategy ? "$(BASE2_USER_HEADERS) " : "", + makefile->linkingStrategy ? "$(BASE2_USER_SOURCES)" : ""); } - fputs("\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) \\\n" - "\t$(USER_HEADERS) $(BASE_USER_HEADERS) \\\n" - "\t$(USER_SOURCES) $(BASE_USER_SOURCES)", fp); - } else { - fputs("$(TTCN3_MODULES) ", fp); - if (makefile->preprocess) { - fputs("$(TTCN3_PP_MODULES) \\\n" - "\t$(TTCN3_INCLUDES) ", fp); + else { + fputs("$(TTCN3_MODULES) ", fp); + if (makefile->preprocess) { + fputs("$(TTCN3_PP_MODULES) \\\n" + "\t$(TTCN3_INCLUDES) ", fp); + } + fputs("$(ASN1_MODULES) \\\n" + "\t$(USER_HEADERS) $(USER_SOURCES)", fp); } - fputs("$(ASN1_MODULES) \\\n" - "\t$(USER_HEADERS) $(USER_SOURCES)", fp); + fputs(" $(OTHER_FILES) \\\n" + "\t| gzip >$(ARCHIVE_DIR)/`basename $(TARGET) .exe`-" + "`date '+%y%m%d-%H%M'`.tgz\n\n", fp); } - fputs(" $(OTHER_FILES) \\\n" - "\t| gzip >$(ARCHIVE_DIR)/`basename $(TARGET) .exe`-" - "`date '+%y%m%d-%H%M'`.tgz\n\n", fp); fprintf(fp, "diag:\n" - "\t$(TTCN3_DIR)/bin/compiler -v 2>&1\n" - "\t$(TTCN3_DIR)/bin/mctr_cli -v 2>&1\n" - "\t$(CXX) -v 2>&1\n" + "\t$(TTCN3_DIR)/bin/compiler -v 2>&1\n" + "\t$(TTCN3_DIR)/bin/mctr_cli -v 2>&1\n" + "\t$(CXX) -v 2>&1\n" "%s" "\t@echo TTCN3_DIR=$(TTCN3_DIR)\n" "\t@echo OPENSSL_DIR=$(OPENSSL_DIR)\n" @@ -2925,12 +3540,13 @@ static void print_makefile(struct makefile_struct *makefile) makefile->dynamic ? "" : "\t$(AR) -V 2>&1\n"); if (add_refd_prjs) { - fputs("referenced-all referenced-shared_objects referenced-executable referenced-library \\\n" - "referenced-objects referenced-check \\\n" - "referenced-clean referenced-archive:\n" - "\t@for dir in $(REFERENCED_PROJECT_DIRS); do \\\n" - "\t $(MAKE) -C $$dir $(subst referenced-,,$@) || exit; \\\n" - "\tdone; \n\n", fp); + fprintf(fp, "referenced-all referenced-shared_objects referenced-executable referenced-library \\\n" + "referenced-objects referenced-check \\\n" + "referenced-clean%s:\n" + "\t@for dir in $(REFERENCED_PROJECT_DIRS); do \\\n" + "\t $(MAKE) -C $$dir $(subst referenced-,,$@) || exit; \\\n" + "\tdone; \n\n", + (makefile->linkingStrategy && makefile->hierarchical) ? "-all" : ""); fputs("referenced-dep:\n" "\t@for dir in $(REFERENCED_PROJECT_DIRS); do \\\n" "\t $(MAKE) -C $$dir $(subst referenced-,,$@) || exit; \\\n" @@ -2953,9 +3569,12 @@ static void print_makefile(struct makefile_struct *makefile) } else { NOTIFY("Makefile skeleton was generated."); } - } else { - ERROR("Output file `%s' already exists. Use switch `-f' to force " - "overwrite.", makefile->output_file); + } + else { + ERROR("Output file `%s' already exists. Use switch `%s' to force " + "overwrite.", + makefile->output_file, + makefile->linkingStrategy ? "-F" : "-f"); } } @@ -2977,7 +3596,8 @@ static void run_makefilegen_commands(struct string2_list* run_command_list) rv = set_working_dir(sub_proj_effective_work_dir); if (rv) ERROR("Could not set working dir to `%s'", sub_proj_effective_work_dir); else { - printf("Executing `%s' in working directory `%s'...\n", command, sub_proj_effective_work_dir); + fprintf(stderr, "Executing `%s' in working directory `%s'...\n", + command, sub_proj_effective_work_dir); rv = system(command); if (rv) ERROR("Execution failed with error code %d", rv); // TODO: it's not clear what system()'s return codes can be in different situations and platforms } @@ -3015,15 +3635,15 @@ static void generate_symlinks(struct string2_list* create_symlink_list) * command line switches. */ static void generate_makefile(size_t n_arguments, char *arguments[], size_t n_other_files, const char *other_files[], const char *output_file, - const char *ets_name, boolean gnu_make, boolean single_mode, + const char *ets_name, char *project_name, boolean gnu_make, boolean single_mode, boolean central_storage, boolean absolute_paths, boolean preprocess, boolean dump_makefile_data, boolean force_overwrite, boolean use_runtime_2, boolean dynamic, boolean makedepend, boolean coverage, const char *code_splitting_mode, const char *tcov_file_name, - boolean Lflag, struct string_list* sub_project_dirs, struct string_list* ttcn3_prep_includes, - struct string_list* ttcn3_prep_defines, struct string_list* prep_includes, struct string_list* prep_defines, - boolean codesplittpd, boolean quietly, boolean disablesubtypecheck, const char* cxxcompiler, - const char* optlevel, const char* optflags, boolean disableber, boolean disableraw, boolean disabletext, + boolean Lflag, boolean Zflag, boolean Hflag, struct string_list* sub_project_dirs, struct string_list* ttcn3_prep_includes, + struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes, + struct string_list* prep_defines, struct string_list* prep_undefines, boolean codesplittpd, boolean quietly, boolean disablesubtypecheck, + const char* cxxcompiler, const char* optlevel, const char* optflags, boolean disableber, boolean disableraw, boolean disabletext, boolean disablexer, boolean disablejson, boolean forcexerinasn, boolean defaultasomit, boolean gccmsgformat, boolean linenumbersonlymsg, boolean includesourceinfo, boolean addsourcelineinfo, boolean suppresswarnings, boolean outparamboundness, struct string_list* solspeclibraries, struct string_list* sol8speclibraries, @@ -3037,6 +3657,7 @@ static void generate_makefile(size_t n_arguments, char *arguments[], struct makefile_struct makefile; init_makefile_struct(&makefile); + makefile.project_name = project_name; makefile.central_storage = central_storage; makefile.gnu_make = gnu_make; makefile.preprocess = preprocess; @@ -3047,11 +3668,15 @@ static void generate_makefile(size_t n_arguments, char *arguments[], makefile.gcc_dep = gnu_make && !makedepend; makefile.coverage = coverage; makefile.library = Lflag; + makefile.linkingStrategy = Zflag; + makefile.hierarchical = Hflag; makefile.sub_project_dirs = sub_project_dirs; makefile.ttcn3_prep_includes = ttcn3_prep_includes; makefile.ttcn3_prep_defines = ttcn3_prep_defines; + makefile.ttcn3_prep_undefines = ttcn3_prep_undefines; makefile.prep_includes = prep_includes; makefile.prep_defines = prep_defines; + makefile.prep_undefines = prep_undefines; makefile.codesplittpd = codesplittpd; makefile.quietly = quietly; makefile.disablesubtypecheck = disablesubtypecheck; @@ -3148,7 +3773,7 @@ static void generate_makefile(size_t n_arguments, char *arguments[], } if (tcov_file_name != NULL) { - makefile.tcov_file_name = mputprintf(makefile.tcov_file_name, "-K %s", tcov_file_name); + makefile.tcov_file_name = mputprintf(makefile.tcov_file_name, "-K %s", tcov_file_name); } if (makefile.nTTCN3Modules >= 1) { @@ -3188,7 +3813,6 @@ static void generate_makefile(size_t n_arguments, char *arguments[], if (dump_makefile_data) dump_makefile_struct(&makefile, 0); if (error_count == 0) print_makefile(&makefile); - free_makefile_struct(&makefile); } @@ -3202,7 +3826,7 @@ static void generate_makefile(size_t n_arguments, char *arguments[], static void usage(void) { fprintf(stderr, "\n" - "usage: %s [-abc" C_flag "dDfFglLmprRstTVwWX] [-K file] [-P dir]" + "usage: %s [-abc" C_flag "dDfFglLmprRstTVwWXZ] [-K file] [-P dir]" " [-U none|type] [-e ets_name] [-o dir|file]\n" " [-t project_descriptor.tpd [-b buildconfig]]\n" " [-O file] ... module_name ... testport_name ...\n" @@ -3242,6 +3866,8 @@ static void usage(void) " -P dir: prints out a file list found in a given TPD relative to the given directory\n" " -X: generate XML file that describes the TPD hierarchy, use with -r\n" " -W: prefix working directories with project name\n" + " -Z: recursive Makefile generation from TPD using object files and dynamic libraries too\n" + " -H: hierachical Makefile generation from TPD use with -Z\n" , program_name, program_name); } @@ -3285,10 +3911,11 @@ int main(int argc, char *argv[]) dxflag = FALSE, fxflag = FALSE, doflag = FALSE, gfflag = FALSE, lnflag = FALSE, isflag = FALSE, asflag = FALSE, swflag = FALSE, Vflag = FALSE, Dflag = FALSE, Wflag = FALSE, - djflag = FALSE; + djflag = FALSE, Zflag = FALSE, Hflag = FALSE; boolean error_flag = FALSE; char *output_file = NULL; char *ets_name = NULL; + char *project_name = NULL; size_t n_other_files = 0; const char **other_files = NULL; const char *code_splitting_mode = NULL; @@ -3301,8 +3928,10 @@ int main(int argc, char *argv[]) struct string2_list* create_symlink_list = NULL; struct string_list* ttcn3_prep_includes = NULL; struct string_list* ttcn3_prep_defines = NULL; + struct string_list* ttcn3_prep_undefines = NULL; struct string_list* prep_includes = NULL; struct string_list* prep_defines = NULL; + struct string_list* prep_undefines = NULL; char *cxxcompiler = NULL; char *optlevel = NULL; char *optflags = NULL; @@ -3318,6 +3947,7 @@ int main(int argc, char *argv[]) char* generatorCommandOutput = NULL; struct string2_list* target_placement_list = NULL; struct string2_list* run_command_list = NULL; + struct string2_list* required_configs = NULL; #ifdef LICENSE license_struct lstr; @@ -3334,7 +3964,7 @@ int main(int argc, char *argv[]) } for ( ; ; ) { - int c = getopt(argc, argv, "O:ab:c" C_flag "dDe:fFgK:o:lLmpP:rRst:TU:vVwWXY"); + int c = getopt(argc, argv, "O:ab:c" C_flag "dDe:fFgK:o:lLmpP:rRst:TU:vVwWXYZH"); if (c == -1) break; switch (c) { case 'O': @@ -3381,6 +4011,9 @@ int main(int argc, char *argv[]) case 'g': SET_FLAG(g); break; + case 'H': + SET_FLAG(H); + break; case 'o': SET_FLAG(o); output_file = optarg; @@ -3401,11 +4034,11 @@ int main(int argc, char *argv[]) SET_FLAG(P); /* Optional arguments with `::' are GNU specific... */ if (get_path_status(optarg) == PS_DIRECTORY) { - file_list_path = optarg; + file_list_path = optarg; } else { - ERROR("The -P flag requires a valid directory as its argument " - "instead of `%s'", optarg); - error_flag = TRUE; + ERROR("The -P flag requires a valid directory as its argument " + "instead of `%s'", optarg); + error_flag = TRUE; } break; case 'r': @@ -3451,6 +4084,9 @@ int main(int argc, char *argv[]) case 'X': SET_FLAG(X); break; + case 'Z': + SET_FLAG(Z); + break; default: error_flag = TRUE; break; @@ -3463,12 +4099,17 @@ int main(int argc, char *argv[]) if ( aflag || bflag || cflag || Cflag || dflag || eflag || fflag || Fflag || gflag || mflag || oflag || lflag || pflag || Pflag || rflag || Rflag || sflag || tflag || Tflag || Vflag || wflag || Xflag || Kflag || Dflag || Wflag || Yflag - || n_other_files > 0) - error_flag = TRUE; + || Zflag || Hflag || n_other_files > 0) + error_flag = TRUE; + } + + if (Zflag) { + if (!gflag) gflag = TRUE; // GNU make + if (!cflag) cflag = TRUE; // central sorage } - if ((bflag || Dflag || Pflag || Vflag || rflag || Wflag) && !tflag) { - ERROR("Using the '-b', '-D', '-P', '-V', '-r' or '-W' option requires the use of the -t' option."); + if ((bflag || Dflag || Pflag || Vflag || rflag || Wflag || Zflag) && !tflag) { + ERROR("Using the '-b', '-D', '-P', '-V', '-r' 'Z' or '-W' option requires the use of the -t' option."); error_flag = TRUE; } @@ -3492,6 +4133,16 @@ int main(int argc, char *argv[]) error_flag = TRUE; } + if (!Zflag && Hflag) { + ERROR("Using the '-H' option requires use of the '-Z' option."); + error_flag = TRUE; + } + + if (Zflag && !Fflag && !fflag) { + ERROR("Using the '-Z' option requires use of the '-F' option."); + error_flag = TRUE; + } + if (lflag && !strncmp(get_platform_string(), "WIN32", 5)) { ERROR("Generating Makefile with dynamic linking enabled is not supported " "on Windows platform"); @@ -3544,12 +4195,18 @@ int main(int argc, char *argv[]) ttcn3_prep_defines = (struct string_list*)Malloc(sizeof(struct string_list)); ttcn3_prep_defines->str = NULL; ttcn3_prep_defines->next = NULL; + ttcn3_prep_undefines = (struct string_list*)Malloc(sizeof(struct string_list)); + ttcn3_prep_undefines->str = NULL; + ttcn3_prep_undefines->next = NULL; prep_includes = (struct string_list*)Malloc(sizeof(struct string_list)); prep_includes->str = NULL; prep_includes->next = NULL; prep_defines = (struct string_list*)Malloc(sizeof(struct string_list)); prep_defines->str = NULL; prep_defines->next = NULL; + prep_undefines = (struct string_list*)Malloc(sizeof(struct string_list)); + prep_undefines->str = NULL; + prep_undefines->next = NULL; solspeclibraries = (struct string_list*)Malloc(sizeof(struct string_list)); solspeclibraries->str = NULL; solspeclibraries->next = NULL; @@ -3593,29 +4250,45 @@ int main(int argc, char *argv[]) run_command_list->str1 = NULL; run_command_list->str2 = NULL; run_command_list->next = NULL; + required_configs = (struct string2_list*)Malloc(sizeof(struct string2_list)); + required_configs->str1 = NULL; + required_configs->str2 = NULL; + required_configs->next = NULL; + tpd_processed = process_tpd(tpd_file_name, tpd_build_config, file_list_path, - &argc, &argv, &optind, &ets_name, + &argc, &argv, &optind, &ets_name, &project_name, &gflag, &sflag, &cflag, &aflag, &pflag, &Rflag, &lflag, &mflag, &Pflag, &Lflag, rflag, Fflag, Tflag, output_file, &abs_work_dir, sub_project_dirs, program_name, prj_graph_fp, - create_symlink_list,ttcn3_prep_includes, ttcn3_prep_defines, prep_includes, prep_defines, &csflag, &quflag, &dsflag, &cxxcompiler, - &optlevel, &optflags, &dbflag, &drflag, &dtflag, &dxflag, &djflag, &fxflag, &doflag, &gfflag, &lnflag, &isflag, + create_symlink_list,ttcn3_prep_includes, ttcn3_prep_defines,ttcn3_prep_undefines, prep_includes, prep_defines, prep_undefines, &csflag, + &quflag, &dsflag, &cxxcompiler, &optlevel, &optflags, &dbflag, &drflag, &dtflag, &dxflag, &djflag, &fxflag, &doflag, &gfflag, &lnflag, &isflag, &asflag, &swflag, &Yflag, solspeclibraries, sol8speclibraries, linuxspeclibraries, freebsdspeclibraries, win32speclibraries, &ttcn3prep, - linkerlibraries, additionalObjects, linkerlibsearchpath, Vflag, Dflag, &generatorCommandOutput, target_placement_list, Wflag, run_command_list); + linkerlibraries, additionalObjects, linkerlibsearchpath, Vflag, Dflag, &Zflag, &Hflag, + &generatorCommandOutput, target_placement_list, Wflag, run_command_list, required_configs); + Free(abs_work_dir); if (prj_graph_fp) { fprintf(prj_graph_fp, "\n"); fclose(prj_graph_fp); } - if (tpd_processed == TPD_FAILED) ERROR("Failed to process %s", tpd_file_name); + if (tpd_processed == TPD_FAILED) { + ERROR("Failed to process %s", tpd_file_name); + exit(EXIT_FAILURE); + } } if (!Pflag) { run_makefilegen_commands(run_command_list); generate_symlinks(create_symlink_list); + if (Zflag) { + if (Fflag) + NOTIFY("Makefile generation from top-level TPD: %s", tpd_file_name); + if (!Fflag && fflag) + NOTIFY("Makefile generation from lower level TPD: %s", tpd_file_name); + } generate_makefile(argc - optind, argv + optind, n_other_files, other_files, - output_file, ets_name, gflag, sflag, cflag, aflag, pflag, dflag, fflag||Fflag, - Rflag, lflag, mflag, Cflag, code_splitting_mode, tcov_file_name, Lflag, rflag ? sub_project_dirs : NULL, ttcn3_prep_includes, - ttcn3_prep_defines, prep_includes, prep_defines, csflag, quflag, dsflag, cxxcompiler, optlevel, optflags, dbflag, + output_file, ets_name, project_name, gflag, sflag, cflag, aflag, pflag, dflag, fflag||Fflag, + Rflag, lflag, mflag, Cflag, code_splitting_mode, tcov_file_name, Lflag, Zflag, Hflag, rflag ? sub_project_dirs : NULL, ttcn3_prep_includes, + ttcn3_prep_defines, ttcn3_prep_undefines, prep_includes, prep_defines, prep_undefines, csflag, quflag, dsflag, cxxcompiler, optlevel, optflags, dbflag, drflag, dtflag, dxflag, djflag, fxflag, doflag, gfflag, lnflag, isflag, asflag, swflag, Yflag, solspeclibraries, sol8speclibraries, linuxspeclibraries, freebsdspeclibraries, win32speclibraries, ttcn3prep, linkerlibraries, additionalObjects, linkerlibsearchpath, generatorCommandOutput, target_placement_list); @@ -3624,8 +4297,10 @@ int main(int argc, char *argv[]) free_string_list(sub_project_dirs); free_string_list(ttcn3_prep_includes); free_string_list(ttcn3_prep_defines); + free_string_list(ttcn3_prep_undefines); free_string_list(prep_includes); free_string_list(prep_defines); + free_string_list(prep_undefines); free_string_list(solspeclibraries); free_string_list(sol8speclibraries); free_string_list(linuxspeclibraries); @@ -3637,6 +4312,7 @@ int main(int argc, char *argv[]) Free(generatorCommandOutput); free_string2_list(target_placement_list); + free_string2_list(required_configs); Free(other_files); if (tpd_processed == TPD_SUCCESS) { @@ -3655,8 +4331,7 @@ int main(int argc, char *argv[]) for (E = 0; E < argc; ++E) Free(argv[E]); Free(argv); } - /* check_mem_leak(program_name); not needed when linked to new.cc */ + /* check_mem_leak(program_name); not needed when linked to new.cc */ return error_count > 0 ? EXIT_FAILURE : EXIT_SUCCESS; } - diff --git a/compiler2/record.c b/compiler2/record.c index 67b7e96..79e914f 100644 --- a/compiler2/record.c +++ b/compiler2/record.c @@ -1799,11 +1799,6 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) /* start_at is the index of the first "real" member of the record */ size_t start_at = uo + (sdef->xerUseOrderPossible != 0); - /* Max. number of EMBED-VALUES strings. The actual number may change - * at runtime: omitted optional (non-attribute) members decrease the - * number of embed strings needed, and xsi:nil=true sets it to zero.*/ - size_t max_embed; - /* Number of optional non-attributes */ size_t n_opt_elements = 0; @@ -1828,7 +1823,6 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) ++n_opt_elements; } } - max_embed = sdef->nElements - start_at - num_attributes + 1; /* Write some helper functions */ def = mputstr(def, @@ -1904,7 +1898,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) /* * * * * * * * * * XER_encode * * * * * * * * * * * * * * */ src = mputprintf(src, "int %s::XER_encode(const XERdescriptor_t& p_td, " - "TTCN_Buffer& p_buf, unsigned int p_flavor, int p_indent) const\n" + "TTCN_Buffer& p_buf, unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const\n" "{\n" " if (!is_bound()) TTCN_EncDec_ErrorContext::error" "(TTCN_EncDec::ET_UNBOUND, \"Encoding an unbound value.\");\n" @@ -1994,7 +1988,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " if (e_xer && (p_td.xer_bits & USE_QNAME)) {\n" " if (field_%s.is_value()) {\n" " p_buf.put_s(11, (cbyte*)\" xmlns:b0='\");\n" - " field_%s.XER_encode(%s_xer_, p_buf, p_flavor | XER_LIST, p_indent+1);\n" + " field_%s.XER_encode(%s_xer_, p_buf, p_flavor | XER_LIST, p_indent+1, 0);\n" " p_buf.put_c('\\'');\n" " }\n" " if (p_td.xer_bits & XER_ATTRIBUTE) begin_attribute(p_td, p_buf);\n" @@ -2003,7 +1997,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " p_buf.put_s(3, (cbyte*)\"b0:\");\n" " sub_len += 3;\n" " }\n" - " sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor | XER_LIST, p_indent+1);\n" + " sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor | XER_LIST, p_indent+1, 0);\n" " if (p_td.xer_bits & XER_ATTRIBUTE) p_buf.put_c('\\'');\n" " } else" /* no newline */ , sdef->elements[0].name @@ -2017,12 +2011,10 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) /* First, the EMBED-VALUES member as an ordinary member if not doing EXER */ if (sdef->xerEmbedValuesPossible) { src = mputprintf(src, - " int exp_emb = %u;\n" " if (!e_xer && (p_td.xer_bits & EMBED_VALUES)) {\n" " ec_1.set_msg(\"%s': \");\n" - " sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+1);\n" + " sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+1, 0);\n" " }\n" - , (unsigned int)max_embed , sdef->elements[0].dispname , sdef->elements[0].name, sdef->elements[0].typegen ); @@ -2031,7 +2023,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) if (sdef->xerUseOrderPossible) { src = mputprintf(src, " if (!e_xer && (p_td.xer_bits & USE_ORDER)) {\n" - " sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+1);\n" + " sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+1, 0);\n" " }\n" , sdef->elements[uo].name, sdef->elements[uo].typegen ); @@ -2067,7 +2059,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) if (i==0 && sdef->xerEmbedValuesPossible && (sdef->elements[i].xerAnyKind & ANY_ATTRIB_BIT)) continue ; src = mputprintf(src, " ec_1.set_msg(\"%s': \");\n" - " tmp_len = field_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+1);\n" + " tmp_len = field_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+1, 0);\n" " %ssub_len += tmp_len;\n" /* do not add if attribute and EXER */ , sdef->elements[i].dispname , sdef->elements[i].name, sdef->elements[i].typegen @@ -2098,46 +2090,19 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) } if (sdef->xerEmbedValuesPossible) { - size_t op; src = mputprintf(src, " ec_1.set_msg(\"%s': \");\n" " if (e_xer && (p_td.xer_bits & EMBED_VALUES)) {\n" - , sdef->elements[0].dispname - ); - - if (sdef->xerUseNilPossible) { - src = mputstr(src, /* 25.2.6 a */ - " if ((p_td.xer_bits & USE_NIL) && nil_attribute) exp_emb = 0;\n" - " else {\n"); - } - - for (op = 0; op < sdef->nElements; ++op) { - if (sdef->elements[op].isOptional && !sdef->elements[op].xerAttribute) { - src = mputprintf(src, - " if (!field_%s.ispresent()) --exp_emb;\n" - , sdef->elements[op].name - ); - } - } - - if (sdef->xerUseNilPossible) src = mputstr(src, " }\n"); - - src = mputprintf(src, - " if (field_%s.size_of()!=exp_emb) " - "TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_CONSTRAINT, " - "\"Wrong number %%d of EMBED-VALUEs, expected %%d\", field_%s.size_of(), exp_emb);\n" - , sdef->elements[0].name - , sdef->elements[0].name); /* write the first string (must come AFTER the attributes) */ - src = mputprintf(src, - " %ssub_len += field_%s[0].XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1);\n" + " if (field_%s.size_of() > 0) {\n" + " sub_len += field_%s[0].XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n" + " }\n" " }\n" - , (sdef->xerUseNilPossible ? "if (exp_emb > 0) " : "") - , sdef->elements[0].name); + , sdef->elements[0].dispname, sdef->elements[0].name, sdef->elements[0].name); if (want_namespaces) { /* here's another chance */ src = mputprintf(src, " else if ( !(p_td.xer_bits & EMBED_VALUES)) {\n" - " %sfield_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+1);\n" + " %sfield_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+1, 0);\n" " }\n" , ((sdef->elements[0].xerAnyKind & ANY_ATTRIB_BIT) ? "" : "sub_len += " ) , sdef->elements[0].name, sdef->elements[0].typegen @@ -2148,6 +2113,17 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) /* Then, all the non-attributes. Structuring the code like this depends on * all attributes appearing before all non-attributes (excluding * special members for EMBED-VALUES, USE-ORDER, etc.) */ + if (sdef->xerEmbedValuesPossible) { + src = mputprintf(src, + " 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" + " 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); + } + if (sdef->xerUseOrderPossible) { int max_ordered = sdef->nElements - start_at - num_attributes; int min_ordered = max_ordered - n_opt_elements; @@ -2169,7 +2145,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) src = mputprintf(src, " if (!nil_attribute) {\n" "%s" - " if (!e_xer) sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+!omit_tag);\n" + " if (!e_xer) sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+!omit_tag, 0);\n" " else" /* no newline */ , (sdef->xerUseNilPossible ? " if (!(p_td.xer_bits & USE_ORDER)) p_flavor |= (p_td.xer_bits & USE_NIL);\n" : "") /* If USE-ORDER is on, the tag-removing effect of USE-NIL has been @@ -2224,7 +2200,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) src = mputprintf(src, " case %lu:\n" " ec_1.set_msg(\"%s': \");\n" - " sub_len += field_%s%s%s%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+!omit_tag);\n" + " sub_len += field_%s%s%s%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+!omit_tag, %s);\n" , (unsigned long)offset++ , sdef->elements[i].dispname @@ -2233,7 +2209,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) , (sdef->xerUseNilPossible ? sdef->elements[i].name : "") , (sdef->xerUseNilPossible ? "()" : "") , sdef->elements[i].typegen - + , sdef->xerEmbedValuesPossible ? "emb_val" : "0" ); src = mputstr(src, " break;\n"); @@ -2246,8 +2222,11 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) if (sdef->xerEmbedValuesPossible) { src = mputprintf(src, - " if (e_xer && i+1 < exp_emb && (p_td.xer_bits & EMBED_VALUES)) { // embed-val\n" - " field_%s[i+1].XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1);\n" + " if (e_xer && (p_td.xer_bits & EMBED_VALUES) && 0 != emb_val &&\n" + " emb_val->embval_index < emb_val->embval_size) { // 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); } @@ -2267,22 +2246,38 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) , sdef->elements[i].dispname ); src = mputprintf(src, - " sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor%s, p_indent+!omit_tag);\n" + " sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor%s, p_indent+!omit_tag, %s);\n" , sdef->elements[i].name, sdef->elements[i].typegen , sdef->xerUseNilPossible ? "| (p_td.xer_bits & USE_NIL)" : "" + , sdef->xerEmbedValuesPossible ? "emb_val" : "0" ); if (sdef->xerEmbedValuesPossible) { - unsigned long idx = i - start_at - num_attributes + 1; src = mputprintf(src, - " if (e_xer && exp_emb > %lu && (p_td.xer_bits & EMBED_VALUES)) {\n" - " field_%s[%lu].XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | EMBED_VALUES, p_indent+1);\n" + " if (e_xer && (p_td.xer_bits & EMBED_VALUES) && 0 != emb_val &&\n" + " emb_val->embval_index < emb_val->embval_size) {\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" - , idx - , sdef->elements[0].name, idx); + , 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" + " 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" + " }\n" + " delete emb_val;\n" + " }\n" + , sdef->elements[0].name); + } + src = mputstr(src, " } // QN?\n"); { @@ -2335,7 +2330,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) src = mputprintf(src, /* XERSTUFF decodegen for record/SEQUENCE*/ "int %s::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader," - " unsigned int p_flavor)\n" + " unsigned int p_flavor, embed_values_dec_struct_t*)\n" "{\n" " bound_flag = TRUE;\n" /* Remove XER_LIST, XER_RECOF from p_flavor. This is not required @@ -2441,8 +2436,9 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) } else { /* must be the ANY-ATTRIBUTES */ src = mputprintf(src, - " field_%s.set_size(0);\n", - sdef->elements[aaa].name); + " field_%s%s;\n" + , sdef->elements[aaa].name + , sdef->elements[aaa].isOptional ? " = OMIT_VALUE" : ".set_size(0)"); } } @@ -2493,7 +2489,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) src = mputprintf(src, " if (check_name(attr_name, %s_xer_, 1) && check_namespace(ns_uri, %s_xer_)) {\n" " ec_1.set_msg(\"%s': \");\n" - " field_%s.XER_decode(%s_xer_, p_reader, p_flavor | (p_td.xer_bits & USE_NIL));\n" + " field_%s.XER_decode(%s_xer_, p_reader, p_flavor | (p_td.xer_bits & USE_NIL), 0);\n" " } else" , sdef->elements[i].typegen, sdef->elements[i].typegen , sdef->elements[i].dispname /* set_msg */ @@ -2514,8 +2510,8 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) /* we are at a dangling else */ src = mputprintf(src, " {\n" - " TTCN_EncDec_ErrorContext ec_0(\"Attribute %%d: \", (int)num_aa);" - " UNIVERSAL_CHARSTRING& new_elem = field_%s[num_aa++];\n" + " TTCN_EncDec_ErrorContext ec_0(\"Attribute %%d: \", (int)num_aa);\n" + " UNIVERSAL_CHARSTRING& new_elem = field_%s%s[num_aa++];\n" /* Construct the AnyAttributeFormat (X.693amd1, 18.2.6) */ " TTCN_Buffer aabuf;\n" " const xmlChar *x_name = p_reader.LocalName();\n" @@ -2536,6 +2532,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " new_elem.decode_utf8(aabuf.get_len(), aabuf.get_data());\n" " } \n" , sdef->elements[aa_index].name + , sdef->elements[aa_index].isOptional ? "()" : "" , sdef->elements[aa_index].typegen, sdef->elements[aa_index].typegen ); } @@ -2584,7 +2581,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " if (!(p_td.xer_bits & EMBED_VALUES)) {\n" " ec_1.set_msg(\"%s': \");\n" " field_%s.XER_decode(%s_xer_, p_reader, " - "p_flavor | (p_td.xer_bits & USE_NIL)| (tag_closed ? PARENT_CLOSED : 0));\n" + "p_flavor | (p_td.xer_bits & USE_NIL)| (tag_closed ? PARENT_CLOSED : 0), 0);\n" " }\n" , sdef->elements[0].dispname , sdef->elements[0].name, sdef->elements[0].typegen @@ -2618,7 +2615,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) src = mputprintf(src, " {\n" " ec_1.set_msg(\"%s': \");\n" - " field_%s.XER_decode(%s_xer_, p_reader, p_flavor | (p_td.xer_bits & USE_NIL));\n" + " field_%s.XER_decode(%s_xer_, p_reader, p_flavor | (p_td.xer_bits & USE_NIL), 0);\n" " }\n" , sdef->elements[i].dispname , sdef->elements[i].name, sdef->elements[i].typegen @@ -2633,6 +2630,17 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) if (num_attributes || sdef->xerEmbedValuesPossible || sdef->xerUseOrderPossible) { src = mputstr(src, "}\n"); } + + if (sdef->xerEmbedValuesPossible) { + src = mputprintf(src, + " 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" + " emb_val->embval_index = 0;\n" + " field_%s.set_size(0);\n" + " }\n", sdef->elements[0].name, sdef->elements[0].name); + } if (sdef->xerUseOrderPossible) { size_t begin = start_at + num_attributes; /* first non-attribute */ @@ -2657,23 +2665,6 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) } } - if (sdef->xerEmbedValuesPossible) { /* EMBED-VALUES with USE-ORDER */ - src = mputprintf(src, - " if (p_td.xer_bits & EMBED_VALUES) {\n" - " field_%s.set_size(%lu);\n" - " %s::of_type empty_string(\"\");\n" - " for (int j_j=0; j_j<%lu; ++j_j) {\n" - " field_%s[j_j] = empty_string;\n" - " }\n" - " }\n" - , sdef->elements[0].name - , (unsigned long)(n_embed + 1) - , sdef->elements[0].type - , (unsigned long)(n_embed + 1) - , sdef->elements[0].name - ); - } - if (sdef->xerUseNilPossible) { /* USE-NIL and USE-ORDER */ src = mputprintf(src, " if (nil_attribute) field_%s.set_size(0);\n else" @@ -2684,18 +2675,26 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " {\n" " field_%s.set_size(0);\n" " int e_val, num_seen = 0, *seen_f = new int[%lu];\n" - " for (int i=0; i < %lu; ++i) {\n" - " for (rd_ok=p_reader.Ok(); rd_ok==1; rd_ok=p_reader.Read()) {\n" , sdef->elements[uo].name , (unsigned long)(n_embed) + ); + if (sdef->xerEmbedValuesPossible) { + // The index of the latest embedded value can change outside of this function + // (if the field is a untagged record of), in this case the next value should + // be ignored, as it's already been handled by the record of + src = mputstr(src, " int last_embval_index = 0;\n"); + } + src = mputprintf(src, + " for (int i=0; i < %lu; ++i) {\n" + " for (rd_ok=p_reader.Ok(); rd_ok==1; rd_ok=p_reader.Read()) {\n" , (unsigned long)(n_embed)); if (sdef->xerEmbedValuesPossible) { /* read and store embedValues text if present */ src = mputprintf(src, - " if ((p_td.xer_bits & EMBED_VALUES) && (p_reader.NodeType()==XML_READER_TYPE_TEXT)) {\n" + " if (0 != emb_val && p_reader.NodeType()==XML_READER_TYPE_TEXT) {\n" " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" - " field_%s[i] = emb_ustr;\n" + " field_%s[emb_val->embval_index] = emb_ustr;\n" " }\n" , sdef->elements[0].name); } @@ -2706,7 +2705,16 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " }\n" " if (rd_ok != 1) break;\n" " const char * x_name = (const char*)p_reader.LocalName();\n" /* Name or LocalName ? */); - + + if (sdef->xerEmbedValuesPossible) { + src = mputstr(src, + " if (0 != emb_val) {\n" + " if (last_embval_index == emb_val->embval_index) {\n" + " ++emb_val->embval_index;\n" + " }\n" + " last_embval_index = emb_val->embval_index;\n" + " }\n"); + } /* * * * * code for USE-ORDER * * * * */ @@ -2716,20 +2724,20 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) src = mputprintf(src, " if (check_name(x_name, %s_xer_, 1)) {\n" " ec_1.set_msg(\"%s': \");\n" - " field_%s%s%s%s.XER_decode(%s_xer_, p_reader, p_flavor);\n" + " field_%s%s%s%s.XER_decode(%s_xer_, p_reader, p_flavor, %s);\n" , sdef->elements[i].typegen , sdef->elements[i].dispname - , (sdef->xerUseNilPossible ? sdef->elements[sdef->nElements-1].name: sdef->elements[i].name) , (sdef->xerUseNilPossible ? "()." : "") , (sdef->xerUseNilPossible ? sdef->elements[i].name : "") , (sdef->xerUseNilPossible ? "()" : "") , sdef->elements[i].typegen + , sdef->xerEmbedValuesPossible ? "emb_val" : "0" ); src = mputprintf(src, - " field_%s[i] = e_val = %s::of_type::%s;\n" - , sdef->elements[uo].name - , sdef->elements[uo].typegen, sdef->elements[i].name); + " field_%s[i] = e_val = %s::of_type::%s;\n" + , sdef->elements[uo].name + , sdef->elements[uo].typegen, sdef->elements[i].name); src = mputstr(src, " }\n else"); } } @@ -2753,7 +2761,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " }\n" " if (!next_any) {\n" " ec_1.set_msg(\"%s': \");\n" - " field_%s%s%s%s.XER_decode(%s_xer_, p_reader, p_flavor);\n" + " field_%s%s%s%s.XER_decode(%s_xer_, p_reader, p_flavor, 0);\n" " field_%s[i] = e_val;\n" " any_found = true;\n" " }\n" @@ -2781,11 +2789,16 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) if (sdef->xerEmbedValuesPossible) { /* read and store embedValues text if present */ src = mputprintf(src, - " if ((p_td.xer_bits & EMBED_VALUES) && (p_reader.NodeType()==XML_READER_TYPE_TEXT)) {\n" - " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" - " field_%s[%lu] = emb_ustr;\n" + " if (0 != emb_val) {\n" + " if (p_reader.NodeType()==XML_READER_TYPE_TEXT) {\n" + " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" + " field_%s[emb_val->embval_index] = emb_ustr;\n" + " }\n" + " if (last_embval_index == emb_val->embval_index) {\n" + " ++emb_val->embval_index;\n" + " }\n" " }\n" - , sdef->elements[0].name, (unsigned long)(n_embed)); + , sdef->elements[0].name); } src = mputprintf(src, @@ -2816,16 +2829,29 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " p_reader.MoveToElement();\n" " } else {\n"); } + if (sdef->xerEmbedValuesPossible) { + // The index of the latest embedded value can change outside of this function + // (if the field is a untagged record of), in this case the next value should + // be ignored, as it's already been handled by the record of + // Omitted fields can also reset this value + src = mputstr(src, " int last_embval_index = 0;\n"); + } /* for all the non-attribute fields... */ for (i = start_at + num_attributes; i < sdef->nElements; ++i) { if (sdef->xerEmbedValuesPossible) { /* read and store embedValues text if present */ src = mputprintf(src, - " if ((p_td.xer_bits & EMBED_VALUES) && (p_reader.NodeType()==XML_READER_TYPE_TEXT)) {\n" - " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" - " field_%s[%lu] = emb_ustr;\n" + " if (0 != emb_val) {\n" + " if (p_reader.NodeType()==XML_READER_TYPE_TEXT) {\n" + " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" + " field_%s[emb_val->embval_index] = emb_ustr;\n" + " }\n" + " if (last_embval_index == emb_val->embval_index) {\n" + " ++emb_val->embval_index;\n" + " }\n" + " last_embval_index = emb_val->embval_index;\n" " }\n" - , sdef->elements[0].name, (unsigned long)(i-(start_at+num_attributes))); + , sdef->elements[0].name); } /* The DEFAULT-FOR-EMPTY member can not be involved with EMBED-VALUES, * so we can use the same pattern: optional "if(...) else" before {} @@ -2860,69 +2886,59 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) src = mputprintf(src, " field_%s.XER_decode(%s_xer_, p_reader, p_flavor" - " | (p_td.xer_bits & USE_NIL)| (tag_closed ? PARENT_CLOSED : 0));\n" + " | (p_td.xer_bits & USE_NIL)| (tag_closed ? PARENT_CLOSED : 0), %s);\n" " }\n" - , sdef->elements[i].name, sdef->elements[i].typegen); + , sdef->elements[i].name, sdef->elements[i].typegen + , sdef->xerEmbedValuesPossible ? "emb_val" : "0"); + if (sdef->xerEmbedValuesPossible) { + src = mputprintf(src, + " if (!field_%s.is_present()) {\n" + // there was no new element, the last embedded value is for the next field + // (or the end of the record if this is the last field) + " last_embval_index = -1;\n" + " }\n" + , sdef->elements[i].name); + } } /* next field */ - if (sdef->xerUseNilPossible) { - src = mputstr(src, " } // use_nil\n"); - } - if (sdef->xerEmbedValuesPossible) { /* read and store embedValues text if present */ src = mputprintf(src, - " if ((p_td.xer_bits & EMBED_VALUES) && (p_reader.NodeType()==XML_READER_TYPE_TEXT)) {\n" - " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" - " field_%s[%lu] = emb_ustr;\n" + " if (0 != emb_val) {\n" + " if (p_reader.NodeType()==XML_READER_TYPE_TEXT) {\n" + " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" + " field_%s[emb_val->embval_index] = emb_ustr;\n" + " }\n" + " if (last_embval_index == emb_val->embval_index) {\n" + " ++emb_val->embval_index;\n" + " }\n" " }\n" - , sdef->elements[0].name, (unsigned long)(i-(start_at+num_attributes))); + , sdef->elements[0].name); + } + + if (sdef->xerUseNilPossible) { + src = mputstr(src, " } // use_nil\n"); } + if (sdef->xerUseOrderPossible) { + src = mputstr(src, " } // uo\n"); + } + if (sdef->xerEmbedValuesPossible) { - size_t op; src = mputprintf(src, - /* Set the embed-values member to the correct nr of strings */ - " if (e_xer && (p_td.xer_bits & EMBED_VALUES)) {\n" - " int exp_embed = %lu;\n" - , (unsigned long)max_embed - ); - - if (sdef->xerUseNilPossible) { - src = mputstr(src, - " if (nil_attribute) exp_embed = 0;\n" - " else {"); - } - - for (op = 0; op < sdef->nElements; ++op) { - if (sdef->elements[op].isOptional && !sdef->elements[op].xerAttribute) { - src = mputprintf(src, - " if (!field_%s.ispresent()) --exp_embed;\n" - , sdef->elements[op].name - ); - } - } - - if (sdef->xerUseNilPossible) src = mputstr(src, " }\n"); - - src = mputprintf(src, - " field_%s.set_size(exp_embed);//normal\n" + " if (0 != emb_val) {\n" " %s::of_type empty_string(\"\");\n" - " for (int j_j=0; j_jembval_index; ++j_j) {\n" " if (!field_%s[j_j].is_bound()) field_%s[j_j] = empty_string;\n" " }\n" - " }" - , sdef->elements[0].name + " delete emb_val;\n" + " }\n" , sdef->elements[0].type , sdef->elements[0].name , sdef->elements[0].name ); } - if (sdef->xerUseOrderPossible) { - src = mputstr(src, " } // uo\n"); - } - if (sdef->xerUseQName) { src = mputstr(src, " } // qn\n"); } @@ -5773,8 +5789,8 @@ static void defEmptyRecordClass(const struct_def *sdef, ); src = mputprintf(src, - "int %s::XER_encode(const XERdescriptor_t& p_td," - " TTCN_Buffer& p_buf, unsigned int p_flavor, int p_indent) const{\n" + "int %s::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, " + "unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const{\n" " int encoded_length=(int)p_buf.get_len();\n" " int is_indented = !is_canonical(p_flavor);\n" " int e_xer = is_exer(p_flavor);\n" @@ -5791,7 +5807,7 @@ static void defEmptyRecordClass(const struct_def *sdef, "// written by %s in " __FILE__ " at %d\n" #endif "int %s::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader, " - "unsigned int p_flavor)\n" + "unsigned int p_flavor, embed_values_dec_struct_t*)\n" "{\n" " int e_xer = is_exer(p_flavor);\n" " bound_flag = true;\n" diff --git a/compiler2/record_of.c b/compiler2/record_of.c index 0b76165..b820722 100644 --- a/compiler2/record_of.c +++ b/compiler2/record_of.c @@ -56,8 +56,6 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "int n_elements;\n" "%s **value_elements;\n" "} *val_ptr;\n" - "Vector refd_indices;\n" - "int max_refd_index;\n" #ifndef NDEBUG , __FUNCTION__, __LINE__ #endif @@ -98,63 +96,6 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "}\n" "}\n\n", name, name, dispname, name, dispname, name, name, name, name, name); } - - /* function that returns the actual number of elements */ - def = mputstr(def, "int get_nof_elements() const;\n"); - src = mputprintf(src, - "int %s::get_nof_elements() const\n" - "{\n" - " int nof_elements = (val_ptr != NULL) ? val_ptr->n_elements : 0;\n" - " if (!refd_indices.empty()) {\n" - " while (nof_elements > 0) {\n" - " if (is_elem_bound(nof_elements - 1)) {\n" - " break;\n" - " }\n" - " --nof_elements;\n" - " }\n" - " }\n" - " return nof_elements;\n" - "}\n\n", name); - - /* element boundness check function */ - def = mputstr(def, "bool is_elem_bound(int index) const;\n"); - src = mputprintf(src, - "bool %s::is_elem_bound(int index) const\n" - "{\n" - " return val_ptr->value_elements[index] != NULL &&\n" - " val_ptr->value_elements[index]->is_bound();\n" - "}\n\n", name); - - /* function that calculates and caches the maximum referenced index */ - def = mputstr(def, "int get_max_refd_index();\n"); - src = mputprintf(src, - "int %s::get_max_refd_index()\n" - "{\n" - " if (refd_indices.empty()) {\n" - " return -1;\n" - " }\n" - " if (-1 == max_refd_index) {\n" - " for (size_t i = 0; i < refd_indices.size(); ++i) {\n" - " if (refd_indices[i] > max_refd_index) {\n" - " max_refd_index = refd_indices[i];\n" - " }\n" - " }\n" - " }\n" - " return max_refd_index;\n" - "}\n\n", name); - - /* referenced index check function */ - def = mputstr(def, "bool is_index_refd(int index);\n"); - src = mputprintf(src, - "bool %s::is_index_refd(int index)\n" - "{\n" - " for (size_t i = 0; i < refd_indices.size(); ++i) {\n" - " if (index == refd_indices[i]) {\n" - " return true;\n" - " }\n" - " }\n" - " return false;\n" - "}\n\n", name); /* public member functions */ def = mputstr(def, "\npublic:\n"); @@ -166,7 +107,6 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "%s::%s()\n" "{\n" "val_ptr = NULL;\n" - "max_refd_index = -1;\n" "}\n\n", name, name); def = mputprintf(def, "%s(null_type other_value);\n", name); @@ -177,7 +117,6 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "val_ptr->ref_count = 1;\n" "val_ptr->n_elements = 0;\n" "val_ptr->value_elements = NULL;\n" - "max_refd_index = -1;\n" "}\n\n", name, name); /* copy constructor */ @@ -187,23 +126,9 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "{\n" "if (!other_value.is_bound()) " "TTCN_error(\"Copying an unbound value of type %s.\");\n" - "if (other_value.refd_indices.empty()) {\n" "val_ptr = other_value.val_ptr;\n" "val_ptr->ref_count++;\n" - "}\n" - "else {\n" - // there are references to at least one element => the array must be copied - "val_ptr = NULL;\n" - "int nof_elements = other_value.get_nof_elements();\n" - "set_size(nof_elements);\n" - "for (int i = 0; i < nof_elements; ++i) {\n" - "if (other_value.is_elem_bound(i)) {\n" - "val_ptr->value_elements[i] = new %s(*(other_value.val_ptr->value_elements[i]));\n" - "}\n" - "}\n" - "}\n" - "max_refd_index = -1;\n" - "}\n\n", name, name, name, dispname, type); + "}\n\n", name, name, name, dispname); /* destructor */ def = mputprintf(def, "~%s();\n\n", name); @@ -226,7 +151,6 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "val_ptr = NULL;\n" "}\n" "else if (val_ptr->ref_count == 1) {\n" - "if (refd_indices.empty()) {\n" "for (int elem_count = 0; elem_count < val_ptr->n_elements;\n" "elem_count++)\n" "if (val_ptr->value_elements[elem_count] != NULL)\n" @@ -235,10 +159,6 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "delete val_ptr;\n" "val_ptr = NULL;\n" "}\n" - "else {\n" - "set_size(0);\n" - "}\n" - "}\n" "else\n" "TTCN_error(\"Internal error: Invalid reference counter in a record " "of/set of value.\");\n" @@ -250,7 +170,11 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) src = mputprintf(src, "%s& %s::operator=(null_type)\n" "{\n" - "set_size(0);\n" + "clean_up();\n" + "val_ptr = new recordof_setof_struct;\n" + "val_ptr->ref_count = 1;\n" + "val_ptr->n_elements = 0;\n" + "val_ptr->value_elements = NULL;\n" "return *this;\n" "}\n\n", name, name); @@ -259,39 +183,15 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) src = mputprintf(src, "%s& %s::operator=(const %s& other_value)\n" "{\n" - "if (!other_value.is_bound()) " + "if (other_value.val_ptr == NULL) " "TTCN_error(\"Assigning an unbound value of type %s.\");\n" "if (this != &other_value) {\n" - "if (refd_indices.empty() && other_value.refd_indices.empty()) {\n" "clean_up();\n" "val_ptr = other_value.val_ptr;\n" "val_ptr->ref_count++;\n" "}\n" - "else {\n" - // there are references to at least one element => the array must be copied - "int nof_elements = other_value.get_nof_elements();\n" - "set_size(nof_elements);\n" - "for (int i = 0; i < nof_elements; ++i) {\n" - "if (other_value.is_elem_bound(i)) {\n" - "if (val_ptr->value_elements[i] == NULL) {\n" - "val_ptr->value_elements[i] = new %s;\n" - "}\n" - "*val_ptr->value_elements[i] = *other_value.val_ptr->value_elements[i];\n" - "}\n" - "else if (val_ptr->value_elements[i] != NULL) {\n" - "if (is_index_refd(i)) {\n" - "val_ptr->value_elements[i]->clean_up();\n" - "}\n" - "else {\n" - "delete val_ptr->value_elements[i];\n" - "val_ptr->value_elements[i] = NULL;\n" - "}\n" - "}\n" - "}\n" - "}\n" - "}\n" "return *this;\n" - "}\n\n", name, name, name, dispname, type); + "}\n\n", name, name, name, dispname); /* comparison operators */ def = mputstr(def, "boolean operator==(null_type other_value) const;\n"); @@ -301,7 +201,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "if (val_ptr == NULL)\n" "TTCN_error(\"The left operand of comparison is an unbound value of " "type %s.\");\n" - "return get_nof_elements() == 0 ;\n" + "return val_ptr->n_elements == 0 ;\n" "}\n\n", name, dispname); def = mputprintf(def, "boolean operator==(const %s& other_value) const;\n", @@ -319,22 +219,23 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) dispname, dispname); if (sdef->kind == SET_OF) { src = mputstr(src, - "return compare_set_of(this, get_nof_elements(), &other_value, " - "other_value.get_nof_elements(), compare_function);\n"); + "return compare_set_of(this, val_ptr->n_elements, &other_value, " + "(other_value.val_ptr)->n_elements, compare_function);\n"); } else { src = mputstr (src, - "if (get_nof_elements() != other_value.get_nof_elements())\n" + "if (val_ptr->n_elements != (other_value.val_ptr)->n_elements)\n" "return FALSE;\n" - "for (int elem_count = 0; elem_count < get_nof_elements(); elem_count++){\n" - "if (is_elem_bound(elem_count)){\n" - "if (other_value.is_elem_bound(elem_count)){\n" + "for (int elem_count = 0; elem_count < val_ptr->n_elements; elem_count++){\n" + "if (val_ptr->value_elements[elem_count] != NULL){\n" + "if ((other_value.val_ptr)->value_elements[elem_count] != NULL){\n" " if (*val_ptr->value_elements[elem_count] != " "*(other_value.val_ptr)->value_elements[elem_count]) " "return FALSE;\n" "} else return FALSE;\n" "} else {\n" - "if (other_value.is_elem_bound(elem_count)) return FALSE;\n" + "if ((other_value.val_ptr)->value_elements[elem_count] != NULL) " + "return FALSE;\n" "}\n" "}\n" "return TRUE;\n"); @@ -403,9 +304,9 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "TTCN_error(\"Accessing an element in an unbound value of type %s.\");\n" "if (index_value < 0) TTCN_error(\"Accessing an element of type %s " "using a negative index: %%d.\", index_value);\n" - "if (index_value >= get_nof_elements()) TTCN_error(\"Index overflow in " + "if (index_value >= val_ptr->n_elements) TTCN_error(\"Index overflow in " "a value of type %s: The index is %%d, but the value has only %%d " - "elements.\", index_value, get_nof_elements());\n" + "elements.\", index_value, val_ptr->n_elements);\n" "return (val_ptr->value_elements[index_value] != NULL) ?\n" "*val_ptr->value_elements[index_value] : UNBOUND_ELEM;\n" "}\n\n", type, name, dispname, dispname, dispname); @@ -449,17 +350,16 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "if (val_ptr == NULL) " "TTCN_error(\"Performing rotation operation on an unbound value of type " "%s.\");\n" - "int nof_elements = get_nof_elements();\n" - "if (nof_elements == 0) return *this;\n" + "if (val_ptr->n_elements == 0) return *this;\n" "int rc;\n" - "if (rotate_count>=0) rc = rotate_count %% nof_elements;\n" - "else rc = nof_elements - ((-rotate_count) %% nof_elements);\n" + "if (rotate_count>=0) rc = rotate_count %% val_ptr->n_elements;\n" + "else rc = val_ptr->n_elements - ((-rotate_count) %% val_ptr->n_elements);\n" "if (rc == 0) return *this;\n" "%s ret_val;\n" - "ret_val.set_size(nof_elements);\n" - "for (int i=0; ivalue_elements[(i+rc)%%nof_elements] =" + "ret_val.set_size(val_ptr->n_elements);\n" + "for (int i=0; in_elements; i++) {\n" + "if (val_ptr->value_elements[i] != NULL) {\n" + "ret_val.val_ptr->value_elements[(i+rc)%%val_ptr->n_elements] =" "new %s(*val_ptr->value_elements[i]);\n" "}\n" "}\n" @@ -475,20 +375,18 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "{\n" "if (val_ptr == NULL || other_value.val_ptr == NULL) " "TTCN_error(\"Unbound operand of %s concatenation.\");\n" - "int nof_elements = get_nof_elements();\n" - "if (nof_elements == 0) return other_value;\n" - "int other_value_nof_elements = other_value.get_nof_elements();" - "if (other_value_nof_elements == 0) return *this;\n" + "if (val_ptr->n_elements == 0) return other_value;\n" + "if (other_value.val_ptr->n_elements == 0) return *this;\n" "%s ret_val;\n" - "ret_val.set_size(nof_elements + other_value_nof_elements);\n" - "for (int i=0; in_elements+other_value.val_ptr->n_elements);\n" + "for (int i=0; in_elements; i++) {\n" + "if (val_ptr->value_elements[i] != NULL) {\n" "ret_val.val_ptr->value_elements[i] = new %s(*val_ptr->value_elements[i]);\n" "}\n" "}\n" - "for (int i=0; ivalue_elements[i + nof_elements] = " + "for (int i=0; in_elements; i++) {\n" + "if (other_value.val_ptr->value_elements[i] != NULL) {\n" + "ret_val.val_ptr->value_elements[i+val_ptr->n_elements] = " "new %s(*other_value.val_ptr->value_elements[i]);\n" "}\n" "}\n" @@ -504,12 +402,12 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "if (val_ptr == NULL) " "TTCN_error(\"The first argument of substr() is an unbound value of " "type %s.\");\n" - "check_substr_arguments(get_nof_elements(), index, returncount, " + "check_substr_arguments(val_ptr->n_elements, index, returncount, " "\"%s\",\"element\");\n" "%s ret_val;\n" "ret_val.set_size(returncount);\n" "for (int i=0; ivalue_elements[i+index] != NULL) {\n" "ret_val.val_ptr->value_elements[i] = " "new %s(*val_ptr->value_elements[i+index]);\n" "}\n" @@ -529,26 +427,24 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "if (repl.val_ptr == NULL) " "TTCN_error(\"The fourth argument of replace() is an unbound value of " "type %s.\");\n" - "int nof_elements = get_nof_elements();\n" - "check_replace_arguments(nof_elements, index, len, " + "check_replace_arguments(val_ptr->n_elements, index, len, " "\"%s\",\"element\");\n" "%s ret_val;\n" - "int repl_nof_elements = repl.get_nof_elements();\n" - "ret_val.set_size(nof_elements + repl_nof_elements - len);\n" + "ret_val.set_size(val_ptr->n_elements + repl.val_ptr->n_elements - len);\n" "for (int i = 0; i < index; i++) {\n" - "if (is_elem_bound(i)) {\n" + "if (val_ptr->value_elements[i] != NULL) {\n" "ret_val.val_ptr->value_elements[i] = new %s(*val_ptr->value_elements[i]);\n" "}\n" "}\n" - "for (int i = 0; i < repl_nof_elements; i++) {\n" - "if (repl.is_elem_bound(i)) {\n" + "for (int i = 0; i < repl.val_ptr->n_elements; i++) {\n" + "if (repl.val_ptr->value_elements[i] != NULL) {\n" "ret_val.val_ptr->value_elements[i+index] = " "new %s(*repl.val_ptr->value_elements[i]);\n" "}\n" "}\n" - "for (int i = 0; i < nof_elements - index - len; i++) {\n" - "if (is_elem_bound(index+i+len)) {\n" - "ret_val.val_ptr->value_elements[index+i+repl_nof_elements] = " + "for (int i = 0; i < val_ptr->n_elements - index - len; i++) {\n" + "if (val_ptr->value_elements[index+i+len] != NULL) {\n" + "ret_val.val_ptr->value_elements[index+i+repl.val_ptr->n_elements] = " "new %s(*val_ptr->value_elements[index+i+len]);\n" "}\n" "}\n" @@ -604,40 +500,19 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "val_ptr->n_elements = new_size;\n" "} else if (new_size < val_ptr->n_elements) {\n" "for (int elem_count = new_size; elem_count < val_ptr->n_elements; " - "elem_count++) {\n" - "if (val_ptr->value_elements[elem_count] != NULL) {\n" - "if (is_index_refd(elem_count)) {\n" - "val_ptr->value_elements[elem_count]->clean_up();\n" - "}\n" - "else {\n" + "elem_count++)\n" + "if (val_ptr->value_elements[elem_count] != NULL)" "delete val_ptr->value_elements[elem_count];\n" - "val_ptr->value_elements[elem_count] = 0;\n" - "}\n" - "}\n" - "}\n" - "if (new_size <= get_max_refd_index()) {\n" - "new_size = get_max_refd_index() + 1;\n" - "}\n" - "if (new_size < val_ptr->n_elements) {\n" "val_ptr->value_elements = (%s**)" "reallocate_pointers((void**)val_ptr->value_elements, " "val_ptr->n_elements, new_size);\n" "val_ptr->n_elements = new_size;\n" "}\n" - "}\n" "}\n\n", name, dispname, type, type, type, dispname, type); /* is_bound function */ def = mputstr(def, - "boolean is_bound() const;\n"); - src = mputprintf(src, - "boolean %s::is_bound() const\n" - "{\n" - "if (refd_indices.empty()) {\n" - "return (val_ptr != NULL);\n" - "}\n" - "return (get_nof_elements() != 0);\n" - "}\n\n", name); + "inline boolean is_bound() const {return val_ptr != NULL; }\n"); /* is_present function */ def = mputstr(def, @@ -650,8 +525,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "boolean %s::is_value() const\n" "{\n" "if (val_ptr == NULL) return false;\n" - "for(int i = 0; i < get_nof_elements(); ++i) {\n" - "if (!is_elem_bound(i) || " + "for(int i = 0; i < val_ptr->n_elements; ++i) {\n" + "if (val_ptr->value_elements[i] == NULL || " "!val_ptr->value_elements[i]->is_value()) return FALSE;\n" "}\n" "return TRUE;\n" @@ -667,7 +542,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "if (val_ptr == NULL) " "TTCN_error(\"Performing sizeof operation on an unbound value of type " "%s.\");\n" - "return get_nof_elements();\n" + "return val_ptr->n_elements;\n" "}\n\n", name, dispname); /* lengthof operation */ @@ -678,8 +553,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "if (val_ptr == NULL) " "TTCN_error(\"Performing lengthof operation on an unbound value of type " "%s.\");\n" - "for (int my_length=get_nof_elements(); my_length>0; my_length--) " - "if (is_elem_bound(my_length-1)) return my_length;\n" + "for (int my_length=val_ptr->n_elements; my_length>0; my_length--) " + "if (val_ptr->value_elements[my_length-1] != NULL) return my_length;\n" "return 0;\n" "}\n\n", name, dispname); @@ -693,13 +568,13 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "TTCN_Logger::log_event_unbound();\n" "return;\n" "}\n" - "switch (get_nof_elements()) {\n" + "switch (val_ptr->n_elements) {\n" "case 0:\n" "TTCN_Logger::log_event_str(\"{ }\");\n" "break;\n" "default:\n" "TTCN_Logger::log_event_str(\"{ \");\n" - "for (int elem_count = 0; elem_count < get_nof_elements(); " + "for (int elem_count = 0; elem_count < val_ptr->n_elements; " "elem_count++) {\n" "if (elem_count > 0) TTCN_Logger::log_event_str(\", \");\n" "(*this)[elem_count].log();\n" @@ -786,35 +661,9 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) src = mputprintf(src, "void %s::set_implicit_omit()\n{\n" "if (val_ptr == NULL) return;\n" - "for (int i = 0; i < get_nof_elements(); i++) {\n" - "if (is_elem_bound(i)) val_ptr->value_elements[i]->set_implicit_omit();\n" + "for (int i = 0; i < val_ptr->n_elements; i++) {\n" + "if (val_ptr->value_elements[i] != NULL) val_ptr->value_elements[i]->set_implicit_omit();\n" "}\n}\n\n", name); - - /* functions for inserting and removing references to elements of the record of */ - def = mputstr(def, " void add_refd_index(int index);\n"); - src = mputprintf(src, - "void %s::add_refd_index(int index)\n" - "{\n" - " refd_indices.push_back(index);\n" - " if (index > get_max_refd_index()) {\n" - " max_refd_index = index;\n" - " }\n" - "}\n\n", name); - - def = mputstr(def, " void remove_refd_index(int index);\n"); - src = mputprintf(src, - "void %s::remove_refd_index(int index)\n" - "{\n" - " for (size_t i = refd_indices.size(); i > 0; --i) {\n" - " if (refd_indices[i - 1] == index) {\n" - " refd_indices.erase_at(i - 1);\n" - " break;\n" - " }\n" - " }\n" - " if (get_max_refd_index() == index) {\n" - " max_refd_index = -1;\n" - " }\n" - "}\n\n", name); /* encoding / decoding functions */ def = mputstr(def, "void encode_text(Text_Buf& text_buf) const;\n"); @@ -823,8 +672,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "{\n" "if (val_ptr == NULL) " "TTCN_error(\"Text encoder: Encoding an unbound value of type %s.\");\n" - "text_buf.push_int(get_nof_elements());\n" - "for (int elem_count = 0; elem_count < get_nof_elements(); " + "text_buf.push_int(val_ptr->n_elements);\n" + "for (int elem_count = 0; elem_count < val_ptr->n_elements; " "elem_count++)\n" "(*this)[elem_count].encode_text(text_buf);\n" "}\n\n", name, dispname); @@ -833,18 +682,19 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) src = mputprintf(src, "void %s::decode_text(Text_Buf& text_buf)\n" "{\n" - "int new_size = text_buf.pull_int().get_val();\n" - "if (new_size < 0)\n TTCN_error(\"Text decoder: Negative size " + "clean_up();\n" + "val_ptr = new recordof_setof_struct;\n" + "val_ptr->ref_count = 1;\n" + "val_ptr->n_elements = text_buf.pull_int().get_val();\n" + "if (val_ptr->n_elements < 0) TTCN_error(\"Text decoder: Negative size " "was received for a value of type %s.\");\n" - "set_size(new_size);\n" - "for (int elem_count = 0; elem_count < new_size; " + "val_ptr->value_elements = (%s**)allocate_pointers(val_ptr->n_elements);\n" + "for (int elem_count = 0; elem_count < val_ptr->n_elements; " "elem_count++) {\n" - "if (val_ptr->value_elements[elem_count] == NULL) {\n" "val_ptr->value_elements[elem_count] = new %s;\n" - "}\n" "val_ptr->value_elements[elem_count]->decode_text(text_buf);\n" "}\n" - "}\n\n", name, dispname, type); + "}\n\n", name, dispname, type, type); if(ber_needed || raw_needed || text_needed || xer_needed || json_needed) def_encdec(name, &def, &src, ber_needed, raw_needed, text_needed, @@ -868,7 +718,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n" " return encoded_length;\n" " }\n" - " for(int a=0;an_elements;a++){\n" " if(a!=0 && p_td.text->separator_encode){\n" " p_buf.put_cs(*p_td.text->separator_encode);\n" " encoded_length+=p_td.text->separator_encode->lengthof();\n" @@ -914,9 +764,13 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " ml++;\n" " }\n" " if(first_call) {\n" - " set_size(0);\n" + " clean_up();\n" + " val_ptr=new recordof_setof_struct;\n" + " val_ptr->ref_count=1;\n" + " val_ptr->n_elements=0;\n" + " val_ptr->value_elements=NULL;\n" " }\n" - " int more=get_nof_elements();\n" + " int more=val_ptr->n_elements;\n" " while(TRUE){\n" " %s *val=new %s;\n" " pos=p_buf.get_pos();\n" @@ -931,17 +785,11 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " break;\n" " }\n" " sep_found=FALSE;\n" - " if (refd_indices.empty()) {\n" - " val_ptr->value_elements = (%s**)reallocate_pointers" + " val_ptr->value_elements = (%s**)reallocate_pointers" "((void**)val_ptr->value_elements, val_ptr->n_elements, " "val_ptr->n_elements + 1);\n" - " val_ptr->value_elements[val_ptr->n_elements]=val;\n" - " val_ptr->n_elements++;\n" - " }\n" - " else {\n" - " (*this)[get_nof_elements()] = *val;\n" - " delete val;\n" - " }\n" + " val_ptr->value_elements[val_ptr->n_elements]=val;\n" + " val_ptr->n_elements++;\n" " decoded_length+=len;\n" " if(p_td.text->separator_decode){\n" " int tl;\n" @@ -977,7 +825,9 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " if((tl=p_td.text->end_decode->match_begin(p_buf))<0){\n" " if(no_err){" " if(!first_call){\n" - " set_size(more);\n" + " for(int a=more; an_elements; a++) " + "delete val_ptr->value_elements[a];\n" + " val_ptr->n_elements=more;\n" " }\n" " return -1;\n" " }\n" @@ -990,7 +840,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " decoded_length+=tl;\n" " p_buf.increase_pos(tl);\n" " }\n" - " if(get_nof_elements()==0){\n" + " if(val_ptr->n_elements==0){\n" " if(!(p_td.text->end_decode || p_td.text->begin_decode)) {\n" " if(no_err)return -1;\n" " TTCN_EncDec_ErrorContext::error" @@ -998,7 +848,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " return decoded_length;\n" " }\n" " }\n" - " if(!first_call && more==get_nof_elements() && " + " if(!first_call && more==val_ptr->n_elements && " "!(p_td.text->end_decode || p_td.text->begin_decode)) return -1;\n" " return decoded_length;\n" "}\n" @@ -1018,7 +868,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " if(!new_tlv) {\n" " new_tlv=ASN_BER_TLV_t::construct(NULL);\n" " TTCN_EncDec_ErrorContext ec;\n" - " 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" @@ -1039,23 +889,32 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " TTCN_EncDec_ErrorContext ec_0(\"While decoding '%%s' type: \"," " p_td.name);\n" " stripped_tlv.chk_constructed_flag(TRUE);\n" - " set_size(0);\n" + " clean_up();\n" + " val_ptr = new recordof_setof_struct;\n" + " val_ptr->ref_count = 1;\n" + " val_ptr->n_elements = 0;\n" + " val_ptr->value_elements = NULL;\n" " size_t V_pos=0;\n" " ASN_BER_TLV_t tmp_tlv;\n" " TTCN_EncDec_ErrorContext ec_1(\"Component #\");\n" " TTCN_EncDec_ErrorContext ec_2(\"0: \");\n" " while(BER_decode_constdTLV_next(stripped_tlv, V_pos, L_form, " "tmp_tlv)) {\n" - " (*this)[get_nof_elements()].BER_decode_TLV(%s_descr_, tmp_tlv, " + " val_ptr->value_elements = (%s**)reallocate_pointers(" + "(void**)val_ptr->value_elements, val_ptr->n_elements, " + "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, " "L_form);\n" - " ec_2.set_msg(\"%%d: \", get_nof_elements());\n" + " ec_2.set_msg(\"%%d: \", val_ptr->n_elements);\n" " }\n" " return TRUE;\n" "}\n" "\n" , name, sdef->oftypedescrname , sdef->kind==SET_OF?" new_tlv->sort_tlvs();\n":"" - , name, sdef->oftypedescrname + , name, type, type, sdef->oftypedescrname ); if(sdef->has_opentypes) { @@ -1072,9 +931,9 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " p_typelist.push(this);\n" " TTCN_EncDec_ErrorContext ec_0(\"Component #\");\n" " TTCN_EncDec_ErrorContext ec_1;\n" - " for(int elem_i=0; elem_in_elements; elem_i++) {\n" " ec_1.set_msg(\"%%d: \", elem_i);\n" - " (*this)[elem_i].BER_decode_opentypes(p_typelist," + " val_ptr->value_elements[elem_i]->BER_decode_opentypes(p_typelist," " L_form);\n" " }\n" " p_typelist.pop();\n" @@ -1096,9 +955,13 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " int decoded_field_length=0;\n" " size_t start_of_field=0;\n" " if(first_call) {\n" - " set_size(0);\n" + " clean_up();\n" + " val_ptr=new recordof_setof_struct;\n" + " val_ptr->ref_count=1;\n" + " val_ptr->n_elements=0;\n" + " val_ptr->value_elements=NULL;\n" " }\n" - " int start_field=get_nof_elements();\n" + " int start_field=val_ptr->n_elements;\n" " if(p_td.raw->fieldlength || sel_field!=-1){\n" " int a=0;\n" " if(sel_field==-1) sel_field=p_td.raw->fieldlength;\n" @@ -1109,10 +972,12 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " decoded_length+=decoded_field_length;\n" " limit-=decoded_field_length;\n" " }\n" + " if(a==0) val_ptr->n_elements=0;\n" " } else {\n" " int a=start_field;\n" " if(limit==0){\n" " if(!first_call) return -1;\n" + " val_ptr->n_elements=0;\n" " return decoded_length+p_buf.increase_pos_padd(p_td.raw->padding)" "+prepaddlength;\n" " }\n" @@ -1121,7 +986,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " decoded_field_length=(*this)[a].RAW_decode(%s_descr_,p_buf,limit," "top_bit_ord,TRUE);\n" " if(decoded_field_length < 0){\n" - " set_size(get_nof_elements() - 1);\n" + " delete &(*this)[a];\n" + " val_ptr->n_elements--;\n" " p_buf.set_pos_bit(start_of_field);\n" " if(a>start_field){\n" " return decoded_length+p_buf.increase_pos_padd(p_td.raw->padding)" @@ -1149,8 +1015,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "RAW_enc_tree& myleaf) const{\n" " int encoded_length=0;\n" " int encoded_num_of_records=p_td.raw->fieldlength?" - "smaller(get_nof_elements(), p_td.raw->fieldlength)" - ":get_nof_elements();\n" + "smaller(val_ptr->n_elements, p_td.raw->fieldlength)" + ":val_ptr->n_elements;\n" " myleaf.isleaf=FALSE;\n" " myleaf.rec_of=TRUE;\n" " myleaf.body.node.num_of_nodes=encoded_num_of_records;\n" @@ -1215,7 +1081,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " if (val_ptr) try {\n" " char **new_ns;\n" " size_t num_new;\n" - " for (int i = 0; i < get_nof_elements(); ++i) {\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" " merge_ns(collected_ns, num_collected, new_ns, num_new);\n" @@ -1235,8 +1101,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) , name, sdef->oftypedescrname); src=mputprintf(src, - "int %s::XER_encode(const XERdescriptor_t& p_td," - " TTCN_Buffer& p_buf, unsigned int p_flavor, int p_indent) const\n{\n" + "int %s::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, " + "unsigned int p_flavor, int p_indent, embed_values_enc_struct_t* emb_val) const\n{\n" " if (val_ptr == 0) TTCN_error(\"Attempt to XER-encode an unbound record of\");\n" /* TODO type name */ " int encoded_length=(int)p_buf.get_len();\n" " boolean e_xer = is_exer(p_flavor);\n" @@ -1244,8 +1110,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " || (p_flavor & USE_TYPE_ATTR)));\n" " boolean indenting = !is_canonical(p_flavor) && own_tag;\n" "%s" /* Factor out p_indent if not attribute */ - " int nof_elements = get_nof_elements();\n" - " if (nof_elements==0) {\n" /* Empty record of */ + " if (val_ptr->n_elements==0) {\n" /* Empty record of */ , name , sdef->xerAttribute ? "" : " if (indenting) do_indent(p_buf, p_indent);\n" ); @@ -1298,9 +1163,9 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " unsigned char saved[4];\n" " memcpy(saved, buf_data + (buf_len - shorter), shorter);\n" " p_buf.increase_length(-shorter);\n" - " for (int i = 0; i < nof_elements; ++i) {\n" + " for (int i = 0; i < val_ptr->n_elements; ++i) {\n" " TTCN_EncDec_ErrorContext ec_0(\"Attribute %d: \", i);\n" - " if (!is_elem_bound(i)) {\n" + " if (val_ptr->value_elements[i] == NULL) {\n" " TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n" " \"Encoding an unbound universal charstring value.\");\n" " continue;\n" @@ -1330,7 +1195,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " p_buf.put_s(ns_len, (const unsigned char*)ns);\n" " UNIVERSAL_CHARSTRING before(sp_at, (const universal_char*)(*val_ptr->value_elements[i]));\n" - " before.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | ANY_ATTRIBUTES, p_indent);\n" + " before.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | ANY_ATTRIBUTES, p_indent, 0);\n" // Ensure the namespace abides to its restrictions " if (p_td.xer_bits & (ANY_FROM | ANY_EXCEPT)) {\n" " TTCN_Buffer ns_buf;\n" @@ -1358,7 +1223,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n" " UNIVERSAL_CHARSTRING after(len - j, (const universal_char*)(*val_ptr->value_elements[i]) + j);\n" - " after.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | ANY_ATTRIBUTES, p_indent);\n" + " after.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | ANY_ATTRIBUTES, p_indent, 0);\n" // Put this attribute in a dummy element and walk through it to check its validity " TTCN_Buffer check_buf;\n" " check_buf.put_s(2, (unsigned char*)\"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" + " ++emb_val->embval_index;\n" + " }\n" - temporarily removed in RT1 */ " 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);\n" + " (*this)[i].XER_encode(%s_xer_, p_buf, p_flavor, p_indent+own_tag, emb_val);\n" " }\n" " if (indenting && !is_exerlist(p_flavor)) {\n", sdef->oftypedescrname @@ -1453,7 +1324,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "// written by %s in " __FILE__ " at %d\n" #endif "int %s::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader, " - "unsigned int p_flavor)\n{\n" + "unsigned int p_flavor, embed_values_dec_struct_t* emb_val)\n{\n" " boolean e_xer = is_exer(p_flavor);\n" " int xerbits = p_td.xer_bits;\n" " if (p_flavor & XER_TOPLEVEL) xerbits &= ~UNTAGGED;\n" @@ -1462,7 +1333,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) /* not toplevel anymore and remove the flags for USE-UNION the oftype doesn't need them */ " p_flavor &= ~XER_TOPLEVEL & ~XER_LIST & ~USE_TYPE_ATTR;\n" " int rd_ok=1, xml_depth=-1;\n" - " set_size(0);\n" /* empty but initialized array */ + " *this = NULL_VALUE;\n" /* empty but initialized array */ " int type = 0;\n" /* none */ " if (own_tag) for (rd_ok = p_reader.Ok(); rd_ok == 1; rd_ok = p_reader.Read()) {\n" " type = p_reader.NodeType();\n" @@ -1530,14 +1401,14 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) /* 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)[get_nof_elements()].XER_decode(%s_xer_, reader_2, p_flavor);\n" - " if (p_flavor & EXIT_ON_ERROR && !(*this)[get_nof_elements() - 1].is_bound()) {\n" - " if (1 == get_nof_elements()) {\n" + " (*this)[val_ptr->n_elements].XER_decode(%s_xer_, 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 " clean_up();\n" " } else {\n" // Some elements were successfully decoded -> only delete the last one - " set_size(get_nof_elements() - 1);\n" + " set_size(val_ptr->n_elements - 1);\n" " }\n" " xmlFree(x_val);\n" " return -1;\n" @@ -1580,7 +1451,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) * for the element type (a string), so behave like a record-of * (string with ANY-ELEMENT): call the non-const operator[] * to create a new element, then read the entire XML element into it. */ - " (*this)[get_nof_elements()] = (const char*)p_reader.ReadOuterXml();\n" + " (*this)[val_ptr->n_elements] = (const char*)p_reader.ReadOuterXml();\n" /* Consume the element, then move ahead */ " for (rd_ok = p_reader.Read(); rd_ok == 1 && p_reader.Depth() > xml_depth; rd_ok = p_reader.Read()) {}\n" " if (p_reader.NodeType() != XML_READER_TYPE_ELEMENT) rd_ok = p_reader.Read();\n" @@ -1596,7 +1467,10 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " break;\n" " }\n" /* The call to the non-const operator[] creates the element */ - " (*this)[get_nof_elements()].XER_decode(%s_xer_, p_reader, p_flavor);\n" + " (*this)[val_ptr->n_elements].XER_decode(%s_xer_, 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" " }\n" " }\n" " else if (XML_READER_TYPE_END_ELEMENT == type) {\n" @@ -1607,6 +1481,11 @@ 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" + " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" + " emb_val->embval_array->set_embedded_value(emb_val->embval_index, emb_ustr);\n" + " rd_ok = p_reader.Read();\n" + " }\n" - temporarily removed in RT1 */ " else {\n" " rd_ok = p_reader.Read();\n" " }\n" @@ -1629,7 +1508,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " return -1;\n" " }\n\n" " int enc_len = p_tok.put_next_token(JSON_TOKEN_ARRAY_START, NULL);\n" - " for(int i = 0; i < get_nof_elements(); ++i) {\n" + " for(int i = 0; i < val_ptr->n_elements; ++i) {\n" " int ret_val = (*this)[i].JSON_encode(%s_descr_, p_tok);\n" " if (0 > ret_val) break;\n" " enc_len += ret_val;\n" @@ -1669,17 +1548,11 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) " }\n" " return JSON_ERROR_FATAL;\n" " }\n" - " if (refd_indices.empty()) {\n" - " val_ptr->value_elements = (%s**)reallocate_pointers(\n" - " (void**)val_ptr->value_elements, val_ptr->n_elements, val_ptr->n_elements + 1);\n" - " val_ptr->value_elements[val_ptr->n_elements] = val;\n" - " val_ptr->n_elements++;\n" - " dec_len += ret_val;\n" - " }\n" - " else {\n" - " (*this)[get_nof_elements()] = *val;\n" - " delete val;\n" - " }\n" + " val_ptr->value_elements = (%s**)reallocate_pointers(\n" + " (void**)val_ptr->value_elements, val_ptr->n_elements, val_ptr->n_elements + 1);\n" + " val_ptr->value_elements[val_ptr->n_elements] = val;\n" + " val_ptr->n_elements++;\n" + " dec_len += ret_val;\n" " }\n\n" " dec_len += p_tok.get_next_token(&token, NULL, NULL);\n" " if (JSON_TOKEN_ARRAY_END != token) {\n" @@ -1714,7 +1587,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "if (other_value.val_ptr == NULL)\n" "TTCN_error(\"The right operand of comparison is an unbound value of " "type %s.\");\n" - "return other_value.get_nof_elements() == 0;\n" + "return other_value.val_ptr->n_elements == 0;\n" "}\n\n", name, dispname); output->header.function_prototypes = @@ -2657,8 +2530,8 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct , name, sdef->oftypedescrname); src=mputprintf(src, - "int %s::XER_encode(const XERdescriptor_t& p_td," - " TTCN_Buffer& p_buf, unsigned int p_flavor, int p_indent) const\n{\n" + "int %s::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, " + "unsigned int p_flavor, int p_indent, embed_values_enc_struct_t* emb_val) const\n{\n" " if (n_elements==-1) TTCN_error(\"Attempt to XER-encode an unbound record of\");\n" /* TODO type name */ " int encoded_length=(int)p_buf.get_len();\n" " boolean e_xer = is_exer(p_flavor);\n" @@ -2746,7 +2619,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " p_buf.put_s(ns_len, (const unsigned char*)ns);\n" " UNIVERSAL_CHARSTRING before(sp_at, (const universal_char*)(value_elements[i]));\n" - " before.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | ANY_ATTRIBUTES, p_indent);\n" + " before.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | ANY_ATTRIBUTES, p_indent, 0);\n" // Ensure the namespace abides to its restrictions " if (p_td.xer_bits & (ANY_FROM | ANY_EXCEPT)) {\n" " TTCN_Buffer ns_buf;\n" @@ -2774,7 +2647,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " }\n" " UNIVERSAL_CHARSTRING after(len - j, (const universal_char*)(value_elements[i]) + j);\n" - " after.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | ANY_ATTRIBUTES, p_indent);\n" + " after.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, p_flavor | ANY_ATTRIBUTES, p_indent, 0);\n" // Put this attribute in a dummy element and walk through it to check its validity " TTCN_Buffer check_buf;\n" " check_buf.put_s(2, (unsigned char*)\" 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" + " ++emb_val->embval_index;\n" + " }\n" - temporarily removed in RT1 */ " 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);\n" + " value_elements[i].XER_encode(%s_xer_, p_buf, p_flavor, p_indent+own_tag, emb_val);\n" " }\n" " if (indenting && !is_exerlist(p_flavor)) {\n", sdef->oftypedescrname @@ -2869,7 +2748,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct "// written by %s in " __FILE__ " at %d\n" #endif "int %s::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader, " - "unsigned int p_flavor)\n{\n" + "unsigned int p_flavor, embed_values_dec_struct_t* emb_val)\n{\n" " boolean e_xer = is_exer(p_flavor);\n" " int xerbits = p_td.xer_bits;\n" " if (p_flavor & XER_TOPLEVEL) xerbits &= ~UNTAGGED;\n" @@ -2946,7 +2825,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct /* 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);\n" + " (*this)[n_elements].XER_decode(%s_xer_, 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 @@ -3012,7 +2891,10 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct " break;\n" " }\n" /* The call to the non-const operator[] creates the element */ - " operator [](n_elements).XER_decode(%s_xer_, p_reader, p_flavor);\n" + " operator [](n_elements).XER_decode(%s_xer_, p_reader, p_flavor, emb_val);\n" + " if (0 != emb_val && !own_tag && n_elements > 1) {\n" + " ++emb_val->embval_index;\n" + " }\n" " }\n" " }\n" " else if (XML_READER_TYPE_END_ELEMENT == type) {\n" @@ -3023,6 +2905,11 @@ 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" + " UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n" + " emb_val->embval_array->set_embedded_value(emb_val->embval_index, emb_ustr);\n" + " rd_ok = p_reader.Read();\n" + " }\n" - temporarily removed in RT1 */ " else {\n" " rd_ok = p_reader.Read();\n" " }\n" @@ -3099,11 +2986,6 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct "}\n\n" , name, type, sdef->oftypedescrname); } - - /* functions for keeping track of referenced indices (only implemented for regular record of class) */ - def = mputstr(def, - "void add_refd_index(int) {}\n" - "void remove_refd_index(int) {}\n\n"); /* end of class */ def = mputstr(def, "};\n\n"); diff --git a/compiler2/subtype.cc b/compiler2/subtype.cc index d59cf5c..29b0232 100644 --- a/compiler2/subtype.cc +++ b/compiler2/subtype.cc @@ -1241,6 +1241,30 @@ bool SubtypeConstraint::is_length_compatible(const SubtypeConstraint *p_st) cons return ((*length_restriction * *(p_st->length_restriction)).is_empty()!=TTRUE); } +bool SubtypeConstraint::is_upper_limit_infinity() const +{ + if (ST_INTEGER == subtype && integer_st) { + return integer_st->is_upper_limit_infinity(); + } + if (ST_FLOAT == subtype && float_st) { + return float_st->is_upper_limit_infinity(); + } + return false; +} + +bool SubtypeConstraint::is_lower_limit_infinity() const +{ + if (ST_INTEGER == subtype && integer_st) { + return integer_st->is_lower_limit_infinity(); + } + + if (ST_FLOAT == subtype && float_st) { + return float_st->is_lower_limit_infinity(); + } + return false; +} + + void SubtypeConstraint::except(const SubtypeConstraint* other) { if (other==NULL) FATAL_ERROR("SubtypeConstraint::except()"); diff --git a/compiler2/subtype.hh b/compiler2/subtype.hh index a9618aa..f7fde1a 100644 --- a/compiler2/subtype.hh +++ b/compiler2/subtype.hh @@ -199,6 +199,8 @@ public: bool is_compatible_with_elem() const; // used to check compatibility of structured types bool is_length_compatible(const SubtypeConstraint *p_st) const; + bool is_upper_limit_infinity() const; + bool is_lower_limit_infinity() const; }; /** diff --git a/compiler2/subtypestuff.cc b/compiler2/subtypestuff.cc index 02adf32..bc18d92 100644 --- a/compiler2/subtypestuff.cc +++ b/compiler2/subtypestuff.cc @@ -451,6 +451,16 @@ string RealRangeListConstraint::to_string() const return ret_val; } +bool RealRangeListConstraint::is_upper_limit_infinity () const +{ + return rlc.is_upper_limit_infinity(); +} + +bool RealRangeListConstraint::is_lower_limit_infinity () const +{ + return rlc.is_lower_limit_infinity(); +} + //////////////////////////////////////////////////////////////////////////////// string BooleanListConstraint::to_string() const diff --git a/compiler2/subtypestuff.hh b/compiler2/subtypestuff.hh index 86970b3..473213e 100644 --- a/compiler2/subtypestuff.hh +++ b/compiler2/subtypestuff.hh @@ -260,6 +260,9 @@ public: LIMITTYPE get_minimal() const; LIMITTYPE get_maximal() const; + bool is_upper_limit_infinity() const; + bool is_lower_limit_infinity() const; + string to_string(bool add_brackets=true) const; /** conversion from integer range to size range, @@ -538,6 +541,20 @@ LIMITTYPE RangeListConstraint::get_maximal() const return values[values.size()-1]; } +template +bool RangeListConstraint::is_upper_limit_infinity () const +{ + if (0 == values.size()) return false; + return LIMITTYPE::maximum == values[values.size()-1]; +} + +template +bool RangeListConstraint::is_lower_limit_infinity () const +{ + if (0 == values.size()) return false; + return LIMITTYPE::minimum == values[0]; +} + template string RangeListConstraint::to_string(bool add_brackets) const { @@ -597,6 +614,8 @@ public: real_limit_t get_maximal() const { return rlc.get_maximal(); } string to_string() const; + bool is_upper_limit_infinity() const; + bool is_lower_limit_infinity() const; }; //////////////////////////////////////////////////////////////////////////////// diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 80c0563..7b0a70c 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -2707,28 +2707,37 @@ namespace Ttcn { return false; } - void Module::add_types_to_json_schema(JSON_Tokenizer& json) + void Module::generate_json_schema(JSON_Tokenizer& json, map& json_refs) { // add a new property for this module - json.put_next_token(JSON_TOKEN_NAME, modid->get_dispname().c_str()); + json.put_next_token(JSON_TOKEN_NAME, modid->get_ttcnname().c_str()); // add type definitions into an object json.put_next_token(JSON_TOKEN_OBJECT_START); - // pass the JSON tokenizer onto each type definition + // cycle through each type, generate schema segment and reference when needed for (size_t i = 0; i < asss->get_nof_asss(); ++i) { Def_Type* def = dynamic_cast(asss->get_ass_byIndex(i)); if (def != NULL) { - def->generate_json_schema(json); + Type* t = def->get_Type(); + if (t->has_encoding(Type::CT_JSON)) { + // insert type's schema segment + t->generate_json_schema(json, false, false); + + if (json_refs_for_all_types && !json_refs.has_key(t)) { + // create JSON schema reference for the type + JSON_Tokenizer* json_ref = new JSON_Tokenizer; + json_refs.add(t, json_ref); + t->generate_json_schema_ref(*json_ref); + } + } } } // end of type definitions json.put_next_token(JSON_TOKEN_OBJECT_END); - } - - void Module::add_func_to_json_schema(map& json_refs) - { + + // insert function data for (size_t i = 0; i < asss->get_nof_asss(); ++i) { Def_ExtFunction* def = dynamic_cast(asss->get_ass_byIndex(i)); if (def != NULL) { @@ -3124,13 +3133,6 @@ namespace Ttcn { } w_attrib_path->set_parent(p_path); } - - void Def_Type::generate_json_schema(JSON_Tokenizer& json) - { - if (type->has_encoding(Type::CT_JSON)) { - type->generate_json_schema(json, false, false); - } - } // ================================= // ===== Def_Const @@ -6729,13 +6731,7 @@ namespace Ttcn { // the schema segment doesn't exist yet, create it and insert the reference json = new JSON_Tokenizer; json_refs.add(type, json); - json->put_next_token(JSON_TOKEN_OBJECT_START); - json->put_next_token(JSON_TOKEN_NAME, "$ref"); - char* ref_str = mprintf("\"#/definitions/%s/%s\"", - type->get_my_scope()->get_scope_mod()->get_modid().get_dispname().c_str(), - type->get_dispname().c_str()); - json->put_next_token(JSON_TOKEN_STRING, ref_str); - Free(ref_str); + type->generate_json_schema_ref(*json); } // insert a property to specify which function this is (encoding or decoding) @@ -9087,7 +9083,7 @@ namespace Ttcn { case AP_REF: if (gen_restriction_check!=TR_NONE || gen_post_restriction_check!=TR_NONE) return false; - if (ref->get_subrefs() != NULL) { + if (use_runtime_2 && ref->get_subrefs() != NULL) { FieldOrArrayRefs* subrefs = ref->get_subrefs(); for (size_t i = 0; i < subrefs->get_nof_refs(); ++i) { if (FieldOrArrayRef::ARRAY_REF == subrefs->get_ref(i)->get_type()) { @@ -9488,7 +9484,7 @@ namespace Ttcn { } } - if (ActualPar::AP_REF == par->get_selection()) { + if (use_runtime_2 && ActualPar::AP_REF == par->get_selection()) { // if the parameter references an element of a record of/set of, then // the record of object needs to know, so it doesn't delete the referenced // element @@ -9526,17 +9522,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 - string tmp_id = ref->get_my_scope()->get_scope_mod_gen()->get_temporary_id(); - expr->preamble = mputprintf(expr->preamble, - "INTEGER %s = %s;\n" + expr->preamble = mputprintf(expr->preamble, "%s.add_refd_index(%s);\n", - tmp_id.c_str(), index_expr.expr, array_expr.expr, index_expr.expr); + array_expr.expr, index_expr.expr); expr->postamble = mputprintf(expr->postamble, - "%s.remove_refd_index(%s);\n" - "if (%s >= %s.size_of()) TTCN_warning(\"" - "Warning: possibly incompatible behaviour related to TR HT24380;" - " for details see release notes\");\n", - array_expr.expr, index_expr.expr, tmp_id.c_str(), array_expr.expr); + "%s.remove_refd_index(%s);\n", + 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/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index 85e6999..06a57a6 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -625,14 +625,15 @@ namespace Ttcn { bool is_visible(const Identifier& id, visibility_t visibility); - /** Generates JSON schema segments for the types defined in the module - * and adds them to the JSON schema parameter. */ - void add_types_to_json_schema(JSON_Tokenizer& json); - - /** Generates JSON schemas containing references to the types that have JSON - * encoding and/or decoding functions declared in the module. Information - * related to these functions is also inserted after the references. */ - void add_func_to_json_schema(map& json_refs); + /** Generates JSON schema segments for the types defined in the modules, + * and references to these types. Information related to the types' + * JSON encoding and decoding functions is also inserted after the references. + * + * @param json JSON document containing the main schema, schema segments for + * the types will be inserted here + * @param json_refs map of JSON documents containing the references and function + * info related to each type */ + virtual void generate_json_schema(JSON_Tokenizer& json, map& json_refs); }; /** @@ -888,10 +889,6 @@ namespace Ttcn { virtual void set_with_attr(MultiWithAttrib* p_attrib); virtual WithAttribPath* get_attrib_path(); virtual void set_parent_path(WithAttribPath* p_path); - - /** Generates a JSON schema segment for the defined type and inserts it into - * the JSON schema parameter. */ - void generate_json_schema(JSON_Tokenizer& json); }; /** diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 717c361..2a452a9 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -152,13 +152,11 @@ namespace Ttcn { else return get_parent_scope()->get_ass_bySRef(p_ref); } - Type *StatementBlock::get_mtc_system_comptype(bool is_system, bool is_connecting) + Type *StatementBlock::get_mtc_system_comptype(bool is_system) { // return NULL outside test cases - if (!my_def || ((is_system || !is_connecting) && - my_def->get_asstype() != Common::Assignment::A_TESTCASE)) { + if (!my_def || my_def->get_asstype() != Common::Assignment::A_TESTCASE) return 0; - } if (is_system) { Def_Testcase *t_tc = dynamic_cast(my_def); if (!t_tc) FATAL_ERROR("StatementBlock::get_mtc_system_comptype()"); @@ -4958,7 +4956,7 @@ error: } } - Type *Statement::chk_comp_ref(Value *p_val, bool allow_mtc, bool allow_system, bool is_connecting) + Type *Statement::chk_comp_ref(Value *p_val, bool allow_mtc, bool allow_system) { if (!my_sb->get_my_def()) error("Component operation is not allowed in the control part"); @@ -5001,8 +4999,7 @@ error: p_val->error("A component reference was expected as operand"); return 0; } - Type *ret_val = is_connecting ? p_val->get_component_governor() : - p_val->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE); + Type *ret_val = p_val->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE); if (!ret_val) return 0; ret_val = ret_val->get_type_refd_last(); switch (ret_val->get_typetype()) { @@ -5020,7 +5017,7 @@ error: Type *Statement::chk_conn_endpoint(Value *p_compref, Reference *p_portref, bool allow_system) { - Type *comp_type = chk_comp_ref(p_compref, true, allow_system, true); + Type *comp_type = chk_comp_ref(p_compref, true, allow_system); if (comp_type) { ComponentTypeBody *comp_body = comp_type->get_CompBody(); p_portref->set_base_scope(comp_body); diff --git a/compiler2/ttcn3/Statement.hh b/compiler2/ttcn3/Statement.hh index 9a36b1e..1c1aa6c 100644 --- a/compiler2/ttcn3/Statement.hh +++ b/compiler2/ttcn3/Statement.hh @@ -96,7 +96,7 @@ namespace Ttcn { void register_def(Definition *p_def); virtual bool has_ass_withId(const Identifier& p_id); virtual Common::Assignment* get_ass_bySRef(Ref_simple *p_ref); - virtual Type *get_mtc_system_comptype(bool is_system, bool is_connecting); + virtual Type *get_mtc_system_comptype(bool is_system); Definition* get_my_def() const { return my_def; } virtual Ttcn::StatementBlock *get_statementblock_scope(); void set_my_sb(StatementBlock *p_sb, size_t p_index); @@ -702,9 +702,8 @@ namespace Ttcn { * type is a component type). Returns a pointer to the component * type if available or NULL otherwise. Flags \a allow_mtc and \a * allow_system indicate whether the mtc or system component - * reference is acceptable in this context. Flag \a is_connecting - * is set if the component is part of a 'map' or 'connect' statement. */ - Type *chk_comp_ref(Value *p_val, bool allow_mtc, bool allow_system, bool is_connecting = false); + * reference is acceptable in this context. */ + Type *chk_comp_ref(Value *p_val, bool allow_mtc, bool allow_system); /** Checks an endpoint for a port connection or mapping. Parameter * \a p_compref is a component reference, \a p_portref refers to * a port within the corresponding component type. A pointer to diff --git a/compiler2/ttcn3/Ttcn2Json.cc b/compiler2/ttcn3/Ttcn2Json.cc index ab34103..fb70102 100644 --- a/compiler2/ttcn3/Ttcn2Json.cc +++ b/compiler2/ttcn3/Ttcn2Json.cc @@ -36,31 +36,32 @@ void Ttcn2Json::create_schema(JSON_Tokenizer& json) json.put_next_token(JSON_TOKEN_NAME, "definitions"); json.put_next_token(JSON_TOKEN_OBJECT_START, NULL); - // insert module names and schemas for types - modules->add_types_to_json_schema(json); + // insert module names and schemas for types; gather references to types and + // JSON encoding/decoding function information + map json_refs; + modules->generate_json_schema(json, json_refs); // end of type definitions json.put_next_token(JSON_TOKEN_OBJECT_END, NULL); - - // top-level "anyOf" structure containing references to the types the schema validates - json.put_next_token(JSON_TOKEN_NAME, "anyOf"); - json.put_next_token(JSON_TOKEN_ARRAY_START, NULL); - - // gather type references and JSON encoding/decoding function data - map json_refs; - modules->add_func_to_json_schema(json_refs); - - // close schema segments and add them to the main schema - for (size_t i = 0; i < json_refs.size(); ++i) { - JSON_Tokenizer* segment = json_refs.get_nth_elem(i); - segment->put_next_token(JSON_TOKEN_OBJECT_END, NULL); - insert_schema(json, *segment); - delete segment; + + if (!json_refs.empty()) { + // top-level "anyOf" structure containing references to the types the schema validates + // don't insert an empty "anyOf" if there are no references + json.put_next_token(JSON_TOKEN_NAME, "anyOf"); + json.put_next_token(JSON_TOKEN_ARRAY_START, NULL); + + // close schema segments and add them to the main schema + for (size_t i = 0; i < json_refs.size(); ++i) { + JSON_Tokenizer* segment = json_refs.get_nth_elem(i); + segment->put_next_token(JSON_TOKEN_OBJECT_END, NULL); + insert_schema(json, *segment); + delete segment; + } + json_refs.clear(); + + // end of the "anyOf" structure + json.put_next_token(JSON_TOKEN_ARRAY_END, NULL); } - json_refs.clear(); - - // end of the "anyOf" structure - json.put_next_token(JSON_TOKEN_ARRAY_END, NULL); // top-level object end json.put_next_token(JSON_TOKEN_OBJECT_END, NULL); diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc index 8052ecc..bf646c6 100644 --- a/compiler2/ttcn3/TtcnTemplate.cc +++ b/compiler2/ttcn3/TtcnTemplate.cc @@ -1729,7 +1729,8 @@ namespace Ttcn { vs->add_v(v); } ret_val = new Value(Value::V_SEQOF, vs); - if (gov) ret_val->set_my_governor(gov->get_parent_type()); + if (gov) gov = gov->get_parent_type(); + if (gov) ret_val->set_my_governor(gov); break; } case NAMED_TEMPLATE_LIST: { NamedValues *nvs = new NamedValues; @@ -1744,7 +1745,8 @@ namespace Ttcn { nvs->add_nv(nv); } ret_val = new Value(Value::V_SEQ, nvs); - if (gov) ret_val->set_my_governor(gov->get_parent_type()); + if (gov) gov = gov->get_parent_type(); + if (gov) ret_val->set_my_governor(gov); break; } case INDEXED_TEMPLATE_LIST: { Values *ivs = new Values(true); @@ -1759,7 +1761,8 @@ namespace Ttcn { ivs->add_iv(iv); } ret_val = new Value(Value::V_SEQOF, ivs); - if (gov) ret_val->set_my_governor(gov->get_parent_type()); + if (gov) gov = gov->get_parent_type(); + if (gov) ret_val->set_my_governor(gov); break; } default: FATAL_ERROR("Template::get_Value()"); diff --git a/compiler2/ttcn3/compiler.c b/compiler2/ttcn3/compiler.c index 9f8675b..ce428ba 100644 --- a/compiler2/ttcn3/compiler.c +++ b/compiler2/ttcn3/compiler.c @@ -310,6 +310,10 @@ 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/union.c b/compiler2/union.c index 0393bcc..e469f4a 100644 --- a/compiler2/union.c +++ b/compiler2/union.c @@ -1306,7 +1306,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output) src = mputprintf(src, /* XERSTUFF XER_encode for union */ "int %s::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, " - "unsigned int p_flavor, int p_indent) const\n" + "unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const\n" "{\n" "%s" " if (%s==union_selection) {\n" @@ -1318,7 +1318,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output) " int encoded_length=(int)p_buf.get_len();\n" , name , (use_runtime_2 ? " if (err_descr) return XER_encode_negtest" - "(err_descr, p_td, p_buf, p_flavor, p_indent);\n" : "") + "(err_descr, p_td, p_buf, p_flavor, p_indent, 0);\n" : "") , unbound_value ); @@ -1380,7 +1380,7 @@ 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, " - "p_indent + (!p_indent || !omit_tag));\n" + "p_indent + (!p_indent || !omit_tag), 0);\n" " break;\n", selection_prefix, sdef->elements[i].name, sdef->elements[i].dispname, @@ -1403,11 +1403,11 @@ void defUnionClass(struct_def const *sdef, output_struct *output) def = mputstr(def, "int XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, " "const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, " - "unsigned int p_flavor, int p_indent) const;\n"); + "unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const;\n"); src = mputprintf(src, /* XERSTUFF XER_encode for union */ "int %s::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, " "const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, " - "unsigned int p_flavor, int p_indent) const\n" + "unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const\n" "{\n" " if (%s==union_selection) {\n" " TTCN_error(\"Attempt to XER-encode an unbound union value.\");\n" @@ -1486,15 +1486,15 @@ void defUnionClass(struct_def const *sdef, output_struct *output) "(\"internal error: erroneous value typedescriptor missing\");\n" " else err_vals->value->errval->XER_encode(" "*err_vals->value->type_descr->xer, p_buf, flavor_0, " - "p_indent + (!p_indent || !omit_tag));\n" + "p_indent + (!p_indent || !omit_tag), 0);\n" " }\n" " }\n" " } else {\n" " ec_1.set_msg(\"%s': \");\n" " if (emb_descr) field_%s->XER_encode_negtest(emb_descr, " - "%s_xer_, p_buf, flavor_0, p_indent + (!p_indent || !omit_tag));\n" + "%s_xer_, p_buf, flavor_0, p_indent + (!p_indent || !omit_tag), 0);\n" " else field_%s->XER_encode(%s_xer_, p_buf, flavor_0, " - "p_indent + (!p_indent || !omit_tag));\n" + "p_indent + (!p_indent || !omit_tag), 0);\n" " }\n" " break;\n", selection_prefix, sdef->elements[i].name, /* case label */ @@ -1533,7 +1533,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output) #endif src = mputprintf(src, /* XERSTUFF decoder functions for union */ "int %s::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader," - " unsigned int p_flavor)\n" + " unsigned int p_flavor, embed_values_dec_struct_t*)\n" "{\n" " int e_xer = is_exer(p_flavor);\n" " int type = 0;\n" /* None */ @@ -1643,7 +1643,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output) " ec_2.set_msg(\"%s': \");\n" " if (%s==union_selection) {\n" " matched = %d;\n" - " %s().XER_decode(%s_xer_, p_reader, flavor_1);\n" + " %s().XER_decode(%s_xer_, p_reader, flavor_1, 0);\n" " }\n" " if (field_%s->is_bound()) break; else clean_up();\n" " }\n", @@ -1696,7 +1696,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output) src = mputprintf(src, " %sif (%s::can_start(elem_name, ns_uri, %s_xer_, flavor_1) || (%s_xer_.xer_bits & ANY_ELEMENT)) {\n" " ec_2.set_msg(\"%s': \");\n" - " %s%s().XER_decode(%s_xer_, p_reader, flavor_1);\n" + " %s%s().XER_decode(%s_xer_, p_reader, flavor_1, 0);\n" " if (!%s%s().is_bound()) {\n" " TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, \"Failed to decode field.\");\n" " }\n" @@ -1713,7 +1713,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output) src = mputprintf(src, " %sif ((e_xer && (type==XML_READER_TYPE_END_ELEMENT || !own_tag)) || %s::can_start(elem_name, ns_uri, %s_xer_, flavor_1) || (%s_xer_.xer_bits & ANY_ELEMENT)) {\n" "empty_xml: ec_2.set_msg(\"%s': \");\n" - " %s%s().XER_decode(%s_xer_, p_reader, flavor_1);\n" + " %s%s().XER_decode(%s_xer_, p_reader, flavor_1, 0);\n" " if (!%s%s().is_bound()) {\n" " TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, \"Failed to decode field.\");\n" " }\n" diff --git a/compiler2/xpather.cc b/compiler2/xpather.cc index 14c15a6..d816584 100644 --- a/compiler2/xpather.cc +++ b/compiler2/xpather.cc @@ -29,7 +29,10 @@ // Do _NOT_ #include "string.hh", it drags in ustring.o, common/Quadruple.o, // Int.o, ttcn3/PatternString.o, and then the entire AST :( #include "map.hh" +#include "ProjectGenHelper.hh" #include "../common/path.h" +#include "ttcn3/ttcn3_preparser.h" +#include "asn1/asn1_preparser.h" // in makefile.c void ERROR (const char *fmt, ...); @@ -52,6 +55,8 @@ void fatal_error(const char * filename, int lineno, const char * fmt, ...) abort(); } +ProjectGenHelper& projGenHelper = ProjectGenHelper::Instance(); + /// Run an XPath query and return an xmlXPathObjectPtr, which must be freed xmlXPathObjectPtr run_xpath(xmlXPathContextPtr xpathCtx, const char *xpathExpr) { @@ -218,12 +223,299 @@ void xsdbool2boolean(const XPathContext& xpathCtx, const char *actcfg, } } +extern "C" string_list* getExternalLibs(const char* projName) +{ + if (!projGenHelper.getZflag()) return NULL; + ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName); + if (!proj) return NULL; + + std::vector externalLibs; + projGenHelper.getExternalLibs(externalLibs); + + if (0 == externalLibs.size()) return NULL; + + struct string_list* head = (struct string_list*)Malloc(sizeof(struct string_list)); + struct string_list* last_elem = head; + struct string_list* tail = head; + + for (size_t i = 0; i < externalLibs.size(); ++i) { + tail = last_elem; + last_elem->str = mcopystr(externalLibs[i]); + last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list)); + last_elem = last_elem->next; + } + Free(last_elem); + tail->next = NULL; + return head; +} + +extern "C" string_list* getExternalLibPathes(const char* projName) +{ + if (!projGenHelper.getZflag()) return NULL; + ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName); + if (!proj) return NULL; + + std::vector externalLibs; + projGenHelper.getExternalLibSearchPathes(externalLibs); + + if (0 == externalLibs.size()) return NULL; + + struct string_list* head = (struct string_list*)Malloc(sizeof(struct string_list)); + struct string_list* last_elem = head; + struct string_list* tail = head; + + for (size_t i = 0; i < externalLibs.size(); ++i) { + tail = last_elem; + last_elem->str = mcopystr(externalLibs[i]); + last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list)); + last_elem = last_elem->next; + } + Free(last_elem); + tail->next = NULL; + return head; +} + +extern "C" string_list* getRefWorkingDirs(const char* projName) +{ + if (!projGenHelper.getZflag()) return NULL; + ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName); + if (!proj) FATAL_ERROR("Project \"%s\" was not found in the project list", projName); + + struct string_list* head = (struct string_list*)Malloc(sizeof(struct string_list)); + struct string_list* last_elem = head; + struct string_list* tail = head; + last_elem->str = NULL; + last_elem->next = NULL; + for (size_t i = 0; i < proj->numOfRefProjWorkingDirs(); ++i) { + tail = last_elem; + last_elem->str = mcopystr(proj->getRefProjWorkingDir(i).c_str()); + last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list)); + last_elem = last_elem->next; + } + Free(last_elem); + tail->next = NULL; + return head; +} + +extern "C" string2_list* getLinkerLibs(const char* projName) +{ + + if (!projGenHelper.getZflag()) return NULL; + if (1 == projGenHelper.numOfProjects() || 0 == projGenHelper.numOfLibs()){ + return NULL; //no library + } + ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName); + if (!projLib) FATAL_ERROR("Project \"%s\" was not found in the project list", projName); + + struct string2_list* head = (struct string2_list*)Malloc(sizeof(struct string2_list)); + struct string2_list* last_elem = head; + struct string2_list* tail = head; + last_elem->next = NULL; + last_elem->str1 = NULL; + last_elem->str2 = NULL; + for (std::map::const_iterator it = projGenHelper.getHead(); + it != projGenHelper.getEnd(); ++it) { + if ((it->second).isLibrary()) { + if (!(it->second).getLinkingStrategy() && + !projLib->hasLinkerLibTo((it->second).getProjectName())) { // static linked library + continue; + } + std::string relPath = projLib->setRelativePathTo((it->second).getProjectAbsWorkingDir()); + if (relPath == std::string(".")) { + continue; // the relpath shows to itself + } + tail = last_elem; + last_elem->str1 = mcopystr(relPath.c_str()); + last_elem->str2 = mcopystr((it->second).getTargetExecName().c_str()); + last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list)); + last_elem = last_elem->next; + } + } + tail->next = NULL; + Free(last_elem); + + if (head->str1 && head->str2) + return head; + else + return NULL; +} + +extern "C" const char* getLibFromProject(const char* projName) +{ + if (!projGenHelper.getZflag()) return NULL; + ProjectDescriptor* lib = projGenHelper.getTargetOfProject(projName); + if (lib) return lib->getTargetExecName().c_str(); + return NULL; +} + +extern "C" void erase_libs() { + projGenHelper.cleanUp(); +} + +extern "C" void print_libs() { + projGenHelper.print(); +} + + +extern "C" boolean hasSubProject(const char* projName) { + if (!projGenHelper.getZflag()) return FALSE; + if (projGenHelper.getHflag()) + return static_cast(projGenHelper.hasReferencedProject()); + else if(std::string(projName) == projGenHelper.getToplevelProjectName()) + return static_cast(projGenHelper.hasReferencedProject()); + else + return FALSE; +} + +extern "C" boolean hasExternalLibrary(const char* libName, const char* projName) { + if (!projGenHelper.getZflag()) return FALSE; + ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName); + if (projLib && projLib->hasLinkerLib(libName)) + return TRUE; + else + return FALSE; +} + +extern "C" boolean isTopLevelExecutable(const char* projName) { + if (!projGenHelper.getZflag()) return false; + ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName); + if (projGenHelper.getToplevelProjectName() != std::string(projName)) return FALSE; + if (proj && proj->isLibrary()) + return FALSE; + else + return TRUE; +} + +extern "C" boolean isDynamicLibrary(const char* key) { + if (!projGenHelper.getZflag()) return false; + ProjectDescriptor* proj = projGenHelper.getProjectDescriptor(key); + if (proj) return proj->getLinkingStrategy(); + FATAL_ERROR("Library \"%s\" was not found", key); + return false; +} + +extern "C" const char* getTPDFileName(const char* projName) { + if (!projGenHelper.getZflag()) return NULL; + ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName); + if (proj) return proj->getTPDFileName().c_str(); + FATAL_ERROR("TPD file name to project \"%s\" was not found", projName); +} + +extern "C" const char* getPathToRootDir(const char* projName) { + if (!projGenHelper.getZflag()) return NULL; + ProjectDescriptor* proj = projGenHelper.getTargetOfProject(projName); + const char* rootDir = projGenHelper.getRootDirOS(projName).c_str(); + if (proj && rootDir) { + return rootDir; + } + FATAL_ERROR("Project \"%s\": no relative path was found to top directory at OS level.", projName); +} + +extern "C" const char* findLibraryPath(const char* libraryName, const char* projName) +{ + if (!projGenHelper.getZflag()) return NULL; + ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName); + if (!projLib) FATAL_ERROR("Project \"%s\" was not found in the project list", projName); + ProjectDescriptor* libLib = projGenHelper.getProjectDescriptor(libraryName); + if (!libLib) return NULL; + std::string str = projLib->setRelativePathTo(libLib->getProjectAbsWorkingDir()); + size_t refIndex = projLib->getLibSearchPathIndex(libLib->getProjectName()); + if (refIndex > projLib->numOfLibSearchPaths()) return NULL; + projLib->setLibSearchPath(refIndex, str); + return projLib->getLibSearchPath(libLib->getProjectName()); +} + +extern "C" const char* findLibraryName(const char* libraryName, const char* projName) +{ + if (!projGenHelper.getZflag()) return NULL; + ProjectDescriptor* projLib = projGenHelper.getTargetOfProject(projName); + if (!projLib) FATAL_ERROR("Project \"%s\" was not found in the project list", projName); + ProjectDescriptor* libLib = projGenHelper.getProjectDescriptor(libraryName); + if (!libLib) return NULL; + for (size_t i = 0; i < projLib->numOfReferencedProjects(); ++i) { + const std:: string refProjName = projLib->getReferencedProject(i); + ProjectDescriptor* refLib = projGenHelper.getTargetOfProject(refProjName.c_str()); + if (refLib->getTargetExecName() == std::string(libraryName)) + return libraryName; + } + return NULL; +} + +extern "C" boolean isTtcn3ModuleInLibrary(const char* moduleName) +{ + if (!projGenHelper.getZflag()) return FALSE; + return (boolean)projGenHelper.isTtcn3ModuleInLibrary(moduleName); +} + +extern "C" boolean isAsn1ModuleInLibrary(const char* moduleName) +{ + if (!projGenHelper.getZflag()) return FALSE; + return (boolean)projGenHelper.isAsn1ModuleInLibrary(moduleName); +} + +extern "C" boolean isSourceFileInLibrary(const char* fileName) +{ + if (!projGenHelper.getZflag()) return FALSE; + return (boolean)projGenHelper.isSourceFileInLibrary(fileName); +} + +extern "C" boolean isHeaderFileInLibrary(const char* fileName) +{ + if (!projGenHelper.getZflag()) return FALSE; + return (boolean)projGenHelper.isHeaderFileInLibrary(fileName); +} + +extern "C" boolean isTtcnPPFileInLibrary(const char* fileName) +{ + if (!projGenHelper.getZflag()) return FALSE; + return (boolean)projGenHelper.isTtcnPPFileInLibrary(fileName); +} + + +extern "C" boolean buildObjects(const char* projName, boolean add_referenced) +{ + if (!projGenHelper.getZflag()) return FALSE; + if (projGenHelper.getHflag()) return FALSE; + if (add_referenced) return FALSE; + ProjectDescriptor* desc =projGenHelper.getTargetOfProject(projName); + if (desc && desc->isLibrary()) return FALSE; + return TRUE; +} + +void append_to_library_list (const char* prjName, + const XPathContext& xpathCtx, + const char *actcfg) +{ + if (!projGenHelper.getZflag()) return; + + char *exeXpath = mprintf( + "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']" + "/ProjectProperties/MakefileSettings/targetExecutable/text()", + actcfg); + XPathObject exeObj(run_xpath(xpathCtx, exeXpath)); + Free(exeXpath); + std::string lib_name; + if (exeObj->nodesetval && exeObj->nodesetval->nodeNr > 0) { + const char* target_executable = (const char*)exeObj->nodesetval->nodeTab[0]->content; + autostring target_exe_dir(get_dir_from_path(target_executable)); + autostring target_exe_file(get_file_from_path(target_executable)); + lib_name = target_exe_file; + ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(prjName); + if (projDesc) { + projDesc->setTargetExecName(lib_name.c_str()); + } + } +} + // data structures and functions to manage excluded folders/files -map excluded_files; +map excluded_files; -boolean is_excluded_file(const cstring& path) { - return excluded_files.has_key(path); +boolean is_excluded_file(const cstring& path, const char* project) { + if (!excluded_files.has_key(path)) return false; + const char* proj = excluded_files[path]; + if (0 == strcmp(project, proj)) return true; + return false; } vector excluded_folders; @@ -305,58 +597,80 @@ static void clear_seen_tpd_files(map& seen_tpd_files) { seen_tpd_files.clear(); } +const char* get_act_config(struct string2_list* cfg, const char* project_name) { + while (cfg && cfg->str1 && project_name) { + if (!strcmp(cfg->str1, project_name)) return cfg->str2; + cfg = cfg->next; + } + return NULL; +} + static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcfg, const char *file_list_path, int *p_argc, char ***p_argv, - int *p_optind, char **p_ets_name, + int *p_optind, char **p_ets_name, char **p_project_name, boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess, boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag, boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level, const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs, const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes, - struct string_list* ttcn3_prep_defines, struct string_list* prep_includes, struct string_list* prep_defines, - boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag, char** cxxcompiler, - char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, boolean* p_djflag, - boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag, + struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes, + struct string_list* prep_defines, struct string_list* prep_undefines, boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag, + char** cxxcompiler, char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, + boolean* p_djflag, boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag, boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, struct string_list* solspeclibs, struct string_list* sol8speclibs, struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep, struct string_list* linkerlibs, struct string_list* additionalObjects, struct string_list* linkerlibsearchp, boolean Vflag, boolean Dflag, - char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, struct string2_list* run_command_list, - map& seen_tpd_files); + boolean *p_Zflag, boolean *p_Hflag, char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, + struct string2_list* run_command_list, map& seen_tpd_files, struct string2_list* required_configs); extern "C" tpd_result process_tpd(const char *p_tpd_name, const char *actcfg, const char *file_list_path, int *p_argc, char ***p_argv, - int *p_optind, char **p_ets_name, + int *p_optind, char **p_ets_name, char **p_project_name, boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess, boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag, boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level, const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs, const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes, - struct string_list* ttcn3_prep_defines, struct string_list* prep_includes, struct string_list* prep_defines, - boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag, char** cxxcompiler, - char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, boolean* p_djflag, - boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag, + struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes, + struct string_list* prep_defines, struct string_list* prep_undefines, boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag, + char** cxxcompiler, char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, + boolean* p_djflag, boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag, boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, struct string_list* solspeclibs, struct string_list* sol8speclibs, struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep, - string_list* linkerlibs, string_list* additionalObjects, string_list* linkerlibsearchp, boolean Vflag, boolean Dflag, - char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, struct string2_list* run_command_list) { + string_list* linkerlibs, string_list* additionalObjects, string_list* linkerlibsearchp, boolean Vflag, boolean Dflag, boolean *p_Zflag, + boolean *p_Hflag, char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, + struct string2_list* run_command_list, struct string2_list* required_configs) { map seen_tpd_files; + projGenHelper.setZflag(*p_Zflag); + projGenHelper.setWflag(prefix_workdir); + projGenHelper.setHflag(*p_Hflag); tpd_result success = process_tpd_internal(p_tpd_name, - actcfg, file_list_path, p_argc, p_argv, p_optind, p_ets_name, + actcfg, file_list_path, p_argc, p_argv, p_optind, p_ets_name, p_project_name, p_gflag, p_sflag, p_cflag, p_aflag, preprocess, p_Rflag, p_lflag, p_mflag, p_Pflag, p_Lflag, recursive, force_overwrite, gen_only_top_level, output_file, abs_work_dir_p, sub_project_dirs, program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes, - ttcn3_prep_defines, prep_includes, prep_defines, - p_csflag, p_quflag, p_dsflag, cxxcompiler, + ttcn3_prep_defines, ttcn3_prep_undefines, prep_includes, prep_defines, + prep_undefines, p_csflag, p_quflag, p_dsflag, cxxcompiler, optlevel, optflags, p_dbflag, p_drflag, p_dtflag, p_dxflag, p_djflag, p_fxflag, p_doflag, p_gfflag, p_lnflag, p_isflag, p_asflag, p_swflag, p_Yflag, solspeclibs, sol8speclibs, linuxspeclibs, freebsdspeclibs, win32speclibs, ttcn3prep, - linkerlibs, additionalObjects, linkerlibsearchp, Vflag, Dflag, - generatorCommandOutput, target_placement_list, prefix_workdir, run_command_list, seen_tpd_files); + linkerlibs, additionalObjects, linkerlibsearchp, Vflag, Dflag, p_Zflag, + p_Hflag, generatorCommandOutput, target_placement_list, prefix_workdir, + run_command_list, seen_tpd_files, required_configs); + + if (TPD_FAILED == success) exit(EXIT_FAILURE); + + if (false == projGenHelper.sanityCheck()) { + fprintf (stderr, "makefilegen exits\n"); + exit(EXIT_FAILURE); + } + + projGenHelper.generateRefProjectWorkingDirsTo(*p_project_name); for (size_t i = 0, num = seen_tpd_files.size(); i < num; ++i) { const cstring& key = seen_tpd_files.get_nth_key(i); @@ -381,22 +695,23 @@ extern "C" tpd_result process_tpd(const char *p_tpd_name, const char *actcfg, // it must nevertheless make a copy on the heap via mcopystr(). static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcfg, const char *file_list_path, int *p_argc, char ***p_argv, - int *p_optind, char **p_ets_name, + int *p_optind, char **p_ets_name, char **p_project_name, boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess, boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag, boolean *p_Lflag, boolean recursive, boolean force_overwrite, boolean gen_only_top_level, const char *output_file, char** abs_work_dir_p, struct string_list* sub_project_dirs, const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes, - struct string_list* ttcn3_prep_defines, struct string_list* prep_includes, struct string_list* prep_defines, - boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag, char** cxxcompiler, - char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, boolean* p_djflag, - boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag, + struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes, + struct string_list* prep_defines, struct string_list* prep_undefines, boolean *p_csflag, boolean *p_quflag, boolean* p_dsflag, + char** cxxcompiler, char** optlevel, char** optflags, boolean* p_dbflag, boolean* p_drflag, boolean* p_dtflag, boolean* p_dxflag, + boolean* p_djflag, boolean* p_fxflag, boolean* p_doflag, boolean* p_gfflag, boolean* p_lnflag, boolean* p_isflag, boolean* p_asflag, boolean* p_swflag, boolean* p_Yflag, struct string_list* solspeclibs, struct string_list* sol8speclibs, struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3prep, - string_list* linkerlibs, string_list* additionalObjects, string_list* linkerlibsearchp, boolean Vflag, boolean Dflag, - char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, struct string2_list* run_command_list, - map& seen_tpd_files) + string_list* linkerlibs, string_list* additionalObjects, string_list* linkerlibsearchp, boolean Vflag, boolean Dflag, boolean *p_Zflag, + boolean *p_Hflag, char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, + struct string2_list* run_command_list, map& seen_tpd_files, struct string2_list* required_configs) { + tpd_result result = TPD_SUCCESS; // read-only non-pointer aliases //char** const& local_argv = *p_argv; int const& local_argc = *p_argc; @@ -410,7 +725,10 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf autostring tpd_dir(get_dir_from_path(p_tpd_name)); autostring abs_tpd_dir(get_absolute_dir(tpd_dir, NULL)); - + if (NULL == (const char*)abs_tpd_dir) { + ERROR("absolut TPD directory could not be retreaved from %s", (const char*)tpd_dir); + return TPD_FAILED; + } autostring tpd_filename(get_file_from_path(p_tpd_name)); autostring abs_tpd_name(compose_path_name(abs_tpd_dir, tpd_filename)); @@ -552,8 +870,25 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf } // next FolderResource } - if (actcfg == NULL) + ///////////////////////////////////////////////////////////////////////////// { + char *projectNameXpath = mprintf("/TITAN_Project_File_Information/ProjectName/text()"); + XPathObject projectNameObj(run_xpath(xpathCtx, projectNameXpath)); + Free(projectNameXpath); + if (projectNameObj->nodesetval && projectNameObj->nodesetval->nodeNr > 0) { + *p_project_name = mcopystr((const char*)projectNameObj->nodesetval->nodeTab[0]->content); + projGenHelper.addTarget(*p_project_name); + projGenHelper.setToplevelProjectName(*p_project_name); + ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name); + if (projDesc) projDesc->setProjectAbsTpdDir((const char*)abs_tpd_dir); + } + } + ///////////////////////////////////////////////////////////////////////////// + + if (!actcfg) { + actcfg = get_act_config(required_configs,*p_project_name); + } + if (actcfg == NULL) { // Find out the active config XPathObject activeConfig(run_xpath(xpathCtx, "/TITAN_Project_File_Information/ActiveConfiguration/text()")); @@ -590,8 +925,6 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf return TPD_FAILED; } } - - ///////////////////////////////////////////////////////////////////////////// // working directory stuff autostring workdir; { @@ -623,6 +956,8 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf const char *real_workdir = folders[workdir]; // This is relative to the location of the tpd file excluded_folders.add(real_workdir); // excluded by convention + autostring proj_abs_workdir; + autostring abs_workdir; // If -D flag was specified then we ignore the workdir // in the TPD (the current dir is considered the work dir). @@ -643,7 +978,8 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf break; default: if (recursive || local_argc != 0) { // we only want to create workdir if necessary - printf("Working directory `%s' in project `%s' does not exist, trying to create it...\n", real_workdir, (const char*)abs_tpd_dir); + fprintf(stderr, "Working directory `%s' in project `%s' does not exist, trying to create it...\n", + real_workdir, (const char*)abs_tpd_dir); int rv = mkdir(real_workdir, 0755); if (rv) ERROR("Could not create working directory, mkdir() failed: %s", strerror(errno)); else printf("Working directory created\n"); @@ -660,8 +996,21 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf if (hasWorkDir) { //we created working directory, or its already been created (from a parent makefilegen process maybe) *abs_work_dir_p = get_absolute_dir(real_workdir, abs_tpd_dir); abs_workdir = (mcopystr(*abs_work_dir_p)); + proj_abs_workdir = mcopystr(*abs_work_dir_p); } } + + if (Dflag) { // the path to subproject working dir is needed to find the linkerlibsearchpath + proj_abs_workdir = compose_path_name(abs_tpd_dir, real_workdir); + } + + ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name); + if (projDesc) { + projDesc->setProjectAbsWorkingDir((const char*)proj_abs_workdir); + projDesc->setProjectWorkingDir(real_workdir); + projDesc->setTPDFileName(p_tpd_name); + } + ///////////////////////////////////////////////////////////////////////////// // Gather the excluded folders in the active config @@ -697,7 +1046,7 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf xmlNodePtr curnode = nodes->nodeTab[i]; cstring aa((const char*)curnode->content); - excluded_files.add(aa, 0); + excluded_files.add(aa, *p_project_name); } } @@ -742,13 +1091,45 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf } cstring cpath(path); - if (!is_excluded_file(cpath) && !is_excluded_folder(path)) { + if (!is_excluded_file(cpath, *p_project_name) && !is_excluded_folder(path)) { // relativeURI wins over rawURI char *ruri = uri ? mcopystr(uri) : cook(raw, path_vars); - if (files.has_key(cpath)) { ERROR("A FileResource %s must be unique!", (const char*)cpath); - } else { + } + else { + const char* file_path = ruri; + expstring_t rel_file_dir = get_dir_from_path(file_path); + expstring_t file_name = get_file_from_path(file_path); + expstring_t abs_dir_path = get_absolute_dir(rel_file_dir, abs_tpd_dir); + expstring_t abs_file_name = compose_path_name(abs_dir_path, file_name); + if (abs_file_name != NULL) { + if (get_path_status(abs_file_name) == PS_FILE) { + FILE *fp = fopen(abs_file_name, "r"); + if (fp != NULL) { + char* ttcn3_module_name; + if (is_ttcn3_module(abs_file_name, fp, &ttcn3_module_name)) { + projGenHelper.addTtcn3ModuleToProject(*p_project_name, ttcn3_module_name); + } + Free(ttcn3_module_name); + char* asn1_module_name; + if (is_asn1_module(abs_file_name, fp, &asn1_module_name)) { + projGenHelper.addAsn1ModuleToProject(*p_project_name, asn1_module_name); + } + Free(asn1_module_name); + if (projGenHelper.isCPPSourceFile(file_name)) { + projGenHelper.addUserSourceToProject(*p_project_name, file_name); + } + if (projGenHelper.isCPPHeaderFile(file_name)) { + projGenHelper.addUserHeaderToProject(*p_project_name, file_name); + } + if (projGenHelper.isTtcnPPFile(file_name)) { + projGenHelper.addTtcnPPToProject(*p_project_name, file_name); + } + } + fclose(fp); + } + } files.add(cpath, ruri); // relativeURI to the TPD location { // set the *preprocess value if .ttcnpp file was found const size_t ttcnpp_extension_len = 7; // ".ttcnpp" @@ -757,6 +1138,10 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf *preprocess = TRUE; } } + Free(rel_file_dir); + Free(file_name); + Free(abs_dir_path); + Free(abs_file_name); } } } // next FileResource @@ -765,6 +1150,7 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf // Check options xsdbool2boolean(xpathCtx, actcfg, "useAbsolutePath", p_aflag); xsdbool2boolean(xpathCtx, actcfg, "GNUMake", p_gflag); + if (*p_Zflag) *p_lflag = FALSE; xsdbool2boolean(xpathCtx, actcfg, "dynamicLinking", p_lflag); xsdbool2boolean(xpathCtx, actcfg, "functiontestRuntime", p_Rflag); xsdbool2boolean(xpathCtx, actcfg, "singleMode", p_sflag); @@ -785,6 +1171,9 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf xsdbool2boolean(xpathCtx, actcfg, "suppressWarnings", p_swflag); xsdbool2boolean(xpathCtx, actcfg, "outParamBoundness", p_Yflag); + projDesc = projGenHelper.getTargetOfProject(*p_project_name); + if (projDesc) projDesc->setLinkingStrategy(*p_lflag); + // Extract the "incremental dependencies" option { boolean incremental_deps = TRUE; @@ -811,7 +1200,7 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf // Extract the default target option // if it is not defined as a command line argument if (!(*p_Lflag)) { - char *defTargetXpath = mprintf( + expstring_t defTargetXpath = mprintf( "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']" "/ProjectProperties/MakefileSettings/defaultTarget/text()", actcfg); @@ -828,6 +1217,8 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf " The available targets are: 'executable', 'library'", content); } } + ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name); + if (projDesc) projDesc->setLibrary(*p_Lflag); } // Executable name (don't care unless top-level invocation) @@ -939,6 +1330,36 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf } } } + { + //TTCN3preprocessorUnDefines + char *ttcn3preUndefinesXpath = mprintf( + "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']" + "/ProjectProperties/MakefileSettings/TTCN3preprocessorUndefines/listItem/text()", + actcfg); + XPathObject ttcn3preUndefinesObj(run_xpath(xpathCtx, ttcn3preUndefinesXpath)); + Free(ttcn3preUndefinesXpath); + + xmlNodeSetPtr nodes = ttcn3preUndefinesObj->nodesetval; + + if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) { + const char* content = (const char*)ttcn3preUndefinesObj->nodesetval->nodeTab[i]->content; + + // add includes to the end of list + if (ttcn3_prep_undefines) { + // go to last element + struct string_list* last_elem = ttcn3_prep_undefines; + while (last_elem->next) last_elem = last_elem->next; + // add string to last element if empty or create new last element and add it to that + if (last_elem->str) { + last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list)); + last_elem = last_elem->next; + last_elem->next = NULL; + } + last_elem->str = mcopystr(content); + } + } + } + { //preprocessorIncludes char *preincludesXpath = mprintf( @@ -998,6 +1419,35 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf } } } + { + //preprocessorUnDefines + char *preUndefinesXpath = mprintf( + "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']" + "/ProjectProperties/MakefileSettings/preprocessorUndefines/listItem/text()", + actcfg); + XPathObject preUndefinesObj(run_xpath(xpathCtx, preUndefinesXpath)); + Free(preUndefinesXpath); + + xmlNodeSetPtr nodes = preUndefinesObj->nodesetval; + + if (nodes) for (int i = 0; i < nodes->nodeNr; ++i) { + const char* content = (const char*)preUndefinesObj->nodesetval->nodeTab[i]->content; + + // add includes to the end of list + if (prep_undefines) { + // go to last element + struct string_list* last_elem = prep_undefines; + while (last_elem->next) last_elem = last_elem->next; + // add string to last element if empty or create new last element and add it to that + if (last_elem->str) { + last_elem->next = (struct string_list*)Malloc(sizeof(struct string_list)); + last_elem = last_elem->next; + last_elem->next = NULL; + } + last_elem->str = mcopystr(content); + } + } + } { char *cxxCompilerXpath = mprintf( "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']" @@ -1229,6 +1679,16 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf } } { + //The project name needed the hierarchical projects + char* prjNameStr = 0; + char *prjNameStrXpath = mprintf("/TITAN_Project_File_Information/ProjectName/text()"); + XPathObject prjName(run_xpath(xpathCtx, prjNameStrXpath)); + if (prjName->nodesetval && prjName->nodesetval->nodeNr == 1) { + prjNameStr = (char*)prjName->nodesetval->nodeTab[0]->content; + } + Free(prjNameStrXpath); + append_to_library_list (prjNameStr, xpathCtx, actcfg); + //linkerLibraries char *linkerlibsXpath = mprintf( "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']" @@ -1255,6 +1715,9 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf } replacechar(&content); last_elem->str = content; + + ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name); + if (projDesc) projDesc->addToLinkerLibs(last_elem->str); } } } @@ -1285,6 +1748,9 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf } replacechar(&content); last_elem->str = content; + + ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name); + if (projDesc) projDesc->addToLibSearchPaths(last_elem->str); } } } @@ -1350,6 +1816,63 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf } } +// collect the required configurations + { + if (required_configs) { + char* cfgReqsXpath(mprintf( + "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']" + "/ProjectProperties/ConfigurationRequirements/configurationRequirement", + actcfg)); + XPathObject reqcfgObjects(run_xpath(xpathCtx, cfgReqsXpath)); + Free (cfgReqsXpath); + xmlNodeSetPtr configs = reqcfgObjects->nodesetval; + if (configs) for (int i = 0; i < configs->nodeNr; ++i) { + xmlNodePtr curNodePtr = configs->nodeTab[i]->children; + const char* projectName = NULL; + const char* reqConfig = NULL; + while(curNodePtr) { + if (!strcmp((const char*)curNodePtr->name, "projectName")) { + projectName = (const char*)curNodePtr->children->content; + } + if (!strcmp((const char*)curNodePtr->name, "rerquiredConfiguration") || // backward compatibility + !strcmp((const char*)curNodePtr->name, "requiredConfiguration")) { + reqConfig = (const char*)curNodePtr->children->content; + } + curNodePtr = curNodePtr->next; + } + struct string2_list* last_elem = required_configs; + bool duplicate = false; + while (last_elem->next) { + if (!strcmp(last_elem->str1, projectName) && !strcmp(last_elem->str2, reqConfig)) { + duplicate = true; + } + else if (!strcmp(last_elem->str1, projectName) && strcmp(last_elem->str2, reqConfig)) { + ERROR("Required configuration is inconsistent : Project '%s' cannot have 2 " + "different configuration '%s' '%s'", + last_elem->str1, last_elem->str2, reqConfig); + result = TPD_FAILED; + } + last_elem = last_elem->next; + } + // add string to last element if empty or create new last element and add it to that + if (last_elem->str1 && !duplicate) { + if (strcmp(last_elem->str1, projectName) || strcmp(last_elem->str2, reqConfig)) { + last_elem->next = (struct string2_list*)Malloc(sizeof(struct string2_list)); + last_elem = last_elem->next; + last_elem->next = NULL; + } + else { + duplicate = true; + } + } + if (!duplicate) { + last_elem->str1 = mcopystr(projectName); + last_elem->str2 = mcopystr(reqConfig); + } + } + } + } + // Referenced projects { XPathObject subprojects(run_xpath(xpathCtx, @@ -1374,28 +1897,17 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf if (name && projectLocationURI) { // collected both // see if there is a specified configuration for the project - const char *my_actcfg = NULL; - autostring req_xpath(mprintf( - "/TITAN_Project_File_Information/Configurations/Configuration[@name='%s']" - "/ProjectProperties/ConfigurationRequirements/configurationRequirement" - "/projectName[text()='%s']" - // Up to this point, we selected the projectName node which contains - // the name of the subproject. But we want its sibling. - // So we go up one and down the other path. - "/parent::*/rerquiredConfiguration/text()", - //Yes, it's rerquiredConfiguration; the Designer misspells it :( - actcfg, name)); - XPathObject reqcfgObj(run_xpath(xpathCtx, req_xpath)); - if (reqcfgObj->nodesetval && reqcfgObj->nodesetval->nodeNr == 1) { - my_actcfg = (const char*)reqcfgObj->nodesetval->nodeTab[0]->content; - } + ProjectDescriptor* projDesc = projGenHelper.getTargetOfProject(*p_project_name); + if (projDesc) projDesc->addToReferencedProjects(name); + + const char *my_actcfg = NULL; int my_argc = 0; char *my_args[] = { NULL }; char **my_argv = my_args + 0; int my_optind = 0; boolean my_gflag = *p_gflag, my_aflag = *p_aflag, my_cflag = *p_cflag, // pass down - my_Rflag = *p_Rflag, my_Pflag = *p_Pflag, + my_Rflag = *p_Rflag, my_Pflag = *p_Pflag, my_Zflag = *p_Zflag, my_Hflag = *p_Hflag, my_sflag = 0, my_Lflag = 0, my_lflag = 0, my_mflag = 0, my_csflag = 0, my_quflag = 0, my_dsflag = 0, my_dbflag = 0, my_drflag = 0, my_dtflag = 0, my_dxflag = 0, my_djflag = 0, my_fxflag = 0, my_doflag = 0, @@ -1403,24 +1915,28 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf my_swflag = 0, my_Yflag = 0; char *my_ets = NULL; - + char *my_proj_name = NULL; autostring abs_projectLocationURI( compose_path_name(abs_tpd_dir, projectLocationURI)); char* sub_proj_abs_work_dir = NULL; + tpd_result success = process_tpd_internal((const char*)abs_projectLocationURI, - my_actcfg, file_list_path, &my_argc, &my_argv, &my_optind, &my_ets, + my_actcfg, file_list_path, &my_argc, &my_argv, &my_optind, &my_ets, &my_proj_name, &my_gflag, &my_sflag, &my_cflag, &my_aflag, preprocess, &my_Rflag, &my_lflag, &my_mflag, &my_Pflag, &my_Lflag, recursive, force_overwrite, gen_only_top_level, NULL, &sub_proj_abs_work_dir, - sub_project_dirs, program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes, ttcn3_prep_defines, prep_includes, prep_defines, &my_csflag, + sub_project_dirs, program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes, ttcn3_prep_defines, ttcn3_prep_undefines, + prep_includes, prep_defines, prep_undefines, &my_csflag, &my_quflag, &my_dsflag, cxxcompiler, optlevel, optflags, &my_dbflag, &my_drflag, &my_dtflag, &my_dxflag, &my_djflag, &my_fxflag, &my_doflag, &my_gfflag, &my_lnflag, &my_isflag, &my_asflag, &my_swflag, &my_Yflag, solspeclibs, sol8speclibs, linuxspeclibs, freebsdspeclibs, win32speclibs, - ttcn3prep, linkerlibs, additionalObjects, linkerlibsearchp, Vflag, FALSE, NULL, NULL, prefix_workdir, run_command_list, seen_tpd_files); + ttcn3prep, linkerlibs, additionalObjects, linkerlibsearchp, Vflag, FALSE, &my_Zflag, + &my_Hflag, NULL, NULL, prefix_workdir, run_command_list, seen_tpd_files, required_configs); + autostring sub_proj_abs_work_dir_as(sub_proj_abs_work_dir); // ?! if (success == TPD_SUCCESS) { - + my_actcfg = get_act_config(required_configs, my_proj_name); if (recursive) { // call ttcn3_makefilegen on referenced project's tpd file // -r is not needed any more because top level process traverses all projects recursively expstring_t command = mprintf("%s -cVD", program_name); @@ -1432,6 +1948,8 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf if (*p_Rflag) command = mputc(command, 'R'); if (*p_lflag) command = mputc(command, 'l'); if (*p_mflag) command = mputc(command, 'm'); + if (*p_Zflag) command = mputc(command, 'Z'); + if (*p_Hflag) command = mputc(command, 'H'); command = mputstr(command, " -t "); command = mputstr(command, (const char*)abs_projectLocationURI); if (my_actcfg) { @@ -1491,6 +2009,7 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf Free(my_argv); // free the array; we keep the pointers Free(my_ets); + Free(my_proj_name); } else if (success == TPD_FAILED) { ERROR("Failed to process %s", (const char*)abs_projectLocationURI); @@ -1650,5 +2169,5 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, const char *actcf xmlCleanupParser(); // ifdef debug xmlMemoryDump(); - return TPD_SUCCESS; + return result; } diff --git a/compiler2/xpather.h b/compiler2/xpather.h index fc5b9fc..935e225 100644 --- a/compiler2/xpather.h +++ b/compiler2/xpather.h @@ -27,6 +27,112 @@ char* str2; struct string2_list* next; }; +#ifdef __cplusplus +extern "C" +#endif +boolean isTopLevelExecutable(const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +boolean isDynamicLibrary(const char* key); + +#ifdef __cplusplus +extern "C" +#endif +const char* findLibraryPath(const char* libraryName, const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +const char* findLibraryName(const char* libraryName, const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +void erase_libs(); + +#ifdef __cplusplus +extern "C" +#endif +const char* getLibFromProject(const char* projName); + +#ifdef __cplusplus + extern "C" +#endif +struct string_list* getExternalLibs(const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +struct string_list* getExternalLibPathes(const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +struct string2_list* getLinkerLibs(const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +struct string_list* getRefWorkingDirs(const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +boolean hasExternalLibrary(const char* libName, const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +boolean hasSubProject(const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +void print_libs(); + +#ifdef __cplusplus +extern "C" +#endif +boolean isTtcn3ModuleInLibrary(const char* moduleName); + +#ifdef __cplusplus +extern "C" +#endif +const char* getTPDFileName(const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +const char* getPathToRootDir(const char* projName); + +#ifdef __cplusplus +extern "C" +#endif +boolean isAsn1ModuleInLibrary(const char* moduleName); + +#ifdef __cplusplus +extern "C" +#endif +boolean isSourceFileInLibrary(const char* fileName); + +#ifdef __cplusplus +extern "C" +#endif +boolean isHeaderFileInLibrary(const char* fileName); + +#ifdef __cplusplus +extern "C" +#endif +boolean isTtcnPPFileInLibrary(const char* fileName); + +#ifdef __cplusplus +extern "C" +#endif +boolean buildObjects(const char* projName, boolean add_referenced); + + /** * * @param p_tpd_name filename @@ -102,7 +208,7 @@ enum tpd_result process_tpd(const char *p_tpd_name, const char *actcfg, const char *file_list_path, int *argc, char ***argv, - int *optind, char **ets_name, + int *optind, char **ets_name, char **project_name, boolean *gnu_make, boolean *single_mode, boolean *central_storage, boolean *absolute_paths, boolean *preprocess, boolean *use_runtime_2, @@ -110,14 +216,15 @@ tpd_result process_tpd(const char *p_tpd_name, const char *actcfg, boolean *library, boolean recursive, boolean force_overwrite, boolean gen_only_top_level, const char *output_file, char** abs_work_dir, struct string_list* sub_project_dirs, const char* program_name, FILE* prj_graph_fp, struct string2_list* create_symlink_list, struct string_list* ttcn3_prep_includes, - struct string_list* ttcn3_prep_defines, struct string_list* prep_includes, struct string_list* prep_defines, - boolean *codesplit, boolean *quietly, boolean *disablesubtypecheck, char** cxxcompiler, - char** optlevel, char** optflags, boolean *disableber, boolean *disableraw, boolean *disabletext, boolean *disablexer, + struct string_list* ttcn3_prep_defines, struct string_list* ttcn3_prep_undefines, struct string_list* prep_includes, + struct string_list* prep_defines, struct string_list* prep_undefines, boolean *codesplit, boolean *quietly, boolean *disablesubtypecheck, + char** cxxcompiler, char** optlevel, char** optflags, boolean *disableber, boolean *disableraw, boolean *disabletext, boolean *disablexer, boolean *disablejson, boolean *forcexerinasn, boolean *defaultasomit, boolean *gccmessageformat, boolean *linenumber, boolean *includesourceinfo, boolean *addsourcelineinfo, boolean *suppresswarnings, boolean *outparamboundness, struct string_list* solspeclibs, struct string_list* sol8speclibs, struct string_list* linuxspeclibs, struct string_list* freebsdspeclibs, struct string_list* win32speclibs, char** ttcn3preprocessor, struct string_list* linkerlibs, struct string_list* additionalObjects, struct string_list* linkerlibsearchpath, boolean Vflag, boolean Dflag, - char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, struct string2_list* run_command_list); + boolean *Zflag, boolean *Hflag, char** generatorCommandOutput, struct string2_list* target_placement_list, boolean prefix_workdir, struct string2_list* run_command_list, + struct string2_list* required_configs); #endif /* XPATHER_H_ */ diff --git a/core/ASN_Any.cc b/core/ASN_Any.cc index daf4620..129081b 100644 --- a/core/ASN_Any.cc +++ b/core/ASN_Any.cc @@ -25,6 +25,15 @@ void ASN_ANY::encode(const TTCN_Typedescriptor_t& p_td, tlv->put_in_buffer(p_buf); ASN_BER_TLV_t::destruct(tlv); break;} + case TTCN_EncDec::CT_JSON: { + TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); + if(!p_td.json) + TTCN_EncDec_ErrorContext::error_internal + ("No JSON descriptor available for type '%s'.", p_td.name); + JSON_Tokenizer tok(va_arg(pvar, int) != 0); + JSON_encode(p_td, tok); + p_buf.put_s(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer()); + break;} case TTCN_EncDec::CT_RAW: default: TTCN_error("Unknown coding method requested to encode type '%s'", @@ -48,6 +57,19 @@ void ASN_ANY::decode(const TTCN_Typedescriptor_t& p_td, BER_decode_TLV(p_td, tlv, L_form); if(tlv.isComplete) p_buf.increase_pos(tlv.get_len()); break;} + case TTCN_EncDec::CT_JSON: { + TTCN_EncDec_ErrorContext ec("While JSON-decoding type '%s': ", p_td.name); + if(!p_td.json) + TTCN_EncDec_ErrorContext::error_internal + ("No JSON descriptor available for type '%s'.", p_td.name); + JSON_Tokenizer tok((const char*)p_buf.get_data(), p_buf.get_len()); + if(JSON_decode(p_td, tok, false)<0) + ec.error(TTCN_EncDec::ET_INCOMPL_MSG, + "Can not decode type '%s', because invalid or incomplete" + " message was received" + , p_td.name); + p_buf.set_pos(tok.get_buf_pos()); + break;} case TTCN_EncDec::CT_RAW: default: TTCN_error("Unknown coding method requested to decode type '%s'", diff --git a/core/ASN_CharacterString.cc b/core/ASN_CharacterString.cc index c9c01f0..f4ae4a5 100644 --- a/core/ASN_CharacterString.cc +++ b/core/ASN_CharacterString.cc @@ -646,7 +646,7 @@ boolean CHARACTER_STRING_identification::BER_decode_TLV(const TTCN_Typedescripto // FIXME maybe: XER_encode and decode is virtually identical to EMBEDDED_PDV int CHARACTER_STRING_identification::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { int encoded_length=(int)p_buf.get_len(); @@ -655,22 +655,22 @@ int CHARACTER_STRING_identification::XER_encode(const XERdescriptor_t& p_td, flavor &= XER_MASK; switch (union_selection) { case ALT_syntaxes: - field_syntaxes->XER_encode(EMBEDDED_PDV_identification_sxs_xer_, p_buf, flavor, indent); + field_syntaxes->XER_encode(EMBEDDED_PDV_identification_sxs_xer_, p_buf, flavor, indent, 0); break; case ALT_syntax: - field_syntax->XER_encode(EMBEDDED_PDV_identification_sx_xer_, p_buf, flavor, indent); + field_syntax->XER_encode(EMBEDDED_PDV_identification_sx_xer_, p_buf, flavor, indent, 0); break; case ALT_presentation__context__id: - field_presentation__context__id->XER_encode(EMBEDDED_PDV_identification_pci_xer_, p_buf, flavor, indent); + field_presentation__context__id->XER_encode(EMBEDDED_PDV_identification_pci_xer_, p_buf, flavor, indent, 0); break; case ALT_context__negotiation: - field_context__negotiation->XER_encode(EMBEDDED_PDV_identification_cn_xer_, p_buf, flavor, indent); + field_context__negotiation->XER_encode(EMBEDDED_PDV_identification_cn_xer_, p_buf, flavor, indent, 0); break; case ALT_transfer__syntax: - field_transfer__syntax->XER_encode(EMBEDDED_PDV_identification_ts_xer_, p_buf, flavor, indent); + field_transfer__syntax->XER_encode(EMBEDDED_PDV_identification_ts_xer_, p_buf, flavor, indent, 0); break; case ALT_fixed: - field_fixed->XER_encode(EMBEDDED_PDV_identification_fix_xer_, p_buf, flavor, indent); + field_fixed->XER_encode(EMBEDDED_PDV_identification_fix_xer_, p_buf, flavor, indent, 0); break; default: TTCN_EncDec_ErrorContext::error_internal("Unknown selection."); @@ -683,7 +683,7 @@ int CHARACTER_STRING_identification::XER_encode(const XERdescriptor_t& p_td, } int CHARACTER_STRING_identification::XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor) + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); // we are supposed to be parked on our element @@ -704,27 +704,27 @@ int CHARACTER_STRING_identification::XER_decode(const XERdescriptor_t& p_td, size_t namelen = strlen(name); switch (namelen) { case 8: // syntaxes - syntaxes().XER_decode(EMBEDDED_PDV_identification_sxs_xer_, reader, flavor); + syntaxes().XER_decode(EMBEDDED_PDV_identification_sxs_xer_, reader, flavor, 0); break; case 6: // syntax - syntax().XER_decode(EMBEDDED_PDV_identification_sx_xer_, reader, flavor); + syntax().XER_decode(EMBEDDED_PDV_identification_sx_xer_, reader, flavor, 0); break; case 23: // presentation-context-id - presentation__context__id().XER_decode(EMBEDDED_PDV_identification_pci_xer_, reader, flavor); + presentation__context__id().XER_decode(EMBEDDED_PDV_identification_pci_xer_, reader, flavor, 0); break; case 19: // context-negotiation - context__negotiation().XER_decode(EMBEDDED_PDV_identification_cn_xer_, reader, flavor); + context__negotiation().XER_decode(EMBEDDED_PDV_identification_cn_xer_, reader, flavor, 0); break; case 15: // transfer-syntax - transfer__syntax().XER_decode(EMBEDDED_PDV_identification_ts_xer_, reader, flavor); + transfer__syntax().XER_decode(EMBEDDED_PDV_identification_ts_xer_, reader, flavor, 0); break; case 5: // fixed - fixed().XER_decode(EMBEDDED_PDV_identification_fix_xer_, reader, flavor); + fixed().XER_decode(EMBEDDED_PDV_identification_fix_xer_, reader, flavor, 0); break; default: @@ -1673,14 +1673,14 @@ boolean CHARACTER_STRING_identification_syntaxes::BER_decode_TLV(const TTCN_Type } int CHARACTER_STRING_identification_syntaxes::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { int encoded_length=(int)p_buf.get_len(); begin_xml(p_td, p_buf, flavor, indent++, false); - field_abstract.XER_encode(CHARACTER_STRING_identification_sxs_abs_xer_, p_buf, flavor, indent); - field_transfer.XER_encode(CHARACTER_STRING_identification_sxs_xfr_xer_, p_buf, flavor, indent); + field_abstract.XER_encode(CHARACTER_STRING_identification_sxs_abs_xer_, p_buf, flavor, indent, 0); + field_transfer.XER_encode(CHARACTER_STRING_identification_sxs_xfr_xer_, p_buf, flavor, indent, 0); end_xml(p_td, p_buf, flavor, --indent, false); @@ -1688,7 +1688,7 @@ int CHARACTER_STRING_identification_syntaxes::XER_encode(const XERdescriptor_t& } int CHARACTER_STRING_identification_syntaxes::XER_decode( - const XERdescriptor_t& /*p_td*/, XmlReaderWrap& reader, unsigned int flavor) + const XERdescriptor_t& /*p_td*/, XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { // we stand on , move ahead first for (int success = reader.Read(); success == 1; success = reader.Read()) { @@ -1698,8 +1698,8 @@ int CHARACTER_STRING_identification_syntaxes::XER_decode( break; } // FIXME this assumes the right element - field_abstract.XER_decode(EMBEDDED_PDV_identification_sxs_abs_xer_, reader, flavor); - field_transfer.XER_decode(EMBEDDED_PDV_identification_sxs_xfr_xer_, reader, flavor); + field_abstract.XER_decode(EMBEDDED_PDV_identification_sxs_abs_xer_, reader, flavor, 0); + field_transfer.XER_decode(EMBEDDED_PDV_identification_sxs_xfr_xer_, reader, flavor, 0); for (int success = 1; success == 1; success = reader.Read()) { int type = reader.NodeType(); @@ -2319,14 +2319,14 @@ boolean CHARACTER_STRING_identification_context__negotiation::BER_decode_TLV(con } int CHARACTER_STRING_identification_context__negotiation::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { int encoded_length=(int)p_buf.get_len(); begin_xml(p_td, p_buf, flavor, indent++, false); - field_presentation__context__id.XER_encode(CHARACTER_STRING_identification_pci_xer_, p_buf, flavor, indent); - field_transfer__syntax .XER_encode(CHARACTER_STRING_identification_ts_xer_ , p_buf, flavor, indent); + field_presentation__context__id.XER_encode(CHARACTER_STRING_identification_pci_xer_, p_buf, flavor, indent, 0); + field_transfer__syntax .XER_encode(CHARACTER_STRING_identification_ts_xer_ , p_buf, flavor, indent, 0); end_xml(p_td, p_buf, flavor, --indent, false); @@ -2334,7 +2334,7 @@ int CHARACTER_STRING_identification_context__negotiation::XER_encode(const XERde } int CHARACTER_STRING_identification_context__negotiation::XER_decode( - const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor) + const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int type = reader.NodeType(), depth = -1; @@ -2345,8 +2345,8 @@ int CHARACTER_STRING_identification_context__negotiation::XER_decode( depth = reader.Depth(); success = reader.Read(); } - field_presentation__context__id.XER_decode(EMBEDDED_PDV_identification_cn_pci_xer_, reader, flavor); - field_transfer__syntax .XER_decode(EMBEDDED_PDV_identification_cn_tsx_xer_, reader, flavor); + field_presentation__context__id.XER_decode(EMBEDDED_PDV_identification_cn_pci_xer_, reader, flavor, 0); + field_transfer__syntax .XER_decode(EMBEDDED_PDV_identification_cn_tsx_xer_, reader, flavor, 0); for (; success == 1; success = reader.Read()) { type = reader.NodeType(); if (XML_READER_TYPE_END_ELEMENT == type) { @@ -2972,7 +2972,7 @@ void CHARACTER_STRING::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_ case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer,p_buf, XER_coding, 0); + XER_encode(*p_td.xer,p_buf, XER_coding, 0, 0); p_buf.put_c('\n'); break;} case TTCN_EncDec::CT_JSON: { @@ -3019,7 +3019,7 @@ void CHARACTER_STRING::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_ if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -3085,7 +3085,8 @@ boolean CHARACTER_STRING::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, cons return TRUE; } -int CHARACTER_STRING::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned int flavor, int indent) const +int CHARACTER_STRING::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, + unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error @@ -3096,10 +3097,10 @@ int CHARACTER_STRING::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf flavor &= ~XER_RECOF; // ASN.1 character string doesn't care begin_xml(p_td, p_buf, flavor, indent++, false); - field_identification.XER_encode(CHARACTER_STRING_identification_xer_, p_buf, flavor, indent); + field_identification.XER_encode(CHARACTER_STRING_identification_xer_, p_buf, flavor, indent, 0); // data-value-descriptor is OPTIONAL and can never be present. // Its encoding is empty. - field_string__value .XER_encode(CHARACTER_STRING_data_value_xer_ , p_buf, flavor, indent); + field_string__value .XER_encode(CHARACTER_STRING_data_value_xer_ , p_buf, flavor, indent, 0); end_xml(p_td, p_buf, flavor, --indent, false); @@ -3107,7 +3108,7 @@ int CHARACTER_STRING::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf } int CHARACTER_STRING::XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor) + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int success = reader.Ok(), depth = -1, type; @@ -3120,13 +3121,13 @@ int CHARACTER_STRING::XER_decode(const XERdescriptor_t& p_td, break; } } - field_identification .XER_decode(CHARACTER_STRING_identification_xer_ , reader, flavor); - field_data__value__descriptor.XER_decode(CHARACTER_STRING_data_value_descriptor_xer_, reader, flavor); + field_identification .XER_decode(CHARACTER_STRING_identification_xer_ , reader, flavor, 0); + field_data__value__descriptor.XER_decode(CHARACTER_STRING_data_value_descriptor_xer_, reader, flavor, 0); if (field_data__value__descriptor.is_value()) { TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, "data-value-descriptor not allowed for EMBEDDED PDV"); } - field_string__value .XER_decode(CHARACTER_STRING_data_value_xer_ , reader, flavor); + field_string__value .XER_decode(CHARACTER_STRING_data_value_xer_ , reader, flavor, 0); for (success = reader.Read(); success == 1; success = reader.Read()) { type = reader.NodeType(); if (XML_READER_TYPE_END_ELEMENT == type) { diff --git a/core/ASN_CharacterString.hh b/core/ASN_CharacterString.hh index 5e0c24b..279bccc 100644 --- a/core/ASN_CharacterString.hh +++ b/core/ASN_CharacterString.hh @@ -86,9 +86,9 @@ public: ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor); + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*); private: boolean BER_decode_set_selection(const ASN_BER_TLV_t& p_tlv); public: @@ -208,9 +208,9 @@ public: ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor); + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*); }; class CHARACTER_STRING_identification_syntaxes_template : public Base_Template { @@ -315,9 +315,9 @@ public: ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor); + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*); }; class CHARACTER_STRING_identification_context__negotiation_template : public Base_Template { @@ -430,8 +430,8 @@ public: void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, TTCN_EncDec::coding_t p_coding, ...); ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); - int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int) const; - int XER_decode(const XERdescriptor_t&, XmlReaderWrap& reader, unsigned int); + 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*); }; class CHARACTER_STRING_template : public Base_Template { diff --git a/core/ASN_EmbeddedPDV.cc b/core/ASN_EmbeddedPDV.cc index 003b81f..7a05319 100644 --- a/core/ASN_EmbeddedPDV.cc +++ b/core/ASN_EmbeddedPDV.cc @@ -633,7 +633,7 @@ boolean EMBEDDED_PDV_identification::BER_decode_TLV(const TTCN_Typedescriptor_t& // FIXME maybe: XER_encode and decode is virtually identical to CHARACTER_STRING int EMBEDDED_PDV_identification::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { int indenting = !is_canonical(flavor); int exer = is_exer(flavor); @@ -646,22 +646,22 @@ int EMBEDDED_PDV_identification::XER_encode(const XERdescriptor_t& p_td, ++indent; switch (union_selection) { case ALT_syntaxes: - field_syntaxes->XER_encode(EMBEDDED_PDV_identification_sxs_xer_, p_buf, flavor, indent);; + field_syntaxes->XER_encode(EMBEDDED_PDV_identification_sxs_xer_, p_buf, flavor, indent, 0);; break; case ALT_syntax: - field_syntax->XER_encode(EMBEDDED_PDV_identification_sx_xer_, p_buf, flavor, indent);; + field_syntax->XER_encode(EMBEDDED_PDV_identification_sx_xer_, p_buf, flavor, indent, 0);; break; case ALT_presentation__context__id: - field_presentation__context__id->XER_encode(EMBEDDED_PDV_identification_pci_xer_, p_buf, flavor, indent);; + field_presentation__context__id->XER_encode(EMBEDDED_PDV_identification_pci_xer_, p_buf, flavor, indent, 0);; break; case ALT_context__negotiation: - field_context__negotiation->XER_encode(EMBEDDED_PDV_identification_cn_xer_, p_buf, flavor, indent);; + field_context__negotiation->XER_encode(EMBEDDED_PDV_identification_cn_xer_, p_buf, flavor, indent, 0);; break; case ALT_transfer__syntax: - field_transfer__syntax->XER_encode(EMBEDDED_PDV_identification_ts_xer_, p_buf, flavor, indent);; + field_transfer__syntax->XER_encode(EMBEDDED_PDV_identification_ts_xer_, p_buf, flavor, indent, 0);; break; case ALT_fixed: - field_fixed->XER_encode(EMBEDDED_PDV_identification_fix_xer_, p_buf, flavor, indent);; + field_fixed->XER_encode(EMBEDDED_PDV_identification_fix_xer_, p_buf, flavor, indent, 0);; break; default: TTCN_EncDec_ErrorContext::error_internal("Unknown selection."); @@ -677,7 +677,7 @@ int EMBEDDED_PDV_identification::XER_encode(const XERdescriptor_t& p_td, } int EMBEDDED_PDV_identification::XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor) + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); // we are supposed to be parked on our element @@ -697,27 +697,27 @@ int EMBEDDED_PDV_identification::XER_decode(const XERdescriptor_t& p_td, size_t namelen = strlen(name); switch (namelen) { case 8: // syntaxes - syntaxes().XER_decode(EMBEDDED_PDV_identification_sxs_xer_, reader, flavor); + syntaxes().XER_decode(EMBEDDED_PDV_identification_sxs_xer_, reader, flavor, 0); break; case 6: // syntax - syntax().XER_decode(EMBEDDED_PDV_identification_sx_xer_, reader, flavor); + syntax().XER_decode(EMBEDDED_PDV_identification_sx_xer_, reader, flavor, 0); break; case 23: // presentation-context-id - presentation__context__id().XER_decode(EMBEDDED_PDV_identification_pci_xer_, reader, flavor); + presentation__context__id().XER_decode(EMBEDDED_PDV_identification_pci_xer_, reader, flavor, 0); break; case 19: // context-negotiation - context__negotiation().XER_decode(EMBEDDED_PDV_identification_cn_xer_, reader, flavor); + context__negotiation().XER_decode(EMBEDDED_PDV_identification_cn_xer_, reader, flavor, 0); break; case 15: // transfer-syntax - transfer__syntax().XER_decode(EMBEDDED_PDV_identification_ts_xer_, reader, flavor); + transfer__syntax().XER_decode(EMBEDDED_PDV_identification_ts_xer_, reader, flavor, 0); break; case 5: // fixed - fixed().XER_decode(EMBEDDED_PDV_identification_fix_xer_, reader, flavor); + fixed().XER_decode(EMBEDDED_PDV_identification_fix_xer_, reader, flavor, 0); break; default: @@ -1667,7 +1667,7 @@ boolean EMBEDDED_PDV_identification_syntaxes::BER_decode_TLV(const TTCN_Typedesc } int EMBEDDED_PDV_identification_syntaxes::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { int indenting = !is_canonical(flavor); int exer = is_exer(flavor); @@ -1678,8 +1678,8 @@ int EMBEDDED_PDV_identification_syntaxes::XER_encode(const XERdescriptor_t& p_td p_buf.put_s((size_t)p_td.namelens[exer] - 1 + indenting, (const unsigned char*)p_td.names[exer]); ++indent; - field_abstract.XER_encode(EMBEDDED_PDV_identification_sxs_abs_xer_, p_buf, flavor, indent); - field_transfer.XER_encode(EMBEDDED_PDV_identification_sxs_xfr_xer_, p_buf, flavor, indent); + field_abstract.XER_encode(EMBEDDED_PDV_identification_sxs_abs_xer_, p_buf, flavor, indent, 0); + field_transfer.XER_encode(EMBEDDED_PDV_identification_sxs_xfr_xer_, p_buf, flavor, indent, 0); if (indenting) do_indent(p_buf, --indent); p_buf.put_c('<'); @@ -1690,7 +1690,7 @@ int EMBEDDED_PDV_identification_syntaxes::XER_encode(const XERdescriptor_t& p_td } int EMBEDDED_PDV_identification_syntaxes::XER_decode(const XERdescriptor_t& /*p_td*/, - XmlReaderWrap& reader, unsigned int flavor) + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { // we stand on , move ahead first int type; for (int success = reader.Read(); success == 1; success = reader.Read()) @@ -1701,8 +1701,8 @@ int EMBEDDED_PDV_identification_syntaxes::XER_decode(const XERdescriptor_t& /*p_ break; } // FIXME this assumes the right element - field_abstract.XER_decode(EMBEDDED_PDV_identification_sxs_abs_xer_, reader, flavor); - field_transfer.XER_decode(EMBEDDED_PDV_identification_sxs_xfr_xer_, reader, flavor); + field_abstract.XER_decode(EMBEDDED_PDV_identification_sxs_abs_xer_, reader, flavor, 0); + field_transfer.XER_decode(EMBEDDED_PDV_identification_sxs_xfr_xer_, reader, flavor, 0); for (int success = 1; success == 1; success = reader.Read()) { type = reader.NodeType(); @@ -2323,7 +2323,7 @@ boolean EMBEDDED_PDV_identification_context__negotiation::BER_decode_TLV(const T } int EMBEDDED_PDV_identification_context__negotiation::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { int indenting = !is_canonical(flavor); int exer = is_exer(flavor); @@ -2334,8 +2334,8 @@ int EMBEDDED_PDV_identification_context__negotiation::XER_encode(const XERdescri p_buf.put_s((size_t)p_td.namelens[exer] - 1 + indenting, (const unsigned char*)p_td.names[exer]); ++indent; - field_presentation__context__id.XER_encode(EMBEDDED_PDV_identification_cn_pci_xer_, p_buf, flavor, indent); - field_transfer__syntax .XER_encode(EMBEDDED_PDV_identification_cn_tsx_xer_, p_buf, flavor, indent); + field_presentation__context__id.XER_encode(EMBEDDED_PDV_identification_cn_pci_xer_, p_buf, flavor, indent, 0); + field_transfer__syntax .XER_encode(EMBEDDED_PDV_identification_cn_tsx_xer_, p_buf, flavor, indent, 0); if (indenting) do_indent(p_buf, --indent); p_buf.put_c('<'); @@ -2346,7 +2346,7 @@ int EMBEDDED_PDV_identification_context__negotiation::XER_encode(const XERdescri } int EMBEDDED_PDV_identification_context__negotiation::XER_decode( - const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor) + const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int type = reader.NodeType(), depth = -1; @@ -2357,8 +2357,8 @@ int EMBEDDED_PDV_identification_context__negotiation::XER_decode( depth = reader.Depth(); success = reader.Read(); } - field_presentation__context__id.XER_decode(EMBEDDED_PDV_identification_cn_pci_xer_, reader, flavor); - field_transfer__syntax .XER_decode(EMBEDDED_PDV_identification_cn_tsx_xer_, reader, flavor); + field_presentation__context__id.XER_decode(EMBEDDED_PDV_identification_cn_pci_xer_, reader, flavor, 0); + field_transfer__syntax .XER_decode(EMBEDDED_PDV_identification_cn_tsx_xer_, reader, flavor, 0); for (; success == 1; success = reader.Read()) { type = reader.NodeType(); if (XML_READER_TYPE_END_ELEMENT == type) { @@ -2984,7 +2984,7 @@ void EMBEDDED_PDV::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer,p_buf, XER_coding, 0); + XER_encode(*p_td.xer,p_buf, XER_coding, 0, 0); break;} case TTCN_EncDec::CT_JSON: { TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); @@ -3030,7 +3030,7 @@ void EMBEDDED_PDV::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -3097,7 +3097,7 @@ boolean EMBEDDED_PDV::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const AS } int EMBEDDED_PDV::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const { + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error (TTCN_EncDec::ET_UNBOUND, "Encoding an unbound value."); @@ -3111,13 +3111,13 @@ int EMBEDDED_PDV::XER_encode(const XERdescriptor_t& p_td, p_buf.put_s((size_t)p_td.namelens[exer] - 1 + indenting, (const unsigned char*)p_td.names[exer]); flavor &= XER_MASK; ++indent; - field_identification .XER_encode(EMBEDDED_PDV_identification_xer_ , p_buf, flavor, indent); + field_identification .XER_encode(EMBEDDED_PDV_identification_xer_ , p_buf, flavor, indent, 0); if (field_data__value__descriptor.is_value()) { TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, "data-value-descriptor not allowed for EMBEDDED PDV"); } - field_data__value__descriptor.XER_encode(EMBEDDED_PDV_data_value_descriptor_xer_, p_buf, flavor, indent); - field_data__value .XER_encode(EMBEDDED_PDV_data_value_xer_ , p_buf, flavor, indent); + field_data__value__descriptor.XER_encode(EMBEDDED_PDV_data_value_descriptor_xer_, p_buf, flavor, indent, 0); + field_data__value .XER_encode(EMBEDDED_PDV_data_value_xer_ , p_buf, flavor, indent, 0); if (indenting) do_indent(p_buf, --indent); p_buf.put_c('<'); @@ -3127,7 +3127,7 @@ int EMBEDDED_PDV::XER_encode(const XERdescriptor_t& p_td, return (int)p_buf.get_len() - encoded_length; } -int EMBEDDED_PDV::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor) +int EMBEDDED_PDV::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int depth = 1, type, success; @@ -3140,13 +3140,13 @@ int EMBEDDED_PDV::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, break; } } - field_identification .XER_decode(EMBEDDED_PDV_identification_xer_ , reader, flavor); - field_data__value__descriptor.XER_decode(EMBEDDED_PDV_data_value_descriptor_xer_, reader, flavor); + field_identification .XER_decode(EMBEDDED_PDV_identification_xer_ , reader, flavor, 0); + field_data__value__descriptor.XER_decode(EMBEDDED_PDV_data_value_descriptor_xer_, reader, flavor, 0); if (field_data__value__descriptor.is_value()) { TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, "data-value-descriptor not allowed for EMBEDDED PDV"); } - field_data__value .XER_decode(EMBEDDED_PDV_data_value_xer_ , reader, flavor); + field_data__value .XER_decode(EMBEDDED_PDV_data_value_xer_ , reader, flavor, 0); for (success = reader.Read(); success == 1; success = reader.Read()) { type = reader.NodeType(); if (XML_READER_TYPE_END_ELEMENT == type) { diff --git a/core/ASN_EmbeddedPDV.hh b/core/ASN_EmbeddedPDV.hh index 6dce034..0ee44cf 100644 --- a/core/ASN_EmbeddedPDV.hh +++ b/core/ASN_EmbeddedPDV.hh @@ -86,9 +86,9 @@ public: ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); private: boolean BER_decode_set_selection(const ASN_BER_TLV_t& p_tlv); public: @@ -207,8 +207,8 @@ public: //void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, TTCN_EncDec::coding_t p_coding, ...); ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); - int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int) const; - int XER_decode(const XERdescriptor_t&, XmlReaderWrap& reader, unsigned int); + 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*); }; class EMBEDDED_PDV_identification_syntaxes_template : public Base_Template { @@ -312,8 +312,8 @@ public: //void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, TTCN_EncDec::coding_t p_coding, ...); ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); - int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int) const; - int XER_decode(const XERdescriptor_t&, XmlReaderWrap& reader, unsigned int); + 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*); }; class EMBEDDED_PDV_identification_context__negotiation_template : public Base_Template { @@ -423,8 +423,8 @@ public: void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, TTCN_EncDec::coding_t p_coding, ...); ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); - int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int) const; - int XER_decode(const XERdescriptor_t&, XmlReaderWrap&, unsigned int); + int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int, embed_values_enc_struct_t*) const; + int XER_decode(const XERdescriptor_t&, XmlReaderWrap&, unsigned int, embed_values_dec_struct_t*); }; class EMBEDDED_PDV_template : public Base_Template { diff --git a/core/ASN_External.cc b/core/ASN_External.cc index 94836ac..65e7e3d 100644 --- a/core/ASN_External.cc +++ b/core/ASN_External.cc @@ -102,9 +102,9 @@ namespace { /* anonymous namespace */ ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); private: boolean BER_decode_set_selection(const ASN_BER_TLV_t& p_tlv); public: @@ -159,9 +159,9 @@ namespace { /* anonymous namespace */ ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); }; /** Transform the information from the visible format to the encoding format @@ -398,7 +398,7 @@ namespace { /* anonymous namespace */ } int EXTERNALtransfer_encoding::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { int indenting = !is_canonical(flavor); int exer = is_exer(flavor); @@ -411,13 +411,13 @@ namespace { /* anonymous namespace */ ++indent; switch (union_selection) { case ALT_single__ASN1__type: - field_single__ASN1__type->XER_encode(EXTERNAL_encoding_singleASN_xer_, p_buf, flavor, indent); + field_single__ASN1__type->XER_encode(EXTERNAL_encoding_singleASN_xer_, p_buf, flavor, indent, 0); break; case ALT_octet__aligned: - field_octet__aligned ->XER_encode(EXTERNAL_encoding_octet_aligned_xer_, p_buf, flavor, indent); + field_octet__aligned ->XER_encode(EXTERNAL_encoding_octet_aligned_xer_, p_buf, flavor, indent, 0); break; case ALT_arbitrary: - field_arbitrary ->XER_encode(EXTERNAL_encoding_arbitrary_xer_, p_buf, flavor, indent); + field_arbitrary ->XER_encode(EXTERNAL_encoding_arbitrary_xer_, p_buf, flavor, indent, 0); break; case UNBOUND_VALUE: TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, @@ -438,7 +438,7 @@ namespace { /* anonymous namespace */ } int EXTERNALtransfer_encoding::XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor) + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int success = reader.Ok(), type, depth = -1; @@ -461,15 +461,15 @@ namespace { /* anonymous namespace */ switch (*name) { case 's': // single-ASN1-type - single__ASN1__type().XER_decode(EXTERNAL_encoding_singleASN_xer_, reader, flavor); + single__ASN1__type().XER_decode(EXTERNAL_encoding_singleASN_xer_, reader, flavor, 0); break; case 'o': // octet-aligned - octet__aligned().XER_decode(EXTERNAL_encoding_octet_aligned_xer_, reader, flavor); + octet__aligned().XER_decode(EXTERNAL_encoding_octet_aligned_xer_, reader, flavor, 0); break; case 'a': // arbitrary - arbitrary().XER_decode(EXTERNAL_encoding_arbitrary_xer_, reader, flavor); + arbitrary().XER_decode(EXTERNAL_encoding_arbitrary_xer_, reader, flavor, 0); break; default: @@ -555,7 +555,7 @@ namespace { /* anonymous namespace */ } int EXTERNALtransfer::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { int indenting = !is_canonical(flavor); int exer = is_exer(flavor); @@ -566,10 +566,10 @@ namespace { /* anonymous namespace */ p_buf.put_s((size_t)p_td.namelens[exer] - 1 + indenting, (const unsigned char*)p_td.names[exer]); ++indent; - field_direct__reference .XER_encode(EXTERNAL_direct_reference_xer_ , p_buf, flavor, indent); - field_indirect__reference .XER_encode(EXTERNAL_indirect_reference_xer_ , p_buf, flavor, indent); - field_data__value__descriptor.XER_encode(EXTERNAL_data_value_descriptor_xer_, p_buf, flavor, indent); - field_encoding .XER_encode(EXTERNAL_encoding_xer_ , p_buf, flavor, indent); + field_direct__reference .XER_encode(EXTERNAL_direct_reference_xer_ , p_buf, flavor, indent, 0); + field_indirect__reference .XER_encode(EXTERNAL_indirect_reference_xer_ , p_buf, flavor, indent, 0); + field_data__value__descriptor.XER_encode(EXTERNAL_data_value_descriptor_xer_, p_buf, flavor, indent, 0); + field_encoding .XER_encode(EXTERNAL_encoding_xer_ , p_buf, flavor, indent, 0); if (indenting) do_indent(p_buf, --indent); p_buf.put_c('<'); @@ -579,7 +579,8 @@ namespace { /* anonymous namespace */ return (int)p_buf.get_len() - encoded_length; } - int EXTERNALtransfer::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor) + int EXTERNALtransfer::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, + unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int success = reader.Ok(), depth = -1; @@ -593,10 +594,10 @@ namespace { /* anonymous namespace */ } } - field_direct__reference .XER_decode(EXTERNAL_direct_reference_xer_ , reader, flavor); - field_indirect__reference .XER_decode(EXTERNAL_indirect_reference_xer_ , reader, flavor); - field_data__value__descriptor.XER_decode(EXTERNAL_data_value_descriptor_xer_, reader, flavor); - field_encoding .XER_decode(EXTERNAL_encoding_xer_ , reader, flavor); + field_direct__reference .XER_decode(EXTERNAL_direct_reference_xer_ , reader, flavor, 0); + field_indirect__reference .XER_decode(EXTERNAL_indirect_reference_xer_ , reader, flavor, 0); + field_data__value__descriptor.XER_decode(EXTERNAL_data_value_descriptor_xer_, reader, flavor, 0); + field_encoding .XER_decode(EXTERNAL_encoding_xer_ , reader, flavor, 0); for (success = reader.Read(); success == 1; success = reader.Read()) { int type = reader.NodeType(); @@ -694,7 +695,7 @@ boolean EXTERNAL::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BE } int EXTERNAL::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error @@ -702,14 +703,14 @@ int EXTERNAL::XER_encode(const XERdescriptor_t& p_td, } EXTERNALtransfer xfer; xfer.load(*this); - return xfer.XER_encode(p_td, p_buf, flavor, indent); + return xfer.XER_encode(p_td, p_buf, flavor, indent, 0); } int EXTERNAL::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor) + unsigned int flavor, embed_values_dec_struct_t*) { EXTERNALtransfer xfer; - xfer.XER_decode(p_td, reader, flavor); + xfer.XER_decode(p_td, reader, flavor, 0); transfer(&xfer); return 1; // decode successful } @@ -3182,7 +3183,7 @@ void EXTERNAL::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, TTC case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); break;} case TTCN_EncDec::CT_JSON: { TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); @@ -3228,7 +3229,7 @@ void EXTERNAL::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, TTC if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} diff --git a/core/ASN_External.hh b/core/ASN_External.hh index cb926e1..9405c25 100644 --- a/core/ASN_External.hh +++ b/core/ASN_External.hh @@ -403,9 +403,9 @@ public: ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const; boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); }; class EXTERNAL_template : public Base_Template { diff --git a/core/ASN_Null.cc b/core/ASN_Null.cc index 800c533..ab3c9a2 100644 --- a/core/ASN_Null.cc +++ b/core/ASN_Null.cc @@ -105,7 +105,16 @@ void ASN_NULL::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); + break;} + case TTCN_EncDec::CT_JSON: { + TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); + if(!p_td.json) + TTCN_EncDec_ErrorContext::error_internal + ("No JSON descriptor available for type '%s'.", p_td.name); + JSON_Tokenizer tok(va_arg(pvar, int) != 0); + JSON_encode(p_td, tok); + p_buf.put_s(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer()); break;} case TTCN_EncDec::CT_RAW: default: @@ -130,7 +139,7 @@ void ASN_NULL::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if(tlv.isComplete) p_buf.increase_pos(tlv.get_len()); break;} case TTCN_EncDec::CT_XER: { - TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); + TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); XmlReaderWrap reader(p_buf); int success = reader.Read(); @@ -139,10 +148,23 @@ void ASN_NULL::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} + case TTCN_EncDec::CT_JSON: { + TTCN_EncDec_ErrorContext ec("While JSON-decoding type '%s': ", p_td.name); + if(!p_td.json) + TTCN_EncDec_ErrorContext::error_internal + ("No JSON descriptor available for type '%s'.", p_td.name); + JSON_Tokenizer tok((const char*)p_buf.get_data(), p_buf.get_len()); + if(JSON_decode(p_td, tok, false)<0) + ec.error(TTCN_EncDec::ET_INCOMPL_MSG, + "Can not decode type '%s', because invalid or incomplete" + " message was received" + , p_td.name); + p_buf.set_pos(tok.get_buf_pos()); + break;} case TTCN_EncDec::CT_RAW: default: TTCN_error("Unknown coding method requested to decode type '%s'", @@ -181,7 +203,7 @@ boolean ASN_NULL::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, } int ASN_NULL::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent ) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { int exer = is_exer(flavor); TTCN_EncDec_ErrorContext ec("While XER encoding NULL type: "); @@ -205,7 +227,7 @@ int ASN_NULL::XER_encode(const XERdescriptor_t& p_td, } int ASN_NULL::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor) + unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); TTCN_EncDec_ErrorContext ec("While XER decoding NULL type: "); @@ -235,6 +257,32 @@ int ASN_NULL::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, return 1; // decode successful } +int ASN_NULL::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const +{ + if (!is_bound()) { + TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, + "Encoding an unbound ASN.1 NULL value."); + return -1; + } + + return p_tok.put_next_token(JSON_TOKEN_LITERAL_NULL); +} + +int ASN_NULL::JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok, boolean p_silent) +{ + json_token_t token = JSON_TOKEN_NONE; + int dec_len = p_tok.get_next_token(&token, NULL, NULL); + if (JSON_TOKEN_ERROR == token) { + JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, ""); + return JSON_ERROR_FATAL; + } + else if (JSON_TOKEN_LITERAL_NULL != token) { + return JSON_ERROR_INVALID_TOKEN; + } + bound_flag = TRUE; + return dec_len; +} + boolean operator==(asn_null_type, const ASN_NULL& other_value) { if (!other_value.is_bound()) TTCN_error("The right operand of comparison " diff --git a/core/ASN_Null.hh b/core/ASN_Null.hh index e83c564..dae43d0 100644 --- a/core/ASN_Null.hh +++ b/core/ASN_Null.hh @@ -69,9 +69,17 @@ public: boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); + + /** Encodes accordingly to the JSON encoding rules. + * Returns the length of the encoded data. */ + int JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&) const; + + /** Decodes accordingly to the JSON decoding rules. + * Returns the length of the encoded data. */ + int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean); }; extern boolean operator==(asn_null_type par_value, const ASN_NULL& other_value); diff --git a/core/Array.hh b/core/Array.hh index a85ab09..bfbfde7 100644 --- a/core/Array.hh +++ b/core/Array.hh @@ -85,6 +85,13 @@ 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, @@ -145,6 +152,13 @@ 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 }; //////////////////////////////////////////////////////////////////////////////// @@ -227,10 +241,12 @@ public: * Returns the length of the decoded data. */ int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean); - // Dummy functions, only used in record of/set of (the referenced indices +#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 d253707..104e6b0 100644 --- a/core/Basetype.cc +++ b/core/Basetype.cc @@ -16,6 +16,7 @@ #include "JSON.hh" #include "XmlReader.hh" #include "Module_list.hh" +#include "Universal_charstring.hh" #include @@ -74,7 +75,7 @@ void Base_Type::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if(!p_td.xer) TTCN_EncDec_ErrorContext::error_internal( "No XER descriptor available for type '%s'.", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*(p_td.xer),p_buf, XER_coding, 0); + XER_encode(*(p_td.xer),p_buf, XER_coding, 0, 0); p_buf.put_c('\n'); break;} case TTCN_EncDec::CT_JSON: { @@ -148,7 +149,7 @@ void Base_Type::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, for (int success=reader.Read(); success==1; success=reader.Read()) { if (reader.NodeType() == XML_READER_TYPE_ELEMENT) break; } - XER_decode(*(p_td.xer), reader, XER_coding); + XER_decode(*(p_td.xer), reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -966,14 +967,15 @@ int Base_Type::RAW_decode(const TTCN_Typedescriptor_t& p_td, } int Base_Type::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer&, unsigned int, int) const + TTCN_Buffer&, unsigned int, int, embed_values_enc_struct_t*) const { TTCN_error("XER encoding requested for type '%-.*s' which has no" " XER encoding method.", p_td.namelens[0]-2, p_td.names[0]); return 0; } -int Base_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap&, unsigned int) { +int Base_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap&, + unsigned int, embed_values_dec_struct_t*) { TTCN_error("XER decoding requested for type '%-.*s' which has no" " XER decoding method.", p_td.namelens[0]-2, p_td.names[0]); return 0; @@ -1096,7 +1098,7 @@ const TTCN_Typedescriptor_t VERDICTTYPE_descr_={"verdicttype", NULL, NULL, NULL, &VERDICTTYPE_xer_, &VERDICTTYPE_json_, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t OBJID_descr_={"OBJECT IDENTIFIER", &OBJID_ber_, - NULL, NULL, &OBJID_xer_, NULL, TTCN_Typedescriptor_t::OBJID}; + NULL, NULL, &OBJID_xer_, &OBJID_json_, 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}; @@ -1120,10 +1122,10 @@ const TTCN_Typedescriptor_t DEFAULT_descr_={"default", NULL, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t ASN_NULL_descr_={"NULL", &ASN_NULL_ber_, NULL, - NULL, &ASN_NULL_xer_, NULL, TTCN_Typedescriptor_t::DONTCARE}; + NULL, &ASN_NULL_xer_, &ASN_NULL_json_, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t ASN_ANY_descr_={"ANY", &ASN_ANY_ber_, NULL, - NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE}; + NULL, NULL, &ASN_ANY_json_, TTCN_Typedescriptor_t::DONTCARE}; const TTCN_Typedescriptor_t EXTERNAL_descr_={"EXTERNAL", &EXTERNAL_ber_, NULL, NULL, &EXTERNAL_xer_, NULL, TTCN_Typedescriptor_t::DONTCARE}; @@ -1141,7 +1143,7 @@ const TTCN_Typedescriptor_t UTF8String_descr_={"UTF8String", &UTF8String_ber_, NULL, NULL, &UTF8String_xer_, NULL, TTCN_Typedescriptor_t::UTF8STRING}; const TTCN_Typedescriptor_t ASN_ROID_descr_={"RELATIVE-OID", &ASN_ROID_ber_, - NULL, NULL, &ASN_ROID_xer_, NULL, TTCN_Typedescriptor_t::ROID}; + NULL, NULL, &ASN_ROID_xer_, &ASN_ROID_json_, TTCN_Typedescriptor_t::ROID}; const TTCN_Typedescriptor_t NumericString_descr_={"NumericString", &NumericString_ber_, NULL, NULL, &NumericString_xer_, NULL, TTCN_Typedescriptor_t::DONTCARE}; diff --git a/core/Basetype.hh b/core/Basetype.hh index fca5d1c..2e49375 100644 --- a/core/Basetype.hh +++ b/core/Basetype.hh @@ -15,6 +15,7 @@ #include "Vector.hh" #ifdef TITAN_RUNTIME_2 #include "Struct_of.hh" +#include "XER.hh" #endif struct ASN_BERdescriptor_t; @@ -25,6 +26,8 @@ struct XERdescriptor_t; struct TTCN_JSONdescriptor_t; class XmlReaderWrap; class Module_Param; +struct embed_values_enc_struct_t; +struct embed_values_dec_struct_t; /** @brief Type descriptor * @@ -204,7 +207,7 @@ public: */ virtual void set_to_present(); /** @} */ - + virtual ~Base_Type() { } #endif @@ -444,15 +447,16 @@ public: * @param p_buf buffer * @param flavor one of XER_flavor values * @param indent indentation level + * @param emb_val embed values data (only relevant for record of types) * @return number of bytes written into the buffer */ VIRTUAL_IF_RUNTIME_2 int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t* emb_val) const; #ifdef TITAN_RUNTIME_2 virtual int XER_encode_negtest(const Erroneous_descriptor_t* /*p_err_descr*/, const XERdescriptor_t& /*p_td*/, TTCN_Buffer& /*p_buf*/, - unsigned int /*flavor*/, int /*indent*/) const; + unsigned int /*flavor*/, int /*indent*/, embed_values_enc_struct_t* /*emb_val*/) const; #endif /** Decode the current object from the supplied buffer. @@ -482,10 +486,11 @@ public: * @param p_td type descriptor * @param reader Wrapper around the XML processor * @param flavor one of XER_flavor values + * @param emb_val embed values data (only relevant for record of types) * @return number of bytes "consumed" */ VIRTUAL_IF_RUNTIME_2 int XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor); + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t* emb_val); /** Return an array of namespace declarations. * @@ -651,15 +656,17 @@ protected: } *val_ptr; Erroneous_descriptor_t* err_descr; - /** Stores the indices of elements that are referenced by 'out' and 'inout' parameters. - * These elements must not be deleted.*/ - Vector refd_indices; - - /** Cached maximum value of \a refd_indices (default: -1).*/ - int max_refd_index; + struct refd_index_struct { + /** Stores the indices of elements that are referenced by 'out' and 'inout' parameters. + * These elements must not be deleted.*/ + Vector refd_indices; + + /** Cached maximum value of \a refd_indices (default: -1).*/ + int max_refd_index; + } *refd_ind_ptr; static boolean compare_function(const Record_Of_Type *left_ptr, int left_index, const Record_Of_Type *right_ptr, int right_index); - Record_Of_Type() : val_ptr(NULL), err_descr(NULL), max_refd_index(-1) {} + Record_Of_Type() : val_ptr(NULL), err_descr(NULL), refd_ind_ptr(NULL) {} Record_Of_Type(null_type other_value); Record_Of_Type(const Record_Of_Type& other_value); /// Assignment disabled @@ -765,14 +772,14 @@ public: virtual int TEXT_decode(const TTCN_Typedescriptor_t&, TTCN_Buffer&, Limit_Token_List&, boolean no_err=FALSE, boolean first_call=TRUE); virtual int XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, - unsigned int flavor, int indent) const; + unsigned int flavor, int indent, embed_values_enc_struct_t*) const; 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) const; + 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, const Erroneous_descriptor_t* emb_descr, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; - virtual int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int); + 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*); virtual boolean isXerAttribute() const; virtual boolean isXmlValueList() const; @@ -905,11 +912,12 @@ public: virtual int TEXT_decode(const TTCN_Typedescriptor_t&, TTCN_Buffer&, Limit_Token_List&, boolean no_err=FALSE, boolean first_call=TRUE); virtual int XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, - unsigned int flavor, int indent) const; + unsigned int flavor, int indent, embed_values_enc_struct_t*) const; virtual int XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, - unsigned int flavor, int indent) const; - virtual int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int); + unsigned int flavor, int indent, embed_values_enc_struct_t*) const; + virtual int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, + unsigned int, embed_values_dec_struct_t*); /// @{ /// Methods overridden in the derived (generated) class virtual int get_xer_num_attr() const { return 0; /* default */ } @@ -932,7 +940,7 @@ public: private: /// Helper for XER_encode_negtest int encode_field(int i, const Erroneous_values_t* err_vals, const Erroneous_descriptor_t* emb_descr, - TTCN_Buffer& p_buf, unsigned int sub_flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int sub_flavor, int indent, embed_values_enc_struct_t* emb_val) const; }; //////////////////////////////////////////////////////////////////////////////// @@ -978,8 +986,9 @@ public: virtual int TEXT_decode(const TTCN_Typedescriptor_t&, TTCN_Buffer&, Limit_Token_List&, boolean no_err=FALSE, boolean first_call=TRUE); virtual int XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, - unsigned int flavor, int indent) const; - virtual int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int); + unsigned int flavor, int indent, embed_values_enc_struct_t*) const; + virtual int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, + unsigned int, embed_values_dec_struct_t*); /** Encodes accordingly to the JSON encoding rules. * Returns the length of the encoded data. */ diff --git a/core/Bitstring.cc b/core/Bitstring.cc index 513bc29..d55b1fa 100644 --- a/core/Bitstring.cc +++ b/core/Bitstring.cc @@ -612,10 +612,10 @@ void BITSTRING::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); break;} case TTCN_EncDec::CT_JSON: { - TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); + TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); if(!p_td.json) TTCN_EncDec_ErrorContext::error_internal ("No JSON descriptor available for type '%s'.", p_td.name); @@ -665,7 +665,7 @@ void BITSTRING::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, , p_td.name); break;} case TTCN_EncDec::CT_XER: { - TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); + TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); XmlReaderWrap reader(p_buf); int success = reader.Read(); @@ -674,7 +674,7 @@ void BITSTRING::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -1008,7 +1008,7 @@ int BITSTRING::RAW_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& buff, } int BITSTRING::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error @@ -1032,7 +1032,7 @@ int BITSTRING::XER_encode(const XERdescriptor_t& p_td, } int BITSTRING::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor) + unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int success = reader.Ok(), depth = -1, type; diff --git a/core/Bitstring.hh b/core/Bitstring.hh index ed25023..f106161 100644 --- a/core/Bitstring.hh +++ b/core/Bitstring.hh @@ -172,8 +172,8 @@ public: int RAW_decode(const TTCN_Typedescriptor_t& , TTCN_Buffer&, int, raw_order_t, boolean no_err=FALSE, int sel_field=-1, boolean first_call=TRUE); - int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int) const; - int XER_decode(const XERdescriptor_t&, XmlReaderWrap& reader, unsigned int); + 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*); /** Encodes accordingly to the JSON encoding rules. * Returns the length of the encoded data. */ diff --git a/core/Boolean.cc b/core/Boolean.cc index 80bc0ec..210ff85 100644 --- a/core/Boolean.cc +++ b/core/Boolean.cc @@ -204,7 +204,7 @@ void BOOLEAN::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); break;} case TTCN_EncDec::CT_JSON: { TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); @@ -275,7 +275,7 @@ void BOOLEAN::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, , p_td.name); break;} case TTCN_EncDec::CT_XER: { - TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); + TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); XmlReaderWrap reader(p_buf); for (int success = reader.Read(); success==1; success=reader.Read()) { @@ -283,7 +283,7 @@ void BOOLEAN::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -575,7 +575,7 @@ int BOOLEAN::RAW_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& buff, } int BOOLEAN::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error @@ -608,7 +608,7 @@ int BOOLEAN::XER_encode(const XERdescriptor_t& p_td, } int BOOLEAN::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor) + unsigned int flavor, embed_values_dec_struct_t*) { const boolean exer = is_exer(flavor); int XMLValueList = !exer && is_record_of(flavor); diff --git a/core/Boolean.hh b/core/Boolean.hh index 2a1c07b..0807ea5 100644 --- a/core/Boolean.hh +++ b/core/Boolean.hh @@ -102,9 +102,9 @@ public: 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& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); /** Encodes accordingly to the JSON encoding rules. * Returns the length of the encoded data. */ diff --git a/core/Charstring.cc b/core/Charstring.cc index c0cbe33..180fc91 100644 --- a/core/Charstring.cc +++ b/core/Charstring.cc @@ -731,7 +731,7 @@ void CHARSTRING::encode(const TTCN_Typedescriptor_t& p_td, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); p_buf.put_c('\n'); break;} case TTCN_EncDec::CT_JSON: { @@ -804,7 +804,7 @@ void CHARSTRING::decode(const TTCN_Typedescriptor_t& p_td, , p_td.name); break;} case TTCN_EncDec::CT_XER: { - TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); + TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); XmlReaderWrap reader(p_buf); int success = reader.Read(); @@ -813,7 +813,7 @@ void CHARSTRING::decode(const TTCN_Typedescriptor_t& p_td, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -1145,7 +1145,7 @@ extern const char cb64[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int CHARSTRING::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, @@ -1270,7 +1270,7 @@ unsigned int xlate(cbyte*in, int phase, unsigned char*dest) { } int CHARSTRING::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor) { + unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int success = reader.Ok(), depth = -1; diff --git a/core/Charstring.hh b/core/Charstring.hh index 22a2c56..4ca62b4 100644 --- a/core/Charstring.hh +++ b/core/Charstring.hh @@ -205,8 +205,8 @@ public: 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) const; - int XER_decode(const XERdescriptor_t&, XmlReaderWrap& reader, unsigned int); + 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*); /** Returns the charstring in the format a string would appear in C or TTCN-3 code. * Inserts double quotation marks to the beginning and end of the string and diff --git a/core/Float.cc b/core/Float.cc index 5a3d83d..50c1c91 100644 --- a/core/Float.cc +++ b/core/Float.cc @@ -290,7 +290,7 @@ void FLOAT::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); break;} case TTCN_EncDec::CT_JSON: { TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); @@ -343,7 +343,7 @@ void FLOAT::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, , p_td.name); break;} case TTCN_EncDec::CT_XER: { - TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); + TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); XmlReaderWrap reader(p_buf); for (int success = reader.Read(); success==1; success=reader.Read()) { @@ -351,7 +351,7 @@ void FLOAT::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -765,7 +765,7 @@ int FLOAT::RAW_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& buff, } int FLOAT::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error( @@ -794,7 +794,7 @@ int FLOAT::XER_encode(const XERdescriptor_t& p_td, } int FLOAT::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor) + unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int success = reader.Ok(), depth = -1; diff --git a/core/Float.hh b/core/Float.hh index 76e32b4..013d39d 100644 --- a/core/Float.hh +++ b/core/Float.hh @@ -136,9 +136,9 @@ public: int sel_field=-1, boolean first_call=TRUE); int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); /** Encodes accordingly to the JSON encoding rules. * Returns the length of the encoded data. */ diff --git a/core/Hexstring.cc b/core/Hexstring.cc index 04c6746..27c7e4a 100644 --- a/core/Hexstring.cc +++ b/core/Hexstring.cc @@ -623,7 +623,7 @@ void HEXSTRING::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); break;} case TTCN_EncDec::CT_JSON: { TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); @@ -665,7 +665,7 @@ void HEXSTRING::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, " message was received", p_td.name); break;} case TTCN_EncDec::CT_XER: { - TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); + TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); XmlReaderWrap reader(p_buf); int success = reader.Read(); @@ -674,12 +674,12 @@ void HEXSTRING::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} case TTCN_EncDec::CT_JSON: { - TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); + TTCN_EncDec_ErrorContext ec("While JSON-decoding type '%s': ", p_td.name); if(!p_td.json) TTCN_EncDec_ErrorContext::error_internal ("No JSON descriptor available for type '%s'.", p_td.name); @@ -790,7 +790,7 @@ extern char base64_decoder_table[256]; extern const char cb64[]; int HEXSTRING::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error @@ -864,7 +864,7 @@ Because of this, the bit shifting is different. The first three bytes */ int HEXSTRING::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor) + unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int success = reader.Ok(), depth = -1, type; diff --git a/core/Hexstring.hh b/core/Hexstring.hh index c4392ab..1fd91e8 100644 --- a/core/Hexstring.hh +++ b/core/Hexstring.hh @@ -125,9 +125,9 @@ public: int RAW_decode(const TTCN_Typedescriptor_t&, TTCN_Buffer&, int, raw_order_t, boolean no_err=FALSE, int sel_field=-1, boolean first_call=TRUE); int XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, - unsigned int flavor, int indent) const; + unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); /** Encodes accordingly to the JSON encoding rules. * Returns the length of the encoded data. */ diff --git a/core/Integer.cc b/core/Integer.cc index 331cd94..b997527 100644 --- a/core/Integer.cc +++ b/core/Integer.cc @@ -715,7 +715,7 @@ void INTEGER::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); break;} case TTCN_EncDec::CT_JSON: { TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); @@ -794,7 +794,7 @@ void INTEGER::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -1265,7 +1265,7 @@ int INTEGER::RAW_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& buff, } int INTEGER::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, - unsigned int flavor, int indent) const + unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if (!is_bound()) { TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, @@ -1295,7 +1295,7 @@ int INTEGER::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, } int INTEGER::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor) + unsigned int flavor, embed_values_dec_struct_t*) { const boolean exer = is_exer(flavor); int depth = -1, success = reader.Ok(), type; diff --git a/core/Integer.hh b/core/Integer.hh index 1e48b62..bf6ec35 100644 --- a/core/Integer.hh +++ b/core/Integer.hh @@ -161,11 +161,11 @@ public: /** @brief Encode according to XML Encoding Rules. **/ int XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned int flavor, - int indent) const; + int indent, embed_values_enc_struct_t*) const; /** @brief Decode according to XML Encoding Rules. **/ int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); /** Encodes accordingly to the JSON encoding rules. * Returns the length of the encoded data. */ diff --git a/core/JSON.cc b/core/JSON.cc index 59b62db..ad429c4 100644 --- a/core/JSON.cc +++ b/core/JSON.cc @@ -47,3 +47,13 @@ const TTCN_JSONdescriptor_t TeletexString_json_ = { false, NULL, false, NULL }; const TTCN_JSONdescriptor_t VideotexString_json_ = { false, NULL, false, NULL }; const TTCN_JSONdescriptor_t VisibleString_json_ = { false, NULL, false, NULL }; + +const TTCN_JSONdescriptor_t ASN_NULL_json_ = { false, NULL, false, NULL }; + +const TTCN_JSONdescriptor_t OBJID_json_ = { false, NULL, false, NULL }; + +const TTCN_JSONdescriptor_t ASN_ROID_json_ = { false, NULL, false, NULL }; + +const TTCN_JSONdescriptor_t ASN_ANY_json_ = { false, NULL, false, NULL }; + +const TTCN_JSONdescriptor_t ENUMERATED_json_ = { false, NULL, false, NULL }; diff --git a/core/JSON.hh b/core/JSON.hh index 39cbec4..6c9357d 100644 --- a/core/JSON.hh +++ b/core/JSON.hh @@ -64,6 +64,11 @@ extern const TTCN_JSONdescriptor_t IA5String_json_; extern const TTCN_JSONdescriptor_t TeletexString_json_; extern const TTCN_JSONdescriptor_t VideotexString_json_; extern const TTCN_JSONdescriptor_t VisibleString_json_; +extern const TTCN_JSONdescriptor_t ASN_NULL_json_; +extern const TTCN_JSONdescriptor_t OBJID_json_; +extern const TTCN_JSONdescriptor_t ASN_ROID_json_; +extern const TTCN_JSONdescriptor_t ASN_ANY_json_; +extern const TTCN_JSONdescriptor_t ENUMERATED_json_; /** JSON decoder error codes */ enum json_decode_error { diff --git a/core/Makefile b/core/Makefile index bb6ac4d..ff35320 100644 --- a/core/Makefile +++ b/core/Makefile @@ -78,7 +78,8 @@ LoggerPluginManager.cc LegacyLogger.cc LoggingBits.cc \ Module_list.cc Objid.cc Octetstring.cc Parallel_main.cc Port.cc RAW.cc \ Runtime.cc Single_main.cc Snapshot.cc Struct_of.cc Template.cc TEXT.cc \ Textbuf.cc Timer.cc Param_Types.cc Universal_charstring.cc \ -Verdicttype.cc XER.cc XmlReader.cc TitanLoggerControlImpl.cc TCov.cc JSON.cc $(RT2_SOURCES) +Verdicttype.cc XER.cc XmlReader.cc TitanLoggerControlImpl.cc TCov.cc JSON.cc \ +Profiler.cc $(RT2_SOURCES) # Keep GENERATED_SOURCES at the beginning. This may speed up parallel builds # by starting early the compilation of the largest files. @@ -156,7 +157,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 +JSON.hh Profiler.hh # Copied during "make install" ifdef REGEX_DIR diff --git a/core/Objid.cc b/core/Objid.cc index 00d37ba..79fe281 100644 --- a/core/Objid.cc +++ b/core/Objid.cc @@ -264,7 +264,16 @@ void OBJID::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); + break;} + case TTCN_EncDec::CT_JSON: { + TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); + if(!p_td.json) + TTCN_EncDec_ErrorContext::error_internal + ("No JSON descriptor available for type '%s'.", p_td.name); + JSON_Tokenizer tok(va_arg(pvar, int) != 0); + JSON_encode(p_td, tok); + p_buf.put_s(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer()); break;} default: TTCN_error("Unknown coding method requested to encode type '%s'", @@ -293,7 +302,7 @@ void OBJID::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, ("No RAW descriptor available for type '%s'.", p_td.name); break;} case TTCN_EncDec::CT_XER: { - TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); + TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); XmlReaderWrap reader(p_buf); int success = reader.Read(); @@ -302,10 +311,23 @@ void OBJID::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} + case TTCN_EncDec::CT_JSON: { + TTCN_EncDec_ErrorContext ec("While JSON-decoding type '%s': ", p_td.name); + if(!p_td.json) + TTCN_EncDec_ErrorContext::error_internal + ("No JSON descriptor available for type '%s'.", p_td.name); + JSON_Tokenizer tok((const char*)p_buf.get_data(), p_buf.get_len()); + if(JSON_decode(p_td, tok, false)<0) + ec.error(TTCN_EncDec::ET_INCOMPL_MSG, + "Can not decode type '%s', because invalid or incomplete" + " message was received" + , p_td.name); + p_buf.set_pos(tok.get_buf_pos()); + break;} default: TTCN_error("Unknown coding method requested to decode type '%s'", p_td.name); @@ -446,7 +468,7 @@ boolean OBJID::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, int OBJID::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent ) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, @@ -478,8 +500,33 @@ int OBJID::XER_encode(const XERdescriptor_t& p_td, return (int)p_buf.get_len() - encoded_length; } +void OBJID::from_string(char* p_str) +{ + // Count dots to find number of components. (1 dot = 2 components, etc.) + unsigned comps = 1; + const char *p; + for (p = p_str; *p != 0; ++p) { + if (*p == '.') ++comps; + } + // p now points at the end of the string. If it was empty, then there were + // no components; compensate the fact that we started at 1. + init_struct((p != p_str) ? comps : 0); + + char *beg, *end = 0; + comps = 0; + for (beg = p_str; beg < p; ++beg) { + errno = 0; + long ret = strtol(beg, &end, 10); + if (errno) break; + + // TODO check value for too big ? + (*this)[comps++] = ret; + beg = end; // move to the dot; will move past it when incremented + } +} + int OBJID::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor) + unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int success = reader.Ok(), depth = -1; @@ -497,27 +544,8 @@ int OBJID::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, "Bogus object identifier"); return 0; } - // Count dots to find number of components. (1 dot = 2 components, etc.) - unsigned comps = 1; - const char *p; - for (p = val; *p != 0; ++p) { - if (*p == '.') ++comps; - } - // p now points at the end of the string. If it was empty, then there were - // no components; compensate the fact that we started at 1. - init_struct((p != val) ? comps : 0); - - char *beg, *end = 0; - comps = 0; - for (beg = val; beg < p; ++beg) { - errno = 0; - long ret = strtol(beg, &end, 10); - if (errno) break; - - // TODO check value for too big ? - (*this)[comps++] = ret; - beg = end; // move to the dot; will move past it when incremented - } + + from_string(val); xmlFree(val); } @@ -532,6 +560,69 @@ int OBJID::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, return 1; // decode successful } +int OBJID::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const +{ + if (!is_bound()) { + TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, + "Encoding an unbound object identifier value."); + return -1; + } + + char* objid_str = mcopystrn("\"", 1); + for (int i = 0; i < val_ptr->n_components; ++i) { + objid_str = mputprintf(objid_str, "%s" OBJID_FMT, (i > 0 ? "." : ""), val_ptr->components_ptr[i]); + } + objid_str = mputstrn(objid_str, "\"", 1); + int enc_len = p_tok.put_next_token(JSON_TOKEN_STRING, objid_str); + Free(objid_str); + return enc_len; +} + +int OBJID::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent) +{ + json_token_t token = JSON_TOKEN_NONE; + char* value = 0; + size_t value_len = 0; + boolean error = false; + int dec_len = 0; + boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length(); + if (use_default) { + // No JSON data in the buffer -> use default value + value = (char*)p_td.json->default_value; + value_len = strlen(value); + } else { + dec_len = p_tok.get_next_token(&token, &value, &value_len); + } + if (JSON_TOKEN_ERROR == token) { + JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, ""); + return JSON_ERROR_FATAL; + } + else if (JSON_TOKEN_STRING == token || use_default) { + if (use_default || (value_len > 2 && value[0] == '\"' && value[value_len - 1] == '\"')) { + if (!use_default) { + // The default value doesn't have quotes around it + value_len -= 2; + ++value; + } + // need a null-terminated string + char* value2 = mcopystrn(value, value_len); + from_string(value2); + Free(value2); + } + } + else { + return JSON_ERROR_INVALID_TOKEN; + } + + if (error) { + JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FORMAT_ERROR, "string", "object identifier"); + if (p_silent) { + clean_up(); + } + return JSON_ERROR_FATAL; + } + return dec_len; +} void OBJID_template::clean_up() { diff --git a/core/Objid.hh b/core/Objid.hh index c5828b5..b2b7489 100644 --- a/core/Objid.hh +++ b/core/Objid.hh @@ -27,6 +27,10 @@ class OBJID : public Base_Type { void init_struct(int n_components); void copy_value(); + + /** Initializes the object identifier with a string containing the components + * separated by dots. */ + void from_string(char* p_str); public: typedef unsigned int objid_element; @@ -83,9 +87,17 @@ public: boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); int XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); + + /** Encodes accordingly to the JSON encoding rules. + * Returns the length of the encoded data. */ + int JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&) const; + + /** Decodes accordingly to the JSON decoding rules. + * Returns the length of the encoded data. */ + int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean); }; // objid template class diff --git a/core/Octetstring.cc b/core/Octetstring.cc index 948c225..644ca50 100644 --- a/core/Octetstring.cc +++ b/core/Octetstring.cc @@ -573,7 +573,7 @@ void OCTETSTRING::encode(const TTCN_Typedescriptor_t& p_td, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); break;} case TTCN_EncDec::CT_JSON: { TTCN_EncDec_ErrorContext ec("While TEXT-encoding type '%s': ", p_td.name); @@ -645,7 +645,7 @@ void OCTETSTRING::decode(const TTCN_Typedescriptor_t& p_td, , p_td.name); break;} case TTCN_EncDec::CT_XER: { - TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); + TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); XmlReaderWrap reader(p_buf); int success = reader.Read(); @@ -654,7 +654,7 @@ void OCTETSTRING::decode(const TTCN_Typedescriptor_t& p_td, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -849,7 +849,7 @@ extern unsigned int xlate(cbyte* in, int phase, unsigned char* dest); extern const char cb64[]; int OCTETSTRING::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error @@ -894,7 +894,7 @@ int OCTETSTRING::XER_encode(const XERdescriptor_t& p_td, } int OCTETSTRING::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor) + unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int success = reader.Ok(), depth = -1, type; diff --git a/core/Octetstring.hh b/core/Octetstring.hh index 8c8e9b4..bb1428a 100644 --- a/core/Octetstring.hh +++ b/core/Octetstring.hh @@ -150,9 +150,9 @@ public: 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& p_td, TTCN_Buffer& p_buf, - unsigned int flavor, int indent) const; + unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); /** Encodes accordingly to the JSON encoding rules. * Returns the length of the encoded data. */ diff --git a/core/Optional.hh b/core/Optional.hh index 7c47aac..85e1475 100644 --- a/core/Optional.hh +++ b/core/Optional.hh @@ -26,19 +26,23 @@ enum optional_sel { OPTIONAL_UNBOUND, OPTIONAL_OMIT, OPTIONAL_PRESENT }; template class OPTIONAL : public Base_Type { + /** 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. */ + T_type *optional_value; + /** Specifies the state of the optional field - * @tricky The optional value can be modified through parameter references, + * @tricky In Runtime2 the optional value can be modified through parameter references, * in which case this member variable will not be updated. Always use the function * get_selection() instead of directly referencing this variable. */ - optional_sel optional_selection; - - /** The value, if present (owned by OPTIONAL) */ - T_type *optional_value; + optional_sel optional_selection; +#ifdef TITAN_RUNTIME_2 /** Stores the number of elements referenced by 'out' and 'inout' parameters, - * if the optional field is a record of/set of/array. + * if the optional field is a record of/set of/array (only in Runtime2). * If at least one element is referenced, the value must not be deleted. */ - int param_refs; + int param_refs; +#endif /** Set the optional value to present. * If the value was already present, does nothing. @@ -55,9 +59,10 @@ public: void set_to_present() { if (optional_selection != OPTIONAL_PRESENT) { optional_selection = OPTIONAL_PRESENT; - if (optional_value == NULL) { +#ifdef TITAN_RUNTIME_2 + if (optional_value == NULL) +#endif optional_value = new T_type; - } } } @@ -72,6 +77,7 @@ public: inline #endif void set_to_omit() { +#ifdef TITAN_RUNTIME_2 if (is_present()) { if (param_refs > 0) { optional_value->clean_up(); @@ -81,12 +87,21 @@ public: optional_value = NULL; } } +#else + if (optional_selection == OPTIONAL_PRESENT) { + delete optional_value; + } +#endif optional_selection = OPTIONAL_OMIT; } public: /// Default constructor creates an unbound object - OPTIONAL() : optional_selection(OPTIONAL_UNBOUND), optional_value(NULL), param_refs(0) { } + OPTIONAL() : optional_value(NULL), optional_selection(OPTIONAL_UNBOUND) +#ifdef TITAN_RUNTIME_2 + , param_refs(0) +#endif + { } /// Construct an optional object set to omit. /// @p other_value must be OMIT_VALUE, or else dynamic testcase error. @@ -104,12 +119,21 @@ public: /// Construct from an object of different type template OPTIONAL(const T_tmp& other_value) - : optional_selection(OPTIONAL_PRESENT), - optional_value(new T_type(other_value)), - param_refs(0) { } + : optional_value(new T_type(other_value)) + , optional_selection(OPTIONAL_PRESENT) +#ifdef TITAN_RUNTIME_2 + , param_refs(0) +#endif + { } - ~OPTIONAL() - { if (NULL != optional_value) delete optional_value; } + ~OPTIONAL() { +#ifdef TITAN_RUNTIME_2 + if (NULL != optional_value) +#else + if (optional_selection == OPTIONAL_PRESENT) +#endif + delete optional_value; + } void clean_up(); @@ -161,12 +185,20 @@ public: { return is_equal(other_value); } #endif +#ifdef TITAN_RUNTIME_2 boolean is_bound() const; +#else + inline boolean is_bound() const { return optional_selection != OPTIONAL_UNBOUND; } +#endif boolean is_value() const { return optional_selection == OPTIONAL_PRESENT && optional_value->is_value(); } /** Whether the optional value is present. * @return \c true if optional_selection is OPTIONAL_PRESENT, else \c false */ +#ifdef TITAN_RUNTIME_2 boolean is_present() const; +#else + inline boolean is_present() const { return optional_selection==OPTIONAL_PRESENT; } +#endif #ifdef TITAN_RUNTIME_2 /** @name override virtual functions of Base_Type @@ -207,9 +239,14 @@ public: */ boolean ispresent() const; +#ifdef TITAN_RUNTIME_2 /** @tricky Calculates and returns the actual state of the optional object, - * not just the optional_selection member. */ + * not just the optional_selection member. + * (Only needed in Runtime2, in Runtime1 optional_selection is always up to date.) */ optional_sel get_selection() const; +#else + inline optional_sel get_selection() const { return optional_selection; } +#endif void log() const; void set_param(Module_Param& param); @@ -221,10 +258,12 @@ public: raw_order_t top_bit_ord, boolean no_err=FALSE, int sel_field=-1, boolean first_call=TRUE); #endif - int XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& buf, unsigned int flavor, int indent) const; + int XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& buf, unsigned int flavor, + int indent, embed_values_enc_struct_t* emb_val) const; #ifdef TITAN_RUNTIME_2 int XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, - const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned int flavor, int indent) const; + const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned int flavor, + int indent, embed_values_enc_struct_t* emb_val) const; #endif /** Used during XML decoding, in case this object is an AnyElement field in a record. * Determines whether XER_decode() should be called or this field should be omitted. @@ -236,7 +275,8 @@ public: * @param next_field_name name of the next field in the record, or null if this is the last one * @param parent_tag_closed true, if the record's XML tag is closed (is an empty element)*/ bool XER_check_any_elem(XmlReaderWrap& reader, const char* next_field_name, bool parent_tag_closed); - int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor); + int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, + unsigned int flavor, embed_values_dec_struct_t* emb_val); char ** collect_ns(const XERdescriptor_t& p_td, size_t& num, bool& def_ns) const; @@ -274,16 +314,18 @@ public: * Returns the length of the decoded data. */ int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean); +#ifdef TITAN_RUNTIME_2 /** Called before an element of an optional record of/set of is indexed and passed as an - * 'inout' or 'out' parameter to a function. + * '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); /** Called after an element of an optional record of/set of is passed as an - * 'inout' or 'out' parameter to a function. + * 'inout' or 'out' parameter to a function (only in Runtime2). * Redirects the call to the optional value. */ 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/ @@ -302,7 +344,11 @@ public: template Base_Type* OPTIONAL::get_opt_value() { +#ifdef TITAN_RUNTIME_2 if (!is_present()) +#else + if (optional_selection!=OPTIONAL_PRESENT) +#endif TTCN_error("Internal error: get_opt_value() called on a non-present optional field."); return optional_value; } @@ -310,7 +356,11 @@ Base_Type* OPTIONAL::get_opt_value() template const Base_Type* OPTIONAL::get_opt_value() const { +#ifdef TITAN_RUNTIME_2 if (!is_present()) +#else + if (optional_selection!=OPTIONAL_PRESENT) +#endif TTCN_error("Internal error: get_opt_value() const called on a non-present optional field."); return optional_value; } @@ -318,20 +368,35 @@ const Base_Type* OPTIONAL::get_opt_value() const template boolean OPTIONAL::is_seof() const { - return (is_present()) ? optional_value->is_seof() : T_type().is_seof(); + return +#ifdef TITAN_RUNTIME_2 + (is_present()) +#else + (optional_selection==OPTIONAL_PRESENT) +#endif + ? optional_value->is_seof() : T_type().is_seof(); } template const TTCN_Typedescriptor_t* OPTIONAL::get_descriptor() const { - return (is_present()) ? optional_value->get_descriptor() : T_type().get_descriptor(); + return +#ifdef TITAN_RUNTIME_2 + (is_present()) +#else + (optional_selection==OPTIONAL_PRESENT) +#endif + ? optional_value->get_descriptor() : T_type().get_descriptor(); } #endif template OPTIONAL::OPTIONAL(template_sel other_value) - : optional_selection(OPTIONAL_OMIT), optional_value(NULL), param_refs(0) + : optional_value(NULL), optional_selection(OPTIONAL_OMIT) +#ifdef TITAN_RUNTIME_2 + , param_refs(0) +#endif { if (other_value != OMIT_VALUE) TTCN_error("Setting an optional field to an invalid value."); @@ -340,9 +405,11 @@ OPTIONAL::OPTIONAL(template_sel other_value) template OPTIONAL::OPTIONAL(const OPTIONAL& other_value) : Base_Type(other_value) - , optional_selection(other_value.optional_selection) , optional_value(NULL) + , optional_selection(other_value.optional_selection) +#ifdef TITAN_RUNTIME_2 , param_refs(0) +#endif { switch (other_value.optional_selection) { case OPTIONAL_PRESENT: @@ -357,7 +424,10 @@ OPTIONAL::OPTIONAL(const OPTIONAL& other_value) template template OPTIONAL::OPTIONAL(const OPTIONAL& other_value) - : optional_selection(other_value.get_selection()), optional_value(NULL), param_refs(0) + : optional_value(NULL), optional_selection(other_value.get_selection()) +#ifdef TITAN_RUNTIME_2 + , param_refs(0) +#endif { switch (other_value.get_selection()) { case OPTIONAL_PRESENT: @@ -373,6 +443,7 @@ OPTIONAL::OPTIONAL(const OPTIONAL& other_value) template void OPTIONAL::clean_up() { +#ifdef TITAN_RUNTIME_2 if (is_present()) { if (param_refs > 0) { optional_value->clean_up(); @@ -382,6 +453,11 @@ void OPTIONAL::clean_up() optional_value = NULL; } } +#else + if (OPTIONAL_PRESENT == optional_selection) { + delete optional_value; + } +#endif optional_selection = OPTIONAL_UNBOUND; } @@ -399,9 +475,13 @@ OPTIONAL& OPTIONAL::operator=(const OPTIONAL& other_value) { switch (other_value.optional_selection) { case OPTIONAL_PRESENT: - optional_selection = OPTIONAL_PRESENT; +#ifdef TITAN_RUNTIME_2 if (NULL == optional_value) { +#else + if (optional_selection != OPTIONAL_PRESENT) { +#endif optional_value = new T_type(*other_value.optional_value); + optional_selection = OPTIONAL_PRESENT; } else *optional_value = *other_value.optional_value; break; case OPTIONAL_OMIT: @@ -420,9 +500,13 @@ OPTIONAL::operator=(const OPTIONAL& other_value) { switch (other_value.get_selection()) { case OPTIONAL_PRESENT: - optional_selection = OPTIONAL_PRESENT; +#ifdef TITAN_RUNTIME_2 if (NULL == optional_value) { +#else + if (optional_selection != OPTIONAL_PRESENT) { +#endif optional_value = new T_type((const T_tmp&)other_value); + optional_selection = OPTIONAL_PRESENT; } else *optional_value = (const T_tmp&)other_value; break; case OPTIONAL_OMIT: @@ -439,9 +523,13 @@ template template OPTIONAL& OPTIONAL::operator=(const T_tmp& other_value) { - optional_selection = OPTIONAL_PRESENT; +#ifdef TITAN_RUNTIME_2 if (NULL == optional_value) { +#else + if (optional_selection != OPTIONAL_PRESENT) { +#endif optional_value = new T_type(other_value); + optional_selection = OPTIONAL_PRESENT; } else *optional_value = other_value; return *this; } @@ -449,28 +537,52 @@ OPTIONAL::operator=(const T_tmp& other_value) template boolean OPTIONAL::is_equal(template_sel other_value) const { +#ifdef TITAN_RUNTIME_2 if (!is_bound()) { +#else + if (optional_selection == OPTIONAL_UNBOUND) { +#endif if (other_value == UNINITIALIZED_TEMPLATE) return TRUE; TTCN_error("The left operand of comparison is an unbound optional value."); } if (other_value != OMIT_VALUE) TTCN_error("Internal error: The right operand " "of comparison is an invalid value."); - return !is_present(); + return +#ifdef TITAN_RUNTIME_2 + !is_present(); +#else + optional_selection == OPTIONAL_OMIT; +#endif } template boolean OPTIONAL::is_equal(const OPTIONAL& other_value) const { +#ifdef TITAN_RUNTIME_2 if (!is_bound()) { - if (!other_value.is_bound()) return TRUE; + if (!other_value.is_bound()) +#else + if (optional_selection == OPTIONAL_UNBOUND) { + if (other_value.optional_selection == OPTIONAL_UNBOUND) +#endif + return TRUE; TTCN_error("The left operand of " "comparison is an unbound optional value."); } +#ifdef TITAN_RUNTIME_2 if (!other_value.is_bound()) +#else + if (other_value.optional_selection == OPTIONAL_UNBOUND) +#endif TTCN_error("The right operand of comparison is an unbound optional value."); +#ifdef TITAN_RUNTIME_2 boolean present = is_present(); if (present != other_value.is_present()) return FALSE; else if (present) +#else + if (optional_selection != other_value.optional_selection) return FALSE; + else if (optional_selection == OPTIONAL_PRESENT) +#endif return *optional_value == *other_value.optional_value; else return TRUE; } @@ -478,7 +590,11 @@ boolean OPTIONAL::is_equal(const OPTIONAL& other_value) const template template boolean OPTIONAL::is_equal(const T_tmp& other_value) const { +#ifdef TITAN_RUNTIME_2 switch (get_selection()) { +#else + switch (optional_selection) { +#endif case OPTIONAL_PRESENT: return *optional_value == other_value; case OPTIONAL_OMIT: @@ -492,20 +608,37 @@ boolean OPTIONAL::is_equal(const T_tmp& other_value) const template template boolean OPTIONAL::is_equal(const OPTIONAL& other_value) const { +#ifdef TITAN_RUNTIME_2 if (!is_bound()) { - if (!other_value.is_bound()) return TRUE; + if (!other_value.is_bound()) +#else + optional_sel other_selection = other_value.get_selection(); + if (optional_selection == OPTIONAL_UNBOUND) { + if (other_selection == OPTIONAL_UNBOUND) +#endif + return TRUE; TTCN_error("The left operand of " "comparison is an unbound optional value."); } - if (!other_value.is_bound()) TTCN_error("The right operand of " - "comparison is an unbound optional value."); +#ifdef TITAN_RUNTIME_2 + if (!other_value.is_bound()) +#else + if (other_selection == OPTIONAL_UNBOUND) +#endif + TTCN_error("The right operand of comparison is an unbound optional value."); +#ifdef TITAN_RUNTIME_2 boolean present = is_present(); if (present != other_value.is_present()) return FALSE; else if (present) +#else + if (optional_selection != other_selection) return FALSE; + else if (optional_selection == OPTIONAL_PRESENT) +#endif return *optional_value == (const T_tmp&)other_value; else return TRUE; } +#ifdef TITAN_RUNTIME_2 template boolean OPTIONAL::is_bound() const { @@ -535,6 +668,7 @@ boolean OPTIONAL::is_present() const return FALSE; } } +#endif template boolean OPTIONAL::ispresent() const @@ -543,19 +677,24 @@ boolean OPTIONAL::ispresent() const case OPTIONAL_PRESENT: return TRUE; case OPTIONAL_OMIT: +#ifdef TITAN_RUNTIME_2 if (NULL != optional_value) { return optional_value->is_bound(); } +#endif return FALSE; default: +#ifdef TITAN_RUNTIME_2 if (NULL != optional_value && optional_value->is_bound()) { return TRUE; } +#endif TTCN_error("Using an unbound optional field."); - return FALSE; } + return FALSE; } +#ifdef TITAN_RUNTIME_2 template optional_sel OPTIONAL::get_selection() const { @@ -568,11 +707,16 @@ optional_sel OPTIONAL::get_selection() const } return OPTIONAL_UNBOUND; } +#endif template void OPTIONAL::log() const { +#ifdef TITAN_RUNTIME_2 switch (get_selection()) { +#else + switch (optional_selection) { +#endif case OPTIONAL_PRESENT: optional_value->log(); break; @@ -600,7 +744,11 @@ void OPTIONAL::set_param(Module_Param& param) { template void OPTIONAL::encode_text(Text_Buf& text_buf) const { +#ifdef TITAN_RUNTIME_2 switch (get_selection()) { +#else + switch (optional_selection) { +#endif case OPTIONAL_OMIT: text_buf.push_int((RInt)FALSE); break; @@ -625,7 +773,11 @@ void OPTIONAL::decode_text(Text_Buf& text_buf) template int OPTIONAL::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok) const { +#ifdef TITAN_RUNTIME_2 switch(get_selection()) { +#else + switch(optional_selection) { +#endif case OPTIONAL_PRESENT: return optional_value->JSON_encode(p_td, p_tok); case OPTIONAL_OMIT: @@ -640,33 +792,36 @@ int OPTIONAL::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokeni template int OPTIONAL::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent) { + // try the optional value first + set_to_present(); size_t buf_pos = p_tok.get_buf_pos(); - json_token_t token = JSON_TOKEN_NONE; - int dec_len = p_tok.get_next_token(&token, NULL, NULL); - if (JSON_TOKEN_ERROR == token) { - JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, ""); - dec_len = JSON_ERROR_FATAL; - } - else if (JSON_TOKEN_LITERAL_NULL == token) { - set_to_omit(); + int dec_len = optional_value->JSON_decode(p_td, p_tok, p_silent); + if (JSON_ERROR_FATAL == dec_len) { + if (p_silent) { + clean_up(); + } else { + set_to_omit(); + } } - else { - // read the token again - set_to_present(); + else if (JSON_ERROR_INVALID_TOKEN == dec_len) { + // invalid token, rewind the buffer and check if it's a "null" (= omit) + // this needs to be checked after the optional value, because it might also be + // able to decode a "null" value p_tok.set_buf_pos(buf_pos); - int ret_val = optional_value->JSON_decode(p_td, p_tok, p_silent); - if (0 > ret_val) { - if (p_silent) { - clean_up(); - } else { - set_to_omit(); - } + json_token_t token = JSON_TOKEN_NONE; + dec_len = p_tok.get_next_token(&token, NULL, NULL); + if (JSON_TOKEN_LITERAL_NULL == token) { + set_to_omit(); + } + else { + // cannot get JSON_TOKEN_ERROR here, that was already checked by the optional value + dec_len = JSON_ERROR_INVALID_TOKEN; } - dec_len = ret_val; } return dec_len; } +#ifdef TITAN_RUNTIME_2 template void OPTIONAL::add_refd_index(int index) { @@ -681,15 +836,7 @@ void OPTIONAL::remove_refd_index(int index) --param_refs; optional_value->remove_refd_index(index); } - -template -int OPTIONAL::size_of() -{ - if (!is_present()) { - return 0; - } - return optional_value->size_of(); -} +#endif template OPTIONAL::operator T_type&() @@ -701,7 +848,11 @@ OPTIONAL::operator T_type&() template OPTIONAL::operator const T_type&() const { +#ifdef TITAN_RUNTIME_2 if (!is_present()) +#else + if (optional_selection != OPTIONAL_PRESENT) +#endif TTCN_error("Using the value of an optional field containing omit."); return *optional_value; } @@ -712,7 +863,11 @@ OPTIONAL::BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const { BER_chk_descr(p_td); +#ifdef TITAN_RUNTIME_2 switch (get_selection()) { +#else + switch (optional_selection) { +#endif case OPTIONAL_PRESENT: return optional_value->BER_encode_TLV(p_td, p_coding); case OPTIONAL_OMIT: @@ -729,7 +884,11 @@ OPTIONAL::BER_encode_TLV_negtest(const Erroneous_descriptor_t* p_err_des const TTCN_Typedescriptor_t& p_td, unsigned p_coding) const { BER_chk_descr(p_td); +#ifdef TITAN_RUNTIME_2 switch (get_selection()) { +#else + switch (optional_selection) { +#endif case OPTIONAL_PRESENT: return optional_value->BER_encode_TLV_negtest(p_err_descr, p_td, p_coding); case OPTIONAL_OMIT: @@ -752,11 +911,15 @@ int OPTIONAL::RAW_decode(const TTCN_Typedescriptor_t& p_td, template int -OPTIONAL::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& buf, unsigned int flavor, int indent) const +OPTIONAL::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& buf, unsigned int flavor, int indent, embed_values_enc_struct_t* emb_val) const { +#ifdef TITAN_RUNTIME_2 switch (get_selection()) { +#else + switch (optional_selection) { +#endif case OPTIONAL_PRESENT: - return optional_value->XER_encode(p_td, buf, flavor, indent); + return optional_value->XER_encode(p_td, buf, flavor, indent, emb_val); case OPTIONAL_OMIT: return 0; // nothing to do ! default: @@ -770,11 +933,12 @@ OPTIONAL::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& buf, unsi template int OPTIONAL::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, - const XERdescriptor_t& p_td, TTCN_Buffer& buf, unsigned int flavor, int indent) const + const XERdescriptor_t& p_td, TTCN_Buffer& buf, unsigned int flavor, int indent, + embed_values_enc_struct_t* emb_val) const { switch (get_selection()) { case OPTIONAL_PRESENT: - return optional_value->XER_encode_negtest(p_err_descr, p_td, buf, flavor, indent); + return optional_value->XER_encode_negtest(p_err_descr, p_td, buf, flavor, indent, emb_val); case OPTIONAL_OMIT: return 0; // nothing to do ! default: @@ -819,7 +983,8 @@ OPTIONAL::XER_check_any_elem(XmlReaderWrap& reader, const char* next_fie template int -OPTIONAL::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor) +OPTIONAL::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, + unsigned int flavor, embed_values_dec_struct_t* emb_val) { int exer = is_exer(flavor); for (int success = reader.Ok(); success==1; success=reader.Read()) { @@ -841,7 +1006,7 @@ OPTIONAL::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, if (!check_namespace((const char*)reader.NamespaceUri(), p_td)) break; set_to_present(); - optional_value->XER_decode(p_td, reader, flavor); + optional_value->XER_decode(p_td, reader, flavor, emb_val); goto finished; } else break; @@ -858,7 +1023,7 @@ OPTIONAL::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, found_it: set_to_present(); //success = reader.Read(); // move to next thing TODO should it loop till an element ? - optional_value->XER_decode(p_td, reader, flavor); + optional_value->XER_decode(p_td, reader, flavor, emb_val); } else break; // it's not us, bail @@ -881,7 +1046,11 @@ finished: template char ** OPTIONAL::collect_ns(const XERdescriptor_t& p_td, size_t& num, bool& def_ns) const { +#ifdef TITAN_RUNTIME_2 switch (get_selection()) { +#else + switch (optional_selection) { +#endif case OPTIONAL_PRESENT: return optional_value->collect_ns(p_td, num, def_ns); case OPTIONAL_OMIT: @@ -921,8 +1090,12 @@ template void OPTIONAL::BER_decode_opentypes(TTCN_Type_list& p_typelist, unsigned L_form) { +#ifdef TITAN_RUNTIME_2 if (is_present()) { optional_selection = OPTIONAL_PRESENT; +#else + if (optional_selection==OPTIONAL_PRESENT) { +#endif optional_value->BER_decode_opentypes(p_typelist, L_form); } } @@ -933,7 +1106,7 @@ template int OPTIONAL::TEXT_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& buff) const { - if (get_selection()) + if (is_present()) return optional_value->TEXT_encode(p_td, buff); TTCN_error("Internal error: TEXT encoding an unbound/omit optional field."); return 0; @@ -943,7 +1116,7 @@ template int OPTIONAL::TEXT_encode_negtest(const Erroneous_descriptor_t* p_err_descr, const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& buff) const { - if (get_selection()) + if (is_present()) return optional_value->TEXT_encode_negtest(p_err_descr, p_td, buff); TTCN_error("Internal error: TEXT encoding an unbound/omit optional field."); return 0; diff --git a/core/Profiler.cc b/core/Profiler.cc new file mode 100644 index 0000000..860e5c8 --- /dev/null +++ b/core/Profiler.cc @@ -0,0 +1,839 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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.hh" +#include +#include +#include +#include +#include "JSON_Tokenizer.hh" +#include "memory.h" +#include "Runtime.hh" + +//////////////////////////////////// +////////// TTCN3_Profiler ////////// +//////////////////////////////////// + +TTCN3_Profiler ttcn3_prof; + +TTCN3_Profiler::TTCN3_Profiler() +: disable_profiler(FALSE), disable_coverage(FALSE), aggregate_data(FALSE) +, disable_stats(FALSE) +{ + database_filename = mcopystr("profiler.db"); + stats_filename = mcopystr("profiler.stats"); + reset(); +} + +TTCN3_Profiler::~TTCN3_Profiler() +{ + if (!disable_profiler || !disable_coverage) { + import_data(); + export_data(); + if (!disable_stats && (TTCN_Runtime::is_single() || TTCN_Runtime::is_hc())) { + print_stats(); + } + } + for (size_t i = 0; i < profiler_db.size(); ++i) { + Free(profiler_db[i].filename); + for (size_t j = 0; j < profiler_db[i].functions.size(); ++j) { + Free(profiler_db[i].functions[j].name); + } + } + Free(database_filename); + Free(stats_filename); +} + +void TTCN3_Profiler::set_disable_profiler(boolean p_disable_profiler) +{ + disable_profiler = p_disable_profiler; +} + +void TTCN3_Profiler::set_disable_coverage(boolean p_disable_coverage) +{ + disable_coverage = p_disable_coverage; +} + +void TTCN3_Profiler::set_database_filename(const char* p_database_filename) +{ + Free(database_filename); + database_filename = mcopystr(p_database_filename); +} + +void TTCN3_Profiler::set_aggregate_data(boolean p_aggregate_data) +{ + aggregate_data = p_aggregate_data; +} + +void TTCN3_Profiler::set_stats_filename(const char* p_stats_filename) +{ + Free(stats_filename); + stats_filename = mcopystr(p_stats_filename); +} + +void TTCN3_Profiler::set_disable_stats(boolean p_disable_stats) +{ + disable_stats = p_disable_stats; +} + +boolean TTCN3_Profiler::is_profiler_disabled() const +{ + return disable_profiler; +} + +#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() +{ + // delete the database file (from the previous run) if data aggregation is not set + if (!aggregate_data && (!disable_profiler || !disable_coverage)) { + remove(database_filename); + } +} + +void TTCN3_Profiler::import_data() +{ + // open the file, if it exists + FILE* file = fopen(database_filename, "r"); + if (NULL == file) { + return; + } + + // get the file size + fseek(file, 0, SEEK_END); + int file_size = ftell(file); + rewind(file); + + // read the entire file into a character buffer + char* buffer = (char*)Malloc(file_size); + fread(buffer, 1, file_size, file); + + // initialize a JSON tokenizer with the buffer + JSON_Tokenizer json(buffer, file_size); + Free(buffer); + + // attempt to read tokens from the buffer + // if the format is invalid, abort the importing process + json_token_t token = JSON_TOKEN_NONE; + char* value = NULL; + size_t value_len = 0; + + // start of main array + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token); + + // read objects (one for each TTCN-3 file), until the main array end mark is reached + json.get_next_token(&token, NULL, NULL); + while (JSON_TOKEN_OBJECT_START == token) { + size_t file_index = 0; + + // file name: + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 4 || + 0 != strncmp(value, "file", value_len)); + + // read the file name and see if its record already exists + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_STRING != token); + for (file_index = 0; file_index < profiler_db.size(); ++file_index) { + if (strlen(profiler_db[file_index].filename) == value_len - 2 && + 0 == strncmp(profiler_db[file_index].filename, value + 1, value_len - 2)) { + break; + } + } + + // insert a new element if the file was not found + if (profiler_db.size() == file_index) { + profiler_db_item_t item; + item.filename = mcopystrn(value + 1, value_len - 2); + profiler_db.push_back(item); + } + + // functions: + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 9 || + 0 != strncmp(value, "functions", value_len)); + + // read and store the functions (an array of objects, same as before) + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token); + json.get_next_token(&token, NULL, NULL); + while (JSON_TOKEN_OBJECT_START == token) { + size_t function_index = 0; + + // function name: + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 4 || + 0 != strncmp(value, "name", value_len)); + + // read the function name, it will be checked later + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_STRING != token); + char* function_name = mcopystrn(value + 1, value_len - 2); + + // function start line: + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 10 || + 0 != strncmp(value, "start line", value_len)); + + // read the start line and check if the function already exists + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NUMBER != token); + int start_line = atoi(value); + for (function_index = 0; function_index < profiler_db[file_index].functions.size(); ++function_index) { + if (profiler_db[file_index].functions[function_index].lineno == start_line && + 0 == strcmp(profiler_db[file_index].functions[function_index].name, function_name)) { + break; + } + } + + // insert a new element if the function was not found + if (profiler_db[file_index].functions.size() == function_index) { + profiler_db_item_t::profiler_function_data_t func_data; + func_data.name = function_name; + func_data.lineno = start_line; + func_data.exec_count = 0; + func_data.total_time = 0.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)); + + // 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 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); + } + + // end of the function's object + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token); + + // read the next token (either the start of another object or the function array end) + json.get_next_token(&token, NULL, NULL); + } + + // function array end + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token); + + // lines: + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 5 || + 0 != strncmp(value, "lines", value_len)); + + // read and store the lines (an array of objects, same as before) + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token); + json.get_next_token(&token, NULL, NULL); + while (JSON_TOKEN_OBJECT_START == token) { + + // line number: + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 6 || + 0 != strncmp(value, "number", value_len)); + + // read the line number and check if the line already exists + json.get_next_token(&token, &value, &value_len); + 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); + } + } + + 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)); + + // 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); + } + + 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)); + + // 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); + } + + // end of the line's object + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token); + + // read the next token (either the start of another object or the line array end) + json.get_next_token(&token, NULL, NULL); + } + + // line array end + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token); + + // end of the file's object + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token); + + // read the next token (either the start of another object or the main array end) + json.get_next_token(&token, NULL, NULL); + } + + // main array end + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token); +} + +void TTCN3_Profiler::export_data() +{ + // nothing to export if the database is empty + if (profiler_db.empty()) { + return; + } + + // check whether the file can be opened for writing + FILE* file = fopen(database_filename, "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); + return; + } + + // use the JSON tokenizer to create a JSON document from the database + JSON_Tokenizer json(true); + + // main array, contains an element for each file + json.put_next_token(JSON_TOKEN_ARRAY_START, NULL); + for (size_t i = 0; i < profiler_db.size(); ++i) { + + // each file's data is stored in an object + json.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + + // store the file name + json.put_next_token(JSON_TOKEN_NAME, "file"); + char* file_name_str = mprintf("\"%s\"", profiler_db[i].filename); + json.put_next_token(JSON_TOKEN_STRING, file_name_str); + Free(file_name_str); + + // store the function data in an array (one element for each function) + 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) { + + // 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) { + // 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); + 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); + } + + // end of function object + json.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + } + + // end of function data array + json.put_next_token(JSON_TOKEN_ARRAY_END, NULL); + + // store the line data in an array (one element for each line with useful 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 || + 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); + 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); + } + + // end of this line's object + json.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + } + } + + // end of line data array + json.put_next_token(JSON_TOKEN_ARRAY_END, NULL); + + // end of this file's object + json.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + } + + // end of main array + json.put_next_token(JSON_TOKEN_ARRAY_END, NULL); + + // write the JSON document into the file + fprintf(file, "%s\n", json.get_buffer()); + fclose(file); +} + +void TTCN3_Profiler::print_stats() +{ + if (profiler_db.empty()) { + return; + } + + // title + char* title_str = mprintf( + "##################################################\n" + "%s## TTCN-3 %s%s%sstatistics ##%s\n" + "##################################################\n\n\n" + , disable_profiler ? "#######" : (disable_coverage ? "#########" : "") + , disable_profiler ? "" : "profiler " + , (disable_profiler || disable_coverage) ? "" : "and " + , disable_coverage ? "" : "code coverage " + , disable_profiler ? "######" : (disable_coverage ? "#########" : "")); + + // 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 ? "---------" : "")); + + // average time / exec count for lines + char* line_avg_str = NULL; + if (!disable_coverage && !disable_profiler) { + line_avg_str = mcopystr( + "-------------------------------------------------\n" + "- Average time / execution count 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 ? "---------" : "")); + + // average time / exec count for functions + char* func_avg_str = NULL; + if (!disable_coverage && !disable_profiler) { + func_avg_str = mcopystr( + "------------------------------------------------\n" + "- Average time / execution count for functions -\n" + "------------------------------------------------\n"); + } + + // 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"); + } + } + + // 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) { + if (!disable_profiler) { + line_data_str = mputprintf(line_data_str, "%.6lfs", profiler_db[i].lines[j].total_time); + 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 (!disable_coverage) { + 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); + } + } + } + + // 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); + } + } + if (!disable_coverage) { + func_data_str = mputprintf(func_data_str, "%d", profiler_db[i].functions[j].exec_count); + } + + // 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); + + // 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); + } + } + } + + // 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); + } + + // write the statistics to the specified file + FILE* file = fopen(stats_filename, "w"); + if (NULL == file) { + TTCN_warning("Could not open file '%s' for writing. Profiler and/or code coverage " + "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); + fclose(file); +} + +void TTCN3_Profiler::reset() +{ + prev_time = 0.0; + prev_file = NULL; + prev_line = -1; + prev_stack_len = 0; +} + +double TTCN3_Profiler::get_time() +{ + timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec + tv.tv_usec / 1000000.0; +} + +void TTCN3_Profiler::enter_function(const char* filename, int lineno, const char* function_name) +{ + if (disable_profiler && disable_coverage) { + return; + } + + // Note that the execution time of the last line in a function + // 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; + } +} + +void TTCN3_Profiler::execute_line(const char* filename, int lineno) +{ + if (disable_profiler && disable_coverage) { + 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; + + // add the elapsed time to the 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; + } + + // store the current location as previous for the next call + set_prev(disable_profiler ? -1 : TTCN3_Stack_Depth::depth(), filename, lineno); +} + +int TTCN3_Profiler::get_element(const char* filename) +{ + for (size_t i = 0; i < profiler_db.size(); ++i) { + if (0 == strcmp(profiler_db[i].filename, filename)) { + return i; + } + } + + profiler_db_item_t item; + item.filename = mcopystr(filename); + profiler_db.push_back(item); + return profiler_db.size() - 1; +} + +int TTCN3_Profiler::get_function(int element, int lineno) +{ + for (size_t i = 0; i < profiler_db[element].functions.size(); ++i) { + if (profiler_db[element].functions[i].lineno == lineno) { + return i; + } + } + return -1; +} + +void TTCN3_Profiler::create_function(int element, int lineno, const char* function_name) +{ + profiler_db_item_t::profiler_function_data_t func_data; + func_data.lineno = lineno; + func_data.total_time = 0.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) +{ + // 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); + } + } +} + +void TTCN3_Profiler::add_line_time(double elapsed, int element, int lineno) +{ + if (-1 == 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; +} + +void TTCN3_Profiler::add_function_time(double elapsed, int element, int lineno) +{ + int func = get_function(element, lineno); + if (-1 == func) { + return; + } + profiler_db[element].functions[func].total_time += elapsed; +} + +void TTCN3_Profiler::update_last() +{ + if (0.0 == prev_time) { + return; + } + + double currentTime = get_time(); + double elapsed = currentTime - prev_time; + + int element = get_element(prev_file); + + // add the elapsed time to the 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; +} + +void TTCN3_Profiler::set_prev(int stack_len, const char* filename, int lineno) +{ + prev_file = filename; + prev_line = lineno; + if (!disable_profiler) { + prev_time = get_time(); + prev_stack_len = stack_len; + } +} + +///////////////////////////////////// +///////// TTCN3_Stack_Depth ///////// +///////////////////////////////////// + +int TTCN3_Stack_Depth::current_depth = -1; +Vector TTCN3_Stack_Depth::call_stack_timer_db; + +TTCN3_Stack_Depth::TTCN3_Stack_Depth() +{ + if (ttcn3_prof.is_profiler_disabled()) { + return; + } + ++current_depth; +} + +TTCN3_Stack_Depth::~TTCN3_Stack_Depth() +{ + if (ttcn3_prof.is_profiler_disabled()) { + return; + } + ttcn3_prof.update_last(); + remove_stack(); + if (0 == current_depth) { + ttcn3_prof.reset(); + } + --current_depth; +} + +void TTCN3_Stack_Depth::add_stack(int stack_len, const char* caller_file, const char* func_file, + int caller_line, int start_line) +{ + call_stack_timer_item_t item; + item.stack_len = stack_len; + item.caller_file = caller_file; + item.func_file = func_file; + item.caller_line = caller_line; + item.start_line = start_line; + item.elapsed = 0.0; + 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); + + ttcn3_prof.set_prev(call_stack_timer_db[current_depth].stack_len, + call_stack_timer_db[current_depth].caller_file, + call_stack_timer_db[current_depth].caller_line); + + call_stack_timer_db.erase_at(current_depth); +} + +void TTCN3_Stack_Depth::update_stack_elapsed(double elapsed) +{ + for(int i = 0; i <= current_depth; i++) { + call_stack_timer_db[i].elapsed += elapsed; + } +} \ No newline at end of file diff --git a/core/Profiler.hh b/core/Profiler.hh new file mode 100644 index 0000000..c84bb97 --- /dev/null +++ b/core/Profiler.hh @@ -0,0 +1,193 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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_HH +#define PROFILER_HH + +#include "Vector.hh" +#include "Types.h" + +/** This class performs profiling and code coverage on lines and functions in + * TTCN-3 code (requires the -z compiler option). + * Customizable through the configuration file's [PROFILER] section. */ +class TTCN3_Profiler { +public: + + /** Database entry for one file */ + struct profiler_db_item_t { + /** Database entry for one line */ + struct profiler_line_data_t { + /** The line's total execution time */ + double total_time; + /** The number of times this line was executed */ + int exec_count; + }; + /** Database entry for one function (including test cases, alt steps, the control part, etc.) */ + struct profiler_function_data_t { + /** Function name (owned) */ + char* name; + /** Function starting line */ + int lineno; + /** The function's total execution time */ + double 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) */ + Vector lines; + /** Contains database entries for all the functions in this file (one entry + * for each function) */ + Vector functions; + }; + + /** Constructor */ + TTCN3_Profiler(); + /** Destructor - adds all gathered data to the database file and prints + * statistics if necessary */ + ~TTCN3_Profiler(); + + /** 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 */ + void set_disable_coverage(boolean p_disable_coverage); + /** Sets the database file name (default is "profiler.db" - called by the config file parser */ + void set_database_filename(const char* p_database_filename); + /** Enables or disables data aggregation - called by the config file parser */ + void set_aggregate_data(boolean p_aggregate_data); + /** Sets the statistics file name (default is "profiler.stats" - called by the config file parser */ + 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); + + /** Returns true if profiling is disabled */ + boolean is_profiler_disabled() const; + + /** Deletes the database file if data aggregation is not set */ + void init_data_file(); + /** Adds the data from the database file to the local database */ + void import_data(); + /** Writes the local database to the database file (overwrites the file) */ + void export_data(); + + /** Calculates and prints statistics from the gathered data */ + void print_stats(); + + /** 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(); + /** Called when a TTCN-3 function starts execution - stores data */ + void enter_function(const char* filename, int lineno, const char* function_name); + /** 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 */ + int get_element(const char* filename); + /** Returns the index of a TTCN-3 function's entry in the database + * @param element index of the file (where the function is declared) + * @param lineno function start line */ + int get_function(int element, int lineno); + /** Creates a new TTCN-3 function entry and inserts it in the database + * @param element file entry's index + * @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); + /** Adds elapsed time to the specified TTCN-3 code line's total time */ + void add_line_time(double 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); + /** 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: + /** Profiling is disabled if true */ + boolean disable_profiler; + /** Code coverage is disabled if true */ + boolean disable_coverage; + /** Contains the database file name */ + char* database_filename; + /** If true, data gathered by previous runs will be added to the data gathered + * in this run */ + boolean aggregate_data; + /** Contains the statistics file name */ + char* stats_filename; + /** Statistics will not be calculated and printed if true */ + boolean disable_stats; + + /** The time measured at the previous TTCN-3 code line */ + double 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 */ + int prev_line; + /** The local database */ + Vector profiler_db; + /** The stack length at the previously executed line */ + int prev_stack_len; +}; + +/** The global TTCN3_Profiler object + * + * One instance is created in each process (in parallel mode). + * After construction the configuration file parser may change the profiler's settings. + * The destructor merges its data with that of other processes (and possibly with previous runs) + * through the database file. The last destructor (the one in the Host Controller's process) + * prints the statistics (if enabled). */ +extern TTCN3_Profiler ttcn3_prof; + +/** Helper class for profiling + * + * 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: + /** 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)*/ + 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; + }; + + /** Constructor - increases the stack depth */ + TTCN3_Stack_Depth(); + /** Destructor - decreases the stack depth, updates call times in the profiler */ + ~TTCN3_Stack_Depth(); + + /** Returns the current stack depth */ + static int depth() { return current_depth; } + /** Inserts a new function call entry into the call stack database */ + static void add_stack(int stack_len, const char* caller_file, const char* func_file, + int caller_line, int start_line); + /** 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); +private: + /** The current stack depth (starts from 0)*/ + static int current_depth; + /** The call stack database */ + static Vector call_stack_timer_db; +}; + +#endif /* PROFILER_HH */ + diff --git a/core/Template.hh b/core/Template.hh index de50db9..44ccdc4 100644 --- a/core/Template.hh +++ b/core/Template.hh @@ -161,9 +161,11 @@ public: boolean is_omit() const; boolean is_any_or_omit() const; - // Dummy functions, only used in record of/set of value +#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 12a39eb..330f4f2 100644 --- a/core/Universal_charstring.cc +++ b/core/Universal_charstring.cc @@ -1079,7 +1079,7 @@ void UNIVERSAL_CHARSTRING::encode(const TTCN_Typedescriptor_t& p_td, default: // nothing to do break; } - XER_encode(*p_td.xer,p_buf, XER_coding, 0); + XER_encode(*p_td.xer,p_buf, XER_coding, 0, 0); p_buf.put_c('\n'); break; } case TTCN_EncDec::CT_JSON: { @@ -1126,7 +1126,7 @@ void UNIVERSAL_CHARSTRING::decode(const TTCN_Typedescriptor_t& p_td, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break; } @@ -1486,7 +1486,7 @@ boolean UNIVERSAL_CHARSTRING::BER_decode_TLV extern void xml_escape(const unsigned int c, TTCN_Buffer& p_buf); int UNIVERSAL_CHARSTRING::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if(!is_bound()) { TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, @@ -1799,7 +1799,7 @@ in_word_set (const char *str, unsigned int len) universal_char const uspace = {0,0,0,32}; int UNIVERSAL_CHARSTRING::XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor) + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); int success = reader.Ok(), depth = -1; diff --git a/core/Universal_charstring.hh b/core/Universal_charstring.hh index 5185032..62ea9fb 100644 --- a/core/Universal_charstring.hh +++ b/core/Universal_charstring.hh @@ -318,8 +318,8 @@ public: boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const ASN_BER_TLV_t& p_tlv, unsigned L_form); - int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int) const; - int XER_decode(const XERdescriptor_t&, XmlReaderWrap& reader, unsigned int); + 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) * * @param n_octets number of UTF-8 bytes (not characters) diff --git a/core/Verdicttype.cc b/core/Verdicttype.cc index 9cf0f87..e8ba460 100644 --- a/core/Verdicttype.cc +++ b/core/Verdicttype.cc @@ -154,7 +154,7 @@ void VERDICTTYPE::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*p_td.xer, p_buf, XER_coding, 0); + XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); break;} case TTCN_EncDec::CT_JSON: { TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); @@ -227,7 +227,7 @@ void VERDICTTYPE::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, if (type==XML_READER_TYPE_ELEMENT) break; } - XER_decode(*p_td.xer, reader, XER_coding); + XER_decode(*p_td.xer, reader, XER_coding, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -253,7 +253,7 @@ void VERDICTTYPE::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, int VERDICTTYPE::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, - unsigned int p_flavor, int p_indent) const + unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const { int encoded_length=(int)p_buf.get_len(); //const boolean e_xer = is_exer(p_flavor); @@ -285,7 +285,7 @@ verdicttype VERDICTTYPE::str_to_verdict(const char *v, boolean silent) } int VERDICTTYPE::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader, - unsigned int p_flavor) + unsigned int p_flavor, embed_values_dec_struct_t*) { int rd_ok = 1, type; const int e_xer = is_exer(p_flavor); diff --git a/core/Verdicttype.hh b/core/Verdicttype.hh index ea0fdd8..4ea1a52 100644 --- a/core/Verdicttype.hh +++ b/core/Verdicttype.hh @@ -82,9 +82,9 @@ public: TTCN_EncDec::coding_t p_coding, ...); int XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, - unsigned int flavor, int indent) const; + unsigned int flavor, int indent, embed_values_enc_struct_t*) const; int XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, - unsigned int flavor); + unsigned int flavor, embed_values_dec_struct_t*); /** Encodes accordingly to the JSON encoding rules. * Returns the length of the encoded data. */ diff --git a/core/XER.hh b/core/XER.hh index 27c6da5..604ca04 100644 --- a/core/XER.hh +++ b/core/XER.hh @@ -16,6 +16,10 @@ class XmlReaderWrap; class Base_Type; +#ifdef TITAN_RUNTIME_2 +class Record_Of_Type; +class Erroneous_descriptor_t; +#endif class TTCN_Module; /** @defgroup XER XER codec @@ -171,7 +175,7 @@ inline bool is_exerlist(unsigned int f) * Example: * @code * int Foo::XER_encode(const XERdescriptor_t& p_td, - * TTCN_Buffer& p_buf, unsigned int flavor, int indent) const { + * TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { * int canon = is_canonical(flavor); * if (!canon) do_indent(p_buf, indent); * // output the start tag @@ -193,7 +197,7 @@ inline bool is_exerlist(unsigned int f) * * @code * int Foo::XER_encode(const XERdescriptor_t& p_td, - * TTCN_Buffer& p_buf, unsigned int flavor, int indent) const { + * TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { * int canon = is_canonical(flavor); * if (!canon) do_indent(p_buf, indent); * // output an empty element tag @@ -253,6 +257,51 @@ struct XERdescriptor_t const char** ns_uris; }; +/** Information related to the embedded values in XML encoding + * + * Used when a record/set with the EMBED-VALUES coding instruction contains + * one or more record of/set of fields. */ +struct embed_values_enc_struct_t +{ +#ifdef TITAN_RUNTIME_2 + /** Stores the array of embedded values */ + const Record_Of_Type* embval_array; + /** Stores the erroneous descriptor of the embedded values field (for negative tests) */ + const Erroneous_descriptor_t* embval_err; + /** Error value index for the embedded values (for negative tests) */ + int embval_err_val_idx; + /** 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; +#endif + /** Stores the index of the next embedded value to be read */ + int embval_index; +}; + +/** Information related to the embedded values in XML decoding + * + * Used when a record/set with the EMBED-VALUES coding instruction contains + * one or more record of/set of fields. */ +struct embed_values_dec_struct_t +{ +#ifdef TITAN_RUNTIME_2 + /** 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; +#endif + /** Stores the number of embedded values that are currently in the array, + * and the index where the next one should be inserted */ + int embval_index; +}; + /** Check the name of an XML node against a XER type descriptor. * * @param name the (local, unqualified) name of the XML element diff --git a/core/config_process.l b/core/config_process.l index a1bdde0..4d96260 100644 --- a/core/config_process.l +++ b/core/config_process.l @@ -121,7 +121,7 @@ TTCNSTRINGPARSING_COMPONENT "$#&&&(#TTCNSTRINGPARSING_COMPONENT$#&&^#% " %x SC_commentblock SC_cstring SC_DEFINE %s SC_MODULE_PARAMETERS SC_LOGGING SC_TESTPORT_PARAMETERS SC_EXECUTE SC_GROUPS %s SC_COMPONENTS SC_EXTERNAL_COMMANDS SC_MAIN_CONTROLLER SC_INCLUDE SC_ORDERED_INCLUDE -%s SC_STRING2TTCN_COMPONENT +%s SC_STRING2TTCN_COMPONENT SC_PROFILER %% @@ -185,6 +185,13 @@ TTCNSTRINGPARSING_COMPONENT "$#&&&(#TTCNSTRINGPARSING_COMPONENT$#&&^#% " } } +<*>"["{WS}PROFILER{WS}"]" { + if (YY_START!=SC_commentblock && YY_START!=SC_cstring) { + BEGIN(SC_PROFILER); + return ProfilerKeyword; + } +} + <*>"["{WS}TESTPORT_PARAMETERS{WS}"]" { if (YY_START!=SC_commentblock && YY_START!=SC_cstring) { BEGIN(SC_TESTPORT_PARAMETERS); @@ -493,7 +500,7 @@ ifpresent return IfpresentKeyword; infinity return InfinityKeyword; } - + { true { yylval.bool_val = TRUE; @@ -957,6 +964,16 @@ LOG_ALL { [Dd]elete return Delete; } + +{ + [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; +} + control return ControlKeyword; diff --git a/core/config_process.y b/core/config_process.y index dad4009..92c2097 100644 --- a/core/config_process.y +++ b/core/config_process.y @@ -37,6 +37,8 @@ #include "LoggingBits.hh" #include "LoggingParam.hh" +#include "Profiler.hh" + #define YYERROR_VERBOSE #include "config_process.lex.hh" @@ -128,6 +130,7 @@ string_map_t *config_defines; %token ModuleParametersKeyword %token LoggingKeyword +%token ProfilerKeyword %token TestportParametersKeyword %token ExecuteKeyword %token ExternalCommandsKeyword @@ -216,6 +219,12 @@ 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" %type IntegerValue %type FloatValue @@ -375,6 +384,7 @@ ConfigFile: Section: ModuleParametersSection | LoggingSection + | ProfilerSection | TestportParametersSection | ExecuteSection | ExternalCommandsSection @@ -1660,6 +1670,62 @@ LogEventTypesValue: | Detailed { $$ = TTCN_Logger::LOGEVENTTYPES_SUBCATEGORIES; } ; +/*********************** [PROFILER] ********************************/ + +ProfilerSection: + ProfilerKeyword ProfilerSettings +; + +ProfilerSettings: + /* empty */ +| ProfilerSettings ProfilerSetting optSemiColon +; + +ProfilerSetting: + DisableProfilerSetting +| DisableCoverageSetting +| DatabaseFileSetting +| AggregateDataSetting +| StatisticsFileSetting +| DisableStatisticsSetting +; + +DisableProfilerSetting: + DisableProfilerKeyword AssignmentChar BooleanValue { + ttcn3_prof.set_disable_profiler($3); + } +; + +DisableCoverageSetting: + DisableCoverageKeyword AssignmentChar BooleanValue { + ttcn3_prof.set_disable_coverage($3); + } +; + +DatabaseFileSetting: + DatabaseFileKeyword AssignmentChar StringValue { + ttcn3_prof.set_database_filename($3); + } +; + +AggregateDataSetting: + AggregateDataKeyword AssignmentChar BooleanValue { + ttcn3_prof.set_aggregate_data($3); + } +; + +StatisticsFileSetting: + StatisticsFileKeyword AssignmentChar StringValue { + ttcn3_prof.set_stats_filename($3); + } +; + +DisableStatisticsSetting: + DisableStatisticsKeyword AssignmentChar BooleanValue { + ttcn3_prof.set_disable_stats($3); + } +; + /**************** [TESTPORT_PARAMETERS] ****************************/ TestportParametersSection: @@ -2141,6 +2207,8 @@ 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 7a21147..c338947 100644 --- a/core2/Basetype2.cc +++ b/core2/Basetype2.cc @@ -176,9 +176,9 @@ int Base_Type::RAW_encode_negtest_raw(RAW_enc_tree&) const } int Base_Type::XER_encode_negtest(const Erroneous_descriptor_t* /*p_err_descr*/, - const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { - return XER_encode(p_td, p_buf, flavor, indent); // ignore erroneous + return XER_encode(p_td, p_buf, flavor, indent, 0); // ignore erroneous } int Base_Type::RAW_encode_negtest(const Erroneous_descriptor_t *, @@ -225,7 +225,7 @@ void Record_Of_Type::clean_up() val_ptr = NULL; } else if (val_ptr->ref_count == 1) { - if (refd_indices.empty()) { + if (NULL == refd_ind_ptr) { for (int elem_count = 0; elem_count < val_ptr->n_elements; elem_count++) { if (val_ptr->value_elements[elem_count] != NULL) { delete val_ptr->value_elements[elem_count]; @@ -247,7 +247,7 @@ void Record_Of_Type::clean_up() } Record_Of_Type::Record_Of_Type(null_type /*other_value*/) -: Base_Type(), val_ptr(new recordof_setof_struct), err_descr(NULL), max_refd_index(-1) +: Base_Type(), val_ptr(new recordof_setof_struct), err_descr(NULL), refd_ind_ptr(NULL) { val_ptr->ref_count = 1; val_ptr->n_elements = 0; @@ -255,13 +255,13 @@ Record_Of_Type::Record_Of_Type(null_type /*other_value*/) } Record_Of_Type::Record_Of_Type(const Record_Of_Type& other_value) -: Base_Type(other_value), val_ptr(NULL), err_descr(other_value.err_descr), max_refd_index(-1) +: Base_Type(other_value), val_ptr(NULL), err_descr(other_value.err_descr), refd_ind_ptr(NULL) { if (!other_value.is_bound()) TTCN_error("Copying an unbound record of/set of value."); // Increment ref_count only if val_ptr is not NULL if (other_value.val_ptr != NULL) { - if (other_value.refd_indices.empty()) { + if (NULL == other_value.refd_ind_ptr) { val_ptr = other_value.val_ptr; val_ptr->ref_count++; } @@ -281,7 +281,7 @@ Record_Of_Type::Record_Of_Type(const Record_Of_Type& other_value) int Record_Of_Type::get_nof_elements() const { int nof_elements = (val_ptr != NULL) ? val_ptr->n_elements : 0; - if (!refd_indices.empty()) { + if (NULL != refd_ind_ptr) { while (nof_elements > 0) { if (is_elem_bound(nof_elements - 1)) { break; @@ -300,23 +300,26 @@ bool Record_Of_Type::is_elem_bound(int index) const int Record_Of_Type::get_max_refd_index() { - if (refd_indices.empty()) { + if (NULL == refd_ind_ptr) { return -1; } - if (-1 == max_refd_index) { - for (size_t i = 0; i < refd_indices.size(); ++i) { - if (refd_indices[i] > max_refd_index) { - max_refd_index = refd_indices[i]; + if (-1 == refd_ind_ptr->max_refd_index) { + for (size_t i = 0; i < refd_ind_ptr->refd_indices.size(); ++i) { + if (refd_ind_ptr->refd_indices[i] > refd_ind_ptr->max_refd_index) { + refd_ind_ptr->max_refd_index = refd_ind_ptr->refd_indices[i]; } } } - return max_refd_index; + return refd_ind_ptr->max_refd_index; } bool Record_Of_Type::is_index_refd(int index) { - for (size_t i = 0; i < refd_indices.size(); ++i) { - if (index == refd_indices[i]) { + if (NULL == refd_ind_ptr) { + return false; + } + for (size_t i = 0; i < refd_ind_ptr->refd_indices.size(); ++i) { + if (index == refd_ind_ptr->refd_indices[i]) { return true; } } @@ -362,7 +365,7 @@ void Record_Of_Type::set_value(const Base_Type* other_value) TTCN_error("Assigning an unbound value of type %s.", other_value->get_descriptor()->name); if (this != other_recof) { - if (refd_indices.empty() && other_recof->refd_indices.empty()) { + if (NULL == refd_ind_ptr && NULL == other_recof->refd_ind_ptr) { clean_up(); val_ptr = other_recof->val_ptr; val_ptr->ref_count++; @@ -733,7 +736,7 @@ void Record_Of_Type::set_size(int new_size) boolean Record_Of_Type::is_bound() const { - if (refd_indices.empty()) { + if (NULL == refd_ind_ptr) { return (val_ptr != NULL); } return (get_nof_elements() != 0); @@ -1020,7 +1023,7 @@ int Record_Of_Type::TEXT_decode(const TTCN_Typedescriptor_t& p_td, break; } sep_found=FALSE; - if (refd_indices.empty()) { + if (NULL == refd_ind_ptr) { val_ptr->value_elements = (Base_Type**)reallocate_pointers( (void**)val_ptr->value_elements, val_ptr->n_elements, val_ptr->n_elements + 1); val_ptr->value_elements[val_ptr->n_elements]=val; @@ -1469,7 +1472,7 @@ int Record_Of_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenize } return JSON_ERROR_FATAL; } - if (refd_indices.empty()) { + if (NULL == refd_ind_ptr) { val_ptr->value_elements = (Base_Type**)reallocate_pointers( (void**)val_ptr->value_elements, val_ptr->n_elements, val_ptr->n_elements + 1); val_ptr->value_elements[val_ptr->n_elements] = val; @@ -1528,7 +1531,7 @@ void Record_Of_Type::encode(const TTCN_Typedescriptor_t& p_td, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*(p_td.xer),p_buf, XER_coding, 0); + XER_encode(*(p_td.xer),p_buf, XER_coding, 0, 0); p_buf.put_c('\n'); break;} case TTCN_EncDec::CT_JSON: { @@ -1598,7 +1601,7 @@ void Record_Of_Type::decode(const TTCN_Typedescriptor_t& p_td, for (int success=reader.Read(); success==1; success=reader.Read()) { if (reader.NodeType() == XML_READER_TYPE_ELEMENT) break; } - XER_decode(*(p_td.xer), reader, XER_coding | XER_TOPLEVEL); + XER_decode(*(p_td.xer), reader, XER_coding | XER_TOPLEVEL, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -1652,10 +1655,10 @@ static const universal_char sp = { 0,0,0,' ' }; static const universal_char tb = { 0,0,0,9 }; int Record_Of_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, - unsigned int flavor, int indent) const + unsigned int flavor, int indent, embed_values_enc_struct_t* emb_val) const { if (err_descr) { - return XER_encode_negtest(err_descr, p_td, p_buf, flavor, indent); + return XER_encode_negtest(err_descr, p_td, p_buf, flavor, indent, emb_val); } if (val_ptr == 0) TTCN_error( @@ -1745,7 +1748,7 @@ int Record_Of_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, check_namespace_restrictions(p_td, (const char*)cs); } before.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, - flavor | ANY_ATTRIBUTES, indent); + flavor | ANY_ATTRIBUTES, indent, 0); p_buf.put_c('\''); p_buf.put_c(' '); @@ -1767,7 +1770,7 @@ int Record_Of_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, UNIVERSAL_CHARSTRING after(len - j, (const universal_char*)(*elem) + j); after.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, - flavor | ANY_ATTRIBUTES, indent); + flavor | ANY_ATTRIBUTES, indent, 0); // Put this attribute in a dummy element and walk through it to check its validity TTCN_Buffer check_buf; @@ -1785,9 +1788,15 @@ int Record_Of_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned int sub_flavor = flavor | XER_RECOF | (p_td.xer_bits & (XER_LIST)); for (int i = 0; i < nof_elements; ++i) { + if (i > 0 && !own_tag && 0 != emb_val && + emb_val->embval_index < emb_val->embval_array->size_of()) { + emb_val->embval_array->get_at(emb_val->embval_index)->XER_encode( + UNIVERSAL_CHARSTRING_xer_, p_buf, flavor | EMBED_VALUES, indent+1, 0); + ++emb_val->embval_index; + } 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, - sub_flavor, indent+own_tag); + sub_flavor, indent+own_tag, emb_val); } if (indenting && nof_elements && !is_exerlist(flavor)) { @@ -1817,7 +1826,7 @@ int Record_Of_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, */ int Record_Of_Type::encode_element(int i, const Erroneous_values_t* ev, const Erroneous_descriptor_t* ed, - TTCN_Buffer& p_buf, unsigned int sub_flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int sub_flavor, int indent, embed_values_enc_struct_t* emb_val) const { int enc_len = p_buf.get_len(); TTCN_EncDec_ErrorContext ec; @@ -1834,7 +1843,7 @@ int Record_Of_Type::encode_element(int i, if (ev->before->type_descr==NULL) TTCN_error( "internal error: erroneous before type descriptor missing"); ev->before->errval->XER_encode(*ev->before->type_descr->xer, - p_buf, sub_flavor, indent); + p_buf, sub_flavor, indent, 0); } } @@ -1854,16 +1863,16 @@ int Record_Of_Type::encode_element(int i, if (ev->value->type_descr==NULL) TTCN_error( "internal error: erroneous value type descriptor missing"); ev->value->errval->XER_encode(*ev->value->type_descr->xer, - p_buf, sub_flavor, indent); + p_buf, sub_flavor, indent, 0); } } // else -> omit } 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); + get_at(i)->XER_encode_negtest(ed, *get_elem_descr()->xer, 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); + get_at(i)->XER_encode(*get_elem_descr()->xer, p_buf, sub_flavor, indent, emb_val); } } @@ -1878,7 +1887,7 @@ int Record_Of_Type::encode_element(int i, if (ev->after->type_descr==NULL) TTCN_error( "internal error: erroneous after type descriptor missing"); ev->after->errval->XER_encode(*ev->after->type_descr->xer, - p_buf, sub_flavor, indent); + p_buf, sub_flavor, indent, 0); } } @@ -1887,7 +1896,8 @@ int Record_Of_Type::encode_element(int i, // XERSTUFF Record_Of_Type::XER_encode_negtest int Record_Of_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, - const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned flavor, int indent) const + const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned flavor, int indent, + embed_values_enc_struct_t* emb_val) const { if (val_ptr == 0) TTCN_error( "Attempt to XER-encode an unbound record of type %s", get_descriptor()->name); @@ -1949,7 +1959,7 @@ int Record_Of_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr if (ev->before->type_descr==NULL) TTCN_error( "internal error: erroneous before type descriptor missing"); else ev->before->errval->XER_encode(*ev->before->type_descr->xer, - p_buf, flavor, indent); + p_buf, flavor, indent, 0); } } @@ -1960,7 +1970,7 @@ int Record_Of_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr if (ev->value->type_descr==NULL) TTCN_error( "internal error: erroneous value type descriptor missing"); else ev->value->errval->XER_encode(*ev->value->type_descr->xer, - p_buf, flavor, indent); + p_buf, flavor, indent, 0); } } } @@ -2001,7 +2011,7 @@ int Record_Of_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr UNIVERSAL_CHARSTRING before(sp_at, (const universal_char*)(*elem)); before.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, - flavor | ANY_ATTRIBUTES, indent); + flavor | ANY_ATTRIBUTES, indent, 0); p_buf.put_c('\''); p_buf.put_c(' '); @@ -2018,7 +2028,7 @@ int Record_Of_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr UNIVERSAL_CHARSTRING after(len - j, (const universal_char*)(*elem) + j); after.XER_encode(UNIVERSAL_CHARSTRING_xer_, p_buf, - flavor | ANY_ATTRIBUTES, indent); + flavor | ANY_ATTRIBUTES, indent, 0); } } @@ -2031,7 +2041,7 @@ int Record_Of_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr if (ev->after->type_descr==NULL) TTCN_error( "internal error: erroneous after type descriptor missing"); else ev->after->errval->XER_encode(*ev->after->type_descr->xer, - p_buf, flavor, indent); + p_buf, flavor, indent, 0); } } } @@ -2050,13 +2060,26 @@ int Record_Of_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr for (int i = 0; i < nof_elements; ++i) { if (i < p_err_descr->omit_before) continue; + + if (0 != emb_val && i > 0 && !own_tag && + emb_val->embval_index < emb_val->embval_array->size_of()) { + const Erroneous_values_t * ev0_i = NULL; + const Erroneous_descriptor_t* ed0_i = NULL; + if (emb_val->embval_err) { + 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_index; + } 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); - encode_element(i, err_vals, emb_descr, p_buf, sub_flavor, indent+own_tag); + encode_element(i, 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; @@ -2073,7 +2096,7 @@ int Record_Of_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr } int Record_Of_Type::XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor) + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t* emb_val) { int exer = is_exer(flavor); int xerbits = p_td.xer_bits; @@ -2152,7 +2175,7 @@ int Record_Of_Type::XER_decode(const XERdescriptor_t& p_td, // The call to the non-const operator[], I mean get_at(), creates // a new element (because it is indexing one past the last element). // Then we call its XER_decode with the temporary XML reader. - get_at(get_nof_elements())->XER_decode(sub_xer, reader2, flavor); + get_at(get_nof_elements())->XER_decode(sub_xer, reader2, flavor, 0); if (flavor & EXIT_ON_ERROR && !is_elem_bound(get_nof_elements() - 1)) { if (1 == get_nof_elements()) { // Failed to decode even the first element @@ -2218,7 +2241,10 @@ 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); + get_at(get_nof_elements())->XER_decode(*get_elem_descr()->xer, reader, flavor, emb_val); + if (0 != emb_val && !own_tag && get_nof_elements() > 1) { + ++emb_val->embval_index; + } } } else if (XML_READER_TYPE_END_ELEMENT == type) { @@ -2231,6 +2257,11 @@ int Record_Of_Type::XER_decode(const XERdescriptor_t& p_td, } break; } + else if (XML_READER_TYPE_TEXT == type && 0 != emb_val && !own_tag && get_nof_elements() > 0) { + UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value()); + emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr); + success = reader.Read(); + } else { success = reader.Read(); } @@ -2317,22 +2348,30 @@ void Record_Of_Type::set_implicit_omit() void Record_Of_Type::add_refd_index(int index) { - refd_indices.push_back(index); + if (NULL == refd_ind_ptr) { + refd_ind_ptr = new refd_index_struct; + refd_ind_ptr->max_refd_index = -1; + } + refd_ind_ptr->refd_indices.push_back(index); if (index > get_max_refd_index()) { - max_refd_index = index; + refd_ind_ptr->max_refd_index = index; } } void Record_Of_Type::remove_refd_index(int index) { - for (size_t i = refd_indices.size(); i > 0; --i) { - if (refd_indices[i - 1] == index) { - refd_indices.erase_at(i - 1); + for (size_t i = refd_ind_ptr->refd_indices.size(); i > 0; --i) { + if (refd_ind_ptr->refd_indices[i - 1] == index) { + refd_ind_ptr->refd_indices.erase_at(i - 1); break; } } - if (get_max_refd_index() == index) { - max_refd_index = -1; + if (refd_ind_ptr->refd_indices.empty()) { + delete refd_ind_ptr; + refd_ind_ptr = NULL; + } + else if (get_max_refd_index() == index) { + refd_ind_ptr->max_refd_index = -1; } } @@ -2592,7 +2631,7 @@ void Record_Type::encode(const TTCN_Typedescriptor_t& p_td, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*(p_td.xer),p_buf, XER_coding, 0); + XER_encode(*(p_td.xer),p_buf, XER_coding, 0, 0); p_buf.put_c('\n'); break;} case TTCN_EncDec::CT_JSON: { @@ -2678,7 +2717,7 @@ void Record_Type::decode(const TTCN_Typedescriptor_t& p_td, for (int success=reader.Read(); success==1; success=reader.Read()) { if (reader.NodeType() == XML_READER_TYPE_ELEMENT) break; } - XER_decode(*(p_td.xer), reader, XER_coding | XER_TOPLEVEL); + XER_decode(*(p_td.xer), reader, XER_coding | XER_TOPLEVEL, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -3851,10 +3890,10 @@ int Record_Type::get_index_byname(const char *name, const char *uri) const { } int Record_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, - unsigned int flavor, int indent) const + unsigned int flavor, int indent, embed_values_enc_struct_t*) const { if (err_descr) { - return XER_encode_negtest(err_descr, p_td, p_buf, flavor, indent); + return XER_encode_negtest(err_descr, p_td, p_buf, flavor, indent, 0); } if (!is_bound()) { TTCN_EncDec_ErrorContext::error @@ -3961,7 +4000,7 @@ int Record_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, const Base_Type * const q_uri = get_at(0); if (q_uri->is_present()) { p_buf.put_s(11, (cbyte*)" xmlns:b0='"); - q_uri->XER_encode(*xer_descr(0), p_buf, flavor | XER_LIST, indent+1); + q_uri->XER_encode(*xer_descr(0), p_buf, flavor | XER_LIST, indent+1, 0); p_buf.put_c('\''); } @@ -3973,18 +4012,18 @@ int Record_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, sub_len += 3; } const Base_Type* const q_name = get_at(1); - sub_len += q_name->XER_encode(*xer_descr(1), p_buf, flavor | XER_LIST, indent+1); + sub_len += q_name->XER_encode(*xer_descr(1), p_buf, flavor | XER_LIST, indent+1, 0); if (p_td.xer_bits & XER_ATTRIBUTE) p_buf.put_c('\''); } else { // not USE-QNAME if (!exer && (p_td.xer_bits & EMBED_VALUES)) { // The EMBED-VALUES member as an ordinary record of string - sub_len += embed_values->XER_encode(*xer_descr(0), p_buf, flavor, indent+1); + sub_len += embed_values->XER_encode(*xer_descr(0), p_buf, flavor, indent+1, 0); } if (!exer && (p_td.xer_bits & USE_ORDER)) { // The USE-ORDER member as an ordinary record of enumerated - sub_len += use_order->XER_encode(*xer_descr(uo_index), p_buf, flavor, indent+1); + sub_len += use_order->XER_encode(*xer_descr(uo_index), p_buf, flavor, indent+1, 0); } if (exer && (indent==0 || (flavor & DEF_NS_SQUASHED))) // write namespaces for toplevel only @@ -4011,7 +4050,7 @@ int Record_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, for (i = start_at; i < first_nonattr; ++i) { boolean is_xer_attr_field = xer_descr(i)->xer_bits & XER_ATTRIBUTE; ec_1.set_msg("%s': ", fld_name(i)); // attr - int tmp_len = get_at(i)->XER_encode(*xer_descr(i), p_buf, flavor, indent+1); + int tmp_len = get_at(i)->XER_encode(*xer_descr(i), p_buf, flavor, indent+1, 0); if (is_xer_attr_field && !exer) sub_len += tmp_len; /* do not add if attribute and EXER */ } @@ -4043,31 +4082,11 @@ int Record_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, p_buf.put_s(start_tag_len , (cbyte*)">\n"); } - int expected_embed = (field_cnt - first_nonattr + 1); if (exer && (p_td.xer_bits & EMBED_VALUES)) { - ec_1.set_msg("%s': ", fld_name(0)); - int num_opt; - if ((p_td.xer_bits & USE_NIL) && !get_at(field_cnt-1)->ispresent()) { - expected_embed = 0; //25.2.6 a - } - else if ((num_opt = optional_count())) { - const int * optionals = get_optional_indexes(); - for (int opt_idx = 0; opt_idx < num_opt; ++opt_idx) { - // skip optional attributes - if (optionals[opt_idx] < start_at + num_attributes) continue; - // reduce for each omitted member - if (!get_at(optionals[opt_idx])->is_present()) --expected_embed; - } - } - // Check the correct number of EMBED-VALUES (regular non-attributes + 1) - if (embed_values->size_of() != expected_embed) - TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_CONSTRAINT, - "Wrong number %d of EMBED-VALUEs, expected %d", - embed_values->size_of(), expected_embed); /* write the first string */ - if (expected_embed > 0) { + if (embed_values->size_of() > 0) { sub_len += embed_values->get_at(0)->XER_encode(UNIVERSAL_CHARSTRING_xer_, - p_buf, flavor | EMBED_VALUES, indent+1); + p_buf, flavor | EMBED_VALUES, indent+1, 0); } } @@ -4147,33 +4166,55 @@ int Record_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, * pseudo-members for USE-ORDER, etc.) */ // early_to_bed can only be true if exer is true (transitive through nil_attribute) - if (!early_to_bed) for ( i = begin; i < end; ++i ) { - const Base_Type *uoe = 0; // "useOrder enum" - const Enum_Type *enm = 0; // the enum value selecting the field - if (exer && use_order) { - uoe = use_order->get_at(i - begin); - enm = static_cast(uoe); - } - - // "actual" index, may be perturbed by USE-ORDER - int ai = !(exer && (p_td.xer_bits & USE_ORDER)) ? i : - enm->as_int() + useorder_base; - ec_1.set_msg("%s': ", ordered->fld_name(ai)); // non-attr - - const XERdescriptor_t& descr = *ordered->xer_descr(ai); - sub_len += ordered->get_at(ai)->XER_encode(descr, p_buf, - // Pass USE-NIL to the last field (except when USE-ORDER is also in effect, - // because the tag-stripping effect of USE-NIL has been achieved - // by encoding the sub-fields directly). - flavor | ((exer && !use_order && (i == field_cnt-1)) ? (p_td.xer_bits & USE_NIL) : 0), - indent+!omit_tag); - - // Now the next embed-values string (NOT affected by USE-ORDER!) - if (exer && (p_td.xer_bits & EMBED_VALUES) && (i - begin + 1) < expected_embed) { - embed_values->get_at(i - begin + 1)->XER_encode(UNIVERSAL_CHARSTRING_xer_ - , p_buf, flavor | EMBED_VALUES, indent+1); - } - } //for + if (!early_to_bed) { + embed_values_enc_struct_t* emb_val = 0; + if (exer && (p_td.xer_bits & EMBED_VALUES) && embed_values->size_of() > 1) { + emb_val = new embed_values_enc_struct_t; + emb_val->embval_array = embed_values; + emb_val->embval_index = 1; + emb_val->embval_err = 0; + } + + for ( i = begin; i < end; ++i ) { + const Base_Type *uoe = 0; // "useOrder enum" + const Enum_Type *enm = 0; // the enum value selecting the field + if (exer && use_order) { + uoe = use_order->get_at(i - begin); + enm = static_cast(uoe); + } + + // "actual" index, may be perturbed by USE-ORDER + int ai = !(exer && (p_td.xer_bits & USE_ORDER)) ? i : + enm->as_int() + useorder_base; + ec_1.set_msg("%s': ", ordered->fld_name(ai)); // non-attr + + const XERdescriptor_t& descr = *ordered->xer_descr(ai); + sub_len += ordered->get_at(ai)->XER_encode(descr, p_buf, + // Pass USE-NIL to the last field (except when USE-ORDER is also in effect, + // because the tag-stripping effect of USE-NIL has been achieved + // by encoding the sub-fields directly). + flavor | ((exer && !use_order && (i == field_cnt-1)) ? (p_td.xer_bits & USE_NIL) : 0), + indent+!omit_tag, emb_val); + + // Now the next embed-values string (NOT affected by USE-ORDER!) + if (exer && (p_td.xer_bits & EMBED_VALUES) && 0 != emb_val && + emb_val->embval_index < embed_values->size_of()) { + embed_values->get_at(emb_val->embval_index)->XER_encode(UNIVERSAL_CHARSTRING_xer_ + , p_buf, flavor | EMBED_VALUES, indent+1, 0); + ++emb_val->embval_index; + } + } //for + + if (0 != emb_val) { + if (emb_val->embval_index < embed_values->size_of()) { + ec_1.set_msg("%s': ", fld_name(0)); + TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_CONSTRAINT, + "Too many EMBED-VALUEs specified: %d (expected %d or less)", + embed_values->size_of(), emb_val->embval_index); + } + delete emb_val; + } + } // if (!early_to_bed) } // if (QNAME) if (!omit_tag) { @@ -4226,7 +4267,7 @@ int Record_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, */ int Record_Type::encode_field(int i, const Erroneous_values_t* err_vals, const Erroneous_descriptor_t* emb_descr, - TTCN_Buffer& p_buf, unsigned int sub_flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int sub_flavor, int indent, embed_values_enc_struct_t* emb_val) const { int enc_len = 0; TTCN_EncDec_ErrorContext ec; @@ -4240,7 +4281,7 @@ int Record_Type::encode_field(int i, if (err_vals->before->type_descr==NULL) TTCN_error( "internal error: erroneous before typedescriptor missing"); enc_len += err_vals->before->errval->XER_encode( - *err_vals->before->type_descr->xer, p_buf, sub_flavor, indent); + *err_vals->before->type_descr->xer, p_buf, sub_flavor, indent, 0); } } @@ -4253,18 +4294,18 @@ int Record_Type::encode_field(int i, if (err_vals->value->type_descr==NULL) TTCN_error( "internal error: erroneous value typedescriptor missing"); enc_len += err_vals->value->errval->XER_encode( - *err_vals->value->type_descr->xer, p_buf, sub_flavor, indent); + *err_vals->value->type_descr->xer, p_buf, sub_flavor, indent, 0); } } // else -> omit } else { ec.set_msg("Component %s: ", fld_name(i)); if (emb_descr) { enc_len += get_at(i)->XER_encode_negtest(emb_descr, *xer_descr(i), p_buf, - sub_flavor, indent); + sub_flavor, indent, emb_val); } else { // the "real" encoder enc_len += get_at(i)->XER_encode(*xer_descr(i), p_buf, - sub_flavor, indent); + sub_flavor, indent, emb_val); } } @@ -4278,7 +4319,7 @@ int Record_Type::encode_field(int i, if (err_vals->after->type_descr==NULL) TTCN_error( "internal error: erroneous after typedescriptor missing"); enc_len += err_vals->after->errval->XER_encode( - *err_vals->after->type_descr->xer, p_buf, sub_flavor, indent); + *err_vals->after->type_descr->xer, p_buf, sub_flavor, indent, 0); } } @@ -4287,7 +4328,8 @@ int Record_Type::encode_field(int i, // XERSTUFF Record_Type::XER_encode_negtest int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, - const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, unsigned int flavor, int indent, + embed_values_enc_struct_t*) const { if (!is_bound()) { TTCN_EncDec_ErrorContext::error @@ -4411,7 +4453,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, if (ev->before->type_descr==NULL) TTCN_error( "internal error: erroneous before typedescriptor missing"); sub_len += ev->before->errval->XER_encode( - *ev->before->type_descr->xer, p_buf, flavor, indent); + *ev->before->type_descr->xer, p_buf, flavor, indent, 0); } } @@ -4424,7 +4466,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, if (ev->value->type_descr==NULL) TTCN_error( "internal error: erroneous value typedescriptor missing"); sub_len += ev->value->errval->XER_encode( - *ev->value->type_descr->xer, p_buf, flavor, indent); + *ev->value->type_descr->xer, p_buf, flavor, indent, 0); } } // else -> omit } else { @@ -4438,7 +4480,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, // the "real" encoder if (q_uri->is_present()) { p_buf.put_s(11, (cbyte*)" xmlns:b0='"); - sub_len += q_uri->XER_encode(*xer_descr(0), p_buf, flavor | XER_LIST, indent+1); + sub_len += q_uri->XER_encode(*xer_descr(0), p_buf, flavor | XER_LIST, indent+1, 0); p_buf.put_c('\''); } } @@ -4454,7 +4496,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, if (ev->after->type_descr==NULL) TTCN_error( "internal error: erroneous after typedescriptor missing"); sub_len += ev->after->errval->XER_encode( - *ev->after->type_descr->xer, p_buf, flavor, indent); + *ev->after->type_descr->xer, p_buf, flavor, indent, 0); } } @@ -4475,7 +4517,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, if (ev->before->type_descr==NULL) TTCN_error( "internal error: erroneous before typedescriptor missing"); sub_len += ev->before->errval->XER_encode( - *ev->before->type_descr->xer, p_buf, flavor, indent); + *ev->before->type_descr->xer, p_buf, flavor, indent, 0); } } @@ -4488,7 +4530,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, if (ev->value->type_descr==NULL) TTCN_error( "internal error: erroneous value typedescriptor missing"); sub_len += ev->value->errval->XER_encode( - *ev->value->type_descr->xer, p_buf, flavor, indent); + *ev->value->type_descr->xer, p_buf, flavor, indent, 0); } } // else -> omit } else { @@ -4503,7 +4545,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, sub_len += 3; } - sub_len += get_at(1)->XER_encode(*xer_descr(1), p_buf, flavor | XER_LIST, indent+1); + sub_len += get_at(1)->XER_encode(*xer_descr(1), p_buf, flavor | XER_LIST, indent+1, 0); } } @@ -4517,7 +4559,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, if (ev->after->type_descr==NULL) TTCN_error( "internal error: erroneous after typedescriptor missing"); sub_len += ev->after->errval->XER_encode( - *ev->after->type_descr->xer, p_buf, flavor, indent); + *ev->after->type_descr->xer, p_buf, flavor, indent, 0); } } @@ -4526,12 +4568,12 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, else { // not USE-QNAME if (!exer && (p_td.xer_bits & EMBED_VALUES)) { // The EMBED-VALUES member as an ordinary record of string - sub_len += embed_values->XER_encode(*xer_descr(0), p_buf, flavor, indent+1); + sub_len += embed_values->XER_encode(*xer_descr(0), p_buf, flavor, indent+1, 0); } if (!exer && (p_td.xer_bits & USE_ORDER)) { // The USE-ORDER member as an ordinary record of enumerated - sub_len += use_order->XER_encode(*xer_descr(uo_index), p_buf, flavor, indent+1); + sub_len += use_order->XER_encode(*xer_descr(uo_index), p_buf, flavor, indent+1, 0); } if (exer && (indent==0 || (flavor & DEF_NS_SQUASHED))) // write namespaces for toplevel only @@ -4572,7 +4614,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, boolean is_xer_attr_field = xer_descr(i)->xer_bits & XER_ATTRIBUTE; ec_1.set_msg("%s': ", fld_name(i)); // attr - tmp_len = encode_field(i, ev, ed, p_buf, flavor, indent + !omit_tag); + tmp_len = encode_field(i, ev, ed, p_buf, flavor, indent + !omit_tag, 0); if (is_xer_attr_field && !exer) sub_len += tmp_len; // do not add if attribute and EXER @@ -4637,31 +4679,11 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, int embed_values_val_idx = 0; int embed_values_descr_idx = 0; - int expected_embed = (field_cnt - first_nonattr + 1); if (exer && (p_td.xer_bits & EMBED_VALUES)) { ed0 = p_err_descr->next_field_emb_descr(0, edescr_idx); - ec_1.set_msg("%s': ", fld_name(0)); - int num_opt; - if ((p_td.xer_bits & USE_NIL) && !get_at(field_cnt-1)->ispresent()) { - expected_embed = 0; //25.2.6 a - } - else if ((num_opt = optional_count()) > 0) { - const int * optionals = get_optional_indexes(); - for (int opt_idx = 0; opt_idx < num_opt; ++opt_idx) { - // skip optional attributes - if (optionals[opt_idx] < start_at + num_attributes) continue; - // reduce for each omitted member - if (!get_at(optionals[opt_idx])->is_present()) --expected_embed; - } - } - // Check the correct number of EMBED-VALUES (regular non-attributes + 1) - if (embed_values->size_of() != expected_embed) - TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_CONSTRAINT, - "Wrong number %d of EMBED-VALUEs, expected %d", - embed_values->size_of(), expected_embed); // write the first string - if (expected_embed > 0) { + if (embed_values->size_of() > 0) { const Erroneous_values_t * ev0_0 = NULL; const Erroneous_descriptor_t* ed0_0 = NULL; if (ed0) { @@ -4669,7 +4691,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, 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); + p_buf, flavor | EMBED_VALUES, indent+!omit_tag, 0); } } @@ -4757,64 +4779,86 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, // fields of this record; and the USE_ORDER case (with or without USE-NIL). // // early_to_bed can only be true if exer is true (transitive through nil_attribute) - if (!early_to_bed) for ( i = begin; i < end; ++i ) { - - const Base_Type *uoe = 0; // "useOrder enum" - const Enum_Type *enm = 0; // the enum value selecting the field - - // "actual" index, may be perturbed by USE-ORDER. - // We use this value to index the appropriate record. - int ai = i; - - const Erroneous_values_t * ev = NULL; - const Erroneous_descriptor_t* ed = NULL; - if (exer && use_order) { - // If USE-ORDER is in effect, it introduces a level of indirection - // into the indexing of fields: "i" is used to select an element - // of the use_order member (an enum), whose value is used to select - // the field being encoded. - uoe = use_order->get_at(i - begin); - enm = static_cast(uoe); - ai = enm->as_int() + useorder_base; - - // Because it is not guaranteed that ai will increase monotonically, - // we can't use next_field_...(). - ev = p_err_descr->get_field_err_values(ai); - ed = p_err_descr->get_field_emb_descr (ai); - } - else { // not USE-ORDER, sequential access - ev = p_err_descr->next_field_err_values(ai, values_idx); - ed = p_err_descr->next_field_emb_descr (ai, edescr_idx); - } - ec_1.set_msg("%s': ", ordered->fld_name(ai)); // non-attr - - if (ai < p_err_descr->omit_before) continue; - - // omit_after value -1 becomes "very big". - if ((unsigned int)ai > (unsigned int)p_err_descr->omit_after) continue; - // We can't skip all fields with break, because the next ai may be lower - // than omit_after. - - sub_len += ordered->encode_field(ai, ev, ed, p_buf, - // Pass USE-NIL to the last field (except when USE-ORDER is also in effect, - // because the tag-stripping effect of USE-NIL has been achieved - // by encoding the sub-fields directly). - flavor | ((exer && !use_order && (i == field_cnt-1)) ? (p_td.xer_bits & USE_NIL) : 0), - indent + !omit_tag); - - // Now the next embed-values string (NOT affected by USE-ORDER!) - int i1 = i - begin + 1; - if (exer && (p_td.xer_bits & EMBED_VALUES) && i1 < expected_embed) { - const Erroneous_values_t * ev0_i = NULL; - const Erroneous_descriptor_t* ed0_i = NULL; - if (ed0) { - ev0_i = ed0->next_field_err_values(i1, embed_values_val_idx); - ed0_i = ed0->next_field_emb_descr (i1, embed_values_descr_idx); + if (!early_to_bed) { + embed_values_enc_struct_t* emb_val = 0; + if (exer && (p_td.xer_bits & EMBED_VALUES) && embed_values->size_of() > 1) { + emb_val = new embed_values_enc_struct_t; + emb_val->embval_array = embed_values; + emb_val->embval_index = 1; + emb_val->embval_err = ed0; + emb_val->embval_err_val_idx = embed_values_val_idx; + emb_val->embval_err_descr_idx = embed_values_descr_idx; + } + + for ( i = begin; i < end; ++i ) { + + const Base_Type *uoe = 0; // "useOrder enum" + const Enum_Type *enm = 0; // the enum value selecting the field + + // "actual" index, may be perturbed by USE-ORDER. + // We use this value to index the appropriate record. + int ai = i; + + const Erroneous_values_t * ev = NULL; + const Erroneous_descriptor_t* ed = NULL; + if (exer && use_order) { + // If USE-ORDER is in effect, it introduces a level of indirection + // into the indexing of fields: "i" is used to select an element + // of the use_order member (an enum), whose value is used to select + // the field being encoded. + uoe = use_order->get_at(i - begin); + enm = static_cast(uoe); + ai = enm->as_int() + useorder_base; + + // Because it is not guaranteed that ai will increase monotonically, + // we can't use next_field_...(). + ev = p_err_descr->get_field_err_values(ai); + ed = p_err_descr->get_field_emb_descr (ai); + } + else { // not USE-ORDER, sequential access + ev = p_err_descr->next_field_err_values(ai, values_idx); + ed = p_err_descr->next_field_emb_descr (ai, edescr_idx); + } + ec_1.set_msg("%s': ", ordered->fld_name(ai)); // non-attr + + if (ai < p_err_descr->omit_before) continue; + + // omit_after value -1 becomes "very big". + if ((unsigned int)ai > (unsigned int)p_err_descr->omit_after) continue; + // We can't skip all fields with break, because the next ai may be lower + // than omit_after. + + sub_len += ordered->encode_field(ai, ev, ed, p_buf, + // Pass USE-NIL to the last field (except when USE-ORDER is also in effect, + // because the tag-stripping effect of USE-NIL has been achieved + // by encoding the sub-fields directly). + flavor | ((exer && !use_order && (i == field_cnt-1)) ? (p_td.xer_bits & USE_NIL) : 0), + indent + !omit_tag, emb_val); + + // Now the next embed-values string (NOT affected by USE-ORDER!) + if (exer && (p_td.xer_bits & EMBED_VALUES) && 0 != emb_val && + emb_val->embval_index < embed_values->size_of()) { + const Erroneous_values_t * ev0_i = NULL; + const Erroneous_descriptor_t* ed0_i = NULL; + if (ed0) { + 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); + ++emb_val->embval_index; + } + } //for + if (0 != emb_val) { + if (emb_val->embval_index < embed_values->size_of()) { + ec_1.set_msg("%s': ", fld_name(0)); + TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_CONSTRAINT, + "Too many EMBED-VALUEs specified: %d (expected %d or less)", + embed_values->size_of(), emb_val->embval_index); } - embed_values->encode_element(i1, ev0_i, ed0_i, - p_buf, flavor | EMBED_VALUES, indent + !omit_tag); + delete emb_val; } - } //for + } // if (!early_to_bed) } // if (QNAME) @@ -4850,7 +4894,8 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, return (int)p_buf.get_len() - encoded_length; } -int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, unsigned int flavor) +int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, + unsigned int flavor, embed_values_dec_struct_t*) { bound_flag = TRUE; int exer = is_exer(flavor); @@ -4886,7 +4931,9 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, for (int k = 0; k < first_nonattr; ++k) { if (xer_descr(k)->xer_bits & ANY_ATTRIBUTES) { aa_index = k; - static_cast(get_at(aa_index))->set_size(0); + if (!get_at(aa_index)->is_optional()) { + static_cast(get_at(aa_index))->set_size(0); + } break; // there can be only one, 18.2.2 } } @@ -4951,7 +4998,7 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, // First, the (would-be) attributes (unaffected by USE-ORDER) for (i = 0; i < first_nonattr; i++) { ec_1.set_msg("%s': ", fld_name(i)); - get_at(i)->XER_decode(*xer_descr(i), reader, flavor); + get_at(i)->XER_decode(*xer_descr(i), reader, flavor, 0); } // next field } else if (own_tag || parent_tag) { // EXER and not UNTAGGED: do attributes @@ -4993,7 +5040,7 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, if (field_index != -1) { // There is a field. Let it decode the attribute. ec_1.set_msg("%s': ", fld_name(field_index)); - get_at(field_index)->XER_decode(*xer_descr(field_index), reader, flavor); + get_at(field_index)->XER_decode(*xer_descr(field_index), reader, flavor, 0); continue; } @@ -5031,7 +5078,16 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, TTCN_EncDec_ErrorContext ec_2("Attribute %d: ", num_aa); // We have a component with ANY-ATTRIBUTE. It must be a record of // UNIVERSAL_CHARSTRING. Add the attribute to it. - Record_Of_Type *aa = static_cast(get_at(aa_index)); + Record_Of_Type *aa = 0; + if (get_at(aa_index)->is_optional()) { + if (num_aa == 0) { + get_at(aa_index)->set_to_present(); + } + aa = static_cast(get_at(aa_index)->get_opt_value()); + } + else { + aa = static_cast(get_at(aa_index)); + } UNIVERSAL_CHARSTRING *new_elem = static_cast (aa->get_at(num_aa++)); @@ -5092,9 +5148,12 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, } // end if (own_tag) /* * * * * * * * Non-attributes (elements) * * * * * * * * * * * */ - Record_Of_Type* embed_values = 0; + embed_values_dec_struct_t* emb_val = 0; if (exer && (p_td.xer_bits & EMBED_VALUES)) { - embed_values = static_cast(get_at(0)); + emb_val = new embed_values_dec_struct_t; + emb_val->embval_array = static_cast(get_at(0)); + emb_val->embval_array->set_size(0); + emb_val->embval_index = 0; } if (exer && (p_td.xer_bits & USE_ORDER)) { @@ -5144,19 +5203,27 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, int *seen = new int[end-begin]; int num_seen = 0; int last_any_elem = begin - 1; + // The index of the latest embedded value can change outside of this function + // (if the field is a untagged record of), in this case the next value should + // be ignored, as it's already been handled by the record of + int last_embval_index = 0; for (i = begin; i < end; i++) { for (success = reader.Ok(); success == 1; success = reader.Read()) { type = reader.NodeType(); - if (embed_values) { - if (reader.NodeType()==XML_READER_TYPE_TEXT) { - UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value()); - embed_values->get_at(i-begin)->set_value(&emb_ustr); - } + if (0 != emb_val && reader.NodeType()==XML_READER_TYPE_TEXT) { + UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value()); + emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr); } // The non-attribute components must not be UNTAGGED if (type == XML_READER_TYPE_ELEMENT) break; // else if (type==XML_READER_TYPE_END_ELEMENT) panic? } + if (0 != emb_val) { + if (last_embval_index == emb_val->embval_index) { + ++emb_val->embval_index; + } + last_embval_index = emb_val->embval_index; + } if (success != 1) break; const char *name = (const char *)reader.LocalName(); boolean field_name_found = false; @@ -5182,7 +5249,7 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, static_cast(use_order->get_at(i - begin)) ->from_int(in_dex); Base_Type *b = jumbled->get_at(k); - b->XER_decode(*jumbled->xer_descr(k), reader, flavor); + b->XER_decode(*jumbled->xer_descr(k), reader, flavor, emb_val); field_name_found = true; break; } @@ -5208,17 +5275,20 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, static_cast(use_order->get_at(i - begin)) ->from_int(in_dex); Base_Type *b = jumbled->get_at(k); - b->XER_decode(*jumbled->xer_descr(k), reader, flavor); + b->XER_decode(*jumbled->xer_descr(k), reader, flavor, emb_val); last_any_elem = k; break; } } } } // next field - if (embed_values) { + if (0 != emb_val) { if (reader.NodeType()==XML_READER_TYPE_TEXT) { UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value()); - embed_values->get_at(i-begin)->set_value(&emb_ustr); + emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr); + } + if (last_embval_index == emb_val->embval_index) { + ++emb_val->embval_index; } } delete [] seen; @@ -5249,14 +5319,21 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, if (usenil_attribute) { reader.MoveToElement(); // value absent, nothing more to do } else { - int emb_idx = 0; + // The index of the latest embedded value can change outside of this function + // (if the field is a untagged record of), in this case the next value should + // be ignored, as it's already been handled by the record of + // Omitted fields can also reset this value + int last_embval_index = 0; for (; iget_at(emb_idx)->set_value(&emb_ustr); + emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr); } - emb_idx++; + if (last_embval_index == emb_val->embval_index) { + ++emb_val->embval_index; + } + last_embval_index = emb_val->embval_index; } ec_1.set_msg("%s': ", fld_name(i)); if (exer && i==field_cnt-1 && p_td.dfeValue && reader.IsEmptyElement()) { @@ -5281,38 +5358,35 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, if (i == field_cnt-1) new_flavor |= (p_td.xer_bits & USE_NIL); if (tag_closed) new_flavor |= PARENT_CLOSED; - get_at(i)->XER_decode(*xer_descr(i), reader, new_flavor); + get_at(i)->XER_decode(*xer_descr(i), reader, new_flavor, emb_val); } } + if (!get_at(i)->is_present()) { + // there was no new element, the last embedded value is for the next field + // (or the end of the record if this is the last field) + last_embval_index = -1; + } } // next field - if (embed_values) { + if (0 != emb_val) { if (reader.NodeType()==XML_READER_TYPE_TEXT) { UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value()); - embed_values->get_at(emb_idx)->set_value(&emb_ustr); + emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr); + } + if (last_embval_index == emb_val->embval_index) { + ++emb_val->embval_index; } } } } // if use-order - if (embed_values) { - // Set the embed_values member to the correct number of strings - int num_embedded = 0; // if usenil_attribute - if (!usenil_attribute) { - num_embedded = field_cnt - first_nonattr + 1; - const int num_opt = optional_count(); - const int * optionals = get_optional_indexes(); - for (int opt_idx = 0; opt_idx < num_opt; ++opt_idx) { - // skip optional attributes - if (optionals[opt_idx] < start_at + num_attributes) continue; - // reduce for each omitted member - if (!get_at(optionals[opt_idx])->is_present()) --num_embedded; - } - } - embed_values->set_size(num_embedded); + if (0 != emb_val) { static const UNIVERSAL_CHARSTRING emptystring(0, (const char*)NULL); - for (int j = 0; j < num_embedded; ++j) { - if (!embed_values->get_at(j)->is_bound()) embed_values->get_at(j)->set_value(&emptystring); + for (int j = 0; j < emb_val->embval_index; ++j) { + if (!emb_val->embval_array->get_at(j)->is_bound()) { + emb_val->embval_array->get_at(j)->set_value(&emptystring); + } } + delete emb_val; } // if embed-values } // if use-qname @@ -5588,7 +5662,7 @@ void Empty_Record_Type::encode(const TTCN_Typedescriptor_t& p_td, case TTCN_EncDec::CT_XER: { TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); unsigned XER_coding=va_arg(pvar, unsigned); - XER_encode(*(p_td.xer),p_buf, XER_coding, 0); + XER_encode(*(p_td.xer),p_buf, XER_coding, 0, 0); p_buf.put_c('\n'); break;} case TTCN_EncDec::CT_JSON: { @@ -5661,7 +5735,7 @@ void Empty_Record_Type::decode(const TTCN_Typedescriptor_t& p_td, for (int success=reader.Read(); success==1; success=reader.Read()) { if (reader.NodeType() == XML_READER_TYPE_ELEMENT) break; } - XER_decode(*(p_td.xer), reader, XER_coding | XER_TOPLEVEL); + XER_decode(*(p_td.xer), reader, XER_coding | XER_TOPLEVEL, 0); size_t bytes = reader.ByteConsumed(); p_buf.set_pos(bytes); break;} @@ -5770,7 +5844,7 @@ int Empty_Record_Type::TEXT_decode(const TTCN_Typedescriptor_t& p_td, } int Empty_Record_Type::XER_encode(const XERdescriptor_t& p_td, - TTCN_Buffer& p_buf, unsigned int flavor, int indent) const + TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const { int encoded_length=(int)p_buf.get_len(); int indenting = !is_canonical(flavor); @@ -5784,7 +5858,7 @@ int Empty_Record_Type::XER_encode(const XERdescriptor_t& p_td, } int Empty_Record_Type::XER_decode(const XERdescriptor_t& p_td, - XmlReaderWrap& reader, unsigned int flavor) + XmlReaderWrap& reader, unsigned int flavor, embed_values_dec_struct_t*) { int exer = is_exer(flavor); bound_flag = true; diff --git a/doc/License_handling_in_TITAN.doc b/doc/License_handling_in_TITAN.doc index 0ec550a..979fb5e 100644 Binary files a/doc/License_handling_in_TITAN.doc and b/doc/License_handling_in_TITAN.doc differ diff --git a/etc/Makefile b/etc/Makefile index d24f964..68ea356 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -32,4 +32,5 @@ else # cp asciiart/*.txt $(ETCDIR)/asciiart mkdir -p $(ETCDIR)/scripts cp scripts/*.py $(ETCDIR)/scripts + cp scripts/ttcn3_archive.pl $(BINDIR) endif diff --git a/etc/scripts/ttcn3_archive.pl b/etc/scripts/ttcn3_archive.pl new file mode 100644 index 0000000..058f5e3 --- /dev/null +++ b/etc/scripts/ttcn3_archive.pl @@ -0,0 +1,159 @@ +############################################################################### +# 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 +############################################################################### +#!/usr/bin/perl +############################################################################### +# This script is intended to archive the project hierarchy from a TPD file structure +############################################################################### +use 5.010; +use strict; +use warnings; +use Cwd; +use File::Copy; + +my $ttcn3_dir = $ENV{'TTCN3_DIR'}; +my $bindir = $ttcn3_dir . "/bin"; +my $home = cwd(); +my @list = readFile(); +my $tpd = getTPDFileName(\@list); +chomp ($tpd); +if (-l $tpd) #get the path if it is a symlink +{ + $tpd = `readlink $tpd`; + chomp ($tpd); +} +my $root = getPathToRootDir(\@list); # get the workspace directory of the OS +chomp ($root); +chdir ($root) or die "cannot change: $!\n"; +my $cutstring = cwd; # this is string generated from the the absolut path to the workspace +my $archiveDir = getArchiveDir(\@list); #directory to place the archive +$archiveDir = $home . "/" . $archiveDir; +chomp ($archiveDir); +my $createDir = "mkdir -p " . $archiveDir; +my $res = system($createDir); +my $backupFileName = createBackupFileName(); +my $backupfile = $archiveDir . "/" . $backupFileName; +if ($res != 0) { die (" creating directory " . $archiveDir ." failed\n"); } +my $archive = $bindir . "/" . "ttcn3_makefilegen" ." -V -P " . $cutstring . " -t " . $tpd . " | xargs tar cfz ". $archiveDir . "/" . $backupFileName . " 2> /dev/null"; +system($archive); #running it +if (-e $backupfile) { print ("archiving succeeded\n"); } +else { print ("archiving failed\n"); } +chdir ($home) or die "cannot change: $!\n"; +############################################################ +sub readFile +{ + my $makefile = "Makefile"; + open ( FILE, "<", $makefile ) or die ( "failed to open file: $home\/$makefile\n" ); + my @lines = ; + close FILE; + return @lines; +} +############################################################ +sub getPathToRootDir #get the relative path to OS workspace +{ + my @list = @{$_[0]}; + my $search = qr/^ROOT_DIR =/s; + my $offset = 0; + my $line; + for my $i ( 0 .. $#list ) + { + if ( $list[$i] =~ $search ) + { + $line = $list[$i]; + my $dot = '.'; + $offset = index($list[$i], $dot); + last; + } + } + if ($offset == 0) { die ( "no ROOT_DIR variable was found in the Makefile\n" ); } + my $path = substr $line, $offset; + return $path; +} +############################################################ +sub getTPDFileName # TPD filename what the Makefile is created from +{ + my @list = @{$_[0]}; + my $search = qr/^TPD =/s; + my $offset = 0; + my $line; + for my $i ( 0 .. $#list ) + { + if ( $list[$i] =~ $search ) + { + $line = $list[$i]; + my $assign = '='; + $offset = index($list[$i], $assign); + last; + } + } + if ($offset == 0) { die ( "no TPD variable was found in the Makefile\n" ); } + my $file = substr $line, $offset + 1; + $file =~ s/^\s+|\s+$//; # remove heading and traling whitespaces + return $file; +} +############################################################ +sub getArchiveDir # the name of the archive directory +{ + my @list = @{$_[0]}; + my $search = qr/^ARCHIVE_DIR =/s; + my $offset = 0; + my $line; + for my $i ( 0 .. $#list ) + { + if ( $list[$i] =~ $search ) + { + $line = $list[$i]; + my $assign = '='; + $offset = index($list[$i], $assign); + last; + } + } + if ($offset == 0) { die ( "no ARCHIVE_DIR variable was found in the Makefile\n" ); } + my $dir = substr $line, $offset + 1; + $dir =~ s/^\s+|\s+$//; # remove heading and trailing whitespaces + return $dir; +} +############################################################ +sub getExecutableName # the name of the target executable +{ + my @list = @{$_[0]}; + my $search = qr/^EXECUTABLE =/s; + my $offset = 0; + my $line; + for my $i ( 0 .. $#list ) + { + if ( $list[$i] =~ $search ) + { + $line = $list[$i]; + my $assign = '='; + $offset = index($list[$i], $assign); + last; + } + } + if ($offset == 0) { die ( "no EXCUTABLE variable was found in the Makefile\n" ); } + my $exec = substr $line, $offset + 1; + $exec =~ s/^\s+|\s+$//; # remove heading and trailing whitespaces + return $exec; +} +############################################################ +sub createBackupFileName +{ + my $backupFile = getExecutableName(\@list); + my $dot = '.'; + my $result = index($backupFile, $dot); + if ($result > -1) + { + $backupFile = substr $backupFile, 0, $result; + } + chomp ($backupFile); + my $date = `date '+%y%m%d-%H%M'`; + chomp ($date); + my $baseName = $backupFile . "-" . $date . ".tgz"; + chomp ($baseName); + return $baseName; +} +############################################################ \ No newline at end of file diff --git a/etc/xsd/TPD.xsd b/etc/xsd/TPD.xsd index a599afd..d56c8e1 100644 --- a/etc/xsd/TPD.xsd +++ b/etc/xsd/TPD.xsd @@ -367,13 +367,22 @@ XML Schema for JunitLogger plugin - - - - - - - + + + + + + + + + + + + + + + + @@ -453,7 +462,7 @@ XML Schema for JunitLogger plugin diff --git a/function_test/Semantic_Analyser/TTCN3_SA_13_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_13_TD.script index c4c266a..3667858 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_13_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_13_TD.script @@ -1114,49 +1114,6 @@ template RoI t_i10 := permutation((all from t_RoI2),100); error: at or before token `permutation': syntax error, unexpected PermutationKeyword - -:exmp -*---------------------------------------------------------------------* -:h3. Component mapping: invalid ports -.*---------------------------------------------------------------------* -:xmp tab=0. - - - - - - -module test { - -type port P message { - inout charstring; -} with { extension "internal" } - -type component MTCType -{ - port P MyPCO_PT1; -} - -function akarmi () runs on MTCType { -map(mtc:MyPCO_PT, system:MyPCO_PT2); - -} - -testcase tc_akarmi () runs on MTCType { -map(mtc:MyPCO_PT, system:MyPCO_PT2); - -} - -} - - - -Component type `@test.MTCType' does not have port with name `MyPCO_PT' - - -Component type `@test.MTCType' does not have port with name `MyPCO_PT2' - - :exmp diff --git a/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script index d08f2a2..db2b40f 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script @@ -8609,4 +8609,35 @@ Temp.control :exmp. +*-----------------------------------------------------------* +:h3.Adhoc:: HT23335: Type Infinity is not a valid value for type `integer' which as subtype (-1..65535) +.*-----------------------------------------------------------* +:xmp tab=0. + + + + + +module Temp { +const integer limes_i := 65535; +const float limes_f2 := 65535.0; +const float limes_f1 := -1.0; +type record MyRecI { + integer inum (-1..limes_i) +}; +type record MyRecF { + float fnum (limes_f1..limes_f2) +}; + +template MyRecI t1 := { inum := (0..infinity) }; +template MyRecF t2 := { fnum := (-infinity..0.0) }; + +} + + +(?im)\Infinity is not a valid value for type\b + + +:exmp. + :etext. diff --git a/function_test/doc/TTCN3_Executor_TestReport.doc b/function_test/doc/TTCN3_Executor_TestReport.doc index bb3ede9..458f786 100644 Binary files a/function_test/doc/TTCN3_Executor_TestReport.doc and b/function_test/doc/TTCN3_Executor_TestReport.doc differ diff --git a/mctr2/cli/config_read.l b/mctr2/cli/config_read.l index 7d59c22..be8c193 100644 --- a/mctr2/cli/config_read.l +++ b/mctr2/cli/config_read.l @@ -121,7 +121,7 @@ IPV6 [0-9A-Fa-f:.]+(%[0-9A-Za-z]+)? %x SC_blockcomment SC_DEFINE SC_CSTRING SC_ORDERED_INCLUDE %s SC_MODULE_PARAMETERS SC_LOGGING SC_TESTPORT_PARAMETERS SC_EXECUTE SC_GROUPS -%s SC_COMPONENTS SC_EXTERNAL_COMMANDS SC_MAIN_CONTROLLER SC_INCLUDE +%s SC_COMPONENTS SC_EXTERNAL_COMMANDS SC_MAIN_CONTROLLER SC_INCLUDE SC_PROFILER %% int comment_caller = INITIAL; @@ -158,6 +158,13 @@ IPV6 [0-9A-Fa-f:.]+(%[0-9A-Za-z]+)? } } +<*>"["{WS}PROFILER{WS}"]" { + if (YY_START!=SC_blockcomment) { + BEGIN(SC_PROFILER); + RETURN(ProfilerKeyword); + } +} + <*>"["{WS}TESTPORT_PARAMETERS{WS}"]" { if (YY_START!=SC_blockcomment) { BEGIN(SC_TESTPORT_PARAMETERS); @@ -390,7 +397,7 @@ ifpresent RETURN(IfpresentKeyword); infinity RETURN(InfinityKeyword); } - + { true | false RETURN(BooleanValue); @@ -551,6 +558,16 @@ WARNING_UNQUALIFIED RETURN(LoggingBit); [Dd]elete RETURN(Delete); } + +{ +[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; +} + control RETURN(ControlKeyword); diff --git a/mctr2/cli/config_read.y b/mctr2/cli/config_read.y index f70b160..496d4f3 100644 --- a/mctr2/cli/config_read.y +++ b/mctr2/cli/config_read.y @@ -69,12 +69,14 @@ static void yyprint(FILE *file, int type, const YYSTYPE& value); char *str_val; BIGNUM *int_val; double float_val; + boolean bool_val; cf_timestamp_format ts_val; execute_list_item execute_item_val; } %token ModuleParametersKeyword %token LoggingKeyword +%token ProfilerKeyword %token TestportParametersKeyword %token ExecuteKeyword %token ExternalCommandsKeyword @@ -163,6 +165,13 @@ 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" + %type IntegerValue %type FloatValue KillTimerValue %type HostName StringValue LogFileName @@ -219,6 +228,7 @@ ConfigFile: Section: ModuleParametersSection | LoggingSection + | ProfilerSection | TestportParametersSection | ExecuteSection | ExternalCommandsSection @@ -678,6 +688,50 @@ MatchVerbosityValue: | Detailed ; +/*********************** [PROFILER] ********************************/ + +ProfilerSection: + ProfilerKeyword ProfilerSettings +; + +ProfilerSettings: + /* empty */ +| ProfilerSettings ProfilerSetting optSemiColon +; + +ProfilerSetting: + DisableProfilerSetting +| DisableCoverageSetting +| DatabaseFileSetting +| AggregateDataSetting +| StatisticsFileSetting +| DisableStatisticsSetting +; + +DisableProfilerSetting: + DisableProfilerKeyword AssignmentChar BooleanValue +; + +DisableCoverageSetting: + DisableCoverageKeyword AssignmentChar BooleanValue +; + +DatabaseFileSetting: + DatabaseFileKeyword AssignmentChar StringValue { Free($3); } +; + +AggregateDataSetting: + AggregateDataKeyword AssignmentChar BooleanValue +; + +StatisticsFileSetting: + StatisticsFileKeyword AssignmentChar StringValue { Free($3); } +; + +DisableStatisticsSetting: + DisableStatisticsKeyword AssignmentChar BooleanValue +; + /******************* [TESTPORT_PARAMETERS] section *******************/ TestportParametersSection: diff --git a/regression_test/XML/EXER-whitepaper/EmbedValues.ttcnpp b/regression_test/XML/EXER-whitepaper/EmbedValues.ttcnpp index 9ce328c..fc5cb93 100644 --- a/regression_test/XML/EXER-whitepaper/EmbedValues.ttcnpp +++ b/regression_test/XML/EXER-whitepaper/EmbedValues.ttcnpp @@ -154,6 +154,71 @@ testcase decode_emb_any() runs on EMB CHECK_DECODE(exer_dec_emb_any, str_emb_any, EmbedAnyElem, c_emb_any); } +// EMBED-VALUES with untagged array +// the values are also embedded between the array elements, not just the fields of the record +type record Inner { + integer num, + charstring str +} + +type record length (1..infinity) of Inner RoInner; + +type record Outer { + record of universal charstring embed_values, + integer attr, + octetstring bytes, + RoInner stuff +} with { + variant "embedValues"; + variant(attr) "attribute"; + variant(bytes) "name as 'Bytes'"; + variant(stuff) "untagged"; +} + +DECLARE_EXER_ENCODERS(Outer, emb_outer); + +const Outer c_emb_array := { + embed_values := { "one", "two", "three", "four", "five", "six" }, + attr := 48, + bytes := 'DEADBEEF'O, + stuff := { { 3, "abc" }, { 4, "def" }, { -6, "red" }, { 118, "blue" } } +} + +const Outer c_emb_array_w_holes := { + embed_values := { "one", "", "three", "", "five" }, + attr := 48, + bytes := 'DEADBEEF'O, + stuff := { { 3, "abc" }, { 4, "def" }, { -6, "red" }, { 118, "blue" } } +} + +const universal charstring str_emb_array := +"one" & +"DEADBEEFtwo" & +"3abcthree" & +"4deffour" & +"-6redfive" & +"118bluesix\n"; + +const universal charstring str_emb_array_w_holes := +"one" & +"DEADBEEF" & +"3abcthree" & +"4def" & +"-6redfive" & +"118blue\n"; + +testcase encode_emb_array() runs on EMB +{ + CHECK_METHOD(exer_enc_emb_outer, c_emb_array, str_emb_array); + CHECK_METHOD(exer_enc_emb_outer, c_emb_array_w_holes, str_emb_array_w_holes); +} + +testcase decode_emb_array() runs on EMB +{ + CHECK_DECODE(exer_dec_emb_outer, str_emb_array, Outer, c_emb_array); + CHECK_DECODE(exer_dec_emb_outer, str_emb_array_w_holes, Outer, c_emb_array_w_holes); +} + control { execute(encode_emb()); execute(decode_emb()); @@ -161,6 +226,8 @@ 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()); } } diff --git a/regression_test/XML/Makefile b/regression_test/XML/Makefile index 340501f..6d9a50d 100644 --- a/regression_test/XML/Makefile +++ b/regression_test/XML/Makefile @@ -19,7 +19,7 @@ endif XDIRS := $(wildcard $(SHADOWED)) xsdConverter \ HM60295 HN15589 HQ30408 HR49727 $(RT2_ONLY) \ -XmlWorkflow +XmlWorkflow tpdValidTest # List of fake targets: .PHONY: all dep clean run $(XDIRS) $(addsuffix /, $(XDIRS)) profile diff --git a/regression_test/XML/tpdValidTest/Makefile b/regression_test/XML/tpdValidTest/Makefile new file mode 100644 index 0000000..843b772 --- /dev/null +++ b/regression_test/XML/tpdValidTest/Makefile @@ -0,0 +1,12 @@ +############################################################################### +# 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 +############################################################################### + +dep clean distclean: + +all run: + ./tpdValidTest.sh >&2 diff --git a/regression_test/XML/tpdValidTest/tpdValidTest.sh b/regression_test/XML/tpdValidTest/tpdValidTest.sh new file mode 100755 index 0000000..e587670 --- /dev/null +++ b/regression_test/XML/tpdValidTest/tpdValidTest.sh @@ -0,0 +1,22 @@ +#!/bin/bash +############################################################################### +# 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 +############################################################################### + +TPD_DIR="$WORKSPACE/titan_eclipse/Semantic_Analizer_Tests/tpdTest/" +XSD_DIR="$TTCN3_DIR/etc/xsd/" +XSD="TPD.xsd" + +find $TPD_DIR -type f -name *.tpd | xargs -I {} xmllint --noout --schema $XSD_DIR/$XSD {} + +if [ $? -ne 0 ]; then + echo "Not every .tpd is valid! Overall verdict: fail" + exit 1 +else + echo "Every .tpd is valid! Overall verdict: pass" + exit 0 +fi diff --git a/regression_test/compileonly/HT48786/Makefile b/regression_test/compileonly/HT48786/Makefile new file mode 100644 index 0000000..11d4230 --- /dev/null +++ b/regression_test/compileonly/HT48786/Makefile @@ -0,0 +1,45 @@ +############################################################################### +# 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) + +EXTRA_COMPILER_FLAGS = -p -V 63 + +TTCN3_MODULES = Test1.ttcn Test2.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 = HT48786$(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) + +# an extra compilation is tested (with only parsing and maximum verbosity level) +$(GENERATED_SOURCES) $(GENERATED_HEADERS): $(TTCN3_MODULES) + $(TTCN3_COMPILER) $(EXTRA_COMPILER_FLAGS) $(COMPILER_FLAGS) $^ + $(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/HT48786/Test1.ttcn b/regression_test/compileonly/HT48786/Test1.ttcn new file mode 100644 index 0000000..28b6917 --- /dev/null +++ b/regression_test/compileonly/HT48786/Test1.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 Test1 +{ + +type component EMPTY_CT +{ +} + +type record Union +{ + record of integer record_of_integer, + charstring string +}; + +testcase TC_1() runs on EMPTY_CT +{ + var boolean b := false; + var Union u1 := { + record_of_integer := { + str2int("2"), + str2int("3") + } + }; +} + +control { + execute(TC_1()); +} + +} diff --git a/regression_test/compileonly/HT48786/Test2.ttcn b/regression_test/compileonly/HT48786/Test2.ttcn new file mode 100644 index 0000000..ae4a64a --- /dev/null +++ b/regression_test/compileonly/HT48786/Test2.ttcn @@ -0,0 +1,21 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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 Test2 { + +type record of integer Record1; +type record of Record1 Record2; + +function f1() { + var Record2 r1, r2; + r1 := {{1, 2}}; + r2 := valueof(r1); + r2 := valueof({{1, 2}}); +} + +} diff --git a/regression_test/compileonly/Makefile b/regression_test/compileonly/Makefile index facd1da..f5f02fe 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 + attribQualif HT48786 all dep clean distclean: for dir in $(CODIRS); do $(MAKE) -C $$dir $@ || exit; done diff --git a/regression_test/compileonly/mfgen-tpd/invalid_buildconfig_param/Makefile b/regression_test/compileonly/mfgen-tpd/invalid_buildconfig_param/Makefile index 57fb440..e981527 100644 --- a/regression_test/compileonly/mfgen-tpd/invalid_buildconfig_param/Makefile +++ b/regression_test/compileonly/mfgen-tpd/invalid_buildconfig_param/Makefile @@ -26,8 +26,7 @@ BuildHelloTpd: -t ../HelloTpd.tpd -b notexisting 2>&1 | tee ../output CheckHelloTpd: BuildHelloTpd - if [ `grep -c "error: The active build configuration named 'notexisting' does not exist" ./HelloTpd/output` -ne 1 ] \ - || [ `grep -c "error: Failed to process ../HelloTpd.tpd" ./HelloTpd/output` -ne 1 ]; \ + if [ `grep -c "error: The active build configuration named 'notexisting' does not exist" ./HelloTpd/output` -ne 1 ]; \ then exit 1; fi clean: diff --git a/regression_test/compileonly/mfgen-tpd/library/Makefile b/regression_test/compileonly/mfgen-tpd/library/Makefile index 051955a..a4a5665 100644 --- a/regression_test/compileonly/mfgen-tpd/library/Makefile +++ b/regression_test/compileonly/mfgen-tpd/library/Makefile @@ -40,7 +40,7 @@ BuildLibraryL: a.ttcn -L a.ttcn && ${MAKEPROG} CheckLibraryL: BuildLibraryL - if [ ! -f ./bin/a.a ]; then exit 1; fi + if [ ! -f ./bin/liba.a ]; then exit 1; fi if [ -f ./bin/a ]; then exit 1; fi # ttcn3_makefilegen -L; make executable @@ -51,7 +51,7 @@ BuildLibrary3L: a.ttcn -L a.ttcn && ${MAKEPROG} executable CheckLibrary3L: BuildLibrary3L - if [ -f ./bin3/a.a ]; then exit 1; fi + if [ -f ./bin3/liba.a ]; then exit 1; fi if [ ! -f ./bin3/a ]; then exit 1; fi # ttcn3_makefilegen -L; make library @@ -62,7 +62,7 @@ BuildLibrary2L: a.ttcn -L a.ttcn && ${MAKEPROG} library CheckLibrary2L: BuildLibrary2L - if [ ! -f ./bin2/a.a ]; then exit 1; fi + if [ ! -f ./bin2/liba.a ]; then exit 1; fi if [ -f ./bin2/a ]; then exit 1; fi # ttcn3_makefilegen -L; make run @@ -73,7 +73,7 @@ BuildLibrary4L: a.ttcn -L a.ttcn && ${MAKEPROG} all CheckLibrary4L: BuildLibrary4L - if [ ! -f ./bin4/a.a ]; then exit 1; fi + if [ ! -f ./bin4/liba.a ]; then exit 1; fi if [ -f ./bin4/a ]; then exit 1; fi #### Without -L #### @@ -86,7 +86,7 @@ BuildLibrary: a.ttcn a.ttcn && ${MAKEPROG} CheckLibrary: BuildLibrary - if [ -f ./bin/a.a ]; then exit 1; fi + if [ -f ./bin/liba.a ]; then exit 1; fi if [ ! -f ./bin/a ]; then exit 1; fi # ttcn3_makefilegen; make executable @@ -97,7 +97,7 @@ BuildLibrary3: a.ttcn a.ttcn && ${MAKEPROG} executable CheckLibrary3: BuildLibrary3 - if [ -f ./bin3/a.a ]; then exit 1; fi + if [ -f ./bin3/liba.a ]; then exit 1; fi if [ ! -f ./bin3/a ]; then exit 1; fi # ttcn3_makefilegen; make library @@ -108,7 +108,7 @@ BuildLibrary2: a.ttcn a.ttcn && ${MAKEPROG} library CheckLibrary2: BuildLibrary2 - if [ ! -f ./bin2/a.a ]; then exit 1; fi + if [ ! -f ./bin2/liba.a ]; then exit 1; fi if [ -f ./bin2/a ]; then exit 1; fi # ttcn3_makefilegen; make all @@ -119,7 +119,7 @@ BuildLibrary4: a.ttcn a.ttcn && ${MAKEPROG} all CheckLibrary4: BuildLibrary4 - if [ -f ./bin4/a.a ]; then exit 1; fi + if [ -f ./bin4/liba.a ]; then exit 1; fi if [ ! -f ./bin4/a ]; then exit 1; fi ############################### @@ -136,7 +136,7 @@ Build_dynamic: a.ttcn a.ttcn && ${MAKEPROG} Check_dynamic: Build_dynamic - if [ ! -f ./bin_dynamic/a_lib.so ]; then exit 1; fi + if [ ! -f ./bin_dynamic/liba.so ]; then exit 1; fi if [ -f ./bin_dynamic/a ]; then exit 1; fi # ttcn3_makefilegen -L -l; make library @@ -147,7 +147,7 @@ Build_dynamic2: a.ttcn a.ttcn && ${MAKEPROG} library Check_dynamic2: Build_dynamic2 - if [ ! -f ./bin_dynamic2/a_lib.so ]; then exit 1; fi + if [ ! -f ./bin_dynamic2/liba.so ]; then exit 1; fi if [ -f ./bin_dynamic2/a ]; then exit 1; fi # ttcn3_makefilegen -L -l; make executable @@ -158,7 +158,7 @@ Build_dynamic3: a.ttcn a.ttcn && ${MAKEPROG} executable Check_dynamic3: Build_dynamic3 - if [ ! -f ./bin_dynamic3/a_lib.so ]; then exit 1; fi + if [ ! -f ./bin_dynamic3/liba.so ]; then exit 1; fi if [ -f ./bin_dynamic3/a.so ]; then exit 1; fi if [ ! -f ./bin_dynamic3/a ]; then exit 1; fi @@ -172,7 +172,7 @@ Build_dynamic4: a.ttcn a.ttcn && ${MAKEPROG} Check_dynamic4: Build_dynamic4 - if [ -f ./bin_dynamic4/a_lib.so ]; then exit 1; fi + if [ -f ./bin_dynamic4/liba.so ]; then exit 1; fi if [ ! -f ./bin_dynamic4/a ]; then exit 1; fi # ttcn3_makefilegen -l; make library @@ -183,7 +183,7 @@ Build_dynamic5: a.ttcn a.ttcn && ${MAKEPROG} library Check_dynamic5: Build_dynamic5 - if [ ! -f ./bin_dynamic5/a_lib.so ]; then exit 1; fi + if [ ! -f ./bin_dynamic5/liba.so ]; then exit 1; fi if [ -f ./bin_dynamic5/a ]; then exit 1; fi # ttcn3_makefilegen -l; make executable @@ -194,7 +194,7 @@ Build_dynamic6: a.ttcn a.ttcn && ${MAKEPROG} executable Check_dynamic6: Build_dynamic6 - if [ -f ./bin_dynamic6/a_lib.so ]; then exit 1; fi + if [ -f ./bin_dynamic6/liba.so ]; then exit 1; fi if [ ! -f ./bin_dynamic6/a ]; then exit 1; fi @@ -208,7 +208,7 @@ Build_dynamic_central: b.ttcn Central b.ttcn ../central_storage/central.ttcn && ${MAKEPROG} Check_dynamic_central: Build_dynamic_central - if [ ! -f ./bin_central/b_lib.so ]; then exit 1; fi + if [ ! -f ./bin_central/libb.so ]; then exit 1; fi if [ -f ./bin_central/b ]; then exit 1; fi # ttcn3_makefilegen -c -l; make @@ -236,7 +236,7 @@ BuildHelloTpd: CheckHelloTpd: BuildHelloTpd if [ -f HelloTpd/bin/HelloTpd_test.exe ]; then exit 1; fi - if [ ! -f HelloTpd/bin/HelloTpd_test.a ]; then exit 1; fi + if [ ! -f HelloTpd/bin/libHelloTpd_test.a ]; then exit 1; fi # the default target is executable in the tpd file # check if the command line option overrides the one defined in the tpd @@ -249,7 +249,7 @@ BuildHelloTpd2: CheckHelloTpd2: BuildHelloTpd2 if [ -f HelloTpd2/bin/HelloTpd_test.exe ]; then exit 1; fi - if [ ! -f HelloTpd2/bin/HelloTpd_test.a ]; then exit 1; fi + if [ ! -f HelloTpd2/bin/libHelloTpd_test.a ]; then exit 1; fi clean: -rm -rf bin* diff --git a/regression_test/json/Functions.ttcn b/regression_test/json/Functions.ttcn index 18224c8..6064b62 100755 --- a/regression_test/json/Functions.ttcn +++ b/regression_test/json/Functions.ttcn @@ -102,6 +102,9 @@ external function f_enc_cba(in CBA u) return octetstring external function f_enc_stuff(in Stuff x) return octetstring with { extension "prototype(convert) encode(JSON)" } +external function f_enc_hpt(in HasPardType x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + // for ASN.1 types external function f_enc_seqofint(in SeqOfInt x) return octetstring with { extension "prototype(convert) encode(JSON)" } @@ -117,6 +120,12 @@ external function f_enc_strings(in ManyStrings x) return octetstring external function f_enc_complex(in ComplexSet x) return octetstring with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_obj(in Object x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_null(in HasNull x) return octetstring + with { extension "prototype(convert) encode(JSON)" } //=================== Decoders ===================================== @@ -199,6 +208,9 @@ external function f_dec_stuff(in octetstring x) return Stuff external function f_dec_def(in octetstring x) return RecDef with { extension "prototype(convert) decode(JSON)" } +external function f_dec_hpt(in octetstring x) return HasPardType + with { extension "prototype(convert) decode(JSON)" } + // for ASN.1 types external function f_dec_seqofint(in octetstring x) return SeqOfInt with { extension "prototype(convert) decode(JSON)" } @@ -214,6 +226,12 @@ external function f_dec_strings(in octetstring x) return ManyStrings external function f_dec_complex(in octetstring x) return ComplexSet with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_obj(in octetstring x) return Object + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_null(in octetstring x) return HasNull + with { extension "prototype(convert) decode(JSON)" } //============== Internal Functions ==================== diff --git a/regression_test/json/JsonData.asn b/regression_test/json/JsonData.asn index a100699..962186e 100644 --- a/regression_test/json/JsonData.asn +++ b/regression_test/json/JsonData.asn @@ -19,8 +19,10 @@ IMPORTS ; -- Type definitions -- ---------------------- +-- Sequence of SeqOfInt ::= SEQUENCE OF INTEGER +-- Sequence SeqProduct ::= SEQUENCE { name UniversalString, price REAL, @@ -28,12 +30,14 @@ SeqProduct ::= SEQUENCE { available BOOLEAN } +-- Choice Number ::= CHOICE { decimal INTEGER, binary BIT STRING, hexadecimal OCTET STRING } +-- Choice containing all string types AnyString ::= CHOICE { generalstr GeneralString, numericstr NumericString, @@ -48,14 +52,93 @@ AnyString ::= CHOICE { visiblestr VisibleString } +-- Sequence of strings ManyStrings ::= SEQUENCE OF AnyString +-- Set containing all of the above ComplexSet ::= SET { product SeqProduct, numbers SET OF Number, strings ManyStrings } +Priority ::= ENUMERATED { low, normal, medium, high, urgent } + +Conditionality ::= ENUMERATED { optional, conditional, mandatory } + +ProtocolElem-ID ::= INTEGER (0..65535) + +-- IOC +PROTOCOL-ELEMS ::= CLASS +{ + &id ProtocolElem-ID UNIQUE, + &priority Priority, + &Value, + &conditionality Conditionality +} +WITH SYNTAX +{ + ID &id + PRIORITY &priority + TYPE &Value + CONDITIONALITY &conditionality +} + +-- parameterized type +ProtocolElem-Field {PROTOCOL-ELEMS : ElemsSetParam} ::= SEQUENCE +{ + id PROTOCOL-ELEMS.&id ({ElemsSetParam}), + priority PROTOCOL-ELEMS.&priority ({ElemsSetParam}{@id}), + val PROTOCOL-ELEMS.&Value ({ElemsSetParam}{@id}) +} + + +-- Information objects +ies-Set-Element-1 PROTOCOL-ELEMS ::= +{ + ID 0 + PRIORITY low + TYPE INTEGER + CONDITIONALITY mandatory +} + +ies-Set-Element-2 PROTOCOL-ELEMS ::= +{ + ID 1 + PRIORITY high + TYPE IA5String + CONDITIONALITY optional +} +-- Information Object Set +Elems-Set PROTOCOL-ELEMS ::= { ies-Set-Element-1 | ies-Set-Element-2 } + + +-- instantiation +ProtocolElem-Field1 ::= ProtocolElem-Field {{Elems-Set}} + +ProtocolElem-Field2 ::= ProtocolElem-Field {{ies-Set-Element-2 }} + +-- Choice containing NULL +Price ::= CHOICE +{ + value REAL, + invaluable NULL +} + +-- Sequence containing an object identifier and an ANY type +Object ::= SEQUENCE +{ + id OBJECT IDENTIFIER, + data ANY +} + +-- Sequence containing an optional NULL field +HasNull ::= SEQUENCE +{ + theNull NULL OPTIONAL +} + + -- Values and their encoding -- ------------------------------- @@ -114,4 +197,19 @@ c-set-val ComplexSet ::= { c-set-val-str VisibleString ::= "{""product"":{""name"":""Headset"",""price"":28.500000,""available"":false},""numbers"":[{""hexadecimal"":""16678D""},{""decimal"":12}],""strings"":[{""printablestr"":""first""},{""numericstr"":""2""}]}" +-- Object +c-obj Object ::= { + id { joint-iso-itu-t remote-operations(4) informationObjects(5) version1(0) }, + data 'DEADBEEF'H +} + +c-obj-str VisibleString ::= "{""id"":""2.4.5.0"",""data"":""DEADBEEF""}" + +-- HasNull +c-null HasNull ::= { theNull NULL } +c-not-null HasNull ::= {} + +c-null-str VisibleString ::= "{""theNull"":null}" +c-not-null-str VisibleString ::= "{}" + END diff --git a/regression_test/json/Testcases.ttcn b/regression_test/json/Testcases.ttcn index 81cb2fd..e452ecc 100755 --- a/regression_test/json/Testcases.ttcn +++ b/regression_test/json/Testcases.ttcn @@ -517,6 +517,38 @@ testcase tc_asn_complex() runs on MTC { f_bool2verdict(match(f_dec_complex(os), c_set_val)); } +// ====== Special ASN.1 types ====== +// record containing an open type and a possible NULL value +testcase tc_asn_open_type_and_null() runs on MTC { + var HasPardType x := { + pard := { + id := 0, + priority := low, + val := { iNTEGER := 19 } + }, + buul := true, + price := { invaluable := NULL } + }; + var octetstring os := char2oct("{\"pard\":{\"id\":0,\"priority\":\"low\",\"val\":{\"iNTEGER\":19}},\"buul\":true,\"price\":{\"invaluable\":null}}"); + f_check_encoding(encoded := f_enc_hpt(x), expected := os); + f_bool2verdict(match(f_dec_hpt(os), x)); +} + +// SEQUENCE containing an object identifier and an ANY type +testcase tc_asn_objid_and_any() runs on MTC { + var octetstring os := char2oct(c_obj_str); + f_check_encoding(encoded:= f_enc_obj(c_obj), expected := os); + f_bool2verdict(match(f_dec_obj(os), c_obj)); +} + +testcase tc_asn_optional_null() runs on MTC { + var octetstring os := char2oct(c_null_str); + f_check_encoding(encoded:= f_enc_null(c_null), expected := os); + f_bool2verdict(match(f_dec_null(os), c_null)); + os := char2oct(c_not_null_str); + f_check_encoding(encoded:= f_enc_null(c_not_null), expected := os); + f_bool2verdict(match(f_dec_null(os), c_not_null)); +} //========================================================================= // Control @@ -572,6 +604,10 @@ control { execute(tc_asn_choice()); execute(tc_asn_strings()); execute(tc_asn_complex()); + + execute(tc_asn_open_type_and_null()); + execute(tc_asn_objid_and_any()); + execute(tc_asn_optional_null()); } diff --git a/regression_test/json/Types.ttcn b/regression_test/json/Types.ttcn index f1f372c..21eef282 100755 --- a/regression_test/json/Types.ttcn +++ b/regression_test/json/Types.ttcn @@ -7,6 +7,8 @@ ******************************************************************************/ module Types { +import from JsonData all; + const integer c_imported_i :=11; type component MTC {} @@ -156,6 +158,11 @@ type record RecDef { variant(b) "JSON:default(false)"; } +type record HasPardType { + ProtocolElem_Field1 pard, + boolean buul, + Price price +} } with { encode "JSON"; diff --git a/regression_test/recofOper/Makefile b/regression_test/recofOper/Makefile index 654a1d7..e4b9c7a 100644 --- a/regression_test/recofOper/Makefile +++ b/regression_test/recofOper/Makefile @@ -13,8 +13,15 @@ include $(TOPDIR)/Makefile.regression TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) -TTCN3_MODULES = TrecofOper.ttcn TrecofParamRef.ttcn +TTCN3_MODULES = TrecofOper.ttcn +ifdef RT2 +TTCN3_MODULES += TrecofParamRef.ttcn ASN1_MODULES = BerType.asn +CFG_FILE = config_rt2.cfg +else +ASN1_MODULES = +CFG_FILE = config.cfg +endif GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) $(ASN1_MODULES:.asn=.cc) GENERATED_HEADERS = $(GENERATED_SOURCES:.cc=.hh) @@ -41,7 +48,7 @@ clean distclean: dep: $(GENERATED_SOURCES) makedepend $(CPPFLAGS) $(GENERATED_SOURCES) -run: $(TARGET) config.cfg +run: $(TARGET) $(CFG_FILE) ./$^ .NOTPARALLEL: diff --git a/regression_test/recofOper/config.cfg b/regression_test/recofOper/config.cfg index a3b9428..eb0d2a5 100644 --- a/regression_test/recofOper/config.cfg +++ b/regression_test/recofOper/config.cfg @@ -12,4 +12,3 @@ FileMask := LOG_ALL ConsoleMask := TTCN_WARNING | TTCN_ERROR | TTCN_TESTCASE | TTCN_STATISTICS [EXECUTE] TrecofOper -TrecofParamRef diff --git a/regression_test/recofOper/config_rt2.cfg b/regression_test/recofOper/config_rt2.cfg new file mode 100644 index 0000000..8cd9abc --- /dev/null +++ b/regression_test/recofOper/config_rt2.cfg @@ -0,0 +1,15 @@ +############################################################################### +# 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_PARAMETERS] +[LOGGING] +Logfile := "recofOper.log" +FileMask := LOG_ALL +ConsoleMask := TTCN_WARNING | TTCN_ERROR | TTCN_TESTCASE | TTCN_STATISTICS +[EXECUTE] +TrecofOper +TrecofParamRef diff --git a/regression_test/ttcn2json/CompareSchemas.ttcn b/regression_test/ttcn2json/CompareSchemas.ttcn new file mode 100644 index 0000000..426111b --- /dev/null +++ b/regression_test/ttcn2json/CompareSchemas.ttcn @@ -0,0 +1,117 @@ +/****************************************************************************** + * 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 compares two JSON schemas generated by the TITAN compiler +module CompareSchemas { + +////////////////////////////////////// +// JSON schema container data types // +////////////////////////////////////// + +// top level object +type record JsonSchema { + DefSchemas defs, + RefSchemas refs +} + +// definitions section: +type set of DefSchema DefSchemas; + +type record DefSchema { + charstring moduleName, + charstring typeName, + TypeSchema schema +} + +type set of TypeSchemaElement TypeSchema; + +type record TypeSchemaElement { + ElemKey key, + ElemValue val +} + +type enumerated ElemKey { + Ref, Type, SubType, Pattern, OriginalName, UnusedAlias, MinItems, MaxItems, // strVal + AdditionalProperties, OmitAsNull, // boolVal + Default, // strVal or boolVal + Enum, NumericValues, Required, FieldOrder, // strArrayVal + Items, // typeVal + AnyOf, // typeArrayVal + Properties // fieldSetVal +} + +type union ElemValue { + charstring strVal, + boolean boolVal, + record of charstring strArrayVal, + TypeSchema typeVal, + record of TypeSchema typeArrayVal, + set of FieldValue fieldSetVal +} + +type record FieldValue { + charstring fieldName, + TypeSchema schema +} + +// references/functions section: +type set of RefSchema RefSchemas; + +type record RefSchema { + charstring ref, + EncDecData enc optional, + EncDecData dec optional +} + +type record EncDecData { + PrototypeData prototype, + ErrorBehaviorData eb optional, + charstring printing optional +} + +type record of charstring PrototypeData; + +type record of ErrorBehaviorElem ErrorBehaviorData; + +type record ErrorBehaviorElem { + charstring errorType, + charstring errorBehavior +} + +////////////////////////////////// +// Import and compare functions // +////////////////////////////////// + +// Imports a JSON schema from the given file and stores it in the specified container. +// Throws a Dynamic Testcase Error if the file cannot be read or does not have the correct format. +// The resulting JsonSchema should not have any unbound fields. +external function f_ext_import_schema(in charstring file, out JsonSchema schema); + +// Compares the two schemas found in the files specified by the parameters. +// Returns true if they are equal. +function f_compare_schemas(in charstring schema_file1, in charstring schema_file2) return boolean +{ + // read the schemas from the files + var JsonSchema schema1; + f_ext_import_schema(schema_file1, schema1); + var JsonSchema schema2; + f_ext_import_schema(schema_file2, schema2); + + // log both schemas (good luck digging through these...) + //log("Generated (", schema_file1, "): ", schema1); + //log("Expected (", schema_file2, "): ", schema2); + + // set the verdict depending on their equality + if (match(schema1, schema2)) { + return true; + } + log(match(schema1, schema2)); + return false; +} + +} diff --git a/regression_test/ttcn2json/General_Types_e.json b/regression_test/ttcn2json/General_Types_e.json index fa9bfec..3fc889a 100644 --- a/regression_test/ttcn2json/General_Types_e.json +++ b/regression_test/ttcn2json/General_Types_e.json @@ -3,178 +3,222 @@ "General_Types" : { "BIT1" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT10" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT11" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT12" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT12n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT14" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT14_24n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT14n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT15" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT15n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT15np" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT16" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT16_BO_LAST" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT16n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT1n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT1np" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT2" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT24" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT2n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT2np" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT3" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT31" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT32_BO_LAST" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT3n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT3np" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT4" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT4n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT4np" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT5" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT56" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT56n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT5n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT5np" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT6" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT6_BO_LAST" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT6n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT6np" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT7" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT7n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT7np" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT8" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT8n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT9" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "BIT9n" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" }, "CHAR4" : { @@ -183,58 +227,72 @@ }, "Dummy" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "HEX0_16" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX0_18n" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX1" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX15n" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX16n" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX1_20n" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX1_32" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX1_34n" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX24n" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX4n" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX5_16" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX6n" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "HEX8n" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" }, "INT1" : { @@ -343,102 +401,127 @@ }, "OCT0" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT0n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT10" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT100n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT10n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT11" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT11n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT12" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT128n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT12n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT13" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT13n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT14" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT14n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT15" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT15n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT16" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT16n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT17" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT17n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT18" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT18n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT19" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT19n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1List" : { @@ -450,122 +533,152 @@ }, "OCT1_112n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_12" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_127n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_128n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_12n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_15n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_16n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_172n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_18n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_20n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_24n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_260" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_32" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_32n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_34n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_3n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_46n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_4n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_50" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_50n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_5n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_6n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_7n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_8" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1_8n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT1n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT2" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT20" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT20n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT28n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT2List" : { @@ -577,26 +690,32 @@ }, "OCT2n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT3" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT32" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT32n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT34" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT34n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT3List" : { @@ -608,42 +727,52 @@ }, "OCT3_14n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT3_17n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT3_5n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT3_7n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT3_8" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT3_8n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT3n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT4" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT46" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT46n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT4List" : { @@ -655,22 +784,27 @@ }, "OCT4_8n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT4n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT5" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT500n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT50n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT5List" : { @@ -682,14 +816,17 @@ }, "OCT5n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT6" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT69n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT6List" : { @@ -701,10 +838,12 @@ }, "OCT6n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT7" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT7List" : { @@ -716,30 +855,37 @@ }, "OCT7n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT8" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT8n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT9" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCT9n" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCTN" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "OCTNn" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "ProtocolList" : { @@ -761,10 +907,586 @@ "bssmap", "ranap", "dtap" + ], + "numericValues" : [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 ] } } }, "anyOf" : [ + { + "$ref" : "#/definitions/General_Types/OCT7n" + }, + { + "$ref" : "#/definitions/General_Types/OCT8n" + }, + { + "$ref" : "#/definitions/General_Types/OCT9n" + }, + { + "$ref" : "#/definitions/General_Types/BIT2n" + }, + { + "$ref" : "#/definitions/General_Types/BIT3n" + }, + { + "$ref" : "#/definitions/General_Types/BIT4n" + }, + { + "$ref" : "#/definitions/General_Types/BIT5n" + }, + { + "$ref" : "#/definitions/General_Types/BIT6n" + }, + { + "$ref" : "#/definitions/General_Types/BIT7n" + }, + { + "$ref" : "#/definitions/General_Types/BIT8n" + }, + { + "$ref" : "#/definitions/General_Types/BIT9n" + }, + { + "$ref" : "#/definitions/General_Types/BIT12n" + }, + { + "$ref" : "#/definitions/General_Types/BIT14n" + }, + { + "$ref" : "#/definitions/General_Types/BIT15n" + }, + { + "$ref" : "#/definitions/General_Types/BIT16n" + }, + { + "$ref" : "#/definitions/General_Types/BIT56n" + }, + { + "$ref" : "#/definitions/General_Types/BIT14_24n" + }, + { + "$ref" : "#/definitions/General_Types/BIT1np" + }, + { + "$ref" : "#/definitions/General_Types/BIT2np" + }, + { + "$ref" : "#/definitions/General_Types/BIT11" + }, + { + "$ref" : "#/definitions/General_Types/BIT3np" + }, + { + "$ref" : "#/definitions/General_Types/BIT4np" + }, + { + "$ref" : "#/definitions/General_Types/BIT5np" + }, + { + "$ref" : "#/definitions/General_Types/BIT6np" + }, + { + "$ref" : "#/definitions/General_Types/BIT7np" + }, + { + "$ref" : "#/definitions/General_Types/BIT15np" + }, + { + "$ref" : "#/definitions/General_Types/BIT1" + }, + { + "$ref" : "#/definitions/General_Types/BIT2" + }, + { + "$ref" : "#/definitions/General_Types/BIT3" + }, + { + "$ref" : "#/definitions/General_Types/BIT4" + }, + { + "$ref" : "#/definitions/General_Types/BIT1n" + }, + { + "$ref" : "#/definitions/General_Types/BIT5" + }, + { + "$ref" : "#/definitions/General_Types/BIT6" + }, + { + "$ref" : "#/definitions/General_Types/BIT7" + }, + { + "$ref" : "#/definitions/General_Types/BIT8" + }, + { + "$ref" : "#/definitions/General_Types/BIT9" + }, + { + "$ref" : "#/definitions/General_Types/BIT10" + }, + { + "$ref" : "#/definitions/General_Types/OCT46n" + }, + { + "$ref" : "#/definitions/General_Types/BIT12" + }, + { + "$ref" : "#/definitions/General_Types/BIT14" + }, + { + "$ref" : "#/definitions/General_Types/BIT15" + }, + { + "$ref" : "#/definitions/General_Types/BIT16" + }, + { + "$ref" : "#/definitions/General_Types/BIT24" + }, + { + "$ref" : "#/definitions/General_Types/BIT31" + }, + { + "$ref" : "#/definitions/General_Types/BIT56" + }, + { + "$ref" : "#/definitions/General_Types/OCT0n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1n" + }, + { + "$ref" : "#/definitions/General_Types/OCT2n" + }, + { + "$ref" : "#/definitions/General_Types/OCT3n" + }, + { + "$ref" : "#/definitions/General_Types/OCT4n" + }, + { + "$ref" : "#/definitions/General_Types/OCT5n" + }, + { + "$ref" : "#/definitions/General_Types/OCT6n" + }, + { + "$ref" : "#/definitions/General_Types/OCT10n" + }, + { + "$ref" : "#/definitions/General_Types/OCT11n" + }, + { + "$ref" : "#/definitions/General_Types/OCT12n" + }, + { + "$ref" : "#/definitions/General_Types/OCT13n" + }, + { + "$ref" : "#/definitions/General_Types/OCT14n" + }, + { + "$ref" : "#/definitions/General_Types/OCT15n" + }, + { + "$ref" : "#/definitions/General_Types/OCT16n" + }, + { + "$ref" : "#/definitions/General_Types/OCT17n" + }, + { + "$ref" : "#/definitions/General_Types/OCT18n" + }, + { + "$ref" : "#/definitions/General_Types/OCT19n" + }, + { + "$ref" : "#/definitions/General_Types/OCT20n" + }, + { + "$ref" : "#/definitions/General_Types/OCT28n" + }, + { + "$ref" : "#/definitions/General_Types/OCT32n" + }, + { + "$ref" : "#/definitions/General_Types/OCT34n" + }, + { + "$ref" : "#/definitions/General_Types/OCT6" + }, + { + "$ref" : "#/definitions/General_Types/OCT50n" + }, + { + "$ref" : "#/definitions/General_Types/OCT69n" + }, + { + "$ref" : "#/definitions/General_Types/OCT100n" + }, + { + "$ref" : "#/definitions/General_Types/OCT128n" + }, + { + "$ref" : "#/definitions/General_Types/OCT500n" + }, + { + "$ref" : "#/definitions/General_Types/OCTNn" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_3n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_4n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_5n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_6n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_7n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_8n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_12n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_15n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_16n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_18n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_20n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_24n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_32n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_34n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_46n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_50n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_112n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_127n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_128n" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_172n" + }, + { + "$ref" : "#/definitions/General_Types/OCT3_5n" + }, + { + "$ref" : "#/definitions/General_Types/OCT3_7n" + }, + { + "$ref" : "#/definitions/General_Types/OCT3_8n" + }, + { + "$ref" : "#/definitions/General_Types/OCT3_14n" + }, + { + "$ref" : "#/definitions/General_Types/OCT3_17n" + }, + { + "$ref" : "#/definitions/General_Types/OCT4_8n" + }, + { + "$ref" : "#/definitions/General_Types/CHAR4" + }, + { + "$ref" : "#/definitions/General_Types/HEX4n" + }, + { + "$ref" : "#/definitions/General_Types/HEX6n" + }, + { + "$ref" : "#/definitions/General_Types/HEX8n" + }, + { + "$ref" : "#/definitions/General_Types/HEX15n" + }, + { + "$ref" : "#/definitions/General_Types/HEX16n" + }, + { + "$ref" : "#/definitions/General_Types/HEX24n" + }, + { + "$ref" : "#/definitions/General_Types/HEX0_18n" + }, + { + "$ref" : "#/definitions/General_Types/HEX1_20n" + }, + { + "$ref" : "#/definitions/General_Types/HEX1_34n" + }, + { + "$ref" : "#/definitions/General_Types/INT3nb" + }, + { + "$ref" : "#/definitions/General_Types/INT4nb" + }, + { + "$ref" : "#/definitions/General_Types/INT5nb" + }, + { + "$ref" : "#/definitions/General_Types/INT8nb" + }, + { + "$ref" : "#/definitions/General_Types/INT2nbp" + }, + { + "$ref" : "#/definitions/General_Types/INT1nbp" + }, + { + "$ref" : "#/definitions/General_Types/INT3nbp" + }, + { + "$ref" : "#/definitions/General_Types/INT5nbp" + }, + { + "$ref" : "#/definitions/General_Types/INT9nbp" + }, + { + "$ref" : "#/definitions/General_Types/INT13nbp" + }, + { + "$ref" : "#/definitions/General_Types/INT15nbp" + }, + { + "$ref" : "#/definitions/General_Types/BIT6_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/BIT16_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/BIT32_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/Dummy" + }, + { + "$ref" : "#/definitions/General_Types/OCT0" + }, + { + "$ref" : "#/definitions/General_Types/OCT1" + }, + { + "$ref" : "#/definitions/General_Types/OCT2" + }, + { + "$ref" : "#/definitions/General_Types/OCT3" + }, + { + "$ref" : "#/definitions/General_Types/OCT4" + }, + { + "$ref" : "#/definitions/General_Types/OCT5" + }, + { + "$ref" : "#/definitions/General_Types/OCT7" + }, + { + "$ref" : "#/definitions/General_Types/OCT8" + }, + { + "$ref" : "#/definitions/General_Types/OCT9" + }, + { + "$ref" : "#/definitions/General_Types/OCT10" + }, + { + "$ref" : "#/definitions/General_Types/OCT11" + }, + { + "$ref" : "#/definitions/General_Types/OCT12" + }, + { + "$ref" : "#/definitions/General_Types/OCT13" + }, + { + "$ref" : "#/definitions/General_Types/OCT14" + }, + { + "$ref" : "#/definitions/General_Types/OCT15" + }, + { + "$ref" : "#/definitions/General_Types/OCT16" + }, + { + "$ref" : "#/definitions/General_Types/OCT17" + }, + { + "$ref" : "#/definitions/General_Types/OCT18" + }, + { + "$ref" : "#/definitions/General_Types/OCT19" + }, + { + "$ref" : "#/definitions/General_Types/OCT20" + }, + { + "$ref" : "#/definitions/General_Types/OCT32" + }, + { + "$ref" : "#/definitions/General_Types/OCT34" + }, + { + "$ref" : "#/definitions/General_Types/OCT46" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_260" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_8" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_12" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_32" + }, + { + "$ref" : "#/definitions/General_Types/OCT1_50" + }, + { + "$ref" : "#/definitions/General_Types/OCT3_8" + }, + { + "$ref" : "#/definitions/General_Types/OCTN" + }, + { + "$ref" : "#/definitions/General_Types/HEX1" + }, + { + "$ref" : "#/definitions/General_Types/HEX0_16" + }, + { + "$ref" : "#/definitions/General_Types/HEX5_16" + }, + { + "$ref" : "#/definitions/General_Types/HEX1_32" + }, + { + "$ref" : "#/definitions/General_Types/INT1" + }, + { + "$ref" : "#/definitions/General_Types/LIN1" + }, + { + "$ref" : "#/definitions/General_Types/LIN2" + }, + { + "$ref" : "#/definitions/General_Types/LIN2_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/LIN3_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/LIN4_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/INT1b" + }, + { + "$ref" : "#/definitions/General_Types/INT2b" + }, + { + "$ref" : "#/definitions/General_Types/INT3b" + }, + { + "$ref" : "#/definitions/General_Types/INT4b" + }, + { + "$ref" : "#/definitions/General_Types/INT5b" + }, + { + "$ref" : "#/definitions/General_Types/INT6b" + }, + { + "$ref" : "#/definitions/General_Types/INT7b" + }, + { + "$ref" : "#/definitions/General_Types/INT11b_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/INT12b_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/INT13b_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/INT14b_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/INT20b_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/INT31b_BO_LAST" + }, + { + "$ref" : "#/definitions/General_Types/Integers" + }, + { + "$ref" : "#/definitions/General_Types/Integer_array" + }, + { + "$ref" : "#/definitions/General_Types/Protocols" + }, + { + "$ref" : "#/definitions/General_Types/OCT1List" + }, + { + "$ref" : "#/definitions/General_Types/OCT2List" + }, + { + "$ref" : "#/definitions/General_Types/OCT3List" + }, + { + "$ref" : "#/definitions/General_Types/OCT4List" + }, + { + "$ref" : "#/definitions/General_Types/OCT5List" + }, + { + "$ref" : "#/definitions/General_Types/OCT6List" + }, + { + "$ref" : "#/definitions/General_Types/OCT7List" + }, + { + "$ref" : "#/definitions/General_Types/ProtocolList" + } ] } diff --git a/regression_test/ttcn2json/Main.ttcn b/regression_test/ttcn2json/Main.ttcn new file mode 100644 index 0000000..258f2a2 --- /dev/null +++ b/regression_test/ttcn2json/Main.ttcn @@ -0,0 +1,37 @@ +/****************************************************************************** + * 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 Main +{ + +import from PDU_Definitions all; + +type record HasPardType { + ProtocolElem_Field1 pard, + boolean buul, + Price price +} + +external function f_enc_hpt(in HasPardType x) return octetstring + with { extension "prototype(convert) encode(JSON) printing(pretty)" } + +external function f_dec_hpt(in octetstring x) return HasPardType + with { extension "prototype(convert) decode(JSON)" } + +external function f_enc_pard(in ProtocolElem_Field1 x) return octetstring + with { extension "prototype(convert) encode(JSON) printing(pretty)" } + +external function f_enc_obj(in Object x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_dec_obj(in octetstring x) return Object + with { extension "prototype(convert) decode(JSON)" } + +} with { + encode "JSON" +} diff --git a/regression_test/ttcn2json/Main_e.json b/regression_test/ttcn2json/Main_e.json new file mode 100644 index 0000000..40a29b3 --- /dev/null +++ b/regression_test/ttcn2json/Main_e.json @@ -0,0 +1,279 @@ +{ + "definitions" : { + "Main" : { + "HasPardType" : { + "type" : "object", + "subType" : "record", + "properties" : { + "pard" : { + "$ref" : "#/definitions/PDU_Definitions/ProtocolElem_Field1" + }, + "buul" : { + "type" : "boolean" + }, + "price" : { + "$ref" : "#/definitions/PDU_Definitions/Price" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "pard", + "buul", + "price" + ], + "required" : [ + "pard", + "buul", + "price" + ] + } + }, + "PDU_Definitions" : { + "Priority" : { + "enum" : [ + "low", + "normal", + "medium", + "high", + "urgent" + ], + "numericValues" : [ + 0, + 1, + 2, + 3, + 4 + ] + }, + "Conditionality" : { + "enum" : [ + "optional_", + "conditional", + "mandatory" + ], + "numericValues" : [ + 0, + 1, + 2 + ] + }, + "ProtocolElem_ID" : { + "type" : "integer" + }, + "ProtocolElem_Field2" : { + "type" : "object", + "subType" : "record", + "properties" : { + "id" : { + "$ref" : "#/definitions/PDU_Definitions/ProtocolElem_ID" + }, + "priority" : { + "$ref" : "#/definitions/PDU_Definitions/Priority" + }, + "val" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "iA5String" : { + "type" : "string", + "subType" : "charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "iA5String" + ] + } + ] + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "id", + "priority", + "val" + ], + "required" : [ + "id", + "priority", + "val" + ] + }, + "ProtocolElem_Field1" : { + "type" : "object", + "subType" : "record", + "properties" : { + "id" : { + "$ref" : "#/definitions/PDU_Definitions/ProtocolElem_ID" + }, + "priority" : { + "$ref" : "#/definitions/PDU_Definitions/Priority" + }, + "val" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "iNTEGER" : { + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "iNTEGER" + ] + }, + { + "type" : "object", + "properties" : { + "iA5String" : { + "type" : "string", + "subType" : "charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "iA5String" + ] + } + ] + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "id", + "priority", + "val" + ], + "required" : [ + "id", + "priority", + "val" + ] + }, + "Price" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "value_" : { + "anyOf" : [ + { + "type" : "number" + }, + { + "enum" : [ + "not_a_number", + "infinity", + "-infinity" + ] + } + ] + } + }, + "additionalProperties" : false, + "required" : [ + "value_" + ] + }, + { + "type" : "object", + "properties" : { + "invaluable" : { + "type" : "null" + } + }, + "additionalProperties" : false, + "required" : [ + "invaluable" + ] + } + ] + }, + "Object" : { + "type" : "object", + "subType" : "record", + "properties" : { + "id" : { + "type" : "string", + "subType" : "objid", + "pattern" : "^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$" + }, + "data" : { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "id", + "data" + ], + "required" : [ + "id", + "data" + ] + }, + "HasNull" : { + "type" : "object", + "subType" : "record", + "properties" : { + "theNull" : { + "type" : "null" + } + }, + "additionalProperties" : false + } + } + }, + "anyOf" : [ + { + "$ref" : "#/definitions/Main/HasPardType", + "decoding" : { + "prototype" : [ + "convert", + "f_dec_hpt", + "x" + ] + }, + "encoding" : { + "prototype" : [ + "convert", + "f_enc_hpt", + "x" + ], + "printing" : "pretty" + } + }, + { + "$ref" : "#/definitions/PDU_Definitions/ProtocolElem_Field1", + "encoding" : { + "prototype" : [ + "convert", + "f_enc_pard", + "x" + ], + "printing" : "pretty" + } + }, + { + "$ref" : "#/definitions/PDU_Definitions/Object", + "decoding" : { + "prototype" : [ + "convert", + "f_dec_obj", + "x" + ] + }, + "encoding" : { + "prototype" : [ + "convert", + "f_enc_obj", + "x" + ] + } + } + ] +} diff --git a/regression_test/ttcn2json/Makefile b/regression_test/ttcn2json/Makefile index a72bacd..30664bb 100755 --- a/regression_test/ttcn2json/Makefile +++ b/regression_test/ttcn2json/Makefile @@ -13,7 +13,7 @@ include $(TOPDIR)/Makefile.regression TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) -TTCN3_MODULES = PIPEasp_PortType.ttcn PIPEasp_Types.ttcn PIPEasp_Templates.ttcn Shell.ttcn Testcases.ttcn +TTCN3_MODULES = PIPEasp_PortType.ttcn PIPEasp_Types.ttcn PIPEasp_Templates.ttcn Shell.ttcn Testcases.ttcn CompareSchemas.ttcn ASN1_MODULES = @@ -23,14 +23,14 @@ 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_SOURCES = PIPEasp_PT.cc f_ext_import_schema.cc USER_HEADERS = $(USER_SOURCES:.cc=.hh) OBJECTS = $(GENERATED_SOURCES:.cc=.o) $(USER_SOURCES:.cc=.o) TARGET = ttcn2json$(EXESUFFIX) -TEMP_FILES = General_Types.json one.json two.json three.json +TEMP_FILES = General_Types.json one.json two.json three.json Main.json all: $(TARGET) diff --git a/regression_test/ttcn2json/MiniRanap.asn b/regression_test/ttcn2json/MiniRanap.asn new file mode 100644 index 0000000..0be5148 --- /dev/null +++ b/regression_test/ttcn2json/MiniRanap.asn @@ -0,0 +1,80 @@ +------------------------------------------------------------------------------- +-- 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 +------------------------------------------------------------------------------- + +MiniRanap + +-- This module contains a simplified version of the type DirectTransferInformationList-RANAP-RelocInf +-- from the RANAP protocol module and any elements needed to recreate it. +-- Used for tesing the JSON schema generator on an ASN.1 ellipsis type + +DEFINITIONS + +AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS ; + +-- RANAP-CommonDataTypes +Criticality ::= ENUMERATED { reject, ignore, notify } + +Presence ::= ENUMERATED { optionalValue, conditional, mandatory } + +ProtocolIE-ID ::= INTEGER (0..65535) + +-- RANAP-Containers +RANAP-PROTOCOL-IES ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &criticality Criticality, + &Value, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} + +ProtocolIE-ContainerList {INTEGER : lowerBound, INTEGER : upperBound, RANAP-PROTOCOL-IES : IEsSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-Container {{IEsSetParam}} + +ProtocolIE-Container {RANAP-PROTOCOL-IES : IEsSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-Field {{IEsSetParam}} + +ProtocolIE-Field {RANAP-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE { + id RANAP-PROTOCOL-IES.&id ({IEsSetParam}), + criticality RANAP-PROTOCOL-IES.&criticality ({IEsSetParam}{@id}), + valueField RANAP-PROTOCOL-IES.&Value ({IEsSetParam}{@id}) +} + +-- RANAP-PDU-Contents +DirectTransfer-IE-ContainerList { RANAP-PROTOCOL-IES : IEsSetParam } ::= + ProtocolIE-ContainerList { 1, maxNrOfDTs, {IEsSetParam} } + +DirectTransferInformationList-RANAP-RelocInf ::= + DirectTransfer-IE-ContainerList { {DirectTransferInformationItemIEs-RANAP-RelocInf} } + +DirectTransferInformationItemIEs-RANAP-RelocInf RANAP-PROTOCOL-IES ::= { + { ID id-DirectTransferInformationItem-RANAP-RelocInf + CRITICALITY ignore TYPE INTEGER --DirectTransferInformationItem-RANAP-RelocInf + PRESENCE mandatory }, + ... +} + +-- RABAP-Constants +maxNrOfDTs INTEGER ::= 15 + +id-DirectTransferInformationItem-RANAP-RelocInf INTEGER ::= 80 + +maxProtocolIEs INTEGER ::= 65535 + +END + diff --git a/regression_test/ttcn2json/MiniRanap_e.json b/regression_test/ttcn2json/MiniRanap_e.json new file mode 100644 index 0000000..534ec07 --- /dev/null +++ b/regression_test/ttcn2json/MiniRanap_e.json @@ -0,0 +1,94 @@ +{ + "definitions" : { + "MiniRanap" : { + "Criticality" : { + "enum" : [ + "reject", + "ignore", + "notify" + ], + "numericValues" : [ + 0, + 1, + 2 + ] + }, + "DirectTransferInformationList_RANAP_RelocInf" : { + "type" : "array", + "subType" : "record of", + "items" : { + "type" : "array", + "subType" : "record of", + "items" : { + "type" : "object", + "subType" : "record", + "properties" : { + "id" : { + "$ref" : "#/definitions/MiniRanap/ProtocolIE_ID" + }, + "criticality" : { + "$ref" : "#/definitions/MiniRanap/Criticality" + }, + "valueField" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "iNTEGER" : { + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "iNTEGER" + ] + } + ] + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "id", + "criticality", + "valueField" + ], + "required" : [ + "id", + "criticality", + "valueField" + ] + } + } + }, + "Presence" : { + "enum" : [ + "optionalValue", + "conditional", + "mandatory" + ], + "numericValues" : [ + 0, + 1, + 2 + ] + }, + "ProtocolIE_ID" : { + "type" : "integer" + } + } + }, + "anyOf" : [ + { + "$ref" : "#/definitions/MiniRanap/Criticality" + }, + { + "$ref" : "#/definitions/MiniRanap/Presence" + }, + { + "$ref" : "#/definitions/MiniRanap/ProtocolIE_ID" + }, + { + "$ref" : "#/definitions/MiniRanap/DirectTransferInformationList_RANAP_RelocInf" + } + ] +} diff --git a/regression_test/ttcn2json/PDU_Definitions.asn b/regression_test/ttcn2json/PDU_Definitions.asn new file mode 100644 index 0000000..4b33888 --- /dev/null +++ b/regression_test/ttcn2json/PDU_Definitions.asn @@ -0,0 +1,93 @@ +------------------------------------------------------------------------------ +-- 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 +------------------------------------------------------------------------------ + +-- +-- Based on definitions used in S1AP +-- + +PDU-Definitions DEFINITIONS ::= +BEGIN + +Priority ::= ENUMERATED { low, normal, medium, high, urgent } + +Conditionality ::= ENUMERATED { optional, conditional, mandatory } + +ProtocolElem-ID ::= INTEGER (0..65535) + + +--IOC +PROTOCOL-ELEMS ::= CLASS +{ + &id ProtocolElem-ID UNIQUE, + &priority Priority, + &Value, + &conditionality Conditionality +} +WITH SYNTAX +{ + ID &id + PRIORITY &priority + TYPE &Value + CONDITIONALITY &conditionality +} + +--parameterized type +ProtocolElem-Field {PROTOCOL-ELEMS : ElemsSetParam} ::= SEQUENCE +{ + id PROTOCOL-ELEMS.&id ({ElemsSetParam}), + priority PROTOCOL-ELEMS.&priority ({ElemsSetParam}{@id}), + val PROTOCOL-ELEMS.&Value ({ElemsSetParam}{@id}) +} + + +--Information objects +ies-Set-Element-1 PROTOCOL-ELEMS ::= +{ + ID 0 + PRIORITY low + TYPE INTEGER + CONDITIONALITY mandatory +} + +ies-Set-Element-2 PROTOCOL-ELEMS ::= +{ + ID 1 + PRIORITY high + TYPE IA5String + CONDITIONALITY optional +} +--Information Object Set +Elems-Set PROTOCOL-ELEMS ::= { ies-Set-Element-1 | ies-Set-Element-2 } + + +--instantiation +ProtocolElem-Field1 ::= ProtocolElem-Field {{Elems-Set}} + +ProtocolElem-Field2 ::= ProtocolElem-Field {{ies-Set-Element-2 }} + +--Choice containing NULL +Price ::= CHOICE +{ + value REAL, + invaluable NULL +} + +--Sequence containing an object identifier and an ANY type +Object ::= SEQUENCE +{ + id OBJECT IDENTIFIER, + data ANY +} + +--Sequence containing an optional NULL field +HasNull ::= SEQUENCE +{ + theNull NULL OPTIONAL +} + +END diff --git a/regression_test/ttcn2json/Testcases.ttcn b/regression_test/ttcn2json/Testcases.ttcn index 7c3d326..b6ae4a6 100644 --- a/regression_test/ttcn2json/Testcases.ttcn +++ b/regression_test/ttcn2json/Testcases.ttcn @@ -9,6 +9,7 @@ module Testcases { import from Shell all; +import from CompareSchemas all; function f_test_ttcn2json(in charstring p_args, in charstring p_gen_file_name, in charstring p_exp_file_name, in integer p_exp_result) runs on Shell_CT @@ -16,34 +17,32 @@ function f_test_ttcn2json(in charstring p_args, in charstring p_gen_file_name, i var charstring v_cmd := "compiler --ttcn2json " & p_args; f_shellCommandWithVerdict(v_cmd, "", p_exp_result); - /* The generated schema cannot be checked this way, as different platforms generate the parts of the schema - in a different order if (getverdict == pass) { - f_compareFiles(p_gen_file_name, p_exp_file_name, 0); - if (getverdict == fail) { - action("Generated and expected files do not match"); + if (f_compare_schemas(p_gen_file_name, p_exp_file_name) == false) { + setverdict(fail, "Generated and expected files do not match"); } } else { action("Command ", v_cmd, " failed"); - }*/ + } + } testcase tc_t2j_one() runs on Shell_CT { - f_test_ttcn2json("one.ttcn two.ttcn three.ttcn zero.asn", "one.json", "one_e.json", + f_test_ttcn2json("-f one.ttcn two.ttcn three.ttcn zero.asn", "one.json", "one_e.json", c_shell_successWithWarning); } testcase tc_t2j_two() runs on Shell_CT { - f_test_ttcn2json("one.ttcn two.ttcn three.ttcn zero.asn - two.json", "two.json", "one_e.json", + f_test_ttcn2json("-jf one.ttcn two.ttcn three.ttcn zero.asn - two.json", "two.json", "two_e.json", c_shell_successWithWarning); } testcase tc_t2j_three() runs on Shell_CT { - f_test_ttcn2json("-T one.ttcn -T two.ttcn -T three.ttcn -A zero.asn - three.json", "three.json", "one_e.json", + f_test_ttcn2json("-j -T one.ttcn -T two.ttcn -T three.ttcn -A zero.asn - three.json", "three.json", "three_e.json", c_shell_successWithWarning); } @@ -53,11 +52,25 @@ testcase tc_t2j_general_types() runs on Shell_CT c_shell_successWithoutWarningAndError); } +testcase tc_t2j_main_asn() runs on Shell_CT +{ + f_test_ttcn2json("-f Main.ttcn PDU_Definitions.asn", "Main.json", "Main_e.json", + c_shell_successWithoutWarningAndError); +} + +testcase tc_t2j_mini_ranap() runs on Shell_CT +{ + f_test_ttcn2json("MiniRanap.asn", "MiniRanap.json", "MiniRanap_e.json", + c_shell_successWithoutWarningAndError); +} + control { execute(tc_t2j_one()); execute(tc_t2j_two()); execute(tc_t2j_three()); execute(tc_t2j_general_types()); + execute(tc_t2j_main_asn()); + execute(tc_t2j_mini_ranap()); } } diff --git a/regression_test/ttcn2json/f_ext_import_schema.cc b/regression_test/ttcn2json/f_ext_import_schema.cc new file mode 100644 index 0000000..0532083 --- /dev/null +++ b/regression_test/ttcn2json/f_ext_import_schema.cc @@ -0,0 +1,456 @@ +/****************************************************************************** + * 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 "f_ext_import_schema.hh" +#include +#include + +namespace CompareSchemas { + +#define IMPORT_FORMAT_ERROR(cond, comment) \ + if (cond) { \ + TTCN_error("Invalid format for file '%s' (%s). JSON schema could not be imported.", file_name, comment); \ + } + +ElemKey get_elem_key(const char* value, size_t value_len, const char* file_name) +{ + if (4 == value_len && 0 == strncmp(value, "$ref", value_len)) { + return ElemKey::Ref; + } + if (4 == value_len && 0 == strncmp(value, "type", value_len)) { + return ElemKey::Type; + } + if (7 == value_len && 0 == strncmp(value, "subType", value_len)) { + return ElemKey::SubType; + } + if (7 == value_len && 0 == strncmp(value, "pattern", value_len)) { + return ElemKey::Pattern; + } + if (12 == value_len && 0 == strncmp(value, "originalName", value_len)) { + return ElemKey::OriginalName; + } + if (11 == value_len && 0 == strncmp(value, "unusedAlias", value_len)) { + return ElemKey::UnusedAlias; + } + if (20 == value_len && 0 == strncmp(value, "additionalProperties", value_len)) { + return ElemKey::AdditionalProperties; + } + if (10 == value_len && 0 == strncmp(value, "omitAsNull", value_len)) { + return ElemKey::OmitAsNull; + } + if (7 == value_len && 0 == strncmp(value, "default", value_len)) { + return ElemKey::Default; + } + if (8 == value_len && 0 == strncmp(value, "minItems", value_len)) { + return ElemKey::MinItems; + } + if (8 == value_len && 0 == strncmp(value, "maxItems", value_len)) { + return ElemKey::MaxItems; + } + if (4 == value_len && 0 == strncmp(value, "enum", value_len)) { + return ElemKey::Enum; + } + if (13 == value_len && 0 == strncmp(value, "numericValues", value_len)) { + return ElemKey::NumericValues; + } + if (5 == value_len && 0 == strncmp(value, "items", value_len)) { + return ElemKey::Items; + } + if (5 == value_len && 0 == strncmp(value, "anyOf", value_len)) { + return ElemKey::AnyOf; + } + if (8 == value_len && 0 == strncmp(value, "required", value_len)) { + return ElemKey::Required; + } + if (10 == value_len && 0 == strncmp(value, "fieldOrder", value_len)) { + return ElemKey::FieldOrder; + } + if (10 == value_len && 0 == strncmp(value, "properties", value_len)) { + return ElemKey::Properties; + } + // throw the DTE if it didn't return until now + IMPORT_FORMAT_ERROR(true, "unknown type element key"); +} + +TypeSchema extract_type_schema(JSON_Tokenizer& json, const char* file_name) +{ + json_token_t token = JSON_TOKEN_NONE; + char* value = NULL; + size_t value_len = 0; + + // type schema object start + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_START != token, "missing type object start"); + + // type schema elements + TypeSchema type_schema; + int elem_index = 0; + json.get_next_token(&token, &value, &value_len); + while(JSON_TOKEN_NAME == token) { + type_schema[elem_index].key() = get_elem_key(value, value_len, file_name); + switch(type_schema[elem_index].key()) { + case ElemKey::Ref: + case ElemKey::Type: + case ElemKey::SubType: + case ElemKey::Pattern: + case ElemKey::OriginalName: + case ElemKey::UnusedAlias: + case ElemKey::MinItems: + case ElemKey::MaxItems: + case ElemKey::AdditionalProperties: + case ElemKey::OmitAsNull: + case ElemKey::Default: { + // string or boolean value + json.get_next_token(&token, &value, &value_len); + switch (token) { + case JSON_TOKEN_STRING: + case JSON_TOKEN_NUMBER: { + CHARSTRING str_val(value_len, value); + type_schema[elem_index].val().strVal() = str_val; + break; } + case JSON_TOKEN_LITERAL_FALSE: + type_schema[elem_index].val().boolVal() = FALSE; + break; + case JSON_TOKEN_LITERAL_TRUE: + type_schema[elem_index].val().boolVal() = TRUE; + break; + default: + IMPORT_FORMAT_ERROR(JSON_TOKEN_LITERAL_FALSE != token, "string or boolean value expected"); + } + break; } + + case ElemKey::Enum: + case ElemKey::NumericValues: + case ElemKey::Required: + case ElemKey::FieldOrder: { + // string array value + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token, "missing string array start"); + json.get_next_token(&token, &value, &value_len); + int string_index = 0; + while (JSON_TOKEN_STRING == token || JSON_TOKEN_NUMBER == token) { + CHARSTRING str_val(value_len, value); + type_schema[elem_index].val().strArrayVal()[string_index] = str_val; + + // next string + ++string_index; + json.get_next_token(&token, &value, &value_len); + } + + // string array end + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token, "missing string array end"); + break; } + + case ElemKey::Items: { + // type schema value + type_schema[elem_index].val().typeVal() = extract_type_schema(json, file_name); + break; } + + case ElemKey::AnyOf: { + // type schema array value + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token, "missing type array start"); + int type_index = 0; + size_t buf_pos = json.get_buf_pos(); + json.get_next_token(&token, NULL, NULL); + while (JSON_TOKEN_OBJECT_START == token) { + // revert this extraction, the type schema extractor will read the "{" again + json.set_buf_pos(buf_pos); + type_schema[elem_index].val().typeArrayVal()[type_index] = extract_type_schema(json, file_name); + + // next type schema + ++type_index; + buf_pos = json.get_buf_pos(); + json.get_next_token(&token, NULL, NULL); + } + + // type schema array end + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token, "missing type array end"); + break; } + + case ElemKey::Properties: { + // field set value + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_START != token, "missing field set start"); + int field_index = 0; + json.get_next_token(&token, &value, &value_len); + while(JSON_TOKEN_NAME == token) { + // store field name and schema + CHARSTRING field_name(value_len, value); + type_schema[elem_index].val().fieldSetVal()[field_index].fieldName() = field_name; + type_schema[elem_index].val().fieldSetVal()[field_index].schema() = extract_type_schema(json, file_name); + + // next field + ++field_index; + json.get_next_token(&token, &value, &value_len); + } + + // field set value end + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token, "missing field set end"); + break; } + default: + break; + } + + // next schema element + ++elem_index; + json.get_next_token(&token, &value, &value_len); + } + + // type schema object end + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token, "missing type object end"); + return type_schema; +} + +EncDecData extract_enc_dec_data(JSON_Tokenizer& json, const char* file_name) +{ + // initialize (error behavior and printing data might not appear in the schema) + json_token_t token = JSON_TOKEN_NONE; + char* value = NULL; + size_t value_len = 0; + EncDecData data; + data.eb() = OMIT_VALUE; + data.printing() = OMIT_VALUE; + + // enc/dec data start + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_START != token, "missing enc/dec data start"); + json.get_next_token(&token, &value, &value_len); + while(JSON_TOKEN_NAME == token) { + if (9 == value_len && 0 == strncmp(value, "prototype", value_len)) { + // prototype (string array) + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token, "missing prototype array start"); + json.get_next_token(&token, &value, &value_len); + int pt_index = 0; + while(JSON_TOKEN_STRING == token) { + CHARSTRING pt_str(value_len, value); + data.prototype()[pt_index] = pt_str; + + // next prototype element + ++pt_index; + json.get_next_token(&token, &value, &value_len); + } + + // prototype end + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token, "missing prototype array end"); + } + else if (13 == value_len && 0 == strncmp(value, "errorBehavior", value_len)) { + // error behavior (object) + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_START != token, "missing error behavior start"); + json.get_next_token(&token, &value, &value_len); + int eb_index = 0; + while(JSON_TOKEN_NAME == token) { + // store the key-value pair + CHARSTRING error_type(value_len, value); + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_STRING != token, "expected error behavior string"); + CHARSTRING error_behavior(value_len, value); + data.eb()()[eb_index].errorType() = error_type; + data.eb()()[eb_index].errorBehavior() = error_behavior; + + // next pair + ++eb_index; + json.get_next_token(&token, &value, &value_len); + } + + // error behavior end + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token, "missing error behavior end"); + } + else if (8 == value_len && 0 == strncmp(value, "printing", value_len)) { + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_STRING != token, "expected printing string"); + CHARSTRING printing_str(value_len, value); + data.printing()() = printing_str; + } + else { + // invalid key + IMPORT_FORMAT_ERROR(true, "invalid enc/dec data key"); + } + + // next key-value pair + json.get_next_token(&token, &value, &value_len); + } + + // enc/dec data end + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token, "missing enc/dec data end"); + return data; +} + +RefSchema extract_ref_schema(JSON_Tokenizer& json, const char* file_name) +{ + // initialize (set optional fields to "omit") + json_token_t token = JSON_TOKEN_NONE; + char* value = NULL; + size_t value_len = 0; + RefSchema ref_schema; + ref_schema.enc() = OMIT_VALUE; + ref_schema.dec() = OMIT_VALUE; + + // read reference data + json.get_next_token(&token, &value, &value_len); + while(JSON_TOKEN_NAME == token) { + if (4 == value_len && 0 == strncmp(value, "$ref", value_len)) { + // reference + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_STRING != token, "missing reference string"); + CHARSTRING ref_str(value_len, value); + ref_schema.ref() = ref_str; + } + else if (8 == value_len && 0 == strncmp(value, "encoding", value_len)) { + // encoding function + ref_schema.enc()() = extract_enc_dec_data(json, file_name); + } + else if (8 == value_len && 0 == strncmp(value, "decoding", value_len)) { + // encoding function + ref_schema.dec()() = extract_enc_dec_data(json, file_name); + } + else { + // invalid key + IMPORT_FORMAT_ERROR(true, "invalid reference/function data key"); + } + + // next key-value pair + json.get_next_token(&token, &value, &value_len); + } + + // reference & function info end + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token, "missing reference/function data end"); + return ref_schema; +} + +void f__ext__import__schema(const CHARSTRING& file, JsonSchema& schema) +{ + // need a null-terminated string for fopen + char* file_name = mcopystrn((const char*)file, file.lengthof()); + FILE* fp = fopen(file_name, "r"); + try { + if (NULL == fp) { + TTCN_error("Could not open file '%s' for reading. JSON schema could not be imported.", file_name); + } + + // get the file size + fseek(fp, 0, SEEK_END); + int file_size = ftell(fp); + rewind(fp); + + // read the entire file into a character buffer + char* buffer = (char*)Malloc(file_size); + fread(buffer, 1, file_size, fp); + fclose(fp); + + // initialize a JSON tokenizer with the buffer + JSON_Tokenizer json(buffer, file_size); + Free(buffer); + + // extract tokens and store the schema in the JsonSchema parameter + // throw a DTE if the file format is invalid + json_token_t token = JSON_TOKEN_NONE; + char* value = NULL; + size_t value_len = 0; + + // top level object + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_START != token, "missing top level object start"); + + // definitions + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 11 || + 0 != strncmp(value, "definitions", value_len), "missing definitions key"); + + // module list + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_START != token, "missing module list start"); + json.get_next_token(&token, &value, &value_len); + int type_index = 0; + while (JSON_TOKEN_NAME == token) { + // extract module name, it will be inserted later + CHARSTRING module_name(value_len, value); + + // type list + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_START != token, "missing type list start"); + json.get_next_token(&token, &value, &value_len); + while (JSON_TOKEN_NAME == token) { + // extract type name + CHARSTRING type_name(value_len, value); + + // extract type schema + TypeSchema type_schema = extract_type_schema(json, file_name); + + // store definition data + schema.defs()[type_index].moduleName() = module_name; + schema.defs()[type_index].typeName() = type_name; + schema.defs()[type_index].schema() = type_schema; + + // next type + ++type_index; + json.get_next_token(&token, &value, &value_len); + } + + // end of type list + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token, "missing type list end"); + + // next module + json.get_next_token(&token, &value, &value_len); + } + + // end of module list + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token, "missing module list end"); + + if (0 == type_index) { + // no definitions, don't leave the field unbound + schema.defs().set_size(0); + } + + // top level anyOf + json.get_next_token(&token, &value, &value_len); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NAME != token || value_len != 5 || + 0 != strncmp(value, "anyOf", value_len), "missing anyOf key"); + + // reference & function info array + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_START != token, "missing reference/function list start"); + json.get_next_token(&token, NULL, NULL); + int ref_index = 0; + while (JSON_TOKEN_OBJECT_START == token) { + + // extract reference schema + schema.refs()[ref_index] = extract_ref_schema(json, file_name); + + // next reference + ++ref_index; + json.get_next_token(&token, NULL, NULL); + } + + // end of reference & function info array + IMPORT_FORMAT_ERROR(JSON_TOKEN_ARRAY_END != token, "missing reference/function list end"); + + if (0 == ref_index) { + // no references, don't leave the field unbound + schema.refs().set_size(0); + } + + // end of top level object + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_OBJECT_END != token, "missing top level object end"); + + // end of the schema + json.get_next_token(&token, NULL, NULL); + IMPORT_FORMAT_ERROR(JSON_TOKEN_NONE != token, "expected end of file"); + } + catch (...) { + Free(file_name); + throw; + } + Free(file_name); +} + +} + diff --git a/regression_test/ttcn2json/f_ext_import_schema.hh b/regression_test/ttcn2json/f_ext_import_schema.hh new file mode 100644 index 0000000..7ab618d --- /dev/null +++ b/regression_test/ttcn2json/f_ext_import_schema.hh @@ -0,0 +1,27 @@ +/****************************************************************************** + * 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 f_ext_import_schema_HH +#define f_ext_import_schema_HH + +#include "CompareSchemas.hh" + +namespace CompareSchemas { + +/** Imports a JSON schema from a given file to the specified container. + * Throws a Dynamic Testcase Error on failure. + * + * @param file source file name + * @param schema JSON schema container (defined in CompareSchemas.ttcn) + */ +extern void f__ext__import__schema(const CHARSTRING& file, JsonSchema& schema); + +} + +#endif + diff --git a/regression_test/ttcn2json/one_e.json b/regression_test/ttcn2json/one_e.json index f882745..da16123 100644 --- a/regression_test/ttcn2json/one_e.json +++ b/regression_test/ttcn2json/one_e.json @@ -27,6 +27,11 @@ "Short", "Medium", "Tall" + ], + "numericValues" : [ + 0, + 1, + 2 ] }, "Rec" : { @@ -59,6 +64,7 @@ "properties" : { "os" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" }, "buul" : { @@ -147,6 +153,7 @@ "properties" : { "bytes" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" } }, @@ -162,6 +169,11 @@ "Thin", "Medium", "Wide" + ], + "numericValues" : [ + 0, + 1, + 2 ] }, "anytype" : { @@ -195,6 +207,7 @@ "properties" : { "bitstring" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" } }, @@ -212,6 +225,7 @@ "subType" : "record of", "items" : { "type" : "string", + "subType" : "bitstring", "pattern" : "^[01]*$" } }, @@ -239,6 +253,7 @@ "subType" : "record of", "items" : { "type" : "string", + "subType" : "hexstring", "pattern" : "^[0-9A-Fa-f]*$" } }, @@ -261,6 +276,7 @@ "subType" : "set of", "items" : { "type" : "string", + "subType" : "octetstring", "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" } }, @@ -322,6 +338,11 @@ "Small", "Medium", "Large" + ], + "numericValues" : [ + 0, + 1, + 2 ] }, "filled" : { @@ -429,6 +450,109 @@ } }, "Zero" : { + "SeqOfInt" : { + "type" : "array", + "subType" : "record of", + "items" : { + "type" : "integer" + } + }, + "SeqProduct" : { + "type" : "object", + "subType" : "record", + "properties" : { + "name" : { + "type" : "string", + "subType" : "universal charstring" + }, + "price" : { + "anyOf" : [ + { + "type" : "number" + }, + { + "enum" : [ + "not_a_number", + "infinity", + "-infinity" + ] + } + ] + }, + "id" : { + "anyOf" : [ + { + "type" : "null" + }, + { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + } + ], + "omitAsNull" : false + }, + "available" : { + "type" : "boolean" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "name", + "price", + "id", + "available" + ], + "required" : [ + "name", + "price", + "available" + ] + }, + "Number" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "decimal" : { + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "decimal" + ] + }, + { + "type" : "object", + "properties" : { + "binary" : { + "type" : "string", + "subType" : "bitstring", + "pattern" : "^[01]*$" + } + }, + "additionalProperties" : false, + "required" : [ + "binary" + ] + }, + { + "type" : "object", + "properties" : { + "hexadecimal" : { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + } + }, + "additionalProperties" : false, + "required" : [ + "hexadecimal" + ] + } + ] + }, "AnyString" : { "anyOf" : [ { @@ -576,37 +700,12 @@ } ] }, - "Big_Choice" : { - "anyOf" : [ - { - "type" : "object", - "properties" : { - "numbers" : { - "type" : "array", - "subType" : "set of", - "items" : { - "$ref" : "#/definitions/Zero/Number" - } - } - }, - "additionalProperties" : false, - "required" : [ - "numbers" - ] - }, - { - "type" : "object", - "properties" : { - "strings" : { - "$ref" : "#/definitions/Zero/ManyStrings" - } - }, - "additionalProperties" : false, - "required" : [ - "strings" - ] - } - ] + "ManyStrings" : { + "type" : "array", + "subType" : "record of", + "items" : { + "$ref" : "#/definitions/Zero/AnyString" + } }, "Big_Set" : { "type" : "object", @@ -631,6 +730,12 @@ "blue", "green", "yellow" + ], + "numericValues" : [ + 0, + 1, + 2, + 3 ] } }, @@ -648,55 +753,52 @@ "color" ] }, - "ManyStrings" : { - "type" : "array", - "subType" : "record of", - "items" : { - "$ref" : "#/definitions/Zero/AnyString" - } - }, - "Number" : { + "Big_Choice" : { "anyOf" : [ { "type" : "object", "properties" : { - "decimal" : { - "type" : "integer" - } - }, - "additionalProperties" : false, - "required" : [ - "decimal" - ] - }, - { - "type" : "object", - "properties" : { - "binary" : { - "type" : "string", - "pattern" : "^[01]*$" + "numbers" : { + "type" : "array", + "subType" : "set of", + "items" : { + "$ref" : "#/definitions/Zero/Number" + } } }, "additionalProperties" : false, "required" : [ - "binary" + "numbers" ] }, { "type" : "object", "properties" : { - "hexadecimal" : { - "type" : "string", - "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + "strings" : { + "$ref" : "#/definitions/Zero/ManyStrings" } }, "additionalProperties" : false, "required" : [ - "hexadecimal" + "strings" ] } ] }, + "Season" : { + "enum" : [ + "spring", + "summer", + "fall", + "winter" + ], + "numericValues" : [ + 1, + 2, + 3, + 4 + ] + }, "SelectionType" : { "type" : "array", "subType" : "set of", @@ -704,63 +806,18 @@ "$ref" : "#/definitions/Zero/Number" } }, - "SeqOfInt" : { - "type" : "array", - "subType" : "record of", - "items" : { - "type" : "integer" - } + "NullType" : { + "type" : "null" }, - "SeqProduct" : { - "type" : "object", - "subType" : "record", - "properties" : { - "name" : { - "type" : "string", - "subType" : "universal charstring" - }, - "price" : { - "anyOf" : [ - { - "type" : "number" - }, - { - "enum" : [ - "not_a_number", - "infinity", - "-infinity" - ] - } - ] - }, - "id" : { - "anyOf" : [ - { - "type" : "null" - }, - { - "type" : "string", - "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" - } - ], - "omitAsNull" : false - }, - "available" : { - "type" : "boolean" - } - }, - "additionalProperties" : false, - "fieldOrder" : [ - "name", - "price", - "id", - "available" - ], - "required" : [ - "name", - "price", - "available" - ] + "ObjIdType" : { + "type" : "string", + "subType" : "objid", + "pattern" : "^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$" + }, + "RelObjIdType" : { + "type" : "string", + "subType" : "objid", + "pattern" : "^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$" } } }, diff --git a/regression_test/ttcn2json/three_e.json b/regression_test/ttcn2json/three_e.json new file mode 100644 index 0000000..52268ba --- /dev/null +++ b/regression_test/ttcn2json/three_e.json @@ -0,0 +1,866 @@ +{ + "definitions" : { + "one" : { + "HasAny" : { + "type" : "object", + "subType" : "record", + "properties" : { + "num" : { + "type" : "integer" + }, + "at" : { + "$ref" : "#/definitions/one/anytype" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "num", + "at" + ], + "required" : [ + "num", + "at" + ] + }, + "Height" : { + "enum" : [ + "Short", + "Medium", + "Tall" + ], + "numericValues" : [ + 0, + 1, + 2 + ] + }, + "Rec" : { + "type" : "object", + "subType" : "record", + "properties" : { + "num" : { + "type" : "integer", + "default" : 0 + }, + "str" : { + "type" : "string", + "subType" : "universal charstring", + "default" : "empty" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "num", + "str" + ], + "required" : [ + "num", + "str" + ] + }, + "Set" : { + "type" : "object", + "subType" : "set", + "properties" : { + "os" : { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + }, + "buul" : { + "anyOf" : [ + { + "type" : "null" + }, + { + "type" : "boolean" + } + ], + "omitAsNull" : true + }, + "verd" : { + "anyOf" : [ + { + "type" : "null" + }, + { + "enum" : [ + "none", + "pass", + "inconc", + "fail", + "error" + ] + } + ], + "omitAsNull" : false + }, + "numbr" : { + "anyOf" : [ + { + "type" : "number" + }, + { + "enum" : [ + "not_a_number", + "infinity", + "-infinity" + ] + } + ], + "default" : "-infinity" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "os", + "buul", + "verd", + "numbr" + ], + "required" : [ + "os", + "numbr" + ] + }, + "Uni" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "numbr" : { + "anyOf" : [ + { + "type" : "number" + }, + { + "enum" : [ + "not_a_number", + "infinity", + "-infinity" + ] + } + ] + } + }, + "additionalProperties" : false, + "required" : [ + "numbr" + ] + }, + { + "type" : "object", + "properties" : { + "bytes" : { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + } + }, + "additionalProperties" : false, + "required" : [ + "bytes" + ] + } + ] + }, + "Width" : { + "enum" : [ + "Thin", + "Medium", + "Wide" + ], + "numericValues" : [ + 0, + 1, + 2 + ] + }, + "anytype" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "integer" : { + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "integer" + ] + }, + { + "type" : "object", + "properties" : { + "boolean" : { + "type" : "boolean" + } + }, + "additionalProperties" : false, + "required" : [ + "boolean" + ] + }, + { + "type" : "object", + "properties" : { + "bitstring" : { + "type" : "string", + "subType" : "bitstring", + "pattern" : "^[01]*$" + } + }, + "additionalProperties" : false, + "required" : [ + "bitstring" + ] + } + ] + } + }, + "two" : { + "Ints" : { + "type" : "array", + "subType" : "record of", + "items" : { + "type" : "integer" + } + }, + "PosInt" : { + "type" : "integer" + } + }, + "three" : { + "Barrels" : { + "type" : "object", + "subType" : "set", + "properties" : { + "numBarrels" : { + "type" : "integer" + }, + "barrelType" : { + "type" : "object", + "subType" : "record", + "properties" : { + "size" : { + "enum" : [ + "Small", + "Medium", + "Large" + ], + "numericValues" : [ + 0, + 1, + 2 + ] + }, + "filled" : { + "type" : "boolean" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "size", + "filled" + ], + "required" : [ + "size", + "filled" + ] + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "numBarrels", + "barrelType" + ], + "required" : [ + "numBarrels", + "barrelType" + ] + }, + "Nums" : { + "type" : "array", + "subType" : "set of", + "items" : { + "type" : "object", + "subType" : "record", + "properties" : { + "number" : { + "originalName" : "num", + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "number" + ] + } + }, + "Numz" : { + "type" : "object", + "subType" : "record", + "properties" : { + "nums" : { + "$ref" : "#/definitions/three/Nums" + } + }, + "additionalProperties" : false, + "required" : [ + "nums" + ] + }, + "Rex" : { + "type" : "array", + "subType" : "record of", + "items" : { + "$ref" : "#/definitions/one/Rec" + } + }, + "Stuff" : { + "type" : "array", + "subType" : "record of", + "items" : { + "$ref" : "#/definitions/three/Thing" + } + }, + "Thing" : { + "anyOf" : [ + { + "originalName" : "b", + "type" : "boolean" + }, + { + "originalName" : "i", + "unusedAlias" : "int", + "type" : "integer" + }, + { + "originalName" : "cs", + "unusedAlias" : "str", + "type" : "string", + "subType" : "charstring" + }, + { + "originalName" : "rec", + "type" : "object", + "subType" : "record", + "properties" : { + "num" : { + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "num" + ] + } + ] + } + }, + "Zero" : { + "AnyString" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "generalstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "generalstr" + ] + }, + { + "type" : "object", + "properties" : { + "numericstr" : { + "type" : "string", + "subType" : "charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "numericstr" + ] + }, + { + "type" : "object", + "properties" : { + "utf8str" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "utf8str" + ] + }, + { + "type" : "object", + "properties" : { + "printablestr" : { + "type" : "string", + "subType" : "charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "printablestr" + ] + }, + { + "type" : "object", + "properties" : { + "universalstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "universalstr" + ] + }, + { + "type" : "object", + "properties" : { + "bmpstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "bmpstr" + ] + }, + { + "type" : "object", + "properties" : { + "graphicstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "graphicstr" + ] + }, + { + "type" : "object", + "properties" : { + "ia5str" : { + "type" : "string", + "subType" : "charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "ia5str" + ] + }, + { + "type" : "object", + "properties" : { + "teletexstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "teletexstr" + ] + }, + { + "type" : "object", + "properties" : { + "videotexstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "videotexstr" + ] + }, + { + "type" : "object", + "properties" : { + "visiblestr" : { + "type" : "string", + "subType" : "charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "visiblestr" + ] + } + ] + }, + "Big_Choice" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "numbers" : { + "type" : "array", + "subType" : "set of", + "items" : { + "$ref" : "#/definitions/Zero/Number" + } + } + }, + "additionalProperties" : false, + "required" : [ + "numbers" + ] + }, + { + "type" : "object", + "properties" : { + "strings" : { + "$ref" : "#/definitions/Zero/ManyStrings" + } + }, + "additionalProperties" : false, + "required" : [ + "strings" + ] + } + ] + }, + "Big_Set" : { + "type" : "object", + "subType" : "set", + "properties" : { + "product" : { + "$ref" : "#/definitions/Zero/SeqProduct" + }, + "numbers" : { + "type" : "array", + "subType" : "set of", + "items" : { + "$ref" : "#/definitions/Zero/Number" + } + }, + "strings" : { + "$ref" : "#/definitions/Zero/ManyStrings" + }, + "color" : { + "enum" : [ + "red", + "blue", + "green", + "yellow" + ], + "numericValues" : [ + 0, + 1, + 2, + 3 + ] + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "product", + "numbers", + "strings", + "color" + ], + "required" : [ + "product", + "numbers", + "strings", + "color" + ] + }, + "ManyStrings" : { + "type" : "array", + "subType" : "record of", + "items" : { + "$ref" : "#/definitions/Zero/AnyString" + } + }, + "NullType" : { + "type" : "null" + }, + "Number" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "decimal" : { + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "decimal" + ] + }, + { + "type" : "object", + "properties" : { + "binary" : { + "type" : "string", + "subType" : "bitstring", + "pattern" : "^[01]*$" + } + }, + "additionalProperties" : false, + "required" : [ + "binary" + ] + }, + { + "type" : "object", + "properties" : { + "hexadecimal" : { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + } + }, + "additionalProperties" : false, + "required" : [ + "hexadecimal" + ] + } + ] + }, + "ObjIdType" : { + "type" : "string", + "subType" : "objid", + "pattern" : "^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$" + }, + "RelObjIdType" : { + "type" : "string", + "subType" : "objid", + "pattern" : "^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$" + }, + "Season" : { + "enum" : [ + "spring", + "summer", + "fall", + "winter" + ], + "numericValues" : [ + 1, + 2, + 3, + 4 + ] + }, + "SelectionType" : { + "type" : "array", + "subType" : "set of", + "items" : { + "$ref" : "#/definitions/Zero/Number" + } + }, + "SeqOfInt" : { + "type" : "array", + "subType" : "record of", + "items" : { + "type" : "integer" + } + }, + "SeqProduct" : { + "type" : "object", + "subType" : "record", + "properties" : { + "name" : { + "type" : "string", + "subType" : "universal charstring" + }, + "price" : { + "anyOf" : [ + { + "type" : "number" + }, + { + "enum" : [ + "not_a_number", + "infinity", + "-infinity" + ] + } + ] + }, + "id" : { + "anyOf" : [ + { + "type" : "null" + }, + { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + } + ], + "omitAsNull" : false + }, + "available" : { + "type" : "boolean" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "name", + "price", + "id", + "available" + ], + "required" : [ + "name", + "price", + "available" + ] + } + } + }, + "anyOf" : [ + { + "$ref" : "#/definitions/two/Ints", + "decoding" : { + "prototype" : [ + "fast", + "f_dec_ints", + "os", + "x" + ] + }, + "encoding" : { + "prototype" : [ + "fast", + "f_enc_ints", + "eents", + "octus" + ], + "printing" : "pretty" + } + }, + { + "$ref" : "#/definitions/one/Rec", + "decoding" : { + "prototype" : [ + "convert", + "f_dec_rec", + "octie" + ], + "errorBehavior" : { + "ALL" : "WARNING", + "INVAL_MSG" : "ERROR" + } + }, + "encoding" : { + "prototype" : [ + "convert", + "f_enc_rec", + "x" + ] + } + }, + { + "$ref" : "#/definitions/one/Set" + }, + { + "$ref" : "#/definitions/one/Uni" + }, + { + "$ref" : "#/definitions/one/HasAny" + }, + { + "$ref" : "#/definitions/one/Height" + }, + { + "$ref" : "#/definitions/one/Width" + }, + { + "$ref" : "#/definitions/one/anytype" + }, + { + "$ref" : "#/definitions/three/Thing" + }, + { + "$ref" : "#/definitions/three/Stuff" + }, + { + "$ref" : "#/definitions/three/Barrels" + }, + { + "$ref" : "#/definitions/two/PosInt" + }, + { + "$ref" : "#/definitions/Zero/SeqOfInt" + }, + { + "$ref" : "#/definitions/Zero/SeqProduct" + }, + { + "$ref" : "#/definitions/Zero/Number" + }, + { + "$ref" : "#/definitions/three/Nums" + }, + { + "$ref" : "#/definitions/three/Numz" + }, + { + "$ref" : "#/definitions/three/Rex" + }, + { + "$ref" : "#/definitions/Zero/AnyString" + }, + { + "$ref" : "#/definitions/Zero/ManyStrings" + }, + { + "$ref" : "#/definitions/Zero/Big_Set", + "decoding" : { + "prototype" : [ + "convert", + "f_dec_bigset", + "os" + ] + }, + "encoding" : { + "prototype" : [ + "convert", + "f_enc_bigset", + "x" + ] + } + }, + { + "$ref" : "#/definitions/Zero/Big_Choice" + }, + { + "$ref" : "#/definitions/Zero/Season" + }, + { + "$ref" : "#/definitions/Zero/SelectionType" + }, + { + "$ref" : "#/definitions/Zero/NullType" + }, + { + "$ref" : "#/definitions/Zero/ObjIdType" + }, + { + "$ref" : "#/definitions/Zero/RelObjIdType" + } + ] +} diff --git a/regression_test/ttcn2json/two.ttcn b/regression_test/ttcn2json/two.ttcn index e54a5cb..21eb94e 100644 --- a/regression_test/ttcn2json/two.ttcn +++ b/regression_test/ttcn2json/two.ttcn @@ -7,7 +7,7 @@ ******************************************************************************/ module two { - type record of integer Ints; + type record of integer Ints with { encode "JSON" }; type set of universal charstring Strings; @@ -34,4 +34,4 @@ module two { //type record of integer Rec; -} with { encode "JSON" } +} diff --git a/regression_test/ttcn2json/two_e.json b/regression_test/ttcn2json/two_e.json new file mode 100644 index 0000000..27c91bd --- /dev/null +++ b/regression_test/ttcn2json/two_e.json @@ -0,0 +1,794 @@ +{ + "definitions" : { + "one" : { + "HasAny" : { + "type" : "object", + "subType" : "record", + "properties" : { + "num" : { + "type" : "integer" + }, + "at" : { + "$ref" : "#/definitions/one/anytype" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "num", + "at" + ], + "required" : [ + "num", + "at" + ] + }, + "Height" : { + "enum" : [ + "Short", + "Medium", + "Tall" + ], + "numericValues" : [ + 0, + 1, + 2 + ] + }, + "Rec" : { + "type" : "object", + "subType" : "record", + "properties" : { + "num" : { + "type" : "integer", + "default" : 0 + }, + "str" : { + "type" : "string", + "subType" : "universal charstring", + "default" : "empty" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "num", + "str" + ], + "required" : [ + "num", + "str" + ] + }, + "Set" : { + "type" : "object", + "subType" : "set", + "properties" : { + "os" : { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + }, + "buul" : { + "anyOf" : [ + { + "type" : "null" + }, + { + "type" : "boolean" + } + ], + "omitAsNull" : true + }, + "verd" : { + "anyOf" : [ + { + "type" : "null" + }, + { + "enum" : [ + "none", + "pass", + "inconc", + "fail", + "error" + ] + } + ], + "omitAsNull" : false + }, + "numbr" : { + "anyOf" : [ + { + "type" : "number" + }, + { + "enum" : [ + "not_a_number", + "infinity", + "-infinity" + ] + } + ], + "default" : "-infinity" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "os", + "buul", + "verd", + "numbr" + ], + "required" : [ + "os", + "numbr" + ] + }, + "Uni" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "numbr" : { + "anyOf" : [ + { + "type" : "number" + }, + { + "enum" : [ + "not_a_number", + "infinity", + "-infinity" + ] + } + ] + } + }, + "additionalProperties" : false, + "required" : [ + "numbr" + ] + }, + { + "type" : "object", + "properties" : { + "bytes" : { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + } + }, + "additionalProperties" : false, + "required" : [ + "bytes" + ] + } + ] + }, + "Width" : { + "enum" : [ + "Thin", + "Medium", + "Wide" + ], + "numericValues" : [ + 0, + 1, + 2 + ] + }, + "anytype" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "integer" : { + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "integer" + ] + }, + { + "type" : "object", + "properties" : { + "boolean" : { + "type" : "boolean" + } + }, + "additionalProperties" : false, + "required" : [ + "boolean" + ] + }, + { + "type" : "object", + "properties" : { + "bitstring" : { + "type" : "string", + "subType" : "bitstring", + "pattern" : "^[01]*$" + } + }, + "additionalProperties" : false, + "required" : [ + "bitstring" + ] + } + ] + } + }, + "two" : { + "Ints" : { + "type" : "array", + "subType" : "record of", + "items" : { + "type" : "integer" + } + }, + "PosInt" : { + "type" : "integer" + } + }, + "three" : { + "Barrels" : { + "type" : "object", + "subType" : "set", + "properties" : { + "numBarrels" : { + "type" : "integer" + }, + "barrelType" : { + "type" : "object", + "subType" : "record", + "properties" : { + "size" : { + "enum" : [ + "Small", + "Medium", + "Large" + ], + "numericValues" : [ + 0, + 1, + 2 + ] + }, + "filled" : { + "type" : "boolean" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "size", + "filled" + ], + "required" : [ + "size", + "filled" + ] + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "numBarrels", + "barrelType" + ], + "required" : [ + "numBarrels", + "barrelType" + ] + }, + "Nums" : { + "type" : "array", + "subType" : "set of", + "items" : { + "type" : "object", + "subType" : "record", + "properties" : { + "number" : { + "originalName" : "num", + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "number" + ] + } + }, + "Numz" : { + "type" : "object", + "subType" : "record", + "properties" : { + "nums" : { + "$ref" : "#/definitions/three/Nums" + } + }, + "additionalProperties" : false, + "required" : [ + "nums" + ] + }, + "Rex" : { + "type" : "array", + "subType" : "record of", + "items" : { + "$ref" : "#/definitions/one/Rec" + } + }, + "Stuff" : { + "type" : "array", + "subType" : "record of", + "items" : { + "$ref" : "#/definitions/three/Thing" + } + }, + "Thing" : { + "anyOf" : [ + { + "originalName" : "b", + "type" : "boolean" + }, + { + "originalName" : "i", + "unusedAlias" : "int", + "type" : "integer" + }, + { + "originalName" : "cs", + "unusedAlias" : "str", + "type" : "string", + "subType" : "charstring" + }, + { + "originalName" : "rec", + "type" : "object", + "subType" : "record", + "properties" : { + "num" : { + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "num" + ] + } + ] + } + }, + "Zero" : { + "AnyString" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "generalstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "generalstr" + ] + }, + { + "type" : "object", + "properties" : { + "numericstr" : { + "type" : "string", + "subType" : "charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "numericstr" + ] + }, + { + "type" : "object", + "properties" : { + "utf8str" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "utf8str" + ] + }, + { + "type" : "object", + "properties" : { + "printablestr" : { + "type" : "string", + "subType" : "charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "printablestr" + ] + }, + { + "type" : "object", + "properties" : { + "universalstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "universalstr" + ] + }, + { + "type" : "object", + "properties" : { + "bmpstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "bmpstr" + ] + }, + { + "type" : "object", + "properties" : { + "graphicstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "graphicstr" + ] + }, + { + "type" : "object", + "properties" : { + "ia5str" : { + "type" : "string", + "subType" : "charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "ia5str" + ] + }, + { + "type" : "object", + "properties" : { + "teletexstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "teletexstr" + ] + }, + { + "type" : "object", + "properties" : { + "videotexstr" : { + "type" : "string", + "subType" : "universal charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "videotexstr" + ] + }, + { + "type" : "object", + "properties" : { + "visiblestr" : { + "type" : "string", + "subType" : "charstring" + } + }, + "additionalProperties" : false, + "required" : [ + "visiblestr" + ] + } + ] + }, + "Big_Choice" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "numbers" : { + "type" : "array", + "subType" : "set of", + "items" : { + "$ref" : "#/definitions/Zero/Number" + } + } + }, + "additionalProperties" : false, + "required" : [ + "numbers" + ] + }, + { + "type" : "object", + "properties" : { + "strings" : { + "$ref" : "#/definitions/Zero/ManyStrings" + } + }, + "additionalProperties" : false, + "required" : [ + "strings" + ] + } + ] + }, + "Big_Set" : { + "type" : "object", + "subType" : "set", + "properties" : { + "product" : { + "$ref" : "#/definitions/Zero/SeqProduct" + }, + "numbers" : { + "type" : "array", + "subType" : "set of", + "items" : { + "$ref" : "#/definitions/Zero/Number" + } + }, + "strings" : { + "$ref" : "#/definitions/Zero/ManyStrings" + }, + "color" : { + "enum" : [ + "red", + "blue", + "green", + "yellow" + ], + "numericValues" : [ + 0, + 1, + 2, + 3 + ] + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "product", + "numbers", + "strings", + "color" + ], + "required" : [ + "product", + "numbers", + "strings", + "color" + ] + }, + "ManyStrings" : { + "type" : "array", + "subType" : "record of", + "items" : { + "$ref" : "#/definitions/Zero/AnyString" + } + }, + "NullType" : { + "type" : "null" + }, + "Number" : { + "anyOf" : [ + { + "type" : "object", + "properties" : { + "decimal" : { + "type" : "integer" + } + }, + "additionalProperties" : false, + "required" : [ + "decimal" + ] + }, + { + "type" : "object", + "properties" : { + "binary" : { + "type" : "string", + "subType" : "bitstring", + "pattern" : "^[01]*$" + } + }, + "additionalProperties" : false, + "required" : [ + "binary" + ] + }, + { + "type" : "object", + "properties" : { + "hexadecimal" : { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + } + }, + "additionalProperties" : false, + "required" : [ + "hexadecimal" + ] + } + ] + }, + "ObjIdType" : { + "type" : "string", + "subType" : "objid", + "pattern" : "^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$" + }, + "RelObjIdType" : { + "type" : "string", + "subType" : "objid", + "pattern" : "^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$" + }, + "Season" : { + "enum" : [ + "spring", + "summer", + "fall", + "winter" + ], + "numericValues" : [ + 1, + 2, + 3, + 4 + ] + }, + "SelectionType" : { + "type" : "array", + "subType" : "set of", + "items" : { + "$ref" : "#/definitions/Zero/Number" + } + }, + "SeqOfInt" : { + "type" : "array", + "subType" : "record of", + "items" : { + "type" : "integer" + } + }, + "SeqProduct" : { + "type" : "object", + "subType" : "record", + "properties" : { + "name" : { + "type" : "string", + "subType" : "universal charstring" + }, + "price" : { + "anyOf" : [ + { + "type" : "number" + }, + { + "enum" : [ + "not_a_number", + "infinity", + "-infinity" + ] + } + ] + }, + "id" : { + "anyOf" : [ + { + "type" : "null" + }, + { + "type" : "string", + "subType" : "octetstring", + "pattern" : "^([0-9A-Fa-f][0-9A-Fa-f])*$" + } + ], + "omitAsNull" : false + }, + "available" : { + "type" : "boolean" + } + }, + "additionalProperties" : false, + "fieldOrder" : [ + "name", + "price", + "id", + "available" + ], + "required" : [ + "name", + "price", + "available" + ] + } + } + }, + "anyOf" : [ + { + "$ref" : "#/definitions/two/Ints", + "decoding" : { + "prototype" : [ + "fast", + "f_dec_ints", + "os", + "x" + ] + }, + "encoding" : { + "prototype" : [ + "fast", + "f_enc_ints", + "eents", + "octus" + ], + "printing" : "pretty" + } + }, + { + "$ref" : "#/definitions/one/Rec", + "decoding" : { + "prototype" : [ + "convert", + "f_dec_rec", + "octie" + ], + "errorBehavior" : { + "ALL" : "WARNING", + "INVAL_MSG" : "ERROR" + } + }, + "encoding" : { + "prototype" : [ + "convert", + "f_enc_rec", + "x" + ] + } + }, + { + "$ref" : "#/definitions/Zero/Big_Set", + "decoding" : { + "prototype" : [ + "convert", + "f_dec_bigset", + "os" + ] + }, + "encoding" : { + "prototype" : [ + "convert", + "f_enc_bigset", + "x" + ] + } + } + ] +} diff --git a/regression_test/ttcn2json/zero.asn b/regression_test/ttcn2json/zero.asn index 1ab9eec..aaa7e04 100644 --- a/regression_test/ttcn2json/zero.asn +++ b/regression_test/ttcn2json/zero.asn @@ -61,15 +61,20 @@ Big-Choice ::= CHOICE { strings ManyStrings } +Season ::= ENUMERATED { + spring (1), summer (2), fall (3), winter (4) +} + SelectionType ::= numbers < Big-Choice --- non-encodable types NullType ::= NULL ObjIdType ::= OBJECT IDENTIFIER RelObjIdType ::= RELATIVE-OID +-- non-encodable types + EmbPdvType ::= EMBEDDED PDV ExtType ::= EXTERNAL 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 efa789f..62c5615 100755 Binary files a/titan_executor_api/doc/Titan_Executor_API_User_Guide.doc and b/titan_executor_api/doc/Titan_Executor_API_User_Guide.doc differ diff --git a/usrguide/Makefile b/usrguide/Makefile index be02514..00c44cc 100644 --- a/usrguide/Makefile +++ b/usrguide/Makefile @@ -12,13 +12,26 @@ include ../Makefile.cfg .SUFFIXES: .tex .labels .dvi .ps .pdf +DOC2PDF_JAR := ../../titan_playground/jar/doc2pdf.jar +WARNING_TXT := warning.txt TITAN_DOCS := apiguide.doc userguide.doc installationguide.doc referenceguide.doc releasenotes.doc - TITAN_PDFS := $(TITAN_DOCS:.doc=.pdf) ifeq ($(GEN_PDF), yes) -install: $(TITAN_PDFS) +# Install with error handling: Tries to create PDFs and copy the available documents to $(DOCDIR). +# On success (PDF files are successfully created), the PDF files are copied to the $(DOCDIR) directory. +# On failure (if doc2pdf.jar is not available or install_pdf exits with error, so PDFs are not created), the DOC files are copied to the $(DOCDIR) directory instead of the PDF files. +install: + { make test_doc2pdf_jar && make install_pdf; } || make install_error_handling + +# Checks if $(DOC2PDF_JAR) is present, and exit with error if not. +test_doc2pdf_jar: + @{ test -f $(DOC2PDF_JAR) && echo "$(DOC2PDF_JAR) is present .. OK"; } || { echo "ERROR: $(DOC2PDF_JAR) is missing" && false; }; + +# Install PDFs normal case: PDFs are created and copied to the $(DOCDIR) directory. +# PDF creation may fail if doc2pdf.jar fails, which can happen for example if the server, that converts from DOC to PDF, is not available. In this case the target exits with error. +install_pdf: $(TITAN_PDFS) ifdef MINGW $(info Skipped ${CURDIR} for MinGW) else @@ -26,12 +39,28 @@ else cp $(TITAN_PDFS) $(DOCDIR) endif +# Copies DOC files to $(DOCDIR) instead of the PDF files, because PDF creation failed. Also a $(WARNING_TXT) is created +install_error_handling: + @echo "Error handling: DOC files are copied to $(DOCDIR) instead of PDF files" +ifdef MINGW +$(info Skipped ${CURDIR} for MinGW) +else + mkdir -p $(DOCDIR) + cp $(TITAN_DOCS) $(DOCDIR) + @echo "Creating $(WARNING_TXT)" + @echo "DOC files are copied to $(DOCDIR) instead of PDF files." >$(WARNING_TXT) + @echo "It is because $(DOC2PDF_JAR) is missing or failed, which can happen for example if the server, that converts from DOC to PDF, is not available." >>$(WARNING_TXT) + cp $(WARNING_TXT) $(DOCDIR) +endif + +# Converts DOC to PDF +# $@ : target name, for example: apiguide.pdf +# $(basename $@) : target name without extension, for example: apiguide %.pdf : %.doc - @for doc in $(TITAN_DOCS:.doc=); do \ - java -jar ../../titan_playground/jar/doc2pdf.jar $(addsuffix .doc, $$doc) $(addsuffix .pdf, $$doc) || exit; \ - done + @java -jar $(DOC2PDF_JAR) $(basename $@).doc $@ || { echo "ERROR: doc2pdf.jar failed with $(basename $@).doc" && false; } else +# GEN_PDF == no install: endif @@ -45,3 +74,4 @@ clean: distclean:clean dep: + diff --git a/usrguide/PRI.doc b/usrguide/PRI.doc new file mode 100644 index 0000000..b0e48bf Binary files /dev/null and b/usrguide/PRI.doc differ diff --git a/usrguide/apiguide.doc b/usrguide/apiguide.doc index b70d902..6d9e0e6 100644 Binary files a/usrguide/apiguide.doc and b/usrguide/apiguide.doc differ diff --git a/usrguide/installationguide.doc b/usrguide/installationguide.doc index f199061..d530d55 100644 Binary files a/usrguide/installationguide.doc and b/usrguide/installationguide.doc differ diff --git a/usrguide/referenceguide.doc b/usrguide/referenceguide.doc index 3703a43..4bc7ce3 100644 Binary files a/usrguide/referenceguide.doc and b/usrguide/referenceguide.doc differ diff --git a/usrguide/releasenotes.doc b/usrguide/releasenotes.doc index 6c6bbe7..b9c5b49 100644 Binary files a/usrguide/releasenotes.doc and b/usrguide/releasenotes.doc differ diff --git a/usrguide/userguide.doc b/usrguide/userguide.doc index a31a339..da7dd72 100644 Binary files a/usrguide/userguide.doc and b/usrguide/userguide.doc differ