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