Sync with 5.4.1
[deliverable/titan.core.git] / xsdconvert / TTCN3Module.cc
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"
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
26 extern bool e_flag_used;
27 extern bool t_flag_used;
28 extern bool z_flag_used;
29
30 TTCN3Module::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)
44 , blockDefault(not_set)
45 , storedTypeSubstitutions()
46 , element_types()
47 //, importedModules()
48 , variant()
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
56 char *posix = NULL;
57 ssize_t needed = cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, a_filename, NULL, 0);
58 if (needed >= 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
62 }
63 }
64 Mstring filename(posix ? posix : a_filename);
65 Free(posix); // even if NULL
66 #else // Cygwin 1.5
67 char posix[PATH_MAX];
68 int fail = cygwin_conv_to_posix_path(a_filename, posix);
69 Mstring filename(fail ? a_filename : posix);
70 #endif
71
72 #else
73 Mstring filename(a_filename);
74 #endif
75 schemaname = filename.getValueWithoutPrefix('/'); // excludes the path of the input file
76 }
77
78 TTCN3Module::~TTCN3Module() {
79 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next) {
80 delete type->Data;
81 }
82 }
83
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;
89 }
90
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";
97 } else {
98 if (a_targetNamespace == "http://www.w3.org/2001/XMLSchema") {
99 notIntoFile();
100 }
101 targetNamespace = a_targetNamespace;
102 }
103
104 elementFormDefault = a_elementFormDefault;
105 attributeFormDefault = a_attributeFormDefault;
106 blockDefault = a_blockDefault;
107
108 declaredNamespaces = a_declaredNamespaces;
109
110 for (List<NamespaceType>::iterator ns = declaredNamespaces.begin(); ns; ns = ns->Next) {
111 if (ns->Data.uri == targetNamespace) {
112 targetNamespace_connectedPrefix = ns->Data.prefix;
113 break;
114 }
115 }
116 }
117
118 void TTCN3Module::addMainType(const ConstructType typeOfMainType) {
119 switch (typeOfMainType) {
120 case c_simpleType:
121 {
122 SimpleType * new_ST = new SimpleType(parser, this, c_simpleType);
123 definedTypes.push_back(new_ST);
124 new_ST->loadWithValues();
125 break;
126 }
127 case c_element:
128 {
129 SimpleType * new_ST = new SimpleType(parser, this, c_element);
130 definedTypes.push_back(new_ST);
131 new_ST->loadWithValues();
132 break;
133 }
134 case c_attribute:
135 {
136 SimpleType * new_ST = new SimpleType(parser, this, c_attribute);
137 definedTypes.push_back(new_ST);
138 new_ST->loadWithValues();
139 break;
140 }
141 case c_complexType:
142 {
143 ComplexType * new_CT = new ComplexType(parser, this, c_complexType);
144 definedTypes.push_back(new_CT);
145 new_CT->loadWithValues();
146 break;
147 }
148 case c_group:
149 {
150 ComplexType * new_CT = new ComplexType(parser, this, c_group);
151 definedTypes.push_back(new_CT);
152 new_CT->loadWithValues();
153 break;
154 }
155 case c_attributeGroup:
156 {
157 ComplexType * new_CT = new ComplexType(parser, this, c_attributeGroup);
158 definedTypes.push_back(new_CT);
159 new_CT->loadWithValues();
160 break;
161 }
162 case c_include:
163 {
164 ImportStatement * new_INCL = new ImportStatement(parser, this, c_include);
165 definedTypes.push_back(new_INCL);
166 new_INCL->loadWithValues();
167 break;
168 }
169 case c_import:
170 {
171 ImportStatement * new_IMP = new ImportStatement(parser, this, c_import);
172 definedTypes.push_back(new_IMP);
173 new_IMP->loadWithValues();
174 break;
175 }
176 case c_annotation:
177 {
178 Annotation * new_ANN = new Annotation(parser, this, c_annotation);
179 definedTypes.push_back(new_ANN);
180 new_ANN->loadWithValues();
181 break;
182 }
183 case c_idattrib:
184 {
185 Mstring type = empty_string;
186 if (hasDefinedMainType()) {
187 type = getLastMainType().getName().convertedValue;
188 }
189 printWarning(getSchemaname(), type,
190 Mstring("The mapping of ID attribute is not supported."));
191 TTCN3ModuleInventory::getInstance().incrNumWarnings();
192 break;
193 }
194 case c_unknown:
195 case c_schema:
196 break;
197 }
198
199 actualXsdConstruct = typeOfMainType;
200 }
201
202 void TTCN3Module::replaceLastMainType(RootType * t) {
203 delete(definedTypes.back());
204 definedTypes.pop_back();
205 definedTypes.push_back(t);
206 actualXsdConstruct = t->getConstruct();
207 }
208
209 void TTCN3Module::generate_TTCN3_header(FILE * file) {
210 time_t time_current = time(NULL);
211 fprintf(file,
212 "/*******************************************************************************\n"
213 );
214 if (t_flag_used) {
215 fprintf(file,
216 "* Copyright Ericsson Telecom AB\n"
217 "*\n"
218 "* XSD to TTCN-3 Translator\n"
219 "*\n"
220 );
221 } else {
222 fprintf(file,
223 "* Copyright (c) 2000-%-4d Ericsson Telecom AB\n"
224 "*\n"
225 "* XSD to TTCN-3 Translator version: %-40s\n"
226 "*\n",
227 1900 + (localtime(&time_current))->tm_year,
228 PRODUCT_NUMBER
229 );
230 }
231 fprintf(file,
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"
237 "//\n"
238 "// File: %s.ttcn\n"
239 "// Description:\n"
240 "// References:\n"
241 "// Rev:\n"
242 "// Prodnr:\n",
243 modulename.c_str()
244 );
245 if (t_flag_used) {
246 fprintf(file,
247 "// Updated:\n"
248 );
249 } else {
250 fprintf(file,
251 "// Updated: %s",
252 ctime(&time_current)
253 );
254 }
255 fprintf(file,
256 "// Contact: http://ttcn.ericsson.se\n"
257 "//\n"
258 "////////////////////////////////////////////////////////////////////////////////\n"
259 );
260 }
261
262 void TTCN3Module::generate_TTCN3_fileinfo(FILE * file) {
263 fprintf(file,
264 "//\t- %s\n"
265 "//\t\t\t/* xml ",
266 schemaname.c_str()
267 );
268
269 if (!xsdVersion.empty()) {
270 fprintf(file, "version = \"%s\" ", xsdVersion.c_str());
271 }
272 if (!xsdEncoding.empty()) {
273 fprintf(file, "encoding = \"%s\" ", xsdEncoding.c_str());
274 }
275
276 switch (xsdStandalone) {
277 case 0:
278 fprintf(file, "standalone = \"no\" ");
279 break;
280 case 1:
281 fprintf(file, "standalone = \"yes\" ");
282 break;
283 default:
284 break;
285 }
286
287 fprintf(file,
288 "*/\n"
289 "//\t\t\t/* targetnamespace = \"%s\" */\n",
290 targetNamespace.c_str()
291 );
292 }
293
294 void TTCN3Module::generate_TTCN3_modulestart(FILE * file) {
295 fprintf(file,
296 "module %s {\n"
297 "\n"
298 "\n"
299 "import from XSD all;\n"
300 "\n"
301 "\n",
302 modulename.c_str()
303 );
304 }
305
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);
310 }
311 }
312 }
313
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);
318 }
319 }
320 }
321
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);
326 }
327 }
328 }
329
330 void TTCN3Module::generate_with_statement(FILE * file, List<NamespaceType> used_namespaces) {
331 if (e_flag_used) {
332 return;
333 }
334
335 fprintf(file,
336 "with {\n"
337 "encode \"XML\";\n"
338 );
339
340 bool xsi = false;
341
342 for (List<NamespaceType>::iterator usedNS = used_namespaces.begin(); usedNS; usedNS = usedNS->Next) {
343 if (usedNS->Data.uri == "http://www.w3.org/2001/XMLSchema") {
344 xsi = true;
345 continue;
346 }
347 if (usedNS->Data.uri == "NoTargetNamespace") {
348 continue;
349 }
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;
356 break;
357 }
358 }
359 }
360
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());
365 }
366 fprintf(file, "\";\n");
367 }
368
369
370 if (xsi) {
371 fprintf(file,
372 "variant \"controlNamespace \'http://www.w3.org/2001/XMLSchema-instance\' prefix \'xsi\'\";\n");
373 }
374 if (attributeFormDefault == qualified) {
375 fprintf(file,
376 "variant \"attributeFormQualified\";\n");
377 }
378 if (elementFormDefault == qualified) {
379 fprintf(file,
380 "variant \"elementFormQualified\";\n");
381 }
382 fprintf(file,
383 "}\n");
384 }
385
386 void TTCN3Module::TargetNamespace2ModuleName() {
387 Mstring res(targetNamespace);
388
389 if (z_flag_used) {
390 char * found;
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) {
395 res.eraseChar(0);
396 }
397 }
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) {
402 res.eraseChar(0);
403 }
404 }
405 }
406
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] == ' ') ||
411 (res[i] == '.') ||
412 (res[i] == '-') ||
413 (res[i] == '/') ||
414 (res[i] == '#') ||
415 (res[i] == ':')) {
416 res[i] = '_';
417 }
418 }
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] != '_')) {
422 res.eraseChar(i);
423 i--;
424 }
425 }
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] == '_') {
429 res.eraseChar(i);
430 i--;
431 }
432 }
433
434 if (!res.empty()) {
435 // "_" (LOW LINE) characters occurring at the beginning of the name shall be removed
436 if (res[0] == '_') {
437 res.eraseChar(0);
438 }
439 }
440 if (!res.empty()) {
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);
444 }
445 }
446
447 if (res.empty()) {
448 res = "x";
449 } else if (isdigit((const unsigned char) res[0])) {
450 res.insertChar(0, 'x');
451 }
452
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) {
457 postfixing = true;
458 break;
459 }
460 }
461
462 if(postfixing){
463 bool found;
464 int counter = 1;
465 expstring_t tmpname = NULL;
466 do {
467 found = false;
468 Free(tmpname);
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)){
472 found = true;
473 break;
474 }
475 }
476 counter++;
477 } while (found);
478 res = Mstring(tmpname);
479 Free(tmpname);
480 }
481
482 modulename = res;
483 }
484
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());
488
489 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next) {
490 type->Data->dump(1);
491 }
492 }
This page took 0.041115 seconds and 5 git commands to generate.