| 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 "../common/memory.h" |
| 9 | #include "datatypes.h" |
| 10 | #include "enum.h" |
| 11 | #include "encdec.h" |
| 12 | |
| 13 | #include <stdlib.h> |
| 14 | |
| 15 | #include "main.hh" |
| 16 | #include "ttcn3/compiler.h" |
| 17 | |
| 18 | void defEnumClass(const enum_def *edef, output_struct *output) |
| 19 | { |
| 20 | size_t i; |
| 21 | char *def = NULL, *src = NULL; |
| 22 | const char *name = edef->name, *dispname = edef->dispname; |
| 23 | boolean ber_needed = edef->isASN1 && enable_ber(); |
| 24 | boolean raw_needed = edef->hasRaw && enable_raw(); |
| 25 | boolean text_needed= edef->hasText && enable_text(); |
| 26 | boolean xer_needed = edef->hasXer && enable_xer(); |
| 27 | boolean json_needed = edef->hasJson && enable_json(); |
| 28 | |
| 29 | char *enum_type, *qualified_enum_type, *unknown_value, *unbound_value; |
| 30 | enum_type = mcopystr("enum_type"); |
| 31 | qualified_enum_type = mprintf("%s::enum_type", name); |
| 32 | unknown_value = mcopystr("UNKNOWN_VALUE"); |
| 33 | unbound_value = mcopystr("UNBOUND_VALUE"); |
| 34 | |
| 35 | /* Class declaration */ |
| 36 | output->header.class_decls = mputprintf(output->header.class_decls, |
| 37 | "class %s;\n", name); |
| 38 | |
| 39 | /* Class definition */ |
| 40 | def = mputprintf(def, |
| 41 | #ifndef NDEBUG |
| 42 | "// written by %s in " __FILE__ " at %d\n" |
| 43 | #endif |
| 44 | "class %s : public %s { // enum\n" |
| 45 | "friend class %s_template;\n" |
| 46 | #ifndef NDEBUG |
| 47 | , __FUNCTION__, __LINE__ |
| 48 | #endif |
| 49 | , name, (use_runtime_2) ? "Enum_Type" : "Base_Type", name); |
| 50 | def = mputstr(def, "public:\n" |
| 51 | "enum enum_type { "); |
| 52 | for (i = 0; i < edef->nElements; i++) { |
| 53 | def = mputprintf(def, "%s = %d, ", edef->elements[i].name, |
| 54 | edef->elements[i].value); |
| 55 | } |
| 56 | def = mputprintf(def, "UNKNOWN_VALUE = %d, UNBOUND_VALUE = %d };\n" |
| 57 | "private:\n", edef->firstUnused, edef->secondUnused); |
| 58 | def = mputprintf(def, "%s enum_value;\n\n" |
| 59 | "public:\n", enum_type); |
| 60 | |
| 61 | /* constructors */ |
| 62 | def = mputprintf(def, "%s();\n", name); |
| 63 | src = mputprintf(src, "%s::%s()\n" |
| 64 | "{\n" |
| 65 | "enum_value = %s;\n" |
| 66 | "}\n\n", name, name, unbound_value); |
| 67 | |
| 68 | def = mputprintf(def, "%s(int other_value);\n", name); |
| 69 | src = mputprintf(src, |
| 70 | "%s::%s(int other_value)\n" |
| 71 | "{\n" |
| 72 | "if (!is_valid_enum(other_value)) " |
| 73 | "TTCN_error(\"Initializing a variable of enumerated type %s with " |
| 74 | "invalid numeric value %%d.\", other_value);\n" |
| 75 | "enum_value = (%s)other_value;\n" |
| 76 | "}\n\n", |
| 77 | name, name, dispname, enum_type); |
| 78 | |
| 79 | def = mputprintf(def, "%s(%s other_value);\n", name, enum_type); |
| 80 | src = mputprintf(src, |
| 81 | "%s::%s(%s other_value)\n" |
| 82 | "{\n" |
| 83 | "enum_value = other_value;\n" |
| 84 | "}\n\n", name, name, enum_type); |
| 85 | |
| 86 | def = mputprintf(def, "%s(const %s& other_value);\n\n", name, name); |
| 87 | src = mputprintf |
| 88 | (src, |
| 89 | "%s::%s(const %s& other_value)\n" |
| 90 | ": %s()\n" /* Base class DEFAULT constructor*/ |
| 91 | "{\n" |
| 92 | "if (other_value.enum_value == %s) " |
| 93 | "TTCN_error(\"Copying an unbound value of enumerated type %s.\");\n" |
| 94 | "enum_value = other_value.enum_value;\n" |
| 95 | "}\n\n", name, name, name, (use_runtime_2) ? "Enum_Type" : "Base_Type", |
| 96 | unbound_value, dispname); |
| 97 | |
| 98 | /* assignment operators */ |
| 99 | def = mputprintf(def, "%s& operator=(int other_value);\n", name); |
| 100 | src = mputprintf(src, |
| 101 | "%s& %s::operator=(int other_value)\n" |
| 102 | "{\n" |
| 103 | "if (!is_valid_enum(other_value)) " |
| 104 | "TTCN_error(\"Assigning unknown numeric value %%d to a variable " |
| 105 | "of enumerated type %s.\", other_value);\n" |
| 106 | "enum_value = (%s)other_value;\n" |
| 107 | "return *this;\n" |
| 108 | "}\n\n", name, name, dispname, enum_type); |
| 109 | |
| 110 | def = mputprintf(def, "%s& operator=(%s other_value);\n", name, enum_type); |
| 111 | src = mputprintf(src, |
| 112 | "%s& %s::operator=(%s other_value)\n" |
| 113 | "{\n" |
| 114 | "enum_value = other_value;\n" |
| 115 | "return *this;\n" |
| 116 | "}\n\n", name, name, enum_type); |
| 117 | |
| 118 | def = mputprintf(def, "%s& operator=(const %s& other_value);\n\n", name, |
| 119 | name); |
| 120 | src = mputprintf(src, |
| 121 | "%s& %s::operator=(const %s& other_value)\n" |
| 122 | "{\n" |
| 123 | "if (other_value.enum_value == %s) " |
| 124 | "TTCN_error(\"Assignment of an unbound value of enumerated type %s.\");\n" |
| 125 | "enum_value = other_value.enum_value;\n" |
| 126 | "return *this;\n" |
| 127 | "}\n\n", name, name, name, unbound_value, dispname); |
| 128 | |
| 129 | /* Comparison operators */ |
| 130 | def = mputprintf(def, "boolean operator==(%s other_value) const;\n", |
| 131 | enum_type); |
| 132 | src = mputprintf(src, |
| 133 | "boolean %s::operator==(%s other_value) const\n" |
| 134 | "{\n" |
| 135 | "if (enum_value == %s) " |
| 136 | "TTCN_error(\"The left operand of comparison is an unbound value of " |
| 137 | "enumerated type %s.\");\n" |
| 138 | "return enum_value == other_value;\n" |
| 139 | "}\n\n", name, enum_type, unbound_value, dispname); |
| 140 | |
| 141 | def = mputprintf(def, "boolean operator==(const %s& other_value) const;\n", |
| 142 | name); |
| 143 | src = mputprintf(src, |
| 144 | "boolean %s::operator==(const %s& other_value) const\n" |
| 145 | "{\n" |
| 146 | "if (enum_value == %s) " |
| 147 | "TTCN_error(\"The left operand of comparison is an unbound value of " |
| 148 | "enumerated type %s.\");\n" |
| 149 | "if (other_value.enum_value == %s) " |
| 150 | "TTCN_error(\"The right operand of comparison is an unbound value of " |
| 151 | "enumerated type %s.\");\n" |
| 152 | "return enum_value == other_value.enum_value;\n" |
| 153 | "}\n\n", name, name, unbound_value, dispname, unbound_value, dispname); |
| 154 | |
| 155 | def = mputprintf(def, "inline boolean operator!=(%s other_value) " |
| 156 | "const { return !(*this == other_value); }\n", enum_type); |
| 157 | |
| 158 | def = mputprintf(def, "inline boolean operator!=(const %s& other_value) " |
| 159 | "const { return !(*this == other_value); }\n", name); |
| 160 | |
| 161 | def = mputprintf(def, "boolean operator<(%s other_value) const;\n", |
| 162 | enum_type); |
| 163 | src = mputprintf(src, |
| 164 | "boolean %s::operator<(%s other_value) const\n" |
| 165 | "{\n" |
| 166 | "if (enum_value == %s) " |
| 167 | "TTCN_error(\"The left operand of comparison is an unbound value of " |
| 168 | "enumerated type %s.\");\n" |
| 169 | "return enum_value < other_value;\n" |
| 170 | "}\n\n", name, enum_type, unbound_value, dispname); |
| 171 | |
| 172 | def = mputprintf(def, "boolean operator<(const %s& other_value) const;\n", |
| 173 | name); |
| 174 | src = mputprintf(src, |
| 175 | "boolean %s::operator<(const %s& other_value) const\n" |
| 176 | "{\n" |
| 177 | "if (enum_value == %s) " |
| 178 | "TTCN_error(\"The left operand of comparison is an unbound value of " |
| 179 | "enumerated type %s.\");\n" |
| 180 | "if (other_value.enum_value == %s) " |
| 181 | "TTCN_error(\"The right operand of comparison is an unbound value of " |
| 182 | "enumerated type %s.\");\n" |
| 183 | "return enum_value < other_value.enum_value;\n" |
| 184 | "}\n\n", name, name, unbound_value, dispname, unbound_value, dispname); |
| 185 | |
| 186 | def = mputprintf(def, "boolean operator>(%s other_value) const;\n", |
| 187 | enum_type); |
| 188 | src = mputprintf(src, |
| 189 | "boolean %s::operator>(%s other_value) const\n" |
| 190 | "{\n" |
| 191 | "if (enum_value == %s) " |
| 192 | "TTCN_error(\"The left operand of comparison is an unbound value of " |
| 193 | "enumerated type %s.\");\n" |
| 194 | "return enum_value > other_value;\n" |
| 195 | "}\n\n", name, enum_type, unbound_value, dispname); |
| 196 | |
| 197 | def = mputprintf(def, "boolean operator>(const %s& other_value) const;\n", |
| 198 | name); |
| 199 | src = mputprintf(src, |
| 200 | "boolean %s::operator>(const %s& other_value) const\n" |
| 201 | "{\n" |
| 202 | "if (enum_value == %s) " |
| 203 | "TTCN_error(\"The left operand of comparison is an unbound value of " |
| 204 | "enumerated type %s.\");\n" |
| 205 | "if (other_value.enum_value == %s) " |
| 206 | "TTCN_error(\"The right operand of comparison is an unbound value of " |
| 207 | "enumerated type %s.\");\n" |
| 208 | "return enum_value > other_value.enum_value;\n" |
| 209 | "}\n\n", name, name, unbound_value, dispname, unbound_value, dispname); |
| 210 | |
| 211 | def = mputprintf(def, "inline boolean operator<=(%s other_value) " |
| 212 | "const { return !(*this > other_value); }\n", enum_type); |
| 213 | |
| 214 | def = mputprintf(def, "inline boolean operator<=(const %s& other_value) " |
| 215 | "const { return !(*this > other_value); }\n", name); |
| 216 | |
| 217 | def = mputprintf(def, "inline boolean operator>=(%s other_value) " |
| 218 | "const { return !(*this < other_value); }\n", enum_type); |
| 219 | |
| 220 | def = mputprintf(def, "inline boolean operator>=(const %s& other_value) " |
| 221 | "const { return !(*this < other_value); }\n\n", name); |
| 222 | |
| 223 | /* Conversion function: enum_to_str */ |
| 224 | def = mputprintf(def, "static const char *enum_to_str(%s enum_par%s);\n", |
| 225 | enum_type, |
| 226 | edef->xerText ? ", boolean txt = false" : ""); |
| 227 | src = mputprintf(src, "const char *%s::enum_to_str(%s enum_par%s)\n" |
| 228 | "{\n" |
| 229 | "switch (enum_par) {\n", name, enum_type, |
| 230 | edef->xerText ? ", boolean txt" : ""); |
| 231 | for (i = 0; i < edef->nElements; i++) { |
| 232 | if (edef->elements[i].text) { |
| 233 | src = mputprintf(src, |
| 234 | "case %s: if (txt) return \"%s\"; else return \"%s\";\n", |
| 235 | edef->elements[i].name, edef->elements[i].text, edef->elements[i].dispname); |
| 236 | } |
| 237 | else { |
| 238 | src = mputprintf(src, "case %s: return \"%s\";\n", |
| 239 | edef->elements[i].name, edef->elements[i].dispname); |
| 240 | } |
| 241 | } |
| 242 | src = mputstr(src, "default: return \"<unknown>\";\n" |
| 243 | "}\n" |
| 244 | "}\n\n"); |
| 245 | |
| 246 | /* Conversion function: str_to_enum */ |
| 247 | def = mputprintf(def, "static %s str_to_enum(const char *str_par);\n", |
| 248 | enum_type); |
| 249 | src = mputprintf(src, "%s %s::str_to_enum(const char *str_par)\n" |
| 250 | "{\n", qualified_enum_type, name); |
| 251 | for (i = 0; i < edef->nElements; i++) { |
| 252 | if (edef->elements[i].text) { |
| 253 | src = mputprintf(src, "if (!strcmp(str_par, \"%s\") || !strcmp(str_par, \"%s\")) return %s;\n" |
| 254 | "else ", edef->elements[i].text, edef->elements[i].dispname, edef->elements[i].name); |
| 255 | } |
| 256 | else { |
| 257 | src = mputprintf(src, "if (!strcmp(str_par, \"%s\")) return %s;\n" |
| 258 | "else ", edef->elements[i].dispname, edef->elements[i].name); |
| 259 | } |
| 260 | } |
| 261 | src = mputprintf(src, "return %s;\n" |
| 262 | "}\n\n", unknown_value); |
| 263 | |
| 264 | /* Checking function: is_valid_enum */ |
| 265 | def = mputstr(def, "static boolean is_valid_enum(int int_par);\n\n"); |
| 266 | src = mputprintf(src, "boolean %s::is_valid_enum(int int_par)\n" |
| 267 | "{\n" |
| 268 | "switch (int_par) {\n", name); |
| 269 | for (i = 0; i < edef->nElements; i++) { |
| 270 | src = mputprintf(src, "case %d:\n", edef->elements[i].value); |
| 271 | } |
| 272 | src = mputstr(src, "return TRUE;\n" |
| 273 | "default:\n" |
| 274 | "return FALSE;\n" |
| 275 | "}\n" |
| 276 | "}\n\n"); |
| 277 | |
| 278 | /* TTCN-3 predefined function enum2int() */ |
| 279 | def = mputprintf(def, "static int enum2int(%s enum_par);\n", enum_type); |
| 280 | src = mputprintf(src, "int %s::enum2int(%s enum_par)\n" |
| 281 | "{\n" |
| 282 | "if (enum_par==%s || enum_par==%s) TTCN_error(\"The argument of function " |
| 283 | "enum2int() is an %%s value of enumerated type %s.\", " |
| 284 | "enum_par==%s?\"unbound\":\"invalid\");\n" |
| 285 | "return enum_par;\n" |
| 286 | "}\n\n", |
| 287 | name, enum_type, unbound_value, unknown_value, dispname, unbound_value); |
| 288 | def = mputprintf(def, "static int enum2int(const %s& enum_par);\n", name); |
| 289 | src = mputprintf(src, "int %s::enum2int(const %s& enum_par)\n" |
| 290 | "{\n" |
| 291 | "if (enum_par.enum_value==%s || enum_par.enum_value==%s) " |
| 292 | "TTCN_error(\"The argument of function " |
| 293 | "enum2int() is an %%s value of enumerated type %s.\", " |
| 294 | "enum_par==%s?\"unbound\":\"invalid\");\n" |
| 295 | "return enum_par.enum_value;\n" |
| 296 | "}\n\n", |
| 297 | name, name, unbound_value, unknown_value, dispname, unbound_value); |
| 298 | def = mputstr(def, |
| 299 | "int as_int() const { return enum2int(enum_value); }\n" |
| 300 | "void from_int(int p_val) { *this = p_val; }\n"); |
| 301 | |
| 302 | /* miscellaneous members */ |
| 303 | def = mputprintf(def, "operator %s() const;\n", enum_type); |
| 304 | src = mputprintf(src, |
| 305 | "%s::operator %s() const\n" |
| 306 | "{\n" |
| 307 | "if (enum_value == %s) " |
| 308 | "TTCN_error(\"Using the value of an unbound variable of enumerated " |
| 309 | "type %s.\");\n" |
| 310 | "return enum_value;\n" |
| 311 | "}\n\n", name, qualified_enum_type, unbound_value, dispname); |
| 312 | |
| 313 | def = mputprintf(def, "inline boolean is_bound() const " |
| 314 | "{ return enum_value != %s; }\n", unbound_value); |
| 315 | def = mputprintf(def, "inline boolean is_value() const " |
| 316 | "{ return enum_value != %s; }\n", unbound_value); |
| 317 | def = mputprintf(def, "inline void clean_up()" |
| 318 | "{ enum_value = %s; }\n", unbound_value); |
| 319 | |
| 320 | if (use_runtime_2) { |
| 321 | def = mputstr(def, |
| 322 | "boolean is_equal(const Base_Type* other_value) const;\n" |
| 323 | "void set_value(const Base_Type* other_value);\n" |
| 324 | "Base_Type* clone() const;\n" |
| 325 | "const TTCN_Typedescriptor_t* get_descriptor() const;\n"); |
| 326 | src = mputprintf(src, |
| 327 | "boolean %s::is_equal(const Base_Type* other_value) const " |
| 328 | "{ return *this == *(static_cast<const %s*>(other_value)); }\n" |
| 329 | "void %s::set_value(const Base_Type* other_value) " |
| 330 | "{ *this = *(static_cast<const %s*>(other_value)); }\n" |
| 331 | "Base_Type* %s::clone() const { return new %s(*this); }\n" |
| 332 | "const TTCN_Typedescriptor_t* %s::get_descriptor() const " |
| 333 | "{ return &%s_descr_; }\n", |
| 334 | name, name, |
| 335 | name, name, |
| 336 | name, name, |
| 337 | name, name); |
| 338 | } else { |
| 339 | def = mputstr(def, |
| 340 | "inline boolean is_present() const { return is_bound(); }\n"); |
| 341 | } |
| 342 | |
| 343 | def = mputstr(def, "void log() const;\n"); |
| 344 | src = mputprintf(src, |
| 345 | "void %s::log() const\n" |
| 346 | "{\n" |
| 347 | "if (enum_value != %s) TTCN_Logger::log_event_enum(enum_to_str(enum_value), enum_value);\n" |
| 348 | "else TTCN_Logger::log_event_unbound();\n" |
| 349 | "}\n\n", name, unbound_value); |
| 350 | |
| 351 | def = mputstr(def, "void set_param(Module_Param& param);\n"); |
| 352 | src = mputprintf |
| 353 | (src, |
| 354 | "void %s::set_param(Module_Param& param)\n" |
| 355 | "{\n" |
| 356 | " param.basic_check(Module_Param::BC_VALUE, \"enumerated value\");\n" |
| 357 | " if (param.get_type()!=Module_Param::MP_Enumerated) param.type_error(\"enumerated value\", \"%s\");\n" |
| 358 | " enum_value = str_to_enum(param.get_enumerated());\n" |
| 359 | " if (!is_valid_enum(enum_value)) {\n " |
| 360 | " param.error(\"Invalid enumerated value for type %s.\");\n" |
| 361 | " }\n" |
| 362 | "}\n\n", name, dispname, dispname); |
| 363 | |
| 364 | /* encoders/decoders */ |
| 365 | def = mputstr(def, "void encode_text(Text_Buf& text_buf) const;\n"); |
| 366 | src = mputprintf(src, |
| 367 | "void %s::encode_text(Text_Buf& text_buf) const\n" |
| 368 | "{\n" |
| 369 | "if (enum_value == %s) " |
| 370 | "TTCN_error(\"Text encoder: Encoding an unbound value of enumerated " |
| 371 | "type %s.\");\n" |
| 372 | "text_buf.push_int(enum_value);\n" |
| 373 | "}\n\n", name, unbound_value, dispname); |
| 374 | |
| 375 | def = mputstr(def, "void decode_text(Text_Buf& text_buf);\n"); |
| 376 | src = mputprintf(src, |
| 377 | "void %s::decode_text(Text_Buf& text_buf)\n" |
| 378 | "{\n" |
| 379 | "enum_value = (%s)text_buf.pull_int().get_val();\n" |
| 380 | "if (!is_valid_enum(enum_value)) " |
| 381 | "TTCN_error(\"Text decoder: Unknown numeric value %%d was " |
| 382 | "received for enumerated type %s.\", enum_value);\n" |
| 383 | "}\n\n", name, enum_type, dispname); |
| 384 | |
| 385 | /* BER functions */ |
| 386 | if(ber_needed || raw_needed || text_needed || xer_needed || json_needed) |
| 387 | def_encdec(name, &def, &src, ber_needed, |
| 388 | raw_needed,text_needed, xer_needed, json_needed, TRUE); |
| 389 | if(ber_needed) { |
| 390 | src=mputprintf(src, |
| 391 | "ASN_BER_TLV_t* %s::BER_encode_TLV(const TTCN_Typedescriptor_t&" |
| 392 | " p_td, unsigned p_coding) const\n" |
| 393 | "{\n" |
| 394 | " BER_chk_descr(p_td);\n" |
| 395 | " ASN_BER_TLV_t *new_tlv=BER_encode_chk_bound(is_bound());\n" |
| 396 | " if(!new_tlv) {\n" |
| 397 | " BER_encode_chk_enum_valid(p_td, is_valid_enum(enum_value)," |
| 398 | " enum_value);\n" |
| 399 | " new_tlv=BER_encode_TLV_INTEGER(p_coding, enum_value);\n" |
| 400 | " }\n" |
| 401 | " new_tlv=ASN_BER_V2TLV(new_tlv, p_td, p_coding);\n" |
| 402 | " return new_tlv;\n" |
| 403 | "}\n" |
| 404 | "\n" |
| 405 | "boolean %s::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td," |
| 406 | " const ASN_BER_TLV_t& p_tlv, unsigned L_form)\n" |
| 407 | "{\n" |
| 408 | " enum_value = %s;\n" |
| 409 | " BER_chk_descr(p_td);\n" |
| 410 | " ASN_BER_TLV_t stripped_tlv;\n" |
| 411 | " BER_decode_strip_tags(*p_td.ber, p_tlv, L_form, stripped_tlv);\n" |
| 412 | " TTCN_EncDec_ErrorContext ec(\"While decoding ENUMERATED type %s: " |
| 413 | "\");\n" |
| 414 | " int tmp_mfr;\n" |
| 415 | " if (BER_decode_TLV_INTEGER(stripped_tlv, L_form, tmp_mfr)) {\n" |
| 416 | " BER_decode_chk_enum_valid(p_td, is_valid_enum(tmp_mfr), tmp_mfr);\n" |
| 417 | " enum_value = (%s)tmp_mfr;\n" |
| 418 | " return TRUE;\n" |
| 419 | " } else return FALSE;\n" |
| 420 | "}\n\n" |
| 421 | , name, name, unbound_value, dispname, enum_type); |
| 422 | } /* if ber_needed */ |
| 423 | /* new TEXT functions */ |
| 424 | if(text_needed){ |
| 425 | src = mputprintf(src, |
| 426 | "int %s::TEXT_encode(const TTCN_Typedescriptor_t& p_td," |
| 427 | "TTCN_Buffer& p_buf) const{\n" |
| 428 | "int encoded_length=0;\n" |
| 429 | "if(p_td.text->begin_encode){\n" |
| 430 | " p_buf.put_cs(*p_td.text->begin_encode);\n" |
| 431 | " encoded_length+=p_td.text->begin_encode->lengthof();\n" |
| 432 | "}\n" |
| 433 | " if (enum_value == %s) {\n" |
| 434 | " TTCN_EncDec_ErrorContext::error\n" |
| 435 | " (TTCN_EncDec::ET_UNBOUND, \"Encoding an unbound value of " |
| 436 | "enumerated type %s.\");\n" |
| 437 | " if(p_td.text->end_encode){\n" |
| 438 | " p_buf.put_cs(*p_td.text->end_encode);\n" |
| 439 | " encoded_length+=p_td.text->end_encode->lengthof();\n" |
| 440 | " }\n" |
| 441 | " return encoded_length;\n" |
| 442 | " }\n" |
| 443 | "if(p_td.text->val.enum_values==NULL){\n" |
| 444 | " int len=strlen(enum_to_str(enum_value));\n" |
| 445 | " p_buf.put_s(len,(const unsigned char*)enum_to_str(enum_value));\n" |
| 446 | " encoded_length+=len;\n" |
| 447 | "} else {\n" |
| 448 | "switch(enum_value){\n" |
| 449 | , name, unbound_value, dispname |
| 450 | ); |
| 451 | for(i=0;i<edef->nElements;i++){ |
| 452 | src = mputprintf(src, |
| 453 | "case %s: \n" |
| 454 | "if(p_td.text->val.enum_values[%lu].encode_token){\n" |
| 455 | " p_buf.put_cs(*p_td.text->val.enum_values[%lu].encode_token);\n" |
| 456 | " encoded_length+=p_td.text->val.enum_values[%lu]" |
| 457 | ".encode_token->lengthof();\n" |
| 458 | "} else { " |
| 459 | " int len=strlen(enum_to_str(enum_value));\n" |
| 460 | " p_buf.put_s(len,(const unsigned char*)enum_to_str(enum_value));\n" |
| 461 | " encoded_length+=len;\n" |
| 462 | "}\n" |
| 463 | "break;\n" |
| 464 | ,edef->elements[i].name, |
| 465 | (unsigned long) i,(unsigned long) i,(unsigned long) i |
| 466 | ); |
| 467 | } |
| 468 | |
| 469 | src = mputstr(src, |
| 470 | " default:\n" |
| 471 | "break;\n" |
| 472 | "}\n" |
| 473 | "}\n" |
| 474 | " if(p_td.text->end_encode){\n" |
| 475 | " p_buf.put_cs(*p_td.text->end_encode);\n" |
| 476 | " encoded_length+=p_td.text->end_encode->lengthof();\n" |
| 477 | " }\n" |
| 478 | " return encoded_length;\n" |
| 479 | "}\n" |
| 480 | ); |
| 481 | src = mputprintf(src, |
| 482 | "int %s::TEXT_decode(const TTCN_Typedescriptor_t& p_td," |
| 483 | " TTCN_Buffer& p_buf, Limit_Token_List& limit, boolean no_err, boolean){\n" |
| 484 | " int decoded_length=0;\n" |
| 485 | " int str_len=0;\n" |
| 486 | " if(p_td.text->begin_decode){\n" |
| 487 | " int tl;\n" |
| 488 | " if((tl=p_td.text->begin_decode->match_begin(p_buf))<0){\n" |
| 489 | " if(no_err)return -1;\n" |
| 490 | " TTCN_EncDec_ErrorContext::error\n" |
| 491 | " (TTCN_EncDec::ET_TOKEN_ERR, \"The specified token '%%s'" |
| 492 | " not found for '%%s': \",(const char*)*(p_td.text->begin_decode)" |
| 493 | ", p_td.name);\n" |
| 494 | " return 0;\n" |
| 495 | " }\n" |
| 496 | " decoded_length+=tl;\n" |
| 497 | " p_buf.increase_pos(tl);\n" |
| 498 | " }\n" |
| 499 | " if(p_buf.get_read_len()<1 && no_err) return -1;\n" |
| 500 | ,name |
| 501 | ); |
| 502 | |
| 503 | |
| 504 | for(i=0;i<edef->nElements;i++){ |
| 505 | src = mputprintf(src, |
| 506 | "if((str_len=p_td.text->val.enum_values[%lu].decode_token->" |
| 507 | "match_begin(p_buf))!=-1){\n" |
| 508 | " enum_value=%s;\n" |
| 509 | "} else " |
| 510 | ,(unsigned long) i,edef->elements[i].name |
| 511 | ); |
| 512 | } |
| 513 | |
| 514 | src = mputstr(src, |
| 515 | " {\n" |
| 516 | " if(no_err)return -1;\n" |
| 517 | " TTCN_EncDec_ErrorContext::error" |
| 518 | "(TTCN_EncDec::ET_TOKEN_ERR, \"No enum token found for '%s': \"" |
| 519 | ",p_td.name);\n" |
| 520 | " return decoded_length;\n" |
| 521 | "}\n" |
| 522 | " decoded_length+=str_len;\n" |
| 523 | " p_buf.increase_pos(str_len);\n" |
| 524 | " if(p_td.text->end_decode){\n" |
| 525 | " int tl;\n" |
| 526 | " if((tl=p_td.text->end_decode->match_begin(p_buf))<0){\n" |
| 527 | " if(no_err)return -1;\n" |
| 528 | " TTCN_EncDec_ErrorContext::error" |
| 529 | "(TTCN_EncDec::ET_TOKEN_ERR, \"The specified token '%s'" |
| 530 | " not found for '%s': \",(const char*)*(p_td.text->end_decode)" |
| 531 | ",p_td.name);\n" |
| 532 | " return decoded_length;\n" |
| 533 | " }\n" |
| 534 | " decoded_length+=tl;\n" |
| 535 | " p_buf.increase_pos(tl);\n" |
| 536 | " }\n" |
| 537 | " return decoded_length;\n" |
| 538 | "}\n" |
| 539 | ); |
| 540 | } |
| 541 | /* new RAW functions */ |
| 542 | if (raw_needed) { |
| 543 | int min_bits = 0; |
| 544 | int max_val = edef->firstUnused; |
| 545 | size_t a; |
| 546 | for (a = 0; a < edef->nElements; a++) { |
| 547 | int val = edef->elements[a].value; |
| 548 | if (abs(max_val) < abs(val)) max_val = val; |
| 549 | } |
| 550 | if (max_val < 0) { |
| 551 | min_bits = 1; |
| 552 | max_val = -max_val; |
| 553 | } |
| 554 | while (max_val) { |
| 555 | min_bits++; |
| 556 | max_val /= 2; |
| 557 | } |
| 558 | src = mputprintf(src, |
| 559 | "int %s::RAW_decode(const TTCN_Typedescriptor_t& p_td,TTCN_Buffer& p_buf," |
| 560 | "int limit, raw_order_t top_bit_ord, boolean no_err, int, boolean)\n" |
| 561 | "{\n" |
| 562 | " int decoded_value = 0;\n" |
| 563 | " int decoded_length = RAW_decode_enum_type(p_td, p_buf, limit, " |
| 564 | "top_bit_ord, decoded_value, %d, no_err);\n" |
| 565 | " if (decoded_length < 0) return decoded_length;\n" |
| 566 | " if (is_valid_enum(decoded_value)) " |
| 567 | "enum_value = (%s)decoded_value;\n" |
| 568 | " else {\n" |
| 569 | " if(no_err){\n" |
| 570 | " return -1;\n" |
| 571 | " } else {\n" |
| 572 | " TTCN_EncDec_ErrorContext::error\n" |
| 573 | " (TTCN_EncDec::ET_ENC_ENUM, \"Invalid enum value '%%d'" |
| 574 | " for '%%s': \",decoded_value, p_td.name);\n" |
| 575 | " enum_value = %s;\n" |
| 576 | " }\n" |
| 577 | " }\n" |
| 578 | " return decoded_length;\n" |
| 579 | "}\n\n", name, min_bits, enum_type, unknown_value); |
| 580 | src = mputprintf(src, |
| 581 | "int %s::RAW_encode(const TTCN_Typedescriptor_t& p_td, " |
| 582 | "RAW_enc_tree& myleaf) const\n" |
| 583 | "{\n" |
| 584 | " return RAW_encode_enum_type(p_td, myleaf, (int)enum_value, %d);\n" |
| 585 | "}\n\n", name, min_bits); |
| 586 | } /* if raw_needed */ |
| 587 | |
| 588 | if (xer_needed) { /* XERSTUFF encoder codegen for enum */ |
| 589 | /* FIXME This is redundant, |
| 590 | * because the code is identical to BaseType::can_start() |
| 591 | * and enum types are derived from BaseType or EnumType (which, in turn, |
| 592 | * is derived from BaseType). However, the declaration of can_start() |
| 593 | * is written by def_encdec() in encdec.c, which doesn't know |
| 594 | * that this is an enum type. Maybe we need to pass an is_enum to |
| 595 | * def_encdec, and then we can omit generating can_start() for enums. |
| 596 | */ |
| 597 | src = mputprintf(src, |
| 598 | "boolean %s::can_start(const char *name, const char *uri, " |
| 599 | "const XERdescriptor_t& xd, unsigned int flavor) {\n" |
| 600 | " boolean exer = is_exer(flavor);\n" |
| 601 | " return check_name(name, xd, exer) && (!exer || check_namespace(uri, xd));\n" |
| 602 | "}\n\n" |
| 603 | , name |
| 604 | ); |
| 605 | |
| 606 | src = mputprintf(src, |
| 607 | "int %s::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf," |
| 608 | " unsigned int p_flavor, int p_indent) const\n" |
| 609 | "{\n" |
| 610 | " int encoded_length=(int)p_buf.get_len();\n" |
| 611 | " const boolean e_xer = is_exer(p_flavor);\n" |
| 612 | " p_flavor |= (SIMPLE_TYPE | BXER_EMPTY_ELEM);\n" |
| 613 | " if (begin_xml(p_td, p_buf, p_flavor, p_indent, false) == -1) " |
| 614 | "--encoded_length;\n" |
| 615 | " if (!e_xer) p_buf.put_c('<');\n" |
| 616 | , name |
| 617 | ); |
| 618 | if (edef->xerUseNumber) { |
| 619 | src = mputstr(src, |
| 620 | " if (e_xer) {\n" /* compile-time instead of p_td.useNumber */ |
| 621 | " char sval[24];\n" /* unsigned 64 bits fit in 20 characters */ |
| 622 | " int slen = snprintf(sval, 24, \"%d\", enum_value);\n" |
| 623 | " if (slen > 0) p_buf.put_s((size_t)slen, (const unsigned char*)sval);\n" |
| 624 | " }\n" |
| 625 | " else" /* no newline, will take over following curly */ |
| 626 | ); |
| 627 | } |
| 628 | src = mputprintf(src, |
| 629 | " {\n" |
| 630 | " const char * enumval = enum_to_str(enum_value%s);\n" |
| 631 | " p_buf.put_s(strlen(enumval), (const unsigned char*)enumval);\n" |
| 632 | " }\n" |
| 633 | " if (!e_xer) p_buf.put_s(2, (const unsigned char*)\"/>\");\n" |
| 634 | " end_xml(p_td, p_buf, p_flavor, p_indent, false);\n" |
| 635 | , edef->xerText ? ", e_xer" : "" |
| 636 | ); |
| 637 | src = mputstr(src, |
| 638 | " return (int)p_buf.get_len() - encoded_length;\n" |
| 639 | "}\n\n"); |
| 640 | |
| 641 | src = mputprintf(src, /* XERSTUFF decoder codegen for enum */ |
| 642 | #ifndef NDEBUG |
| 643 | "// written by %s in " __FILE__ " at %d\n" |
| 644 | #endif |
| 645 | "int %s::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader," |
| 646 | " unsigned int p_flavor)\n" |
| 647 | "{\n" |
| 648 | " int rd_ok = 1, type;\n" |
| 649 | |
| 650 | " const int e_xer = is_exer(p_flavor);\n" |
| 651 | " const boolean name_tag = !((!e_xer && is_record_of(p_flavor)) || (e_xer && ((p_td.xer_bits & UNTAGGED) ||(is_record_of(p_flavor) && is_exerlist(p_flavor)))));\n" |
| 652 | " if (e_xer && ((p_td.xer_bits & XER_ATTRIBUTE) || is_exerlist(p_flavor))) {\n" |
| 653 | " if ((p_td.xer_bits & XER_ATTRIBUTE)) verify_name(p_reader, p_td, e_xer);\n" |
| 654 | " const char * value = (const char *)p_reader.Value();\n" |
| 655 | " if (value) {\n" |
| 656 | #ifndef NDEBUG |
| 657 | , __FUNCTION__, __LINE__ |
| 658 | #endif |
| 659 | , name); |
| 660 | if (edef->xerUseNumber) { |
| 661 | src = mputprintf(src, |
| 662 | " int tempvalue;\n" |
| 663 | " sscanf(value, \"%%d\", &tempvalue);\n" |
| 664 | " if (is_valid_enum(tempvalue)) enum_value = (%s)tempvalue;\n" /* static_cast would be nice */ |
| 665 | " else enum_value = %s;\n", enum_type, unknown_value |
| 666 | ); |
| 667 | } |
| 668 | else { |
| 669 | src = mputstr(src, " enum_value = str_to_enum(value);\n"); |
| 670 | } |
| 671 | src = mputstr(src, |
| 672 | " }\n" |
| 673 | /* The caller should do AdvanceAttribute() */ |
| 674 | " }\n" |
| 675 | " else {\n" |
| 676 | " if (name_tag)" |
| 677 | /* Go past the opening tag with the type name */ |
| 678 | " for (; rd_ok == 1; rd_ok = p_reader.Read()) {\n" |
| 679 | " type = p_reader.NodeType();\n" |
| 680 | " if (XML_READER_TYPE_ELEMENT == type) {\n" |
| 681 | " rd_ok = p_reader.Read();\n" |
| 682 | " break;\n" |
| 683 | " }\n" |
| 684 | " }\n" |
| 685 | /* Go to the element with the actual data (EmptyElementEnumerated) */ |
| 686 | " for (; rd_ok == 1; rd_ok = p_reader.Read()) {\n" |
| 687 | " type = p_reader.NodeType();\n" |
| 688 | " if (!e_xer && XML_READER_TYPE_ELEMENT == type) break;\n" |
| 689 | " if (XML_READER_TYPE_TEXT == type) break;\n" |
| 690 | " }\n" |
| 691 | " const char *local_name = e_xer ? (const char *)p_reader.Value() : (const char *)p_reader.Name();\n" |
| 692 | /* TextEnumerated EmptyElementEnumerated */ |
| 693 | " if (!local_name) ; else"); |
| 694 | if (edef->xerUseNumber) { |
| 695 | src = mputprintf(src, |
| 696 | " if (e_xer) {\n" |
| 697 | " int tempvalue;\n" |
| 698 | " sscanf(local_name, \"%%d\", &tempvalue);\n" |
| 699 | " if (is_valid_enum(tempvalue)) enum_value = (%s)tempvalue;\n" /* static_cast would be nice */ |
| 700 | " else enum_value = %s;\n" |
| 701 | " }\n" |
| 702 | " else" /* no newline */ , enum_type, unknown_value |
| 703 | ); |
| 704 | } |
| 705 | { |
| 706 | src = mputstr(src, |
| 707 | " {\n" |
| 708 | " for (; '\\t'==*local_name || '\\n'==*local_name; ++local_name) ;\n" /* crutch while default-for-empty always puts in a newline */ |
| 709 | " enum_value = str_to_enum(local_name);\n" |
| 710 | " }\n"); |
| 711 | } |
| 712 | src = mputprintf(src, |
| 713 | " if (name_tag)\n" |
| 714 | " for (rd_ok = p_reader.Read(); rd_ok == 1; rd_ok = p_reader.Read()) {\n" |
| 715 | " type = p_reader.NodeType();\n" |
| 716 | " if (XML_READER_TYPE_END_ELEMENT == type) {\n" |
| 717 | " rd_ok = p_reader.Read();\n" |
| 718 | " break;\n" |
| 719 | " }\n" |
| 720 | " }\n" |
| 721 | " else rd_ok = p_reader.Read();\n" |
| 722 | " }\n" |
| 723 | " if (e_xer && (p_flavor & EXIT_ON_ERROR) && %s == enum_value) clean_up();\n" // set to unbound if decoding failed |
| 724 | " int decoded_length = 0;\n" |
| 725 | " return decoded_length;\n" |
| 726 | "}\n\n" |
| 727 | , unknown_value); |
| 728 | } |
| 729 | if (json_needed) { |
| 730 | // JSON encode |
| 731 | src = mputprintf(src, |
| 732 | "int %s::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const\n" |
| 733 | "{\n" |
| 734 | " if (enum_value == %s) {\n" |
| 735 | " TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n" |
| 736 | " \"Encoding an unbound value of enumerated type %s.\");\n" |
| 737 | " return -1;\n" |
| 738 | " }\n\n" |
| 739 | " char* tmp_str = mprintf(\"\\\"%%s\\\"\", enum_to_str(enum_value));\n" |
| 740 | " int enc_len = p_tok.put_next_token(JSON_TOKEN_STRING, tmp_str);\n" |
| 741 | " Free(tmp_str);\n" |
| 742 | " return enc_len;\n" |
| 743 | "}\n\n" |
| 744 | , name, unbound_value, dispname); |
| 745 | |
| 746 | // JSON decode |
| 747 | src = mputprintf(src, |
| 748 | "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent)\n" |
| 749 | "{\n" |
| 750 | " json_token_t token = JSON_TOKEN_NONE;\n" |
| 751 | " char* value = 0;\n" |
| 752 | " size_t value_len = 0;\n" |
| 753 | " boolean error = false;\n" |
| 754 | " int dec_len = 0;\n" |
| 755 | " boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();\n" |
| 756 | " if (use_default) {\n" |
| 757 | // No JSON data in the buffer -> use default value |
| 758 | " value = (char*)p_td.json->default_value;\n" |
| 759 | " value_len = strlen(value);\n" |
| 760 | " } else {\n" |
| 761 | " dec_len = p_tok.get_next_token(&token, &value, &value_len);\n" |
| 762 | " }\n" |
| 763 | " if (JSON_TOKEN_ERROR == token) {\n" |
| 764 | " JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, \"\");\n" |
| 765 | " return JSON_ERROR_FATAL;\n" |
| 766 | " }\n" |
| 767 | " else if (JSON_TOKEN_STRING == token || use_default) {\n" |
| 768 | " if (use_default || (value_len > 2 && value[0] == '\\\"' && value[value_len - 1] == '\\\"')) {\n" |
| 769 | " if (!use_default) value[value_len - 1] = 0;\n" |
| 770 | " enum_value = str_to_enum(value + (use_default ? 0 : 1));\n" |
| 771 | " if (!use_default) value[value_len - 1] = '\\\"';\n" |
| 772 | " if (%s == enum_value) {\n" |
| 773 | " error = true;\n" |
| 774 | " }\n" |
| 775 | " } else {\n" |
| 776 | " error = true;\n" |
| 777 | " }\n" |
| 778 | " } else {\n" |
| 779 | " enum_value = %s;\n" |
| 780 | " return JSON_ERROR_INVALID_TOKEN;\n" |
| 781 | " }\n\n" |
| 782 | " if (error) {\n" |
| 783 | " JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FORMAT_ERROR, \"string\", \"enumerated\");\n" |
| 784 | " enum_value = %s;\n" |
| 785 | " return JSON_ERROR_FATAL;\n" |
| 786 | " }\n" |
| 787 | " return dec_len;\n" |
| 788 | "}\n\n" |
| 789 | , name, unknown_value, unbound_value, unbound_value); |
| 790 | } |
| 791 | /* end of class */ |
| 792 | def = mputstr(def, "};\n\n"); |
| 793 | |
| 794 | output->header.class_defs = mputstr(output->header.class_defs, def); |
| 795 | Free(def); |
| 796 | output->source.methods = mputstr(output->source.methods, src); |
| 797 | Free(src); |
| 798 | |
| 799 | |
| 800 | Free(enum_type); |
| 801 | Free(qualified_enum_type); |
| 802 | Free(unknown_value); |
| 803 | Free(unbound_value); |
| 804 | } |
| 805 | |
| 806 | void defEnumTemplate(const enum_def *edef, output_struct *output) |
| 807 | { |
| 808 | char *def = NULL, *src = NULL; |
| 809 | const char *name = edef->name, *dispname = edef->dispname; |
| 810 | |
| 811 | char *enum_type, *unbound_value; |
| 812 | enum_type = mprintf("%s::enum_type", name); |
| 813 | unbound_value = mprintf("%s::UNBOUND_VALUE", name); |
| 814 | |
| 815 | /* Class declaration */ |
| 816 | output->header.class_decls = mputprintf(output->header.class_decls, |
| 817 | "class %s_template;\n", name); |
| 818 | |
| 819 | /* Class definition */ |
| 820 | def = mputprintf(def, "class %s_template : public Base_Template {\n" |
| 821 | "union {\n" |
| 822 | "%s single_value;\n" |
| 823 | "struct {\n" |
| 824 | "unsigned int n_values;\n" |
| 825 | "%s_template *list_value;\n" |
| 826 | "} value_list;\n" |
| 827 | "};\n\n", name, enum_type, name); |
| 828 | |
| 829 | /* private members */ |
| 830 | def = mputprintf(def, "void copy_template(const %s_template& " |
| 831 | "other_value);\n", name); |
| 832 | src = mputprintf(src, |
| 833 | "void %s_template::copy_template(const %s_template& " |
| 834 | "other_value)\n" |
| 835 | "{\n" |
| 836 | "set_selection(other_value);\n" |
| 837 | "switch (template_selection) {\n" |
| 838 | "case SPECIFIC_VALUE:\n" |
| 839 | "single_value = other_value.single_value;\n" |
| 840 | "break;\n" |
| 841 | "case OMIT_VALUE:\n" |
| 842 | "case ANY_VALUE:\n" |
| 843 | "case ANY_OR_OMIT:\n" |
| 844 | "break;\n" |
| 845 | "case VALUE_LIST:\n" |
| 846 | "case COMPLEMENTED_LIST:\n" |
| 847 | "value_list.n_values = other_value.value_list.n_values;\n" |
| 848 | "value_list.list_value = new %s_template[value_list.n_values];\n" |
| 849 | "for (unsigned int list_count = 0; list_count < value_list.n_values; " |
| 850 | "list_count++)\n" |
| 851 | "value_list.list_value[list_count].copy_template(" |
| 852 | "other_value.value_list.list_value[list_count]);\n" |
| 853 | "break;\n" |
| 854 | "default:\n" |
| 855 | "TTCN_error(\"Copying an uninitialized/unsupported template of " |
| 856 | "enumerated type %s.\");\n" |
| 857 | "}\n" |
| 858 | "}\n\n", name, name, name, dispname); |
| 859 | |
| 860 | def = mputstr(def, "\npublic:\n"); |
| 861 | |
| 862 | /* constructors */ |
| 863 | def = mputprintf(def, "%s_template();\n", name); |
| 864 | src = mputprintf(src, |
| 865 | "%s_template::%s_template()\n" |
| 866 | "{\n" |
| 867 | "}\n\n", name, name); |
| 868 | |
| 869 | def = mputprintf(def, "%s_template(template_sel other_value);\n", name); |
| 870 | src = mputprintf(src, |
| 871 | "%s_template::%s_template(template_sel other_value)\n" |
| 872 | " : Base_Template(other_value)\n" |
| 873 | "{\n" |
| 874 | "check_single_selection(other_value);\n" |
| 875 | "}\n\n", name, name); |
| 876 | |
| 877 | def = mputprintf(def, "%s_template(int other_value);\n", name); |
| 878 | src = mputprintf(src, |
| 879 | "%s_template::%s_template(int other_value)\n" |
| 880 | " : Base_Template(SPECIFIC_VALUE)\n" |
| 881 | "{\n" |
| 882 | "if (!%s::is_valid_enum(other_value)) " |
| 883 | "TTCN_error(\"Initializing a template of enumerated type %s with " |
| 884 | "unknown numeric value %%d.\", other_value);\n" |
| 885 | "single_value = (%s)other_value;\n" |
| 886 | "}\n\n", name, name, name, dispname, enum_type); |
| 887 | |
| 888 | def = mputprintf(def, "%s_template(%s other_value);\n", name, enum_type); |
| 889 | src = mputprintf(src, |
| 890 | "%s_template::%s_template(%s other_value)\n" |
| 891 | " : Base_Template(SPECIFIC_VALUE)\n" |
| 892 | "{\n" |
| 893 | "single_value = other_value;\n" |
| 894 | "}\n\n", name, name, enum_type); |
| 895 | |
| 896 | def = mputprintf(def, "%s_template(const %s& other_value);\n", name, name); |
| 897 | src = mputprintf(src, |
| 898 | "%s_template::%s_template(const %s& other_value)\n" |
| 899 | " : Base_Template(SPECIFIC_VALUE)\n" |
| 900 | "{\n" |
| 901 | "if (other_value.enum_value == %s) " |
| 902 | "TTCN_error(\"Creating a template from an unbound value of enumerated " |
| 903 | "type %s.\");\n" |
| 904 | "single_value = other_value.enum_value;\n" |
| 905 | "}\n\n", name, name, name, unbound_value, dispname); |
| 906 | |
| 907 | def = mputprintf(def, "%s_template(const OPTIONAL<%s>& other_value);\n", |
| 908 | name, name); |
| 909 | src = mputprintf(src, |
| 910 | "%s_template::%s_template(const OPTIONAL<%s>& other_value)\n" |
| 911 | "{\n" |
| 912 | "switch (other_value.get_selection()) {\n" |
| 913 | "case OPTIONAL_PRESENT:\n" |
| 914 | "set_selection(SPECIFIC_VALUE);\n" |
| 915 | "single_value = (%s)(const %s&)other_value;\n" |
| 916 | "break;\n" |
| 917 | "case OPTIONAL_OMIT:\n" |
| 918 | "set_selection(OMIT_VALUE);\n" |
| 919 | "break;\n" |
| 920 | "default:\n" |
| 921 | "TTCN_error(\"Creating a template of enumerated type %s from an unbound " |
| 922 | "optional field.\");\n" |
| 923 | "}\n" |
| 924 | "}\n\n", name, name, name, enum_type, name, dispname); |
| 925 | |
| 926 | def = mputprintf(def, "%s_template(const %s_template& other_value);\n", |
| 927 | name, name); |
| 928 | src = mputprintf(src, |
| 929 | "%s_template::%s_template(const %s_template& other_value)\n" |
| 930 | " : Base_Template()\n" |
| 931 | "{\n" |
| 932 | "copy_template(other_value);\n" |
| 933 | "}\n\n", name, name, name); |
| 934 | |
| 935 | /* destructor */ |
| 936 | def = mputprintf(def, "~%s_template();\n\n", name); |
| 937 | src = mputprintf(src, |
| 938 | "%s_template::~%s_template()\n" |
| 939 | "{\n" |
| 940 | "clean_up();\n" |
| 941 | "}\n\n", name, name); |
| 942 | |
| 943 | /* is_bound */ |
| 944 | def = mputstr(def, "boolean is_bound() const;\n"); |
| 945 | src = mputprintf(src, "boolean %s_template::is_bound() const\n" |
| 946 | "{\n" |
| 947 | "if (template_selection == UNINITIALIZED_TEMPLATE && !is_ifpresent) " |
| 948 | "return FALSE;\n", name); |
| 949 | src = mputstr(src, "return TRUE;\n" |
| 950 | "}\n\n"); |
| 951 | |
| 952 | /* is_value */ |
| 953 | def = mputstr(def, "boolean is_value() const;\n"); |
| 954 | src = mputprintf(src, "boolean %s_template::is_value() const\n" |
| 955 | "{\n" |
| 956 | "if (template_selection != SPECIFIC_VALUE || is_ifpresent) " |
| 957 | "return FALSE;\n" |
| 958 | "return single_value != %s;\n" |
| 959 | "}\n\n", name, unbound_value); |
| 960 | |
| 961 | /* clean_up */ |
| 962 | def = mputstr(def, "void clean_up();\n"); |
| 963 | src = mputprintf(src, |
| 964 | "void %s_template::clean_up()\n" |
| 965 | "{\n" |
| 966 | "if (template_selection == VALUE_LIST || " |
| 967 | "template_selection == COMPLEMENTED_LIST) " |
| 968 | "delete [] value_list.list_value;\n" |
| 969 | "template_selection = UNINITIALIZED_TEMPLATE;\n" |
| 970 | "}\n\n", name); |
| 971 | |
| 972 | /* assignment operators */ |
| 973 | def = mputprintf(def, "%s_template& operator=(template_sel other_value);\n", |
| 974 | name); |
| 975 | src = mputprintf(src, |
| 976 | "%s_template& %s_template::operator=(template_sel other_value)\n" |
| 977 | "{\n" |
| 978 | "check_single_selection(other_value);\n" |
| 979 | "clean_up();\n" |
| 980 | "set_selection(other_value);\n" |
| 981 | "return *this;\n" |
| 982 | "}\n\n", name, name); |
| 983 | |
| 984 | def = mputprintf(def, "%s_template& operator=(int other_value);\n", |
| 985 | name); |
| 986 | src = mputprintf(src, |
| 987 | "%s_template& %s_template::operator=(int other_value)\n" |
| 988 | "{\n" |
| 989 | "if (!%s::is_valid_enum(other_value)) " |
| 990 | "TTCN_warning(\"Assigning unknown numeric value %%d to a template " |
| 991 | "of enumerated type %s.\", other_value);\n" |
| 992 | "clean_up();\n" |
| 993 | "set_selection(SPECIFIC_VALUE);\n" |
| 994 | "single_value = (%s)other_value;\n" |
| 995 | "return *this;\n" |
| 996 | "}\n\n", name, name, name, dispname, enum_type); |
| 997 | |
| 998 | def = mputprintf(def, "%s_template& operator=(%s other_value);\n", |
| 999 | name, enum_type); |
| 1000 | src = mputprintf(src, |
| 1001 | "%s_template& %s_template::operator=(%s other_value)\n" |
| 1002 | "{\n" |
| 1003 | "clean_up();\n" |
| 1004 | "set_selection(SPECIFIC_VALUE);\n" |
| 1005 | "single_value = other_value;\n" |
| 1006 | "return *this;\n" |
| 1007 | "}\n\n", name, name, enum_type); |
| 1008 | |
| 1009 | def = mputprintf(def, "%s_template& operator=(const %s& other_value);\n", |
| 1010 | name, name); |
| 1011 | src = mputprintf(src, |
| 1012 | "%s_template& %s_template::operator=(const %s& other_value)\n" |
| 1013 | "{\n" |
| 1014 | "if (other_value.enum_value == %s) " |
| 1015 | "TTCN_error(\"Assignment of an unbound value of enumerated type %s to a " |
| 1016 | "template.\");\n" |
| 1017 | "clean_up();\n" |
| 1018 | "set_selection(SPECIFIC_VALUE);\n" |
| 1019 | "single_value = other_value.enum_value;\n" |
| 1020 | "return *this;\n" |
| 1021 | "}\n\n", name, name, name, unbound_value, dispname); |
| 1022 | |
| 1023 | def = mputprintf(def, "%s_template& operator=(const OPTIONAL<%s>& " |
| 1024 | "other_value);\n", name, name); |
| 1025 | src = mputprintf(src, |
| 1026 | "%s_template& %s_template::operator=(const OPTIONAL<%s>& other_value)\n" |
| 1027 | "{\n" |
| 1028 | "clean_up();\n" |
| 1029 | "switch (other_value.get_selection()) {\n" |
| 1030 | "case OPTIONAL_PRESENT:\n" |
| 1031 | "set_selection(SPECIFIC_VALUE);\n" |
| 1032 | "single_value = (%s)(const %s&)other_value;\n" |
| 1033 | "break;\n" |
| 1034 | "case OPTIONAL_OMIT:\n" |
| 1035 | "set_selection(OMIT_VALUE);\n" |
| 1036 | "break;\n" |
| 1037 | "default:\n" |
| 1038 | "TTCN_error(\"Assignment of an unbound optional field to a template of " |
| 1039 | "enumerated type %s.\");\n" |
| 1040 | "}\n" |
| 1041 | "return *this;\n" |
| 1042 | "}\n\n", name, name, name, enum_type, name, dispname); |
| 1043 | |
| 1044 | def = mputprintf(def, "%s_template& operator=(const %s_template& " |
| 1045 | "other_value);\n\n", name, name); |
| 1046 | src = mputprintf(src, |
| 1047 | "%s_template& %s_template::operator=(const %s_template& other_value)\n" |
| 1048 | "{\n" |
| 1049 | "if (&other_value != this) {\n" |
| 1050 | "clean_up();\n" |
| 1051 | "copy_template(other_value);\n" |
| 1052 | "}\n" |
| 1053 | "return *this;\n" |
| 1054 | "}\n\n", name, name, name); |
| 1055 | |
| 1056 | /* match operators */ |
| 1057 | def = mputprintf(def, "boolean match(%s other_value) const;\n", enum_type); |
| 1058 | src = mputprintf(src, |
| 1059 | "boolean %s_template::match(%s other_value) " |
| 1060 | "const\n" |
| 1061 | "{\n" |
| 1062 | "switch (template_selection) {\n" |
| 1063 | "case SPECIFIC_VALUE:\n" |
| 1064 | "return single_value == other_value;\n" |
| 1065 | "case OMIT_VALUE:\n" |
| 1066 | "return FALSE;\n" |
| 1067 | "case ANY_VALUE:\n" |
| 1068 | "case ANY_OR_OMIT:\n" |
| 1069 | "return TRUE;\n" |
| 1070 | "case VALUE_LIST:\n" |
| 1071 | "case COMPLEMENTED_LIST:\n" |
| 1072 | "for (unsigned int list_count = 0; list_count < value_list.n_values; " |
| 1073 | "list_count++)\n" |
| 1074 | "if (value_list.list_value[list_count].match(other_value)) " |
| 1075 | "return template_selection == VALUE_LIST;\n" |
| 1076 | "return template_selection == COMPLEMENTED_LIST;\n" |
| 1077 | "default:\n" |
| 1078 | "TTCN_error(\"Matching an uninitialized/unsupported template of " |
| 1079 | "enumerated type %s.\");\n" |
| 1080 | "}\n" |
| 1081 | "return FALSE;\n" |
| 1082 | "}\n\n", name, enum_type, dispname); |
| 1083 | |
| 1084 | def = mputprintf(def, "boolean match(const %s& other_value) const;\n", |
| 1085 | name); |
| 1086 | src = mputprintf(src, |
| 1087 | "boolean %s_template::match(const %s& other_value) const\n" |
| 1088 | "{\n" |
| 1089 | "if (other_value.enum_value == %s) " |
| 1090 | "TTCN_error(\"Matching a template of enumerated type %s with an unbound " |
| 1091 | "value.\");\n" |
| 1092 | "return match(other_value.enum_value);\n" |
| 1093 | "}\n\n", name, name, unbound_value, dispname); |
| 1094 | |
| 1095 | /* valueof operator */ |
| 1096 | def = mputprintf(def, "%s valueof() const;\n", enum_type); |
| 1097 | src = mputprintf(src, |
| 1098 | "%s %s_template::valueof() const\n" |
| 1099 | "{\n" |
| 1100 | "if (template_selection != SPECIFIC_VALUE || is_ifpresent) " |
| 1101 | "TTCN_error(\"Performing a valueof or send operation on a " |
| 1102 | "non-specific template of enumerated type %s.\");\n" |
| 1103 | "return single_value;\n" |
| 1104 | "}\n\n", enum_type, name, dispname); |
| 1105 | |
| 1106 | /* value list handling operators */ |
| 1107 | def = mputstr |
| 1108 | (def, |
| 1109 | "void set_type(template_sel template_type, unsigned int list_length);\n"); |
| 1110 | src = mputprintf(src, |
| 1111 | "void %s_template::set_type(template_sel template_type, " |
| 1112 | "unsigned int list_length)\n" |
| 1113 | "{\n" |
| 1114 | "if (template_type != VALUE_LIST && template_type != COMPLEMENTED_LIST) " |
| 1115 | "TTCN_error(\"Setting an invalid list type for a template of enumerated " |
| 1116 | "type %s.\");\n" |
| 1117 | "clean_up();\n" |
| 1118 | "set_selection(template_type);\n" |
| 1119 | "value_list.n_values = list_length;\n" |
| 1120 | "value_list.list_value = new %s_template[list_length];\n" |
| 1121 | "}\n\n", name, dispname, name); |
| 1122 | |
| 1123 | def = mputprintf(def, "%s_template& list_item(unsigned int list_index);\n", |
| 1124 | name); |
| 1125 | src = mputprintf(src, |
| 1126 | "%s_template& %s_template::list_item(unsigned int list_index)\n" |
| 1127 | "{\n" |
| 1128 | "if (template_selection != VALUE_LIST && " |
| 1129 | "template_selection != COMPLEMENTED_LIST) " |
| 1130 | "TTCN_error(\"Accessing a list element in a non-list template of " |
| 1131 | "enumerated type %s.\");\n" |
| 1132 | "if (list_index >= value_list.n_values) " |
| 1133 | "TTCN_error(\"Index overflow in a value list template of enumerated type " |
| 1134 | "%s.\");\n" |
| 1135 | "return value_list.list_value[list_index];\n" |
| 1136 | "}\n\n", name, name, dispname, dispname); |
| 1137 | |
| 1138 | if (use_runtime_2) { |
| 1139 | /** virtual stuff */ |
| 1140 | def = mputstr(def, |
| 1141 | "void valueofv(Base_Type* value) const;\n" |
| 1142 | "void set_value(template_sel other_value);\n" |
| 1143 | "void copy_value(const Base_Type* other_value);\n" |
| 1144 | "Base_Template* clone() const;\n" |
| 1145 | "const TTCN_Typedescriptor_t* get_descriptor() const;\n" |
| 1146 | "boolean matchv(const Base_Type* other_value) const;\n" |
| 1147 | "void log_matchv(const Base_Type* match_value) const;\n"); |
| 1148 | src = mputprintf(src, |
| 1149 | "void %s_template::valueofv(Base_Type* value) const " |
| 1150 | "{ *(static_cast<%s*>(value)) = valueof(); }\n" |
| 1151 | "void %s_template::set_value(template_sel other_value) " |
| 1152 | "{ *this = other_value; }\n" |
| 1153 | "void %s_template::copy_value(const Base_Type* other_value) " |
| 1154 | "{ *this = *(static_cast<const %s*>(other_value)); }\n" |
| 1155 | "Base_Template* %s_template::clone() const " |
| 1156 | "{ return new %s_template(*this); }\n" |
| 1157 | "const TTCN_Typedescriptor_t* %s_template::get_descriptor() const " |
| 1158 | "{ return &%s_descr_; }\n" |
| 1159 | "boolean %s_template::matchv(const Base_Type* other_value) const " |
| 1160 | "{ return match(*(static_cast<const %s*>(other_value))); }\n" |
| 1161 | "void %s_template::log_matchv(const Base_Type* match_value) const " |
| 1162 | " { log_match(*(static_cast<const %s*>(match_value))); }\n", |
| 1163 | name, name, |
| 1164 | name, |
| 1165 | name, name, |
| 1166 | name, name, |
| 1167 | name, name, |
| 1168 | name, name, |
| 1169 | name, name); |
| 1170 | } |
| 1171 | |
| 1172 | /* logging functions */ |
| 1173 | def = mputstr(def, "void log() const;\n"); |
| 1174 | src = mputprintf |
| 1175 | (src, |
| 1176 | "void %s_template::log() const\n" |
| 1177 | "{\n" |
| 1178 | "switch (template_selection) {\n" |
| 1179 | "case SPECIFIC_VALUE:\n" |
| 1180 | "TTCN_Logger::log_event_enum(%s::enum_to_str(single_value), single_value);\n" |
| 1181 | "break;\n" |
| 1182 | "case COMPLEMENTED_LIST:\n" |
| 1183 | "TTCN_Logger::log_event_str(\"complement \");\n" |
| 1184 | "case VALUE_LIST:\n" |
| 1185 | "TTCN_Logger::log_char('(');\n" |
| 1186 | "for (unsigned int elem_count = 0; elem_count < value_list.n_values; " |
| 1187 | "elem_count++) {\n" |
| 1188 | "if (elem_count > 0) TTCN_Logger::log_event_str(\", \");\n" |
| 1189 | "value_list.list_value[elem_count].log();\n" |
| 1190 | "}\n" |
| 1191 | "TTCN_Logger::log_char(')');\n" |
| 1192 | "break;\n" |
| 1193 | "default:\n" |
| 1194 | "log_generic();\n" |
| 1195 | "}\n" |
| 1196 | "log_ifpresent();\n" |
| 1197 | "}\n\n", name, name); |
| 1198 | |
| 1199 | def = mputprintf(def, "void log_match(const %s& match_value) const;\n", |
| 1200 | name); |
| 1201 | src = mputprintf(src, |
| 1202 | "void %s_template::log_match(const %s& match_value) " |
| 1203 | "const\n" |
| 1204 | "{\n" |
| 1205 | "match_value.log();\n" |
| 1206 | "TTCN_Logger::log_event_str(\" with \");\n" |
| 1207 | "log();\n" |
| 1208 | "if (match(match_value)) TTCN_Logger::log_event_str(\" matched\");\n" |
| 1209 | "else TTCN_Logger::log_event_str(\" unmatched\");\n" |
| 1210 | "}\n\n", name, name); |
| 1211 | |
| 1212 | /* encoding/decoding functions */ |
| 1213 | def = mputstr(def, "void encode_text(Text_Buf& text_buf) const;\n"); |
| 1214 | src = mputprintf(src, |
| 1215 | "void %s_template::encode_text(Text_Buf& text_buf) " |
| 1216 | "const\n" |
| 1217 | "{\n" |
| 1218 | "encode_text_base(text_buf);\n" |
| 1219 | "switch (template_selection) {\n" |
| 1220 | "case SPECIFIC_VALUE:\n" |
| 1221 | "text_buf.push_int(single_value);\n" |
| 1222 | "case OMIT_VALUE:\n" |
| 1223 | "case ANY_VALUE:\n" |
| 1224 | "case ANY_OR_OMIT:\n" |
| 1225 | "break;\n" |
| 1226 | "case VALUE_LIST:\n" |
| 1227 | "case COMPLEMENTED_LIST:\n" |
| 1228 | "text_buf.push_int(value_list.n_values);\n" |
| 1229 | "for (unsigned int elem_count = 0; elem_count < value_list.n_values; " |
| 1230 | "elem_count++)\n" |
| 1231 | "value_list.list_value[elem_count].encode_text(text_buf);\n" |
| 1232 | "break;\n" |
| 1233 | "default:\n" |
| 1234 | "TTCN_error(\"Text encoder: Encoding an uninitialized/unsupported " |
| 1235 | "template of enumerated type %s.\");\n" |
| 1236 | "}\n" |
| 1237 | "}\n\n", name, dispname); |
| 1238 | |
| 1239 | def = mputstr(def, "void decode_text(Text_Buf& text_buf);\n"); |
| 1240 | src = mputprintf(src, |
| 1241 | "void %s_template::decode_text(Text_Buf& text_buf)\n" |
| 1242 | "{\n" |
| 1243 | "clean_up();\n" |
| 1244 | "decode_text_base(text_buf);\n" |
| 1245 | "switch (template_selection) {\n" |
| 1246 | "case SPECIFIC_VALUE:\n" |
| 1247 | "single_value = (%s)text_buf.pull_int().get_val();\n" |
| 1248 | "if (!%s::is_valid_enum(single_value)) " |
| 1249 | "TTCN_error(\"Text decoder: Unknown numeric value %%d was " |
| 1250 | "received for a template of enumerated type %s.\", single_value);\n" |
| 1251 | "case OMIT_VALUE:\n" |
| 1252 | "case ANY_VALUE:\n" |
| 1253 | "case ANY_OR_OMIT:\n" |
| 1254 | "break;\n" |
| 1255 | "case VALUE_LIST:\n" |
| 1256 | "case COMPLEMENTED_LIST:\n" |
| 1257 | "value_list.n_values = text_buf.pull_int().get_val();\n" |
| 1258 | "value_list.list_value = new %s_template[value_list.n_values];\n" |
| 1259 | "for (unsigned int elem_count = 0; elem_count < value_list.n_values; " |
| 1260 | "elem_count++)\n" |
| 1261 | "value_list.list_value[elem_count].decode_text(text_buf);\n" |
| 1262 | "break;\n" |
| 1263 | "default:\n" |
| 1264 | "TTCN_error(\"Text decoder: An unknown/unsupported selection was " |
| 1265 | "received for a template of enumerated type %s.\");\n" |
| 1266 | "}\n" |
| 1267 | "}\n\n", name, enum_type, name, dispname, name, dispname); |
| 1268 | |
| 1269 | /* TTCN-3 ispresent() function */ |
| 1270 | def = mputstr(def, "boolean is_present() const;\n"); |
| 1271 | src = mputprintf(src, |
| 1272 | "boolean %s_template::is_present() const\n" |
| 1273 | "{\n" |
| 1274 | "if (template_selection==UNINITIALIZED_TEMPLATE) return FALSE;\n" |
| 1275 | "return !match_omit();\n" |
| 1276 | "}\n\n", name); |
| 1277 | |
| 1278 | /* match_omit() */ |
| 1279 | def = mputstr(def, "boolean match_omit() const;\n"); |
| 1280 | src = mputprintf(src, |
| 1281 | "boolean %s_template::match_omit() const\n" |
| 1282 | "{\n" |
| 1283 | "if (is_ifpresent) return TRUE;\n" |
| 1284 | "switch (template_selection) {\n" |
| 1285 | "case OMIT_VALUE:\n" |
| 1286 | "case ANY_OR_OMIT:\n" |
| 1287 | "return TRUE;\n" |
| 1288 | "case VALUE_LIST:\n" |
| 1289 | "case COMPLEMENTED_LIST:\n" |
| 1290 | "for (unsigned int i=0; i<value_list.n_values; i++)\n" |
| 1291 | "if (value_list.list_value[i].match_omit())\n" |
| 1292 | "return template_selection==VALUE_LIST;\n" |
| 1293 | "return template_selection==COMPLEMENTED_LIST;\n" |
| 1294 | "default:\n" |
| 1295 | "return FALSE;\n" |
| 1296 | "}\n" |
| 1297 | "return FALSE;\n" |
| 1298 | "}\n\n", name); |
| 1299 | |
| 1300 | /* set_param() */ |
| 1301 | def = mputstr(def, "void set_param(Module_Param& param);\n"); |
| 1302 | src = mputprintf(src, |
| 1303 | "void %s_template::set_param(Module_Param& param)\n" |
| 1304 | "{\n" |
| 1305 | " param.basic_check(Module_Param::BC_TEMPLATE, \"enumerated template\");\n" |
| 1306 | " switch (param.get_type()) {\n" |
| 1307 | " case Module_Param::MP_Omit:\n" |
| 1308 | " *this = OMIT_VALUE;\n" |
| 1309 | " break;\n" |
| 1310 | " case Module_Param::MP_Any:\n" |
| 1311 | " *this = ANY_VALUE;\n" |
| 1312 | " break;\n" |
| 1313 | " case Module_Param::MP_AnyOrNone:\n" |
| 1314 | " *this = ANY_OR_OMIT;\n" |
| 1315 | " break;\n" |
| 1316 | " case Module_Param::MP_List_Template:\n" |
| 1317 | " case Module_Param::MP_ComplementList_Template:\n" |
| 1318 | " set_type(param.get_type()==Module_Param::MP_List_Template ? VALUE_LIST : COMPLEMENTED_LIST, param.get_size());\n" |
| 1319 | " for (size_t p_i=0; p_i<param.get_size(); p_i++) {\n" |
| 1320 | " list_item(p_i).set_param(*param.get_elem(p_i));\n" |
| 1321 | " }\n" |
| 1322 | " break;\n" |
| 1323 | " case Module_Param::MP_Enumerated: {\n" |
| 1324 | " %s enum_val = %s::str_to_enum(param.get_enumerated());\n" |
| 1325 | " if (!%s::is_valid_enum(enum_val)) {\n" |
| 1326 | " param.error(\"Invalid enumerated value for type %s.\");\n" |
| 1327 | " }\n" |
| 1328 | " *this = enum_val;\n" |
| 1329 | " } break;\n" |
| 1330 | " default:\n" |
| 1331 | " param.type_error(\"enumerated template\", \"%s\");\n" |
| 1332 | " }\n" |
| 1333 | " is_ifpresent = param.get_ifpresent();\n" |
| 1334 | "}\n\n", name, enum_type, name, name, dispname, dispname); |
| 1335 | |
| 1336 | if (!use_runtime_2) { |
| 1337 | /* check template restriction */ |
| 1338 | def = mputstr(def, "void check_restriction(template_res t_res, " |
| 1339 | "const char* t_name=NULL) const;\n"); |
| 1340 | src = mputprintf(src, |
| 1341 | "void %s_template::check_restriction(template_res t_res, const char* t_name) const\n" |
| 1342 | "{\n" |
| 1343 | "if (template_selection==UNINITIALIZED_TEMPLATE) return;\n" |
| 1344 | "switch ((t_name&&(t_res==TR_VALUE))?TR_OMIT:t_res) {\n" |
| 1345 | "case TR_VALUE:\n" |
| 1346 | "if (!is_ifpresent && template_selection==SPECIFIC_VALUE) return;\n" |
| 1347 | "break;\n" |
| 1348 | "case TR_OMIT:\n" |
| 1349 | "if (!is_ifpresent && (template_selection==OMIT_VALUE || " |
| 1350 | "template_selection==SPECIFIC_VALUE)) return;\n" |
| 1351 | "break;\n" |
| 1352 | "case TR_PRESENT:\n" |
| 1353 | "if (!match_omit()) return;\n" |
| 1354 | "break;\n" |
| 1355 | "default:\n" |
| 1356 | "return;\n" |
| 1357 | "}\n" |
| 1358 | "TTCN_error(\"Restriction `%%s' on template of type %%s violated.\", " |
| 1359 | "get_res_name(t_res), t_name ? t_name : \"%s\");\n" |
| 1360 | "}\n\n", name, dispname); |
| 1361 | } |
| 1362 | |
| 1363 | /* end of class */ |
| 1364 | def = mputstr(def, "};\n\n"); |
| 1365 | |
| 1366 | output->header.class_defs = mputstr(output->header.class_defs, def); |
| 1367 | Free(def); |
| 1368 | output->source.methods = mputstr(output->source.methods, src); |
| 1369 | Free(src); |
| 1370 | |
| 1371 | Free(enum_type); |
| 1372 | Free(unbound_value); |
| 1373 | } |