Sync with 5.4.3
[deliverable/titan.core.git] / xsdconvert / TTCN3Module.cc
CommitLineData
970ed795 1///////////////////////////////////////////////////////////////////////////////
3abe9331 2// Copyright (c) 2000-2015 Ericsson Telecom AB
970ed795
EL
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"
9
10#include "RootType.hh"
11#include "SimpleType.hh"
12#include "ComplexType.hh"
13#include "ImportStatement.hh"
14#include "Annotation.hh"
15
16#include "../common/version_internal.h"
17
970ed795
EL
18#if defined(WIN32) && !defined(MINGW)
19#include <cygwin/version.h>
20#include <sys/cygwin.h>
21#include <limits.h>
22#endif
23
24extern bool e_flag_used;
970ed795
EL
25extern bool z_flag_used;
26
27TTCN3Module::TTCN3Module(const char * a_filename, XMLParser * a_parser)
28: parser(a_parser)
29, schemaname()
30, modulename()
31, definedTypes()
32, actualXsdConstruct(c_unknown)
33, xsdVersion()
34, xsdEncoding()
35, xsdStandalone()
36, targetNamespace()
37, targetNamespace_connectedPrefix()
38, declaredNamespaces()
39, elementFormDefault(notset)
40, attributeFormDefault(notset)
3abe9331 41, blockDefault(not_set)
51fa56b9 42, storedTypeSubstitutions()
43, element_types()
970ed795
EL
44//, importedModules()
45, variant()
46, moduleNotIntoFile(false)
3abe9331 47, moduleNotIntoNameConversion(false) {
970ed795
EL
48#if defined(WIN32) && !defined(MINGW)
49 // Transform a Windows style path: "C:\cygwin\tmp\a.xsd"
50 // into a POSIX style path: "/home/a/xsd", so getValueWithoutPrefix('/')
51 // can chop off the directory path.
52#if CYGWIN_VERSION_DLL_MAJOR >= 1007
53 char *posix = NULL;
3abe9331 54 ssize_t needed = cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, a_filename, NULL, 0);
970ed795 55 if (needed >= 0) {
3abe9331 56 posix = (char*) Malloc(needed);
57 if (cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, a_filename, posix, needed)) {
970ed795
EL
58 posix = NULL; // conversion failed
59 }
60 }
61 Mstring filename(posix ? posix : a_filename);
62 Free(posix); // even if NULL
63#else // Cygwin 1.5
64 char posix[PATH_MAX];
65 int fail = cygwin_conv_to_posix_path(a_filename, posix);
66 Mstring filename(fail ? a_filename : posix);
67#endif
68
69#else
70 Mstring filename(a_filename);
71#endif
72 schemaname = filename.getValueWithoutPrefix('/'); // excludes the path of the input file
73}
74
3abe9331 75TTCN3Module::~TTCN3Module() {
970ed795 76 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next) {
3abe9331 77 delete type->Data;
970ed795
EL
78 }
79}
80
81void TTCN3Module::loadValuesFromXMLDeclaration(const char *a_version,
3abe9331 82 const char *a_encoding, int a_standalone) {
970ed795
EL
83 xsdVersion = a_version;
84 xsdEncoding = a_encoding;
85 xsdStandalone = a_standalone;
86}
87
88void TTCN3Module::loadValuesFromSchemaTag(const Mstring& a_targetNamespace,
89 List<NamespaceType> a_declaredNamespaces,
3abe9331 90 FormValue a_elementFormDefault, FormValue a_attributeFormDefault,
91 BlockValue a_blockDefault) {
970ed795
EL
92 if (a_targetNamespace.empty()) {
93 targetNamespace = "NoTargetNamespace";
3abe9331 94 } else {
970ed795
EL
95 if (a_targetNamespace == "http://www.w3.org/2001/XMLSchema") {
96 notIntoFile();
97 }
98 targetNamespace = a_targetNamespace;
99 }
100
101 elementFormDefault = a_elementFormDefault;
102 attributeFormDefault = a_attributeFormDefault;
3abe9331 103 blockDefault = a_blockDefault;
970ed795
EL
104
105 declaredNamespaces = a_declaredNamespaces;
106
3abe9331 107 for (List<NamespaceType>::iterator ns = declaredNamespaces.begin(); ns; ns = ns->Next) {
970ed795
EL
108 if (ns->Data.uri == targetNamespace) {
109 targetNamespace_connectedPrefix = ns->Data.prefix;
110 break;
111 }
112 }
113}
114
3abe9331 115void TTCN3Module::addMainType(const ConstructType typeOfMainType) {
116 switch (typeOfMainType) {
117 case c_simpleType:
118 {
119 SimpleType * new_ST = new SimpleType(parser, this, c_simpleType);
120 definedTypes.push_back(new_ST);
121 new_ST->loadWithValues();
122 break;
123 }
124 case c_element:
125 {
126 SimpleType * new_ST = new SimpleType(parser, this, c_element);
127 definedTypes.push_back(new_ST);
128 new_ST->loadWithValues();
129 break;
130 }
131 case c_attribute:
132 {
133 SimpleType * new_ST = new SimpleType(parser, this, c_attribute);
134 definedTypes.push_back(new_ST);
135 new_ST->loadWithValues();
136 break;
137 }
138 case c_complexType:
139 {
140 ComplexType * new_CT = new ComplexType(parser, this, c_complexType);
141 definedTypes.push_back(new_CT);
142 new_CT->loadWithValues();
143 break;
144 }
145 case c_group:
146 {
147 ComplexType * new_CT = new ComplexType(parser, this, c_group);
148 definedTypes.push_back(new_CT);
149 new_CT->loadWithValues();
150 break;
151 }
152 case c_attributeGroup:
153 {
154 ComplexType * new_CT = new ComplexType(parser, this, c_attributeGroup);
155 definedTypes.push_back(new_CT);
156 new_CT->loadWithValues();
157 break;
158 }
159 case c_include:
160 {
161 ImportStatement * new_INCL = new ImportStatement(parser, this, c_include);
162 definedTypes.push_back(new_INCL);
163 new_INCL->loadWithValues();
164 break;
165 }
166 case c_import:
167 {
168 ImportStatement * new_IMP = new ImportStatement(parser, this, c_import);
169 definedTypes.push_back(new_IMP);
170 new_IMP->loadWithValues();
171 break;
172 }
173 case c_annotation:
174 {
175 Annotation * new_ANN = new Annotation(parser, this, c_annotation);
176 definedTypes.push_back(new_ANN);
177 new_ANN->loadWithValues();
178 break;
179 }
180 case c_idattrib:
181 {
182 Mstring type = empty_string;
183 if (hasDefinedMainType()) {
184 type = getLastMainType().getName().convertedValue;
185 }
186 printWarning(getSchemaname(), type,
187 Mstring("The mapping of ID attribute is not supported."));
188 TTCN3ModuleInventory::getInstance().incrNumWarnings();
189 break;
190 }
191 case c_unknown:
192 case c_schema:
193 break;
970ed795
EL
194 }
195
196 actualXsdConstruct = typeOfMainType;
197}
198
3abe9331 199void TTCN3Module::replaceLastMainType(RootType * t) {
970ed795
EL
200 delete(definedTypes.back());
201 definedTypes.pop_back();
202 definedTypes.push_back(t);
203 actualXsdConstruct = t->getConstruct();
204}
205
3abe9331 206void TTCN3Module::generate_TTCN3_fileinfo(FILE * file) {
970ed795
EL
207 fprintf(file,
208 "//\t- %s\n"
209 "//\t\t\t/* xml ",
210 schemaname.c_str()
3abe9331 211 );
970ed795
EL
212
213 if (!xsdVersion.empty()) {
214 fprintf(file, "version = \"%s\" ", xsdVersion.c_str());
215 }
216 if (!xsdEncoding.empty()) {
217 fprintf(file, "encoding = \"%s\" ", xsdEncoding.c_str());
218 }
219
3abe9331 220 switch (xsdStandalone) {
221 case 0:
222 fprintf(file, "standalone = \"no\" ");
223 break;
224 case 1:
225 fprintf(file, "standalone = \"yes\" ");
226 break;
227 default:
228 break;
970ed795
EL
229 }
230
231 fprintf(file,
232 "*/\n"
233 "//\t\t\t/* targetnamespace = \"%s\" */\n",
234 targetNamespace.c_str()
3abe9331 235 );
970ed795
EL
236}
237
3abe9331 238void TTCN3Module::generate_TTCN3_modulestart(FILE * file) {
970ed795
EL
239 fprintf(file,
240 "module %s {\n"
241 "\n"
242 "\n"
243 "import from XSD all;\n"
244 "\n"
245 "\n",
246 modulename.c_str()
3abe9331 247 );
970ed795
EL
248}
249
3abe9331 250void TTCN3Module::generate_TTCN3_import_statements(FILE * file) {
251 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next) {
252 if (type->Data->getConstruct() == c_import) {
970ed795
EL
253 type->Data->printToFile(file);
254 }
255 }
256}
257
3abe9331 258void TTCN3Module::generate_TTCN3_included_types(FILE * file) {
259 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next) {
260 if (type->Data->getConstruct() == c_include) {
970ed795
EL
261 type->Data->printToFile(file);
262 }
263 }
264}
265
3abe9331 266void TTCN3Module::generate_TTCN3_types(FILE * file) {
267 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next) {
268 if (type->Data->getConstruct() != c_include && type->Data->getConstruct() != c_import) {
970ed795
EL
269 type->Data->printToFile(file);
270 }
271 }
272}
273
3abe9331 274void TTCN3Module::generate_with_statement(FILE * file, List<NamespaceType> used_namespaces) {
275 if (e_flag_used) {
276 return;
277 }
970ed795
EL
278
279 fprintf(file,
280 "with {\n"
3f84031e 281 " encode \"XML\";\n"
3abe9331 282 );
970ed795
EL
283
284 bool xsi = false;
285
3abe9331 286 for (List<NamespaceType>::iterator usedNS = used_namespaces.begin(); usedNS; usedNS = usedNS->Next) {
970ed795
EL
287 if (usedNS->Data.uri == "http://www.w3.org/2001/XMLSchema") {
288 xsi = true;
289 continue;
290 }
291 if (usedNS->Data.uri == "NoTargetNamespace") {
292 continue;
293 }
3abe9331 294 // XXX this inner loop is either redundant now, or it should be elsewhere.
295 // It is quite dodgy to modify(!) namespaces when we are already generating code.
296 for (List<NamespaceType>::iterator usedNS2 = usedNS->Next; usedNS2; usedNS2 = usedNS2->Next) {
970ed795
EL
297 if (usedNS->Data.uri == usedNS2->Data.uri) {
298 if (usedNS2->Data.prefix.empty())
299 usedNS2->Data.prefix = usedNS->Data.prefix;
300 break;
301 }
302 }
303 }
304
305 if (targetNamespace != "NoTargetNamespace") {
3f84031e 306 fprintf(file, " variant \"namespace as \'%s\'", targetNamespace.c_str());
3abe9331 307 if (!targetNamespace_connectedPrefix.empty()) {
970ed795 308 fprintf(file, " prefix \'%s\'", targetNamespace_connectedPrefix.c_str());
3abe9331 309 }
970ed795
EL
310 fprintf(file, "\";\n");
311 }
312
313
314 if (xsi) {
315 fprintf(file,
3f84031e 316 " variant \"controlNamespace \'http://www.w3.org/2001/XMLSchema-instance\' prefix \'xsi\'\";\n");
970ed795
EL
317 }
318 if (attributeFormDefault == qualified) {
319 fprintf(file,
3f84031e 320 " variant \"attributeFormQualified\";\n");
970ed795
EL
321 }
322 if (elementFormDefault == qualified) {
323 fprintf(file,
3f84031e 324 " variant \"elementFormQualified\";\n");
970ed795
EL
325 }
326 fprintf(file,
327 "}\n");
328}
329
3abe9331 330void TTCN3Module::TargetNamespace2ModuleName() {
970ed795
EL
331 Mstring res(targetNamespace);
332
333 if (z_flag_used) {
3abe9331 334 char * found;
335 found = res.foundAt("http://");
336 //check if the http:// is at the beginning of the namespace
337 if (found == res.c_str()) { //res.c_str() returns a pointer to the first char
338 for (int i = 0; i != 7; ++i) {
970ed795 339 res.eraseChar(0);
3abe9331 340 }
341 }
342 found = res.foundAt("urn:");
343 //check if the urn: is at the beginning of the namespace
344 if (found == res.c_str()) { //res.c_str() returns a pointer to the first char
345 for (int i = 0; i != 4; ++i) {
970ed795 346 res.eraseChar(0);
3abe9331 347 }
348 }
970ed795
EL
349 }
350
351 // the characters ' '(SPACE), '.'(FULL STOP) and '-'(HYPEN-MINUS)
352 // and '/', '#', ':' shall all be replaced by a "_" (LOW LINE)
353 for (size_t i = 0; i != res.size(); ++i) {
354 if ((res[i] == ' ') ||
355 (res[i] == '.') ||
356 (res[i] == '-') ||
357 (res[i] == '/') ||
358 (res[i] == '#') ||
3abe9331 359 (res[i] == ':')) {
970ed795
EL
360 res[i] = '_';
361 }
362 }
363 // any character except "A" to "Z", "a" to "z" or "0" to "9" and "_" shall be removed
364 for (size_t i = 0; i != res.size(); ++i) {
3abe9331 365 if (!isalpha((const unsigned char) res[i]) && !isdigit((const unsigned char) res[i]) && (res[i] != '_')) {
970ed795 366 res.eraseChar(i);
3abe9331 367 i--;
970ed795
EL
368 }
369 }
370 // a sequence of two of more "_" (LOW LINE) shall be replaced with a single "_" (LOW LINE)
371 for (size_t i = 1; i < res.size(); ++i) {
3abe9331 372 if (res[i] == '_' && res[i - 1] == '_') {
373 res.eraseChar(i);
374 i--;
375 }
376 }
377
378 if (!res.empty()) {
379 // "_" (LOW LINE) characters occurring at the beginning of the name shall be removed
380 if (res[0] == '_') {
381 res.eraseChar(0);
382 }
383 }
384 if (!res.empty()) {
385 // "_" (LOW LINE) characters occurring at the end of the name shall be removed
386 if (res[res.size() - 1] == '_') {
387 res.eraseChar(res.size() - 1);
970ed795
EL
388 }
389 }
970ed795
EL
390
391 if (res.empty()) {
392 res = "x";
3abe9331 393 } else if (isdigit((const unsigned char) res[0])) {
970ed795
EL
394 res.insertChar(0, 'x');
395 }
396
3abe9331 397 //Postfix with _i if the targetnamespace is different
398 bool postfixing = false;
399 for (List<TTCN3Module*>::iterator mod = TTCN3ModuleInventory::getInstance().getModules().begin(); mod; mod = mod->Next) {
400 if (mod->Data != this && mod->Data->getModulename() == res && mod->Data->getTargetNamespace() != targetNamespace) {
401 postfixing = true;
402 break;
403 }
404 }
405
406 if(postfixing){
407 bool found;
408 int counter = 1;
409 expstring_t tmpname = NULL;
410 do {
411 found = false;
412 Free(tmpname);
413 tmpname = mprintf("%s_%d", res.c_str(), counter);
414 for(List<TTCN3Module*>::iterator mod = TTCN3ModuleInventory::getInstance().getModules().begin(); mod; mod = mod->Next){
415 if(mod->Data != this && mod->Data->getModulename() == Mstring(tmpname)){
416 found = true;
417 break;
418 }
419 }
420 counter++;
421 } while (found);
422 res = Mstring(tmpname);
423 Free(tmpname);
424 }
425
970ed795
EL
426 modulename = res;
427}
428
3abe9331 429void TTCN3Module::dump() const {
970ed795 430 fprintf(stderr, "Module '%s' at %p (from %s)\n",
3abe9331 431 modulename.c_str(), (const void*) this, schemaname.c_str());
970ed795 432
3abe9331 433 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next) {
970ed795
EL
434 type->Data->dump(1);
435 }
436}
This page took 0.045961 seconds and 5 git commands to generate.