Titan Core Initial Contribution
[deliverable/titan.core.git] / xsdconvert / TTCN3Module.cc
CommitLineData
970ed795
EL
1///////////////////////////////////////////////////////////////////////////////
2// Copyright (c) 2000-2014 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
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)
44//, importedModules()
45, variant()
46, moduleNotIntoFile(false)
47, moduleNotIntoNameConversion(false)
48{
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;
55 ssize_t needed = cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, a_filename, NULL, 0);
56 if (needed >= 0) {
57 posix = (char*)Malloc(needed);
58 if (cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, a_filename, posix, needed)) {
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
76TTCN3Module::~TTCN3Module()
77{
78 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next) {
79 delete(type->Data);
80 }
81}
82
83void TTCN3Module::loadValuesFromXMLDeclaration(const char *a_version,
84 const char *a_encoding, int a_standalone)
85{
86 xsdVersion = a_version;
87 xsdEncoding = a_encoding;
88 xsdStandalone = a_standalone;
89}
90
91void TTCN3Module::loadValuesFromSchemaTag(const Mstring& a_targetNamespace,
92 List<NamespaceType> a_declaredNamespaces,
93 FormValue a_elementFormDefault, FormValue a_attributeFormDefault)
94{
95 if (a_targetNamespace.empty()) {
96 targetNamespace = "NoTargetNamespace";
97 }
98 else {
99 if (a_targetNamespace == "http://www.w3.org/2001/XMLSchema") {
100 notIntoFile();
101 }
102 targetNamespace = a_targetNamespace;
103 }
104
105 elementFormDefault = a_elementFormDefault;
106 attributeFormDefault = a_attributeFormDefault;
107
108 declaredNamespaces = a_declaredNamespaces;
109
110 for (List<NamespaceType>::iterator ns = declaredNamespaces.begin(); ns; ns = ns->Next)
111 {
112 if (ns->Data.uri == targetNamespace) {
113 targetNamespace_connectedPrefix = ns->Data.prefix;
114 break;
115 }
116 }
117}
118
119void TTCN3Module::addMainType(ConstructType typeOfMainType)
120{
121 switch (typeOfMainType)
122 {
123 case c_simpleType: {
124 SimpleType * new_ST = new SimpleType(parser, this, c_simpleType);
125 definedTypes.push_back(new_ST);
126 new_ST->loadWithValues();
127 break; }
128 case c_element: {
129 SimpleType * new_ST = new SimpleType(parser, this, c_element);
130 definedTypes.push_back(new_ST);
131 new_ST->loadWithValues();
132 break; }
133 case c_attribute: {
134 SimpleType * new_ST = new SimpleType(parser, this, c_attribute);
135 definedTypes.push_back(new_ST);
136 new_ST->loadWithValues();
137 break; }
138 case c_complexType: {
139 ComplexType * new_CT = new ComplexType(parser, this, c_complexType);
140 definedTypes.push_back(new_CT);
141 new_CT->loadWithValues();
142 break; }
143 case c_group: {
144 ComplexType * new_CT = new ComplexType(parser, this, c_group);
145 definedTypes.push_back(new_CT);
146 new_CT->loadWithValues();
147 break; }
148 case c_attributeGroup: {
149 ComplexType * new_CT = new ComplexType(parser, this, c_attributeGroup);
150 definedTypes.push_back(new_CT);
151 new_CT->loadWithValues();
152 break; }
153 case c_include: {
154 ImportStatement * new_INCL = new ImportStatement(parser, this, c_include);
155 definedTypes.push_back(new_INCL);
156 new_INCL->loadWithValues();
157 break; }
158 case c_import: {
159 ImportStatement * new_IMP = new ImportStatement(parser, this, c_import);
160 definedTypes.push_back(new_IMP);
161 new_IMP->loadWithValues();
162 break; }
163 case c_annotation: {
164 Annotation * new_ANN = new Annotation(parser, this, c_annotation);
165 definedTypes.push_back(new_ANN);
166 new_ANN->loadWithValues();
167 break; }
168 case c_unknown:
169 case c_schema:
170 break;
171 }
172
173 actualXsdConstruct = typeOfMainType;
174}
175
176void TTCN3Module::replaceLastMainType(RootType * t)
177{
178 delete(definedTypes.back());
179 definedTypes.pop_back();
180 definedTypes.push_back(t);
181 actualXsdConstruct = t->getConstruct();
182}
183
184void TTCN3Module::generate_TTCN3_header(FILE * file)
185{
186 time_t time_current = time(NULL);
187 fprintf(file,
188 "/*******************************************************************************\n"
189 );
190 if (t_flag_used) {
191 fprintf(file,
192 "* Copyright Ericsson Telecom AB\n"
193 "*\n"
194 "* XSD to TTCN-3 Translator\n"
195 "*\n"
196 );
197 }
198 else {
199 fprintf(file,
200 "* Copyright Ericsson Telecom AB %-4d\n"
201 "*\n"
202 "* XSD to TTCN-3 Translator version: %-40s\n"
203 "*\n",
204 1900 + (localtime(&time_current))->tm_year,
205 PRODUCT_NUMBER
206 );
207 }
208 fprintf(file,
209 "* All rights reserved. This program and the accompanying materials\n"
210 "* are made available under the terms of the Eclipse Public License v1.0\n"
211 "* which accompanies this distribution, and is available at\n"
212 "* http://www.eclipse.org/legal/epl-v10.html\n"
213 "*******************************************************************************/\n"
214 "//\n"
215 "// File: %s.ttcn\n"
216 "// Description:\n"
217 "// References:\n"
218 "// Rev:\n"
219 "// Prodnr:\n",
220 modulename.c_str()
221 );
222 if (t_flag_used) {
223 fprintf(file,
224 "// Updated:\n"
225 );
226 }
227 else {
228 fprintf(file,
229 "// Updated: %s",
230 ctime(&time_current)
231 );
232 }
233 fprintf(file,
234 "// Contact: http://ttcn.ericsson.se\n"
235 "//\n"
236 "////////////////////////////////////////////////////////////////////////////////\n"
237 );
238}
239
240void TTCN3Module::generate_TTCN3_fileinfo(FILE * file)
241{
242 fprintf(file,
243 "//\t- %s\n"
244 "//\t\t\t/* xml ",
245 schemaname.c_str()
246 );
247
248 if (!xsdVersion.empty()) {
249 fprintf(file, "version = \"%s\" ", xsdVersion.c_str());
250 }
251 if (!xsdEncoding.empty()) {
252 fprintf(file, "encoding = \"%s\" ", xsdEncoding.c_str());
253 }
254
255 switch (xsdStandalone)
256 {
257 case 0:
258 fprintf(file, "standalone = \"no\" ");
259 break;
260 case 1:
261 fprintf(file, "standalone = \"yes\" ");
262 break;
263 default:
264 break;
265 }
266
267 fprintf(file,
268 "*/\n"
269 "//\t\t\t/* targetnamespace = \"%s\" */\n",
270 targetNamespace.c_str()
271 );
272}
273
274void TTCN3Module::generate_TTCN3_modulestart(FILE * file)
275{
276 fprintf(file,
277 "module %s {\n"
278 "\n"
279 "\n"
280 "import from XSD all;\n"
281 "\n"
282 "\n",
283 modulename.c_str()
284 );
285}
286
287void TTCN3Module::generate_TTCN3_import_statements(FILE * file)
288{
289 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next)
290 {
291 if (type->Data->getConstruct() == c_import)
292 {
293 type->Data->printToFile(file);
294 }
295 }
296}
297
298void TTCN3Module::generate_TTCN3_included_types(FILE * file)
299{
300 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next)
301 {
302 if (type->Data->getConstruct() == c_include)
303 {
304 type->Data->printToFile(file);
305 }
306 }
307}
308
309void TTCN3Module::generate_TTCN3_types(FILE * file)
310{
311 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next)
312 {
313 if (type->Data->getConstruct() != c_include && type->Data->getConstruct() != c_import)
314 {
315 type->Data->printToFile(file);
316 }
317 }
318}
319
320void TTCN3Module::generate_with_statement(FILE * file, List<NamespaceType> used_namespaces)
321{
322 if (e_flag_used) return;
323
324 fprintf(file,
325 "with {\n"
326 "encode \"XML\";\n"
327 );
328
329 bool xsi = false;
330
331 for (List<NamespaceType>::iterator usedNS = used_namespaces.begin(); usedNS; usedNS = usedNS->Next)
332 {
333 if (usedNS->Data.uri == "http://www.w3.org/2001/XMLSchema") {
334 xsi = true;
335 continue;
336 }
337 if (usedNS->Data.uri == "NoTargetNamespace") {
338 continue;
339 }
340// XXX this inner loop is either redundant now, or it should be elsewhere.
341// It is quite dodgy to modify(!) namespaces when we are already generating code.
342 for (List<NamespaceType>::iterator usedNS2 = usedNS->Next; usedNS2; usedNS2 = usedNS2->Next)
343 {
344 if (usedNS->Data.uri == usedNS2->Data.uri) {
345 if (usedNS2->Data.prefix.empty())
346 usedNS2->Data.prefix = usedNS->Data.prefix;
347 break;
348 }
349 }
350 }
351
352 if (targetNamespace != "NoTargetNamespace") {
353 fprintf(file, "variant \"namespace as \'%s\'", targetNamespace.c_str());
354 if (!targetNamespace_connectedPrefix.empty())
355 fprintf(file, " prefix \'%s\'", targetNamespace_connectedPrefix.c_str());
356 fprintf(file, "\";\n");
357 }
358
359
360 if (xsi) {
361 fprintf(file,
362 "variant \"controlNamespace \'http://www.w3.org/2001/XMLSchema-instance\' prefix \'xsi\'\";\n");
363 }
364 if (attributeFormDefault == qualified) {
365 fprintf(file,
366 "variant \"attributeFormQualified\";\n");
367 }
368 if (elementFormDefault == qualified) {
369 fprintf(file,
370 "variant \"elementFormQualified\";\n");
371 }
372 fprintf(file,
373 "}\n");
374}
375
376void TTCN3Module::TargetNamespace2ModuleName()
377{
378 Mstring res(targetNamespace);
379
380 if (z_flag_used) {
381 if (res.isFound("http://"))
382 for (int i = 0; i != 7; ++i)
383 res.eraseChar(0);
384 if (res.isFound("urn:"))
385 for (int i = 0; i != 4; ++i)
386 res.eraseChar(0);
387 }
388
389 // the characters ' '(SPACE), '.'(FULL STOP) and '-'(HYPEN-MINUS)
390 // and '/', '#', ':' shall all be replaced by a "_" (LOW LINE)
391 for (size_t i = 0; i != res.size(); ++i) {
392 if ((res[i] == ' ') ||
393 (res[i] == '.') ||
394 (res[i] == '-') ||
395 (res[i] == '/') ||
396 (res[i] == '#') ||
397 (res[i] == ':'))
398 {
399 res[i] = '_';
400 }
401 }
402 // any character except "A" to "Z", "a" to "z" or "0" to "9" and "_" shall be removed
403 for (size_t i = 0; i != res.size(); ++i) {
404 if (!isalpha((const unsigned char)res[i]) && !isdigit((const unsigned char)res[i]) && (res[i] != '_')) {
405 res.eraseChar(i);
406 }
407 }
408 // a sequence of two of more "_" (LOW LINE) shall be replaced with a single "_" (LOW LINE)
409 for (size_t i = 1; i < res.size(); ++i) {
410 while (res[i] == '_' && res[i-1] == '_') {
411 res.eraseChar(i--);
412 }
413 }
414 // "_" (LOW LINE) characters occurring at the beginning of the name shall be removed
415 if (res[0] == '_') res.eraseChar(0);
416 // "_" (LOW LINE) characters occurring at the end of the name shall be removed
417 if (res[res.size()-1] == '_') res.eraseChar(res.size()-1);
418
419 if (res.empty()) {
420 res = "x";
421 }
422 else if (isdigit((const unsigned char)res[0])) {
423 res.insertChar(0, 'x');
424 }
425
426 modulename = res;
427}
428
429void TTCN3Module::dump() const
430{
431 fprintf(stderr, "Module '%s' at %p (from %s)\n",
432 modulename.c_str(), (const void*)this, schemaname.c_str());
433
434 for (List<RootType*>::iterator type = definedTypes.begin(); type; type = type->Next)
435 {
436 type->Data->dump(1);
437 }
438}
This page took 0.039289 seconds and 5 git commands to generate.