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 "GeneralFunctions.hh"
9 #include "SimpleType.hh"
10 #include "TTCN3Module.hh"
12 #include <cctype> // for using "toupper" function
17 extern bool w_flag_used
;
19 // XSDName2TTCN3Name function:
21 // in - input string - XSD name
22 // used_names - set of previously defined types, used field names etc.
23 // type_of_the_name - mode of the function behaviour
24 // res - generated result
25 // variant - generated variant string for TTCN-3
27 void XSDName2TTCN3Name(const Mstring
& in
, QualifiedNames
& used_names
, modeType type_of_the_name
,
28 Mstring
& res
, Mstring
& variant
)
30 static const char* TTCN3_reserved_words
[] =
32 "action", "activate", "address", "alive", "all", "alt", "altstep", "and", "and4b", "any", "anytype", "apply",
33 "bitstring", "boolean", "break",
34 "call", "case", "catch", "char", "charstring", "check", "clear", "complement", "component", "connect",
35 "const", "continue", "control", "create",
36 "deactivate", "default", "derefers", "disconnect", "display", "do", "done",
37 "else", "encode", "enumerated", "error", "except", "exception", "execute", "extends", "extension",
39 "fail", "false", "float", "for", "friend", "from", "function",
40 "getverdict", "getcall", "getreply", "goto", "group",
42 "if", "if present", "import", "in", "inconc", "infinity", "inout", "integer", "interleave",
44 "label", "language", "length", "log",
45 "map", "match", "message", "mixed", "mod", "modifies", "module", "modulepar", "mtc",
46 "noblock", "none", "not", "not4b", "nowait", "null",
47 "objid", "octetstring", "of", "omit", "on", "optional", "or", "or4b", "out", "override",
48 "param", "pass", "pattern", "permutation", "port", "present", "private", "procedure", "public",
49 "raise", "read", "receive", "record", "recursive", "refers", "rem", "repeat", "reply", "return", "running", "runs",
50 "select", "self", "send", "sender", "set", "setverdict", "signature", "start", "stop", "subset",
52 "template", "testcase", "timeout", "timer", "to", "trigger", "true", "type",
53 "union", "universal", "unmap",
54 "value", "valueof", "var", "variant", "verdicttype",
59 static const char* TTCN3_predefined_functions
[] =
61 "bit2int", "bit2hex", "bit2oct", "bit2str",
62 "char2int", "char2oct",
64 "encvalue", "enum2int",
65 "float2int", "float2str",
66 "hex2bit", "hex2int", "hex2oct", "hex2str",
67 "int2bit", "int2char", "int2float", "int2hex", "int2oct", "int2str", "int2unichar",
68 "isvalue", "ischosen", "ispresent",
69 "lengthof", "log2str",
70 "oct2bit", "oct2char", "oct2hex", "oct2int", "oct2str", "oct2unichar"
71 "regexp", "replace", "rnd", "remove_bom", "get_stringencoding",
72 "sizeof", "str2bit", "str2float", "str2hex", "str2int", "str2oct", "substr",
74 "unichar2int", "unichar2char", "unichar2oct",
77 static const char* ASN1_reserved_words
[] =
79 "ABSENT", "ABSTRACT-SYNTAX", "ALL", "APPLICATION", "AUTOMATIC",
80 "BEGIN", "BIT", "BMPString", "BOOLEAN", "BY",
81 "CHARACTER", "CHOICE", "CLASS", "COMPONENT", "COMPONENTS", "CONSTRAINED", "CONTAINING",
82 "DEFAULT", "DEFINITIONS",
83 "EMBEDDED", "ENCODED", "END", "ENUMERATED", "EXCEPT", "EXPLICIT", "EXPORTS", "EXTENSIBILITY",
86 "GeneralizedTime", "GeneralString", "GraphicString",
87 "IA5String", "IDENTIFIER", "IMPLICIT", "IMPLIED", "IMPORTS", "INCLUDES", "INSTANCE", "INTEGER",
88 "INTERSECTION", "ISO646String",
89 "MAX", "MIN", "MINUS-INFINITY",
90 "NULL", "NumericString",
91 "OBJECT", "ObjectDescriptor", "OCTET", "OF", "OPTIONAL",
92 "PATTERN", "PDV", "PLUS-INFINITY", "PRESENT", "PrintableString", "PRIVATE",
93 "REAL", "RELATIVE-OID",
94 "SEQUENCE", "SET", "SIZE", "STRING", "SYNTAX",
95 "T61String", "TAGS", "TeletexString", "TRUE", "TYPE-IDENTIFIER",
96 "UNION", "UNIQUE", "UNIVERSAL", "UniversalString", "UTCTime", "UTF8String",
97 "VideotexString", "VisibleString",
102 Mstring
ns_uri(variant
);
108 if (res
.size() > 0) {
109 /********************************************************
110 * STEP 0 - recognizing XSD built-in types
112 * ******************************************************/
113 // If the type or field reference name is an XSD built-in type then it will be capitalized and get a prefix "XSD."
114 // if (type_of_the_name == type_reference_name || type_of_the_name == field_reference_name) {
116 if (type_of_the_name
== type_reference_name
)
118 if (isBuiltInType(res
)) {
119 res
[0] = toupper(res
[0]);
123 if (res
== "record" ||
131 if (type_of_the_name
== enum_id_name
)
134 for (QualifiedNames::iterator used
= used_names
.begin(); used
; used
= used
->Next
)
136 QualifiedName
tmp(empty_string
, res
);
137 if (tmp
== used
->Data
) {
144 /********************************************************
145 * STEP 1 - character changes
148 * clause 5.2.2.1 - Generic name transformation rules
149 * ******************************************************/
150 // the characters ' '(SPACE), '.'(FULL STOP) and '-'(HYPEN-MINUS)shall all be replaced by a "_" (LOW LINE)
151 for (size_t i
= 0; i
!= res
.size(); ++i
) {
152 if ((res
[i
] == ' ') ||
159 // any character except "A" to "Z", "a" to "z" or "0" to "9" and "_" shall be removed
160 for (size_t i
= 0; i
!= res
.size(); ++i
) {
161 if (!isalpha((const unsigned char)res
[i
]) && !isdigit((const unsigned char)res
[i
]) && (res
[i
] != '_')) {
165 // a sequence of two of more "_" (LOW LINE) shall be replaced with a single "_" (LOW LINE)
166 for (size_t i
= 1; i
< res
.size(); ++i
) {
167 if (res
[i
] == '_' && res
[i
-1] == '_') {
171 // "_" (LOW LINE) characters occurring at the end of the name shall be removed
172 if (!res
.empty() && res
[res
.size()-1] == '_') res
.eraseChar(res
.size()-1);
173 // "_" (LOW LINE) characters occurring at the beginning of the name shall be removed
174 if (!res
.empty() && res
[0] == '_') res
.eraseChar(0);
177 switch (type_of_the_name
)
179 case type_reference_name
:
185 if (islower((const unsigned char)res
[0])) res
.setCapitalized();
186 else if (isdigit((const unsigned char)res
[0])) res
.insertChar(0, 'X');
195 if (isupper((const unsigned char)res
[0])) res
.setUncapitalized();
196 else if (isdigit((const unsigned char)res
[0])) res
.insertChar(0, 'x');
200 /********************************************************
201 * STEP 2 - process if the generated name is
205 * and after any change is made
207 * clause 5.2.2.2 - Succeeding rules
208 * ******************************************************/
209 /********************************************************
210 * according to paragraph a)
211 * ******************************************************/
212 bool postfixing
= false;
213 QualifiedName
qual_name(ns_uri
, res
);
215 switch (type_of_the_name
)
217 // Do not use "res" in this switch; only qual_name
219 for (int k
= 0; ASN1_reserved_words
[k
]; k
++) {
220 if (qual_name
.name
== ASN1_reserved_words
[k
]) {
226 for (QualifiedNames::iterator used
= used_names
.begin(); used
; used
= used
->Next
)
228 if (qual_name
== used
->Data
) {
238 expstring_t tmpname
= NULL
;
242 tmpname
= mprintf("%s_%d", qual_name
.name
.c_str(), counter
);
243 for (QualifiedNames::iterator used
= used_names
.begin(); used
; used
= used
->Next
)
245 if (QualifiedName(/* empty_string ? */ ns_uri
, Mstring(tmpname
)) == used
->Data
) {
252 qual_name
.name
= tmpname
; // NULL will result in an empty string
259 for (int k
= 0; TTCN3_reserved_words
[k
]; k
++) {
260 if (qual_name
.name
== TTCN3_reserved_words
[k
]) postfixing
= true;
262 for (int k
= 0; TTCN3_predefined_functions
[k
]; k
++) {
263 if (qual_name
.name
== TTCN3_predefined_functions
[k
]) postfixing
= true;
267 qual_name
.name
+= "_";
271 for (QualifiedNames::iterator used
= used_names
.begin(); used
; used
= used
->Next
)
273 if (qual_name
== used
->Data
) postfixing
= true;
280 if (type_of_the_name
== field_name
) counter
= 1;
281 else if (type_of_the_name
== enum_id_name
) counter
= 0;
282 if (qual_name
.name
[qual_name
.name
.size()-1] == '_')
283 qual_name
.name
.eraseChar(qual_name
.name
.size()-1);
284 expstring_t tmpname
= mprintf("%s_%d", qual_name
.name
.c_str(), counter
);
289 tmpname
= mprintf("%s_%d", qual_name
.name
.c_str(), counter
);
291 for (QualifiedNames::iterator used
= used_names
.begin(); used
; used
= used
->Next
)
293 if (QualifiedName(/* empty_string ? */ns_uri
, Mstring(tmpname
)) == used
->Data
) {
300 qual_name
.name
= tmpname
;
309 res
= qual_name
.name
;
311 /********************************************************
312 * STEP 3 - the defined name is put into the set of "not_av_names"
313 * ******************************************************/
314 // Finally recently defined name will be put into the set of "set<string> not_av_names"
315 if (type_of_the_name
!= type_reference_name
)
318 for (QualifiedNames::iterator used
= used_names
.begin(); used
; used
= used
->Next
)
320 if (qual_name
== used
->Data
) {
327 used_names
.push_back(qual_name
);
330 /********************************************************
333 * ******************************************************/
334 if (in
== "sequence" ||
336 in
== "sequence_list" ||
341 /********************************************************
342 * STEP 5 - if "input name - in" and "generated name - res"
344 * then a "variant string" has to be generated
345 * ******************************************************/
346 // If the final generated type name, field name or enumeration identifier (res) is different from the original one (in) then ...
350 tmp1
.setUncapitalized();
351 tmp2
.setUncapitalized();
352 switch (type_of_the_name
)
355 if (tmp1
== tmp2
) { // If the only difference is the case of the first letter
356 if (isupper(in
[0])) variant
+= "\"name as capitalized\"";
357 else variant
+= "\"name as uncapitalized\"";
358 } else { // Otherwise if other letters have changed too
359 variant
+= "\"name as '" + in
+ "'\"";
363 // Creating a variant string from a field of a complex type needs to write out the path of the fieldname
364 if (tmp1
== tmp2
) { // If the only difference is the case of the first letter
365 if (isupper(in
[0])) variant
+= "\"name as capitalized\"";
366 else variant
+= "\"name as uncapitalized\"";
367 } else { // Otherwise if other letters have changed too
368 variant
+= "\"name as '" + in
+ "'\"";
372 if (tmp1
== tmp2
) { // If the only difference is the case of the first letter
373 if ( isupper(in
[0]) ) {
374 variant
+= "\"text \'" + res
+ "\' as capitalized\"";
376 variant
+= "\"text \'" + res
+ "\' as uncapitalized\"";
378 } else { // Otherwise if other letters have changed too
379 variant
+= "\"text \'" + res
+ "\' as '" + in
+ "'\"";
388 bool isBuiltInType(const Mstring
& in
)
390 static const char* XSD_built_in_types
[] = {
391 "string", "normalizedString", "token", "Name", "NMTOKEN", "NCName", "ID", "IDREF", "ENTITY",
392 "hexBinary", "base64Binary", "anyURI", "language", "integer", "positiveInteger", "nonPositiveInteger",
393 "negativeInteger", "nonNegativeInteger", "long", "unsignedLong", "int", "unsignedInt", "short",
394 "unsignedShort", "byte", "unsignedByte", "decimal", "float", "double", "duration", "dateTime", "time",
395 "date", "gYearMonth", "gYear", "gMonthDay", "gDay", "gMonth", "NMTOKENS", "IDREFS", "ENTITIES",
396 "QName", "boolean", "anyType", "anySimpleType", NULL
398 const Mstring
& name
= in
.getValueWithoutPrefix(':');
399 for (int i
= 0; XSD_built_in_types
[i
]; ++i
) {
400 if (name
== XSD_built_in_types
[i
]) return true;
405 bool isStringType(const Mstring
& in
)
407 static const char* string_types
[] = {
408 "string", "normalizedString", "token", "Name", "NMTOKEN", "NCName", "ID", "IDREF", "ENTITY",
409 "hexBinary", "base64Binary", "anyURI", "language", NULL
411 const Mstring
& name
= in
.getValueWithoutPrefix(':');
412 for (int i
= 0; string_types
[i
]; ++i
) {
413 if (name
== string_types
[i
]) return true;
418 bool isIntegerType(const Mstring
& in
)
420 static const char* integer_types
[] = {
421 "integer", "positiveInteger", "nonPositiveInteger", "negativeInteger", "nonNegativeInteger", "long",
422 "unsignedLong", "int", "unsignedInt", "short", "unsignedShort", "byte", "unsignedByte", NULL
424 const Mstring
& name
= in
.getValueWithoutPrefix(':');
425 for (int i
= 0; integer_types
[i
]; ++i
) {
426 if (name
== integer_types
[i
]) return true;
431 bool isFloatType(const Mstring
& in
)
433 static const char* float_types
[] = {
434 "decimal", "float", "double", NULL
436 const Mstring
& name
= in
.getValueWithoutPrefix(':');
437 for (int i
= 0; float_types
[i
]; ++i
) {
438 if (name
== float_types
[i
]) return true;
443 bool isTimeType(const Mstring
& in
)
445 static const char* time_types
[] = {
446 "duration", "dateTime", "time", "date", "gYearMonth", "gYear", "gMonthDay", "gDay", "gMonth", NULL
448 const Mstring
& name
= in
.getValueWithoutPrefix(':');
449 for (int i
= 0; time_types
[i
]; ++i
) {
450 if (name
== time_types
[i
]) return true;
455 bool isSequenceType(const Mstring
& in
)
457 static const char* sequence_types
[] = {
458 "NMTOKENS", "IDREFS", "ENTITIES", "QName", NULL
460 const Mstring
& name
= in
.getValueWithoutPrefix(':');
461 for (int i
= 0; sequence_types
[i
]; ++i
) {
462 if (name
== sequence_types
[i
]) return true;
467 bool isBooleanType(const Mstring
& in
)
469 static const Mstring
booltype("boolean");
470 return booltype
== in
.getValueWithoutPrefix(':');
473 bool isQNameType(const Mstring
& in
)
475 static const Mstring
qntype("QName");
476 return qntype
== in
.getValueWithoutPrefix(':');
479 bool isAnyType(const Mstring
& in
)
481 static const char* any_types
[] = {
482 "anyType", "anySimpleType", NULL
484 const Mstring
& name
= in
.getValueWithoutPrefix(':');
485 for (int i
= 0; any_types
[i
]; ++i
) {
486 if (name
== any_types
[i
]) return true;
491 void printError(const Mstring
& filename
, int lineNumber
, const Mstring
& text
)
502 void printError(const Mstring
& filename
, const Mstring
& typeName
, const Mstring
& text
)
513 void printWarning(const Mstring
& filename
, int lineNumber
, const Mstring
& text
)
515 if (w_flag_used
) return;
525 void printWarning(const Mstring
& filename
, const Mstring
& typeName
, const Mstring
& text
)
527 if (w_flag_used
) return;
537 long double stringToLongDouble(const char *input
)
539 long double result
= 0.0;
540 // `strtold()' is not available on older platforms.
541 sscanf(input
, "%Lf", &result
);
545 Mstring
truncatePathWithOneElement(const Mstring
& path
)
548 size_t pathlen
= path
.size();
550 expstring_t temp
= mcopystr(path
.c_str()); // modifiable copy
551 temp
[pathlen
- 1] = '\0'; // ignore last character
552 char * point
= strrchr(temp
, '.');
554 point
[1] = '\0'; // truncate just past the dot
555 result
= Mstring(temp
);
562 RootType
* lookup (const List
<TTCN3Module
*> mods
, const SimpleType
* reference
, wanted w
)
564 const Mstring
& uri
= reference
->getReference().get_uri();
565 const Mstring
& name
= reference
->getReference().get_val();
567 return lookup(mods
, name
, uri
, reference
, w
);
570 RootType
* lookup (const List
<TTCN3Module
*> mods
,
571 const Mstring
& name
, const Mstring
& nsuri
, const RootType
*reference
, wanted w
)
573 RootType
*ret
= NULL
;
574 for (List
<TTCN3Module
*>::iterator module
= mods
.begin(); module
; module
= module
->Next
)
576 ret
= lookup1(module
->Data
, name
, nsuri
, reference
, w
);
577 if (ret
!= NULL
) break;
583 RootType
*lookup1(const TTCN3Module
*module
,
584 const Mstring
& name
, const Mstring
& nsuri
, const RootType
*reference
, wanted w
)
586 if (nsuri
!= module
->getTargetNamespace()) return NULL
;
588 for (List
<RootType
*>::iterator type
= module
->getDefinedTypes().begin(); type
; type
= type
->Next
)
590 switch (type
->Data
->getConstruct())
596 if ((const RootType
*)reference
!= type
->Data
597 && name
== type
->Data
->getName().convertedValue
) {
605 case c_attributeGroup
:
607 if ((const RootType
*)reference
!= type
->Data
608 && name
== type
->Data
->getName().convertedValue
) {
622 int multi(const TTCN3Module
*module
, ReferenceData
const& outside_reference
,
625 int multiplicity
= 0;
627 RootType
* st
= ::lookup1(module
, outside_reference
.get_val(), outside_reference
.get_uri(), obj
, want_ST
);
628 RootType
* ct
= ::lookup1(module
, outside_reference
.get_val(), outside_reference
.get_uri(), obj
, want_CT
);
630 multiplicity
= 1; // locally defined, no qualif needed
632 else for (List
<const TTCN3Module
*>::iterator it
= module
->getImportedModules().begin(); it
; it
= it
->Next
) {
634 st
= ::lookup1(it
->Data
, outside_reference
.get_val(), it
->Data
->getTargetNamespace(), obj
, want_ST
);
635 ct
= ::lookup1(it
->Data
, outside_reference
.get_val(), it
->Data
->getTargetNamespace(), obj
, want_CT
);