Commit | Line | Data |
---|---|---|
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 "GeneralFunctions.hh" | |
9 | #include "SimpleType.hh" | |
10 | #include "TTCN3Module.hh" | |
11 | ||
12 | #include <cctype> // for using "toupper" function | |
13 | #include <cstring> | |
14 | #include <cstdio> | |
15 | #include <cmath> | |
16 | ||
17 | extern bool w_flag_used; | |
18 | ||
19 | // XSDName2TTCN3Name function: | |
20 | // Parameters: | |
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 | |
26 | // | |
27 | void XSDName2TTCN3Name(const Mstring& in, QualifiedNames & used_names, modeType type_of_the_name, | |
28 | Mstring & res, Mstring & variant) | |
29 | { | |
30 | static const char* TTCN3_reserved_words[] = | |
31 | { | |
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", | |
38 | "external", | |
39 | "fail", "false", "float", "for", "friend", "from", "function", | |
40 | "getverdict", "getcall", "getreply", "goto", "group", | |
41 | "halt", "hexstring", | |
42 | "if", "if present", "import", "in", "inconc", "infinity", "inout", "integer", "interleave", | |
43 | "kill", "killed", | |
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", | |
51 | "superset", "system", | |
52 | "template", "testcase", "timeout", "timer", "to", "trigger", "true", "type", | |
53 | "union", "universal", "unmap", | |
54 | "value", "valueof", "var", "variant", "verdicttype", | |
55 | "while", "with", | |
56 | "xor", "xor4b", | |
57 | NULL | |
58 | }; | |
59 | static const char* TTCN3_predefined_functions[] = | |
60 | { | |
61 | "bit2int", "bit2hex", "bit2oct", "bit2str", | |
62 | "char2int", "char2oct", | |
63 | "decomp", "decvalue", | |
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", | |
73 | "testcasename", | |
74 | "unichar2int", "unichar2char", "unichar2oct", | |
75 | NULL | |
76 | }; | |
77 | static const char* ASN1_reserved_words[] = | |
78 | { | |
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", | |
84 | "EXTERNAL", | |
85 | "FALSE", "FROM", | |
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", | |
98 | "WITH", | |
99 | NULL | |
100 | }; | |
101 | ||
102 | Mstring ns_uri(variant); | |
103 | ||
104 | res.clear(); | |
105 | variant.clear(); | |
106 | res = in; | |
107 | ||
108 | if (res.size() > 0) { | |
109 | /******************************************************** | |
110 | * STEP 0 - recognizing XSD built-in types | |
111 | * | |
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) { | |
115 | ||
116 | if (type_of_the_name == type_reference_name) | |
117 | { | |
118 | if (isBuiltInType(res)) { | |
119 | res[0] = toupper(res[0]); | |
120 | res = "XSD." + res; | |
121 | return; | |
122 | } | |
123 | if (res == "record" || | |
124 | res == "union" || | |
125 | res == "set" ) | |
126 | { | |
127 | return; | |
128 | } | |
129 | } | |
130 | ||
131 | if (type_of_the_name == enum_id_name) | |
132 | { | |
133 | bool found = false; | |
134 | for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next) | |
135 | { | |
136 | QualifiedName tmp(empty_string, res); | |
137 | if (tmp == used->Data) { | |
138 | found = true; | |
139 | break; | |
140 | } | |
141 | } | |
142 | if (found) return; | |
143 | } | |
144 | /******************************************************** | |
145 | * STEP 1 - character changes | |
146 | * | |
147 | * according to | |
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] == ' ') || | |
153 | (res[i] == '.') || | |
154 | (res[i] == '-')) | |
155 | { | |
156 | res[i] = '_'; | |
157 | } | |
158 | } | |
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] != '_')) { | |
162 | res.eraseChar(i); | |
163 | } | |
164 | } | |
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] == '_') { | |
168 | res.eraseChar(i--); | |
169 | } | |
170 | } | |
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); | |
175 | } | |
176 | ||
177 | switch (type_of_the_name) | |
178 | { | |
179 | case type_reference_name: | |
180 | case type_name: | |
181 | if (res.empty()) { | |
182 | res = "X"; | |
183 | } | |
184 | else { | |
185 | if (islower((const unsigned char)res[0])) res.setCapitalized(); | |
186 | else if (isdigit((const unsigned char)res[0])) res.insertChar(0, 'X'); | |
187 | } | |
188 | break; | |
189 | case field_name: | |
190 | case enum_id_name: | |
191 | if (res.empty()) { | |
192 | res = "x"; | |
193 | } | |
194 | else { | |
195 | if (isupper((const unsigned char)res[0])) res.setUncapitalized(); | |
196 | else if (isdigit((const unsigned char)res[0])) res.insertChar(0, 'x'); | |
197 | } | |
198 | break; | |
199 | } | |
200 | /******************************************************** | |
201 | * STEP 2 - process if the generated name is | |
202 | * - already used | |
203 | * - a TTCN3 keyword | |
204 | * - an ASN.1 keyword | |
205 | * and after any change is made | |
206 | * according to | |
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); | |
214 | ||
215 | switch (type_of_the_name) | |
216 | { | |
217 | // Do not use "res" in this switch; only qual_name | |
218 | case type_name: { | |
219 | for (int k = 0; ASN1_reserved_words[k]; k++) { | |
220 | if (qual_name.name == ASN1_reserved_words[k]) { | |
221 | postfixing = true; | |
222 | break; | |
223 | } | |
224 | } | |
225 | ||
226 | for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next) | |
227 | { | |
228 | if (qual_name == used->Data) { | |
229 | postfixing = true; | |
230 | break; | |
231 | } | |
232 | } | |
233 | ||
234 | if (postfixing) | |
235 | { | |
236 | bool found = false; | |
237 | int counter = 1; | |
238 | expstring_t tmpname = NULL; | |
239 | do { | |
240 | found = false; | |
241 | Free(tmpname); | |
242 | tmpname = mprintf("%s_%d", qual_name.name.c_str(), counter); | |
243 | for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next) | |
244 | { | |
245 | if (QualifiedName(/* empty_string ? */ ns_uri, Mstring(tmpname)) == used->Data) { | |
246 | found = true; | |
247 | break; | |
248 | } | |
249 | } | |
250 | counter++; | |
251 | } while (found); | |
252 | qual_name.name = tmpname; // NULL will result in an empty string | |
253 | Free(tmpname); | |
254 | postfixing = false; | |
255 | } | |
256 | break; } | |
257 | case field_name: | |
258 | case enum_id_name: | |
259 | for (int k = 0; TTCN3_reserved_words[k]; k++) { | |
260 | if (qual_name.name == TTCN3_reserved_words[k]) postfixing = true; | |
261 | } | |
262 | for (int k = 0; TTCN3_predefined_functions[k]; k++) { | |
263 | if (qual_name.name == TTCN3_predefined_functions[k]) postfixing = true; | |
264 | } | |
265 | if (postfixing) | |
266 | { | |
267 | qual_name.name += "_"; | |
268 | postfixing = false; | |
269 | } | |
270 | ||
271 | for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next) | |
272 | { | |
273 | if (qual_name == used->Data) postfixing = true; | |
274 | } | |
275 | ||
276 | if (postfixing) | |
277 | { | |
278 | bool found = false; | |
279 | int counter = 0; | |
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); | |
285 | do { | |
286 | found = false; | |
287 | if (counter > 0) { | |
288 | Free(tmpname); | |
289 | tmpname = mprintf("%s_%d", qual_name.name.c_str(), counter); | |
290 | } | |
291 | for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next) | |
292 | { | |
293 | if (QualifiedName(/* empty_string ? */ns_uri, Mstring(tmpname)) == used->Data) { | |
294 | found = true; | |
295 | break; | |
296 | } | |
297 | } | |
298 | counter++; | |
299 | } while (found); | |
300 | qual_name.name = tmpname; | |
301 | Free(tmpname); | |
302 | postfixing = false; | |
303 | } | |
304 | break; | |
305 | default: | |
306 | break; | |
307 | } | |
308 | ||
309 | res = qual_name.name; | |
310 | ||
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) | |
316 | { | |
317 | bool found = false; | |
318 | for (QualifiedNames::iterator used = used_names.begin(); used; used = used->Next) | |
319 | { | |
320 | if (qual_name == used->Data) { | |
321 | found = true; | |
322 | break; | |
323 | } | |
324 | } | |
325 | ||
326 | if (!found) { | |
327 | used_names.push_back(qual_name); | |
328 | } | |
329 | } | |
330 | /******************************************************** | |
331 | * STEP 4 | |
332 | * | |
333 | * ******************************************************/ | |
334 | if (in == "sequence" || | |
335 | in == "choice" || | |
336 | in == "sequence_list" || | |
337 | in == "choice_list") | |
338 | { | |
339 | return; | |
340 | } | |
341 | /******************************************************** | |
342 | * STEP 5 - if "input name - in" and "generated name - res" | |
343 | * are different | |
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 ... | |
347 | if (in != res) { | |
348 | Mstring tmp1 = in; | |
349 | Mstring tmp2 = res; | |
350 | tmp1.setUncapitalized(); | |
351 | tmp2.setUncapitalized(); | |
352 | switch (type_of_the_name) | |
353 | { | |
354 | case type_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 + "'\""; | |
360 | } | |
361 | break; | |
362 | case field_name: | |
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 + "'\""; | |
369 | } | |
370 | break; | |
371 | case enum_id_name: | |
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\""; | |
375 | } else { | |
376 | variant += "\"text \'" + res + "\' as uncapitalized\""; | |
377 | } | |
378 | } else { // Otherwise if other letters have changed too | |
379 | variant += "\"text \'" + res + "\' as '" + in + "'\""; | |
380 | } | |
381 | break; | |
382 | default: | |
383 | break; | |
384 | } | |
385 | } | |
386 | } | |
387 | ||
388 | bool isBuiltInType(const Mstring& in) | |
389 | { | |
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 | |
397 | }; | |
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; | |
401 | } | |
402 | return false; | |
403 | } | |
404 | ||
405 | bool isStringType(const Mstring& in) | |
406 | { | |
407 | static const char* string_types[] = { | |
408 | "string", "normalizedString", "token", "Name", "NMTOKEN", "NCName", "ID", "IDREF", "ENTITY", | |
409 | "hexBinary", "base64Binary", "anyURI", "language", NULL | |
410 | }; | |
411 | const Mstring& name = in.getValueWithoutPrefix(':'); | |
412 | for (int i = 0; string_types[i]; ++i) { | |
413 | if (name == string_types[i]) return true; | |
414 | } | |
415 | return false; | |
416 | } | |
417 | ||
418 | bool isIntegerType(const Mstring& in) | |
419 | { | |
420 | static const char* integer_types[] = { | |
421 | "integer", "positiveInteger", "nonPositiveInteger", "negativeInteger", "nonNegativeInteger", "long", | |
422 | "unsignedLong", "int", "unsignedInt", "short", "unsignedShort", "byte", "unsignedByte", NULL | |
423 | }; | |
424 | const Mstring& name = in.getValueWithoutPrefix(':'); | |
425 | for (int i = 0; integer_types[i]; ++i) { | |
426 | if (name == integer_types[i]) return true; | |
427 | } | |
428 | return false; | |
429 | } | |
430 | ||
431 | bool isFloatType(const Mstring& in) | |
432 | { | |
433 | static const char* float_types[] = { | |
434 | "decimal", "float", "double", NULL | |
435 | }; | |
436 | const Mstring& name = in.getValueWithoutPrefix(':'); | |
437 | for (int i = 0; float_types[i]; ++i) { | |
438 | if (name == float_types[i]) return true; | |
439 | } | |
440 | return false; | |
441 | } | |
442 | ||
443 | bool isTimeType(const Mstring& in) | |
444 | { | |
445 | static const char* time_types[] = { | |
446 | "duration", "dateTime", "time", "date", "gYearMonth", "gYear", "gMonthDay", "gDay", "gMonth", NULL | |
447 | }; | |
448 | const Mstring& name = in.getValueWithoutPrefix(':'); | |
449 | for (int i = 0; time_types[i]; ++i) { | |
450 | if (name == time_types[i]) return true; | |
451 | } | |
452 | return false; | |
453 | } | |
454 | ||
455 | bool isSequenceType(const Mstring& in) | |
456 | { | |
457 | static const char* sequence_types[] = { | |
458 | "NMTOKENS", "IDREFS", "ENTITIES", "QName", NULL | |
459 | }; | |
460 | const Mstring& name = in.getValueWithoutPrefix(':'); | |
461 | for (int i = 0; sequence_types[i]; ++i) { | |
462 | if (name == sequence_types[i]) return true; | |
463 | } | |
464 | return false; | |
465 | } | |
466 | ||
467 | bool isBooleanType(const Mstring& in) | |
468 | { | |
469 | static const Mstring booltype("boolean"); | |
470 | return booltype == in.getValueWithoutPrefix(':'); | |
471 | } | |
472 | ||
473 | bool isQNameType(const Mstring& in) | |
474 | { | |
475 | static const Mstring qntype("QName"); | |
476 | return qntype == in.getValueWithoutPrefix(':'); | |
477 | } | |
478 | ||
479 | bool isAnyType(const Mstring& in) | |
480 | { | |
481 | static const char* any_types[] = { | |
482 | "anyType", "anySimpleType", NULL | |
483 | }; | |
484 | const Mstring& name = in.getValueWithoutPrefix(':'); | |
485 | for (int i = 0; any_types[i]; ++i) { | |
486 | if (name == any_types[i]) return true; | |
487 | } | |
488 | return false; | |
489 | } | |
490 | ||
491 | void printError(const Mstring& filename, int lineNumber, const Mstring& text) | |
492 | { | |
493 | fprintf(stderr, | |
494 | "ERROR:\n" | |
495 | "%s (in line %d): " | |
496 | "%s\n", | |
497 | filename.c_str(), | |
498 | lineNumber, | |
499 | text.c_str()); | |
500 | } | |
501 | ||
502 | void printError(const Mstring& filename, const Mstring& typeName, const Mstring& text) | |
503 | { | |
504 | fprintf(stderr, | |
505 | "ERROR:\n" | |
506 | "%s (in type %s): " | |
507 | "%s\n", | |
508 | filename.c_str(), | |
509 | typeName.c_str(), | |
510 | text.c_str()); | |
511 | } | |
512 | ||
513 | void printWarning(const Mstring& filename, int lineNumber, const Mstring& text) | |
514 | { | |
515 | if (w_flag_used) return; | |
516 | fprintf(stderr, | |
517 | "WARNING:\n" | |
518 | "%s (in line %d): " | |
519 | "%s\n", | |
520 | filename.c_str(), | |
521 | lineNumber, | |
522 | text.c_str()); | |
523 | } | |
524 | ||
525 | void printWarning(const Mstring& filename, const Mstring& typeName, const Mstring& text) | |
526 | { | |
527 | if (w_flag_used) return; | |
528 | fprintf(stderr, | |
529 | "WARNING:\n" | |
530 | "%s (in type %s): " | |
531 | "%s\n", | |
532 | filename.c_str(), | |
533 | typeName.c_str(), | |
534 | text.c_str()); | |
535 | } | |
536 | ||
537 | long double stringToLongDouble(const char *input) | |
538 | { | |
539 | long double result = 0.0; | |
540 | // `strtold()' is not available on older platforms. | |
541 | sscanf(input, "%Lf", &result); | |
542 | return result; | |
543 | } | |
544 | ||
545 | Mstring truncatePathWithOneElement(const Mstring& path) | |
546 | { | |
547 | Mstring result; | |
548 | size_t pathlen = path.size(); | |
549 | if (pathlen > 1) { | |
550 | expstring_t temp = mcopystr(path.c_str()); // modifiable copy | |
551 | temp[pathlen - 1] = '\0'; // ignore last character | |
552 | char * point = strrchr(temp, '.'); | |
553 | if (point != NULL) { | |
554 | point[1] = '\0'; // truncate just past the dot | |
555 | result = Mstring(temp); | |
556 | } | |
557 | Free(temp); | |
558 | } | |
559 | return result; | |
560 | } | |
561 | ||
562 | RootType * lookup (const List<TTCN3Module*> mods, const SimpleType * reference, wanted w) | |
563 | { | |
564 | const Mstring& uri = reference->getReference().get_uri(); | |
565 | const Mstring& name = reference->getReference().get_val(); | |
566 | ||
567 | return lookup(mods, name, uri, reference, w); | |
568 | } | |
569 | ||
570 | RootType * lookup (const List<TTCN3Module*> mods, | |
571 | const Mstring& name, const Mstring& nsuri, const RootType *reference, wanted w) | |
572 | { | |
573 | RootType *ret = NULL; | |
574 | for (List<TTCN3Module*>::iterator module = mods.begin(); module; module = module->Next) | |
575 | { | |
576 | ret = lookup1(module->Data, name, nsuri, reference, w); | |
577 | if (ret != NULL) break; | |
578 | } // next doc | |
579 | ||
580 | return ret; | |
581 | } | |
582 | ||
583 | RootType *lookup1(const TTCN3Module *module, | |
584 | const Mstring& name, const Mstring& nsuri, const RootType *reference, wanted w) | |
585 | { | |
586 | if (nsuri != module->getTargetNamespace()) return NULL; | |
587 | ||
588 | for (List<RootType*>::iterator type = module->getDefinedTypes().begin(); type; type = type->Next) | |
589 | { | |
590 | switch (type->Data->getConstruct()) | |
591 | { | |
592 | case c_simpleType: | |
593 | case c_element: | |
594 | case c_attribute: | |
595 | if (w == want_ST) { | |
596 | if ((const RootType*)reference != type->Data | |
597 | && name == type->Data->getName().convertedValue) { | |
598 | return type->Data; | |
599 | } | |
600 | } | |
601 | break; | |
602 | ||
603 | case c_complexType: | |
604 | case c_group: | |
605 | case c_attributeGroup: | |
606 | if (w == want_CT) { | |
607 | if ((const RootType*)reference != type->Data | |
608 | && name == type->Data->getName().convertedValue) { | |
609 | return type->Data; | |
610 | } | |
611 | } | |
612 | break; | |
613 | ||
614 | default: | |
615 | break; | |
616 | } | |
617 | } | |
618 | ||
619 | return NULL; | |
620 | } | |
621 | ||
622 | int multi(const TTCN3Module *module, ReferenceData const& outside_reference, | |
623 | const RootType *obj) | |
624 | { | |
625 | int multiplicity = 0; | |
626 | ||
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); | |
629 | if (st || ct) { | |
630 | multiplicity = 1; // locally defined, no qualif needed | |
631 | } | |
632 | else for (List<const TTCN3Module*>::iterator it = module->getImportedModules().begin(); it; it = it->Next) { | |
633 | // Artificial lookup | |
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); | |
636 | if (st || ct) { | |
637 | ++multiplicity; | |
638 | } | |
639 | } | |
640 | return multiplicity; | |
641 | } | |
642 |