Merge pull request #77 from balaskoa/master
[deliverable/titan.core.git] / xsdconvert / TTCN3Module.cc
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 ******************************************************************************/
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
28 #if defined(WIN32) && !defined(MINGW)
29 #include <cygwin/version.h>
30 #include <sys/cygwin.h>
31 #include <limits.h>
32 #endif
33
34 extern bool e_flag_used;
35 extern bool z_flag_used;
36
37 TTCN3Module::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)
51 , blockDefault(not_set)
52 , storedTypeSubstitutions()
53 , element_types()
54 //, importedModules()
55 , variant()
56 , moduleNotIntoFile(false)
57 , moduleNotIntoNameConversion(false) {
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;
64 ssize_t needed = cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, a_filename, NULL, 0);
65 if (needed >= 0) {
66 posix = (char*) Malloc(needed);
67 if (cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, a_filename, posix, needed)) {
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
85 TTCN3Module::~TTCN3Module() {
86 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next) {
87 delete type->Data;
88 }
89 }
90
91 void TTCN3Module::loadValuesFromXMLDeclaration(const char *a_version,
92 const char *a_encoding, int a_standalone) {
93 xsdVersion = a_version;
94 xsdEncoding = a_encoding;
95 xsdStandalone = a_standalone;
96 }
97
98 void TTCN3Module::loadValuesFromSchemaTag(const Mstring& a_targetNamespace,
99 List<NamespaceType> a_declaredNamespaces,
100 FormValue a_elementFormDefault, FormValue a_attributeFormDefault,
101 BlockValue a_blockDefault) {
102 if (a_targetNamespace.empty()) {
103 targetNamespace = "NoTargetNamespace";
104 } else {
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;
113 blockDefault = a_blockDefault;
114
115 declaredNamespaces = a_declaredNamespaces;
116
117 for (List<NamespaceType>::iterator ns = declaredNamespaces.begin(); ns; ns = ns->Next) {
118 if (ns->Data.uri == targetNamespace) {
119 targetNamespace_connectedPrefix = ns->Data.prefix;
120 break;
121 }
122 }
123 }
124
125 void 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;
204 }
205
206 actualXsdConstruct = typeOfMainType;
207 }
208
209 void TTCN3Module::replaceLastMainType(RootType * t) {
210 delete(definedTypes.back());
211 definedTypes.pop_back();
212 definedTypes.push_back(t);
213 actualXsdConstruct = t->getConstruct();
214 }
215
216 void TTCN3Module::generate_TTCN3_fileinfo(FILE * file) {
217 fprintf(file,
218 "//\t- %s\n"
219 "//\t\t\t/* xml ",
220 schemaname.c_str()
221 );
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
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;
239 }
240
241 fprintf(file,
242 "*/\n"
243 "//\t\t\t/* targetnamespace = \"%s\" */\n",
244 targetNamespace.c_str()
245 );
246 }
247
248 void TTCN3Module::generate_TTCN3_modulestart(FILE * file) {
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()
257 );
258 }
259
260 void 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) {
263 type->Data->printToFile(file);
264 }
265 }
266 }
267
268 void 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) {
271 type->Data->printToFile(file);
272 }
273 }
274 }
275
276 void 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) {
279 type->Data->printToFile(file);
280 }
281 }
282 }
283
284 void TTCN3Module::generate_with_statement(FILE * file, List<NamespaceType> used_namespaces) {
285 if (e_flag_used) {
286 return;
287 }
288
289 fprintf(file,
290 "with {\n"
291 " encode \"XML\";\n"
292 );
293
294 bool xsi = false;
295
296 for (List<NamespaceType>::iterator usedNS = used_namespaces.begin(); usedNS; usedNS = usedNS->Next) {
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 }
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) {
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") {
316 fprintf(file, " variant \"namespace as \'%s\'", targetNamespace.c_str());
317 if (!targetNamespace_connectedPrefix.empty()) {
318 fprintf(file, " prefix \'%s\'", targetNamespace_connectedPrefix.c_str());
319 }
320 fprintf(file, "\";\n");
321 }
322
323
324 if (xsi) {
325 fprintf(file,
326 " variant \"controlNamespace \'http://www.w3.org/2001/XMLSchema-instance\' prefix \'xsi\'\";\n");
327 }
328 if (attributeFormDefault == qualified) {
329 fprintf(file,
330 " variant \"attributeFormQualified\";\n");
331 }
332 if (elementFormDefault == qualified) {
333 fprintf(file,
334 " variant \"elementFormQualified\";\n");
335 }
336 fprintf(file,
337 "}\n");
338 }
339
340 void TTCN3Module::TargetNamespace2ModuleName() {
341 Mstring res(targetNamespace);
342
343 if (z_flag_used) {
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) {
349 res.eraseChar(0);
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) {
356 res.eraseChar(0);
357 }
358 }
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] == '#') ||
369 (res[i] == ':')) {
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) {
375 if (!isalpha((const unsigned char) res[i]) && !isdigit((const unsigned char) res[i]) && (res[i] != '_')) {
376 res.eraseChar(i);
377 i--;
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) {
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);
398 }
399 }
400
401 if (res.empty()) {
402 res = "x";
403 } else if (isdigit((const unsigned char) res[0])) {
404 res.insertChar(0, 'x');
405 }
406
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
436 modulename = res;
437 }
438
439 void TTCN3Module::dump() const {
440 fprintf(stderr, "Module '%s' at %p (from %s)\n",
441 modulename.c_str(), (const void*) this, schemaname.c_str());
442
443 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next) {
444 type->Data->dump(1);
445 }
446 }
This page took 0.052368 seconds and 5 git commands to generate.