1 #include "asn1c_internal.h"
2 #include "asn1c_misc.h"
4 #include <asn1fix_crange.h> /* constraint groker from libasn1fix */
5 #include <asn1fix_export.h> /* other exportable stuff from libasn1fix */
8 * Checks that the given string is not a reserved C/C++ keyword [1],[2].
9 * _* keywords not included, since asn1 identifiers cannot begin with hyphen [3]
10 * [1] ISO/IEC 9899:2011 (C11), 6.4.1
11 * [2] ISO/IEC 14882:2014 (C++14), 2.12
12 * [3] ISO/IEC 8824-1:2003 (asn1) 11.3
14 static char *res_kwd[] = {
16 "auto", "break", "case", "char", "const", "continue", "default", "do",
17 "double", "else", "enum", "extern", "float", "for", "goto", "if",
18 "inline", "int", "long", "register", "restrict", "return", "short",
19 "signed", "sizeof", "static", "struct", "switch", "typedef", "union",
20 "unsigned", "void", "volatile", "while",
22 "alignas", "alignof", "and", "and_eq", "asm", "bitand", "bitor", "bool",
23 "catch", "char16_t", "char32_t", "class", "compl", "const_cast",
24 "constexpr", "decltype", "delete", "delete", "dynamic_cast",
25 "explicit", "export", "false", "friend", "mutable", "namespace", "new",
26 "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
27 "private", "protected", "public", "reinterpret_cast", "static_assert",
28 "static_cast", "template", "this", "thread_local", "throw", "true", "try",
29 "typeid", "typename", "using", "virtual", "wchar_t", "xor", "xor_eq"
32 reserved_keyword(const char *str) {
34 for(i = 0 ; i < sizeof(res_kwd)/sizeof(res_kwd[0]); i++) {
35 if(strcmp(str, res_kwd[i]) == 0)
44 const char *prefix = getenv("ASN1C_PREFIX");
46 if(!prefix) prefix = "";
52 * Construct identifier from multiple parts.
53 * Convert unsafe characters to underscores.
56 asn1c_make_identifier(enum ami_flags_e flags, asn1p_expr_t *expr, ...) {
58 static int storage_size;
66 const char *prefix = NULL;
67 char *sptr[4], **psptr = &sptr[0];
70 if(flags & AMI_USE_PREFIX)
71 prefix = asn1c_prefix();
75 * Estimate the necessary storage size
77 if(expr->Identifier == NULL)
80 * Add MODULE name to resolve clash
82 if(expr->_mark & TM_NAMECLASH) {
83 size += strlen(expr->module->ModuleName) + 2;
84 sptr[sptr_cnt++] = expr->module->ModuleName;
86 sptr[sptr_cnt++] = expr->Identifier;
88 size += strlen(expr->Identifier);
89 if(expr->spec_index != -1 && expr->_lineno) {
91 size += 1 + snprintf(buf, sizeof buf, "%dP%d",
92 expr->_lineno, expr->spec_index);
93 sptr[sptr_cnt++] = (char *)&buf;
98 sptr[sptr_cnt++] = (char *)0;
101 while((str = va_arg(ap, char *)))
102 size += 1 + strlen(str);
104 if(size == -1) return NULL;
107 size += 1 + strlen(prefix);
109 * Make sure we have the required amount of storage.
111 if(storage_size <= size) {
112 char *tmp = malloc(size + 1);
116 storage_size = size + 1;
123 * Fill-in the storage.
128 strcpy(storage, prefix);
133 for(str = 0; str || nextstr; str = nextstr) {
135 nextstr = *(psptr) ? *(psptr++) : va_arg(ap, char *);
138 str = first = nextstr;
139 nextstr = *(psptr) ? *(psptr++) : va_arg(ap, char *);
140 if (!first) continue;
144 nodelimiter = 1; /* No delimiter */
148 if(str[0] == ' ' && str[1] == '\0') {
150 nodelimiter = 1; /* No delimiter */
154 if(str != first && !nodelimiter && !(flags & AMI_NODELIMITER))
155 *p++ = '_'; /* Delimiter between tokens */
159 * If it is a single argument, check that it does not clash
160 * with C/C++ language keywords.
162 if((flags & AMI_CHECK_RESERVED)
163 && str == first && !nextstr && reserved_keyword(str)) {
164 *p++ = toupper(*str++);
172 } else if(!subst_made++) {
173 if((flags & AMI_MASK_ONLY_SPACES)
185 assert((p - storage) <= storage_size);
191 asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
192 asn1p_expr_t *exprid = 0;
193 asn1p_expr_t *top_parent;
194 asn1p_expr_t *terminal = 0;
196 const char *typename;
199 /* Rewind to the topmost parent expression */
200 if((top_parent = expr->parent_expr))
201 while(top_parent->parent_expr)
202 top_parent = top_parent->parent_expr;
204 if(0) DEBUG("asn1c_type_name(%s: 0x%x)",
205 expr->Identifier, expr->expr_type);
207 switch(expr->expr_type) {
209 typename = expr->reference->components[
210 expr->reference->comp_count-1].name;
211 if(typename[0] == '&') {
215 * This is a reference to a type defined in a class.
216 * Resolve it and use instead.
218 tmp.expr = WITH_MODULE_NAMESPACE(
219 arg->expr->module, expr_ns,
220 asn1f_class_access_ex(arg->asn, arg->expr->module, expr_ns,
221 arg->expr, expr->rhs_pspecs,
223 if(!tmp.expr) return NULL;
225 return asn1c_type_name(&tmp, tmp.expr, _format);
228 terminal = WITH_MODULE_NAMESPACE(
229 expr->module, expr_ns,
230 (expr->meta_type == AMT_TYPEREF) ?
231 asn1f_lookup_symbol_ex(arg->asn, expr_ns, expr, expr->reference) :
232 asn1f_find_terminal_type_ex(arg->asn, expr_ns, expr));
234 if(_format == TNF_RSAFE) {
235 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
236 typename = terminal->Identifier;
240 if(_format == TNF_CTYPE || _format == TNF_CONSTYPE) {
242 * If the component references the type itself,
243 * switch to a recursion-safe type naming
244 * ("struct foo" instead of "foo_t").
246 if(terminal && terminal == top_parent) {
251 if(_format != TNF_RSAFE && terminal && ((terminal->spec_index != -1) || (terminal->_mark & TM_NAMECLASH))) {
257 case ASN_BASIC_INTEGER:
258 case ASN_BASIC_ENUMERATED:
260 if((expr->expr_type == ASN_BASIC_REAL
261 && (_format == TNF_CONSTYPE || !(arg->flags & A1C_USE_WIDE_TYPES)
262 || asn1c_REAL_fits(arg, expr) != RL_NOTFIT))
263 || asn1c_type_fits_long(arg, expr)) {
266 if(expr->expr_type == ASN_BASIC_REAL) {
268 } else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN) {
269 return "unsigned long";
275 if(expr->expr_type == ASN_BASIC_REAL) {
276 asn1cnst_range_t *range = asn1constraint_compute_OER_range(
277 expr->Identifier, ASN_BASIC_REAL,
278 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
279 if(range->narrowing == NARROW_FLOAT32) {
280 asn1constraint_range_free(range);
283 asn1constraint_range_free(range);
286 } else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN) {
287 return "unsigned long";
293 switch(expr->expr_type) {
294 case ASN_BASIC_INTEGER:
295 typename = "NativeInteger"; break;
296 case ASN_BASIC_ENUMERATED:
297 typename = "NativeEnumerated"; break;
299 typename = "NativeReal"; break;
306 if(_format != TNF_INCLUDE)
315 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
316 if(_format == TNF_RSAFE)
319 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
320 if(_format == TNF_INCLUDE) {
321 if(expr->expr_type == ASN_CONSTR_SEQUENCE)
322 typename = "constr_SEQUENCE";
323 else if(expr->expr_type == ASN_CONSTR_CHOICE)
324 typename = "constr_CHOICE";
325 else if(expr->expr_type == ASN_CONSTR_SET)
326 typename = "constr_SET";
327 else if(expr->expr_type == ASN_CONSTR_SEQUENCE_OF)
328 typename = "constr_SEQUENCE_OF";
329 else if(expr->expr_type == ASN_CONSTR_SET_OF)
330 typename = "constr_SET_OF";
331 else if(expr->expr_type == ASN_CONSTR_OPEN_TYPE)
332 typename = "OPEN_TYPE";
336 typename = expr->Identifier;
340 prefix = stdname ? "" : asn1c_prefix();
344 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES | AMI_NODELIMITER | (stdname ? 0 : AMI_USE_PREFIX),
345 0, prefix, MODULE_NAME_OF(exprid), exprid ? exprid->Identifier : typename, (char*)0);
347 return asn1c_make_identifier(
348 AMI_MASK_ONLY_SPACES | AMI_NODELIMITER,
349 0, ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
351 prefix, MODULE_NAME_OF(exprid),
352 exprid ? exprid->Identifier : typename,
353 ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
354 ? ".h\"" : ".h>"), (char*)0);
356 return asn1c_make_identifier(stdname ? 0 : AMI_USE_PREFIX, exprid, typename, (char*)0);
357 case TNF_CTYPE: /* C type */
358 case TNF_CONSTYPE: /* C type */
359 return asn1c_make_identifier(stdname ? 0 : AMI_USE_PREFIX, exprid,
360 exprid?"t":typename, exprid?0:"t", (char*)0);
361 case TNF_RSAFE: /* Recursion-safe type */
362 return asn1c_make_identifier(AMI_CHECK_RESERVED | AMI_NODELIMITER, 0,
363 "struct", " ", prefix, MODULE_NAME_OF(exprid), typename, (char*)0);
366 assert(!"unreachable");
370 static asn1p_expr_type_e
371 expr_get_type(arg_t *arg, asn1p_expr_t *expr) {
372 asn1p_expr_t *terminal;
373 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->ns, expr);
374 if(terminal) return terminal->expr_type;
378 enum asn1c_fitsfloat_e
379 asn1c_REAL_fits(arg_t *arg, asn1p_expr_t *expr) {
380 asn1p_expr_type_e etype = expr_get_type(arg, arg->expr);
381 if(etype == ASN_BASIC_REAL) {
382 asn1cnst_range_t *range = asn1constraint_compute_OER_range(
383 expr->Identifier, etype, expr->combined_constraints, ACT_EL_RANGE,
385 enum asn1c_fitsfloat_e fits;
386 switch(range->narrowing) {
388 fits = RL_FITS_FLOAT32;
390 case NARROW_DOUBLE64:
391 fits = RL_FITS_DOUBLE64;
397 asn1constraint_range_free(range);
405 * Check whether the specified INTEGER or ENUMERATED type can be represented
406 * using the generic 'long' or 'unsigned long' type.
408 enum asn1c_fitslong_e
409 asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
410 asn1cnst_range_t *range = 0;
411 asn1cnst_edge_t left;
412 asn1cnst_edge_t right;
416 * Since we don't know the sizeof(long) on the possible target platform
417 * which will be compiling the code generated by asn1c, let's play it
418 * simple: long's range is equal to or greater than int32_t.
419 * NOTE: the most negative integer cannot be written in C, as the C99
420 * standard will give it an unsigned type.
421 * It is defined here as a constant expression.
423 #define RIGHTMAX 2147483647 /* of 32-bit integer type */
424 #define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
426 /* Descend to the terminal type */
427 expr = WITH_MODULE_NAMESPACE(
428 expr->module, expr_ns,
429 asn1f_find_terminal_type_ex(arg->asn, expr_ns, expr));
430 if(expr == 0) return FL_NOTFIT;
432 /* The "fits into long" operation is relevant only for integer types */
433 switch(expr->expr_type) {
434 case ASN_BASIC_INTEGER:
435 case ASN_BASIC_ENUMERATED:
442 * First, evaluate the range of explicitly given identifiers.
444 TQ_FOR(v, &(expr->members), next) {
445 if(v->expr_type != A1TC_UNIVERVAL)
447 if(v->value->value.v_integer < LEFTMIN
448 || v->value->value.v_integer > RIGHTMAX)
452 if(!expr->combined_constraints)
453 return (arg->flags & A1C_USE_WIDE_TYPES)
454 ? FL_NOTFIT : FL_PRESUMED;
457 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
458 * applied (non-standard! but we can deal with this) to the type.
461 range = asn1constraint_compute_constraint_range(expr->Identifier,
463 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
464 CPR_simulate_fbless_SIZE);
466 if(!range->incompatible) {
467 right = range->right;
468 /* Use 4 instead of sizeof(long) is justified! */
469 if(right.type == ARE_VALUE && right.value <= 4)
470 return FL_FITS_SIGNED;
472 asn1constraint_range_free(range);
476 * Third, pull up the PER visible range of the INTEGER.
478 range = asn1constraint_compute_PER_range(expr->Identifier, expr->expr_type,
479 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
484 * because this may or may not indicate wide type.
486 || (range->extensible && (arg->flags & A1C_USE_WIDE_TYPES))
487 || range->empty_constraint
488 || range->incompatible
489 || range->not_PER_visible
491 asn1constraint_range_free(range);
492 return (arg->flags & A1C_USE_WIDE_TYPES)
493 ? FL_NOTFIT : FL_PRESUMED;
497 right = range->right;
498 asn1constraint_range_free(range);
500 /* Special case for unsigned */
501 if(!(arg->flags & A1C_USE_WIDE_TYPES) && left.type == ARE_VALUE
502 && left.value >= 0 && left.value <= 2147483647
503 && right.type == ARE_MAX) {
504 return FL_FITS_UNSIGN;
506 if(left.type == ARE_VALUE
508 && right.type == ARE_VALUE
509 && right.value > 2147483647
510 && right.value <= (asn1c_integer_t)(4294967295UL))
511 return FL_FITS_UNSIGN;
514 /* If some fixed value is outside of target range, not fit */
515 if(left.type == ARE_VALUE
516 && (left.value < LEFTMIN || left.value > RIGHTMAX))
518 if(right.type == ARE_VALUE
519 && (right.value > RIGHTMAX || right.value < LEFTMIN))
522 /* If the range is open, fits only unless -fwide-types is given */
523 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
524 return (arg->flags & A1C_USE_WIDE_TYPES)
525 ? FL_NOTFIT : FL_PRESUMED;
528 return FL_FITS_SIGNED;