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