1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "TTCN3Module.hh"
10 #include "RootType.hh"
11 #include "SimpleType.hh"
12 #include "ComplexType.hh"
13 #include "ImportStatement.hh"
14 #include "Annotation.hh"
16 #include "../common/version_internal.h"
20 #if defined(WIN32) && !defined(MINGW)
21 #include <cygwin/version.h>
22 #include <sys/cygwin.h>
26 extern bool e_flag_used
;
27 extern bool t_flag_used
;
28 extern bool z_flag_used
;
30 TTCN3Module::TTCN3Module(const char * a_filename
, XMLParser
* a_parser
)
35 , actualXsdConstruct(c_unknown
)
40 , targetNamespace_connectedPrefix()
41 , declaredNamespaces()
42 , elementFormDefault(notset
)
43 , attributeFormDefault(notset
)
44 , blockDefault(not_set
)
45 , storedTypeSubstitutions()
49 , moduleNotIntoFile(false)
50 , moduleNotIntoNameConversion(false) {
51 #if defined(WIN32) && !defined(MINGW)
52 // Transform a Windows style path: "C:\cygwin\tmp\a.xsd"
53 // into a POSIX style path: "/home/a/xsd", so getValueWithoutPrefix('/')
54 // can chop off the directory path.
55 #if CYGWIN_VERSION_DLL_MAJOR >= 1007
57 ssize_t needed
= cygwin_conv_path(CCP_WIN_A_TO_POSIX
| CCP_RELATIVE
, a_filename
, NULL
, 0);
59 posix
= (char*) Malloc(needed
);
60 if (cygwin_conv_path(CCP_WIN_A_TO_POSIX
| CCP_RELATIVE
, a_filename
, posix
, needed
)) {
61 posix
= NULL
; // conversion failed
64 Mstring
filename(posix
? posix
: a_filename
);
65 Free(posix
); // even if NULL
68 int fail
= cygwin_conv_to_posix_path(a_filename
, posix
);
69 Mstring
filename(fail
? a_filename
: posix
);
73 Mstring
filename(a_filename
);
75 schemaname
= filename
.getValueWithoutPrefix('/'); // excludes the path of the input file
78 TTCN3Module::~TTCN3Module() {
79 for (List
<RootType
*>::iterator type
= definedTypes
.begin(); type
; type
= type
->Next
) {
84 void TTCN3Module::loadValuesFromXMLDeclaration(const char *a_version
,
85 const char *a_encoding
, int a_standalone
) {
86 xsdVersion
= a_version
;
87 xsdEncoding
= a_encoding
;
88 xsdStandalone
= a_standalone
;
91 void TTCN3Module::loadValuesFromSchemaTag(const Mstring
& a_targetNamespace
,
92 List
<NamespaceType
> a_declaredNamespaces
,
93 FormValue a_elementFormDefault
, FormValue a_attributeFormDefault
,
94 BlockValue a_blockDefault
) {
95 if (a_targetNamespace
.empty()) {
96 targetNamespace
= "NoTargetNamespace";
98 if (a_targetNamespace
== "http://www.w3.org/2001/XMLSchema") {
101 targetNamespace
= a_targetNamespace
;
104 elementFormDefault
= a_elementFormDefault
;
105 attributeFormDefault
= a_attributeFormDefault
;
106 blockDefault
= a_blockDefault
;
108 declaredNamespaces
= a_declaredNamespaces
;
110 for (List
<NamespaceType
>::iterator ns
= declaredNamespaces
.begin(); ns
; ns
= ns
->Next
) {
111 if (ns
->Data
.uri
== targetNamespace
) {
112 targetNamespace_connectedPrefix
= ns
->Data
.prefix
;
118 void TTCN3Module::addMainType(const ConstructType typeOfMainType
) {
119 switch (typeOfMainType
) {
122 SimpleType
* new_ST
= new SimpleType(parser
, this, c_simpleType
);
123 definedTypes
.push_back(new_ST
);
124 new_ST
->loadWithValues();
129 SimpleType
* new_ST
= new SimpleType(parser
, this, c_element
);
130 definedTypes
.push_back(new_ST
);
131 new_ST
->loadWithValues();
136 SimpleType
* new_ST
= new SimpleType(parser
, this, c_attribute
);
137 definedTypes
.push_back(new_ST
);
138 new_ST
->loadWithValues();
143 ComplexType
* new_CT
= new ComplexType(parser
, this, c_complexType
);
144 definedTypes
.push_back(new_CT
);
145 new_CT
->loadWithValues();
150 ComplexType
* new_CT
= new ComplexType(parser
, this, c_group
);
151 definedTypes
.push_back(new_CT
);
152 new_CT
->loadWithValues();
155 case c_attributeGroup
:
157 ComplexType
* new_CT
= new ComplexType(parser
, this, c_attributeGroup
);
158 definedTypes
.push_back(new_CT
);
159 new_CT
->loadWithValues();
164 ImportStatement
* new_INCL
= new ImportStatement(parser
, this, c_include
);
165 definedTypes
.push_back(new_INCL
);
166 new_INCL
->loadWithValues();
171 ImportStatement
* new_IMP
= new ImportStatement(parser
, this, c_import
);
172 definedTypes
.push_back(new_IMP
);
173 new_IMP
->loadWithValues();
178 Annotation
* new_ANN
= new Annotation(parser
, this, c_annotation
);
179 definedTypes
.push_back(new_ANN
);
180 new_ANN
->loadWithValues();
185 Mstring type
= empty_string
;
186 if (hasDefinedMainType()) {
187 type
= getLastMainType().getName().convertedValue
;
189 printWarning(getSchemaname(), type
,
190 Mstring("The mapping of ID attribute is not supported."));
191 TTCN3ModuleInventory::getInstance().incrNumWarnings();
199 actualXsdConstruct
= typeOfMainType
;
202 void TTCN3Module::replaceLastMainType(RootType
* t
) {
203 delete(definedTypes
.back());
204 definedTypes
.pop_back();
205 definedTypes
.push_back(t
);
206 actualXsdConstruct
= t
->getConstruct();
209 void TTCN3Module::generate_TTCN3_header(FILE * file
) {
210 time_t time_current
= time(NULL
);
212 "/*******************************************************************************\n"
216 "* Copyright Ericsson Telecom AB\n"
218 "* XSD to TTCN-3 Translator\n"
223 "* Copyright (c) 2000-%-4d Ericsson Telecom AB\n"
225 "* XSD to TTCN-3 Translator version: %-40s\n"
227 1900 + (localtime(&time_current
))->tm_year
,
232 "* All rights reserved. This program and the accompanying materials\n"
233 "* are made available under the terms of the Eclipse Public License v1.0\n"
234 "* which accompanies this distribution, and is available at\n"
235 "* http://www.eclipse.org/legal/epl-v10.html\n"
236 "*******************************************************************************/\n"
256 "// Contact: http://ttcn.ericsson.se\n"
258 "////////////////////////////////////////////////////////////////////////////////\n"
262 void TTCN3Module::generate_TTCN3_fileinfo(FILE * file
) {
269 if (!xsdVersion
.empty()) {
270 fprintf(file
, "version = \"%s\" ", xsdVersion
.c_str());
272 if (!xsdEncoding
.empty()) {
273 fprintf(file
, "encoding = \"%s\" ", xsdEncoding
.c_str());
276 switch (xsdStandalone
) {
278 fprintf(file
, "standalone = \"no\" ");
281 fprintf(file
, "standalone = \"yes\" ");
289 "//\t\t\t/* targetnamespace = \"%s\" */\n",
290 targetNamespace
.c_str()
294 void TTCN3Module::generate_TTCN3_modulestart(FILE * file
) {
299 "import from XSD all;\n"
306 void TTCN3Module::generate_TTCN3_import_statements(FILE * file
) {
307 for (List
<RootType
*>::iterator type
= definedTypes
.begin(); type
; type
= type
->Next
) {
308 if (type
->Data
->getConstruct() == c_import
) {
309 type
->Data
->printToFile(file
);
314 void TTCN3Module::generate_TTCN3_included_types(FILE * file
) {
315 for (List
<RootType
*>::iterator type
= definedTypes
.begin(); type
; type
= type
->Next
) {
316 if (type
->Data
->getConstruct() == c_include
) {
317 type
->Data
->printToFile(file
);
322 void TTCN3Module::generate_TTCN3_types(FILE * file
) {
323 for (List
<RootType
*>::iterator type
= definedTypes
.begin(); type
; type
= type
->Next
) {
324 if (type
->Data
->getConstruct() != c_include
&& type
->Data
->getConstruct() != c_import
) {
325 type
->Data
->printToFile(file
);
330 void TTCN3Module::generate_with_statement(FILE * file
, List
<NamespaceType
> used_namespaces
) {
342 for (List
<NamespaceType
>::iterator usedNS
= used_namespaces
.begin(); usedNS
; usedNS
= usedNS
->Next
) {
343 if (usedNS
->Data
.uri
== "http://www.w3.org/2001/XMLSchema") {
347 if (usedNS
->Data
.uri
== "NoTargetNamespace") {
350 // XXX this inner loop is either redundant now, or it should be elsewhere.
351 // It is quite dodgy to modify(!) namespaces when we are already generating code.
352 for (List
<NamespaceType
>::iterator usedNS2
= usedNS
->Next
; usedNS2
; usedNS2
= usedNS2
->Next
) {
353 if (usedNS
->Data
.uri
== usedNS2
->Data
.uri
) {
354 if (usedNS2
->Data
.prefix
.empty())
355 usedNS2
->Data
.prefix
= usedNS
->Data
.prefix
;
361 if (targetNamespace
!= "NoTargetNamespace") {
362 fprintf(file
, " variant \"namespace as \'%s\'", targetNamespace
.c_str());
363 if (!targetNamespace_connectedPrefix
.empty()) {
364 fprintf(file
, " prefix \'%s\'", targetNamespace_connectedPrefix
.c_str());
366 fprintf(file
, "\";\n");
372 " variant \"controlNamespace \'http://www.w3.org/2001/XMLSchema-instance\' prefix \'xsi\'\";\n");
374 if (attributeFormDefault
== qualified
) {
376 " variant \"attributeFormQualified\";\n");
378 if (elementFormDefault
== qualified
) {
380 " variant \"elementFormQualified\";\n");
386 void TTCN3Module::TargetNamespace2ModuleName() {
387 Mstring
res(targetNamespace
);
391 found
= res
.foundAt("http://");
392 //check if the http:// is at the beginning of the namespace
393 if (found
== res
.c_str()) { //res.c_str() returns a pointer to the first char
394 for (int i
= 0; i
!= 7; ++i
) {
398 found
= res
.foundAt("urn:");
399 //check if the urn: is at the beginning of the namespace
400 if (found
== res
.c_str()) { //res.c_str() returns a pointer to the first char
401 for (int i
= 0; i
!= 4; ++i
) {
407 // the characters ' '(SPACE), '.'(FULL STOP) and '-'(HYPEN-MINUS)
408 // and '/', '#', ':' shall all be replaced by a "_" (LOW LINE)
409 for (size_t i
= 0; i
!= res
.size(); ++i
) {
410 if ((res
[i
] == ' ') ||
419 // any character except "A" to "Z", "a" to "z" or "0" to "9" and "_" shall be removed
420 for (size_t i
= 0; i
!= res
.size(); ++i
) {
421 if (!isalpha((const unsigned char) res
[i
]) && !isdigit((const unsigned char) res
[i
]) && (res
[i
] != '_')) {
426 // a sequence of two of more "_" (LOW LINE) shall be replaced with a single "_" (LOW LINE)
427 for (size_t i
= 1; i
< res
.size(); ++i
) {
428 if (res
[i
] == '_' && res
[i
- 1] == '_') {
435 // "_" (LOW LINE) characters occurring at the beginning of the name shall be removed
441 // "_" (LOW LINE) characters occurring at the end of the name shall be removed
442 if (res
[res
.size() - 1] == '_') {
443 res
.eraseChar(res
.size() - 1);
449 } else if (isdigit((const unsigned char) res
[0])) {
450 res
.insertChar(0, 'x');
453 //Postfix with _i if the targetnamespace is different
454 bool postfixing
= false;
455 for (List
<TTCN3Module
*>::iterator mod
= TTCN3ModuleInventory::getInstance().getModules().begin(); mod
; mod
= mod
->Next
) {
456 if (mod
->Data
!= this && mod
->Data
->getModulename() == res
&& mod
->Data
->getTargetNamespace() != targetNamespace
) {
465 expstring_t tmpname
= NULL
;
469 tmpname
= mprintf("%s_%d", res
.c_str(), counter
);
470 for(List
<TTCN3Module
*>::iterator mod
= TTCN3ModuleInventory::getInstance().getModules().begin(); mod
; mod
= mod
->Next
){
471 if(mod
->Data
!= this && mod
->Data
->getModulename() == Mstring(tmpname
)){
478 res
= Mstring(tmpname
);
485 void TTCN3Module::dump() const {
486 fprintf(stderr
, "Module '%s' at %p (from %s)\n",
487 modulename
.c_str(), (const void*) this, schemaname
.c_str());
489 for (List
<RootType
*>::iterator type
= definedTypes
.begin(); type
; type
= type
->Next
) {