blob: a60553b8527ceead2331430a7c8645ec9c0113f6 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include "asn1c_internal.h"
Lev Walkin59004fa2004-08-20 13:37:01 +00002#include "asn1c_misc.h"
3
Lev Walkin082cadc2005-08-14 02:18:27 +00004#include <asn1fix_crange.h> /* constraint groker from libasn1fix */
5#include <asn1fix_export.h> /* other exportable stuff from libasn1fix */
Lev Walkinf15320b2004-06-03 03:38:44 +00006
Lev Walkinf15320b2004-06-03 03:38:44 +00007/*
Ozbolt Menegatti11a3d682016-10-24 15:22:57 +02008 * 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
Lev Walkin801fabc2005-01-28 12:18:50 +000013 */
14static char *res_kwd[] = {
Ozbolt Menegatti11a3d682016-10-24 15:22:57 +020015 /* C */
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",
21 /* C++ */
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"
Lev Walkin3fe2e122005-03-03 21:29:27 +000030};
Lev Walkin801fabc2005-01-28 12:18:50 +000031static int
32reserved_keyword(const char *str) {
Lev Walkinc46b7cb2006-08-18 02:27:55 +000033 size_t i;
Lev Walkin801fabc2005-01-28 12:18:50 +000034 for(i = 0 ; i < sizeof(res_kwd)/sizeof(res_kwd[0]); i++) {
35 if(strcmp(str, res_kwd[i]) == 0)
36 return 1;
37 }
38 return 0;
39}
40
41/*
Lev Walkinf15320b2004-06-03 03:38:44 +000042 * Construct identifier from multiple parts.
43 * Convert unsafe characters to underscores.
44 */
45char *
Lev Walkina00d6b32006-03-21 03:40:38 +000046asn1c_make_identifier(enum ami_flags_e flags, asn1p_expr_t *expr, ...) {
Lev Walkinf15320b2004-06-03 03:38:44 +000047 static char *storage;
48 static int storage_size;
49 int nodelimiter = 0;
50 va_list ap;
51 char *str;
Lev Walkin801fabc2005-01-28 12:18:50 +000052 char *nextstr;
Lev Walkina00d6b32006-03-21 03:40:38 +000053 char *first = 0;
54 char *second = 0;
Lev Walkinc46b7cb2006-08-18 02:27:55 +000055 ssize_t size;
Lev Walkinf15320b2004-06-03 03:38:44 +000056 char *p;
57
Lev Walkina00d6b32006-03-21 03:40:38 +000058 if(expr) {
59 /*
60 * Estimate the necessary storage size
61 */
62 if(expr->Identifier == NULL)
63 return "Member";
64 size = strlen(expr->Identifier);
65 if(expr->spec_index != -1) {
66 static char buf[32];
67 second = buf;
68 size += 1 + snprintf(buf, sizeof buf, "%dP%d",
69 expr->_lineno, expr->spec_index);
70 }
71 } else {
72 size = -1;
73 }
Lev Walkinf15320b2004-06-03 03:38:44 +000074
Lev Walkina00d6b32006-03-21 03:40:38 +000075 va_start(ap, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +000076 while((str = va_arg(ap, char *)))
77 size += 1 + strlen(str);
78 va_end(ap);
Lev Walkina00d6b32006-03-21 03:40:38 +000079 if(size == -1) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +000080
81 /*
82 * Make sure we have this amount of storage.
83 */
84 if(storage_size <= size) {
Lev Walkind8b83642016-03-14 02:00:27 -070085 free(storage);
Lev Walkinf15320b2004-06-03 03:38:44 +000086 storage = malloc(size + 1);
87 if(storage) {
88 storage_size = size;
89 } else {
90 storage_size = 0;
91 return NULL;
92 }
93 }
94
95 /*
96 * Fill-in the storage.
97 */
Lev Walkina00d6b32006-03-21 03:40:38 +000098 va_start(ap, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +000099 p = storage;
Lev Walkina00d6b32006-03-21 03:40:38 +0000100 nextstr = "";
101 for(p = storage, str = 0; str || nextstr; str = nextstr) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000102 int subst_made = 0;
Lev Walkina00d6b32006-03-21 03:40:38 +0000103 nextstr = second ? second : va_arg(ap, char *);
104
105 if(str == 0) {
106 if(expr) {
107 str = expr->Identifier;
108 first = str;
109 second = 0;
110 } else {
111 first = nextstr;
112 continue;
113 }
114 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000115
116 if(str[0] == ' ' && str[1] == '\0') {
117 *p++ = ' ';
118 nodelimiter = 1; /* No delimiter */
119 continue;
120 }
121
Lev Walkin22b5ed42006-09-13 02:51:20 +0000122 if(str != first && !nodelimiter && !(flags & AMI_NODELIMITER))
Lev Walkinf15320b2004-06-03 03:38:44 +0000123 *p++ = '_'; /* Delimiter between tokens */
124 nodelimiter = 0;
125
Lev Walkin801fabc2005-01-28 12:18:50 +0000126 /*
127 * If it is a single argument, check that it does not clash
128 * with C/C++ language keywords.
129 */
130 if((flags & AMI_CHECK_RESERVED)
Lev Walkina00d6b32006-03-21 03:40:38 +0000131 && str == first && !nextstr && reserved_keyword(str)) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000132 *p++ = toupper(*str++);
133 /* Fall through */
134 }
135
Lev Walkinf15320b2004-06-03 03:38:44 +0000136 for(; *str; str++) {
137 if(isalnum(*str)) {
138 *p++ = *str;
139 subst_made = 0;
140 } else if(!subst_made++) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000141 if((flags & AMI_MASK_ONLY_SPACES)
142 && !isspace(*str)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000143 *p ++ = *str;
144 } else {
145 *p++ = '_';
146 }
147 }
148 }
149 }
150 va_end(ap);
151 *p = '\0';
152
153 assert((p - storage) <= storage_size);
154
155 return storage;
156}
157
Lev Walkinf15320b2004-06-03 03:38:44 +0000158char *
159asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
Lev Walkina00d6b32006-03-21 03:40:38 +0000160 asn1p_expr_t *exprid = 0;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000161 asn1p_expr_t *top_parent;
Lev Walkina00d6b32006-03-21 03:40:38 +0000162 asn1p_expr_t *terminal;
Lev Walkin22b5ed42006-09-13 02:51:20 +0000163 int stdname = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000164 char *typename;
165
Lev Walkin5a8219a2004-09-08 00:28:57 +0000166 /* Rewind to the topmost parent expression */
167 if((top_parent = expr->parent_expr))
168 while(top_parent->parent_expr)
169 top_parent = top_parent->parent_expr;
170
Lev Walkin725883b2006-10-09 12:07:58 +0000171 if(0) DEBUG("asn1c_type_name(%s: 0x%x)",
172 expr->Identifier, expr->expr_type);
Lev Walkinc2a75092006-03-14 11:52:12 +0000173
Lev Walkinf15320b2004-06-03 03:38:44 +0000174 switch(expr->expr_type) {
175 case A1TC_REFERENCE:
176 typename = expr->reference->components[
177 expr->reference->comp_count-1].name;
178 if(typename[0] == '&') {
179 arg_t tmp = *arg;
180
181 /*
182 * This is a reference to a type defined in a class.
183 * Resolve it and use instead.
184 */
Lev Walkinb85a8132005-08-18 13:38:19 +0000185 tmp.expr = asn1f_class_access_ex(arg->asn,
Lev Walkina00d6b32006-03-21 03:40:38 +0000186 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
Lev Walkinc2a75092006-03-14 11:52:12 +0000187 if(!tmp.expr) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000188
Lev Walkinf15320b2004-06-03 03:38:44 +0000189 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000190 }
191
Lev Walkina00d6b32006-03-21 03:40:38 +0000192 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
193
Lev Walkinc8285712005-03-04 22:18:20 +0000194 if(_format == TNF_RSAFE) {
Lev Walkinc8285712005-03-04 22:18:20 +0000195 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
196 typename = terminal->Identifier;
197 }
198 }
199
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000200 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000201 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000202 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000203 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000204 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000205 */
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000206 if(terminal && terminal == top_parent) {
207 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000208 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000209 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000210
211 if(terminal && terminal->spec_index != -1) {
212 exprid = terminal;
213 typename = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000214 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000215
Lev Walkinf15320b2004-06-03 03:38:44 +0000216 break;
217 case ASN_BASIC_INTEGER:
218 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000219 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-08-14 02:18:27 +0000220 if((expr->expr_type == ASN_BASIC_REAL
Lev Walkin2a744a72013-03-27 01:56:23 -0700221 && !(arg->flags & A1C_USE_WIDE_TYPES))
Lev Walkin082cadc2005-08-14 02:18:27 +0000222 || asn1c_type_fits_long(arg, expr)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000223 switch(_format) {
224 case TNF_CTYPE:
225 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000226 if(expr->expr_type == ASN_BASIC_REAL)
227 return "double";
Lev Walkin8bb57a22007-12-03 13:41:36 +0000228 else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN)
229 return "unsigned long";
Lev Walkinf15320b2004-06-03 03:38:44 +0000230 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000231 return "long";
Lev Walkin22b5ed42006-09-13 02:51:20 +0000232 default:
233 typename = 0;
234 switch(expr->expr_type) {
235 case ASN_BASIC_INTEGER:
236 typename = "NativeInteger"; break;
237 case ASN_BASIC_ENUMERATED:
238 typename = "NativeEnumerated"; break;
239 case ASN_BASIC_REAL:
240 typename = "NativeReal"; break;
241 default:
242 break;
243 }
244 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000245 }
Lev Walkin22b5ed42006-09-13 02:51:20 +0000246 if(typename) {
247 if(_format != TNF_INCLUDE)
248 return typename;
249 stdname = 1;
250 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000251 }
252 }
253 /* Fall through */
254 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000255 if(expr->expr_type
256 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000257 if(_format == TNF_RSAFE)
258 _format = TNF_CTYPE;
Lev Walkin22b5ed42006-09-13 02:51:20 +0000259 stdname = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000260 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
261 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000262 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000263 typename = expr->Identifier;
264 }
265 }
266
267 switch(_format) {
268 case TNF_UNMODIFIED:
Lev Walkina00d6b32006-03-21 03:40:38 +0000269 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES,
270 0, exprid ? exprid->Identifier : typename, 0);
Lev Walkin22b5ed42006-09-13 02:51:20 +0000271 case TNF_INCLUDE:
272 return asn1c_make_identifier(
273 AMI_MASK_ONLY_SPACES | AMI_NODELIMITER,
Lev Walkinffd035e2010-10-16 01:26:57 -0700274 0, ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
275 ? "\"" : "<"),
Lev Walkin22b5ed42006-09-13 02:51:20 +0000276 exprid ? exprid->Identifier : typename,
Lev Walkinffd035e2010-10-16 01:26:57 -0700277 ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
278 ? ".h\"" : ".h>"), 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000279 case TNF_SAFE:
Lev Walkina00d6b32006-03-21 03:40:38 +0000280 return asn1c_make_identifier(0, exprid, typename, 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000281 case TNF_CTYPE: /* C type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000282 return asn1c_make_identifier(0, exprid,
283 exprid?"t":typename, exprid?0:"t", 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000284 case TNF_RSAFE: /* Recursion-safe type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000285 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
Lev Walkinc8285712005-03-04 22:18:20 +0000286 "struct", " ", typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000287 }
288
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000289 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000290 return typename;
291}
292
Lev Walkin082cadc2005-08-14 02:18:27 +0000293/*
294 * Check whether the specified INTEGER or ENUMERATED type can be represented
Lev Walkin8bb57a22007-12-03 13:41:36 +0000295 * using the generic 'long' or 'unsigned long' type.
Lev Walkin082cadc2005-08-14 02:18:27 +0000296 */
297enum asn1c_fitslong_e
298asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
299 asn1cnst_range_t *range = 0;
300 asn1cnst_edge_t left;
301 asn1cnst_edge_t right;
302 asn1p_expr_t *v;
303
304/*
305 * Since we don't know the sizeof(long) on the possible target platform
306 * which will be compiling the code generated by asn1c, let's play it
307 * simple: long's range is equal to or greater than int32_t.
Lev Walkin4c97bd62005-08-15 01:01:24 +0000308 * NOTE: the most negative integer cannot be written in C, as the C99
309 * standard will give it an unsigned type.
310 * It is defined here as a constant expression.
Lev Walkin082cadc2005-08-14 02:18:27 +0000311 */
Lev Walkinc08c3cf2005-08-15 01:04:48 +0000312#define RIGHTMAX 2147483647 /* of 32-bit integer type */
313#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
Lev Walkin082cadc2005-08-14 02:18:27 +0000314
315 /* Descend to the terminal type */
316 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
317 if(expr == 0) return FL_NOTFIT;
318
319 /* The "fits into long" operation is relevant only for integer types */
320 switch(expr->expr_type) {
321 case ASN_BASIC_INTEGER:
322 case ASN_BASIC_ENUMERATED:
323 break;
324 default:
325 return FL_NOTFIT;
326 }
327
328 /*
329 * First, evaluate the range of explicitly given identifiers.
330 */
331 TQ_FOR(v, &(expr->members), next) {
332 if(v->expr_type != A1TC_UNIVERVAL)
333 continue;
334 if(v->value->value.v_integer < LEFTMIN
335 || v->value->value.v_integer > RIGHTMAX)
336 return FL_NOTFIT;
337 }
338
Lev Walkin4b553412005-08-14 14:45:44 +0000339 if(!expr->combined_constraints)
Lev Walkin2a744a72013-03-27 01:56:23 -0700340 return (arg->flags & A1C_USE_WIDE_TYPES)
341 ? FL_NOTFIT : FL_PRESUMED;
Lev Walkin4b553412005-08-14 14:45:44 +0000342
Lev Walkin082cadc2005-08-14 02:18:27 +0000343 /*
Lev Walkin4b553412005-08-14 14:45:44 +0000344 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
345 * applied (non-standard! but we can deal with this) to the type.
346 * Check the range.
Lev Walkin082cadc2005-08-14 02:18:27 +0000347 */
Lev Walkin4b553412005-08-14 14:45:44 +0000348 range = asn1constraint_compute_PER_range(expr->expr_type,
349 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
350 CPR_simulate_fbless_SIZE);
351 if(range) {
352 if(!range->incompatible) {
353 right = range->right;
354 /* Use 4 instead of sizeof(long) is justified! */
355 if(right.type == ARE_VALUE && right.value <= 4)
Lev Walkin8bb57a22007-12-03 13:41:36 +0000356 return FL_FITS_SIGNED;
Lev Walkin4b553412005-08-14 14:45:44 +0000357 }
358 asn1constraint_range_free(range);
359 }
360
361 /*
362 * Third, pull up the PER visible range of the INTEGER.
363 */
364 range = asn1constraint_compute_PER_range(expr->expr_type,
365 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
Lev Walkine5086e32014-02-10 11:00:51 -0800366
Lev Walkin082cadc2005-08-14 02:18:27 +0000367 if(!range
Lev Walkine5086e32014-02-10 11:00:51 -0800368 /* Commenting out
369 || range->extensible
370 * because this may or may not indicate wide type.
371 */
Lev Walkin334d5cc2014-02-10 11:06:56 -0800372 || (range->extensible && (arg->flags & A1C_USE_WIDE_TYPES))
Lev Walkin082cadc2005-08-14 02:18:27 +0000373 || range->empty_constraint
Lev Walkin082cadc2005-08-14 02:18:27 +0000374 || range->incompatible
375 || range->not_PER_visible
376 ) {
377 asn1constraint_range_free(range);
Lev Walkin2a744a72013-03-27 01:56:23 -0700378 return (arg->flags & A1C_USE_WIDE_TYPES)
379 ? FL_NOTFIT : FL_PRESUMED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000380 }
381
382 left = range->left;
383 right = range->right;
384 asn1constraint_range_free(range);
385
Lev Walkin8bb57a22007-12-03 13:41:36 +0000386 /* Special case for unsigned */
387 if(left.type == ARE_VALUE
388 && left.value >= 0
389 && right.type == ARE_VALUE
390 && right.value > 2147483647
Lev Walkin1b3a1352016-01-10 13:15:02 -0800391 && right.value <= (asn1c_integer_t)(4294967295UL))
Lev Walkin8bb57a22007-12-03 13:41:36 +0000392 return FL_FITS_UNSIGN;
393
394
Lev Walkin082cadc2005-08-14 02:18:27 +0000395 /* If some fixed value is outside of target range, not fit */
396 if(left.type == ARE_VALUE
397 && (left.value < LEFTMIN || left.value > RIGHTMAX))
398 return FL_NOTFIT;
399 if(right.type == ARE_VALUE
400 && (right.value > RIGHTMAX || right.value < LEFTMIN))
401 return FL_NOTFIT;
402
Lev Walkin2a744a72013-03-27 01:56:23 -0700403 /* If the range is open, fits only unless -fwide-types is given */
Lev Walkin082cadc2005-08-14 02:18:27 +0000404 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
Lev Walkin2a744a72013-03-27 01:56:23 -0700405 return (arg->flags & A1C_USE_WIDE_TYPES)
406 ? FL_NOTFIT : FL_PRESUMED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000407 }
408
Lev Walkin8bb57a22007-12-03 13:41:36 +0000409 return FL_FITS_SIGNED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000410}
411