blob: 90c669adc9eff423af0449ac2e943e4f82a2fdaf [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/*
Lev Walkin801fabc2005-01-28 12:18:50 +00008 * Checks that the given string is not a reserved C/C++ keyword.
Lev Walkin3fe2e122005-03-03 21:29:27 +00009 * ISO/IEC 9899:1999 (C99), A.1.2
Lev Walkin801fabc2005-01-28 12:18:50 +000010 */
11static char *res_kwd[] = {
Lev Walkin30ae27b2013-03-19 17:15:28 -070012 "auto", "break", "case", "char", "const", "continue", "default",
13 "do", "double", "else", "enum", "extern", "float", "for", "goto",
14 "if", "inline", "int", "long", "register", "restrict", "return",
15 "short", "signed", "sizeof", "static", "struct", "switch", "typedef",
16 "union", "unsigned", "void", "volatile", "while",
17 "_Bool", "_Complex", "_Imaginary",
18 /* C++ */
Lev Walkin2a744a72013-03-27 01:56:23 -070019 "class", "explicit", "bool", "mutable",
Lev Walkin30ae27b2013-03-19 17:15:28 -070020 "template", "typeid", "typename", "and", "and_eq",
21 "or", "or_eq", "xor", "xor_eq", "not", "not_eq",
22 "bitor", "compl", "bitand",
23 "const_cast", "dynamic_cast", "reinterpret_cast",
24 "static_cast", "true", "false", "namespace", "using",
25 "throw", "try", "catch"
Lev Walkin3fe2e122005-03-03 21:29:27 +000026};
Lev Walkin801fabc2005-01-28 12:18:50 +000027static int
28reserved_keyword(const char *str) {
Lev Walkinc46b7cb2006-08-18 02:27:55 +000029 size_t i;
Lev Walkin801fabc2005-01-28 12:18:50 +000030 for(i = 0 ; i < sizeof(res_kwd)/sizeof(res_kwd[0]); i++) {
31 if(strcmp(str, res_kwd[i]) == 0)
32 return 1;
33 }
34 return 0;
35}
36
37/*
Lev Walkinf15320b2004-06-03 03:38:44 +000038 * Construct identifier from multiple parts.
39 * Convert unsafe characters to underscores.
40 */
41char *
Lev Walkina00d6b32006-03-21 03:40:38 +000042asn1c_make_identifier(enum ami_flags_e flags, asn1p_expr_t *expr, ...) {
Lev Walkinf15320b2004-06-03 03:38:44 +000043 static char *storage;
44 static int storage_size;
45 int nodelimiter = 0;
46 va_list ap;
47 char *str;
Lev Walkin801fabc2005-01-28 12:18:50 +000048 char *nextstr;
Lev Walkina00d6b32006-03-21 03:40:38 +000049 char *first = 0;
50 char *second = 0;
Lev Walkinc46b7cb2006-08-18 02:27:55 +000051 ssize_t size;
Lev Walkinf15320b2004-06-03 03:38:44 +000052 char *p;
53
Lev Walkina00d6b32006-03-21 03:40:38 +000054 if(expr) {
55 /*
56 * Estimate the necessary storage size
57 */
58 if(expr->Identifier == NULL)
59 return "Member";
60 size = strlen(expr->Identifier);
61 if(expr->spec_index != -1) {
62 static char buf[32];
63 second = buf;
64 size += 1 + snprintf(buf, sizeof buf, "%dP%d",
65 expr->_lineno, expr->spec_index);
66 }
67 } else {
68 size = -1;
69 }
Lev Walkinf15320b2004-06-03 03:38:44 +000070
Lev Walkina00d6b32006-03-21 03:40:38 +000071 va_start(ap, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +000072 while((str = va_arg(ap, char *)))
73 size += 1 + strlen(str);
74 va_end(ap);
Lev Walkina00d6b32006-03-21 03:40:38 +000075 if(size == -1) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +000076
77 /*
78 * Make sure we have this amount of storage.
79 */
80 if(storage_size <= size) {
Lev Walkind8b83642016-03-14 02:00:27 -070081 free(storage);
Lev Walkinf15320b2004-06-03 03:38:44 +000082 storage = malloc(size + 1);
83 if(storage) {
84 storage_size = size;
85 } else {
86 storage_size = 0;
87 return NULL;
88 }
89 }
90
91 /*
92 * Fill-in the storage.
93 */
Lev Walkina00d6b32006-03-21 03:40:38 +000094 va_start(ap, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +000095 p = storage;
Lev Walkina00d6b32006-03-21 03:40:38 +000096 nextstr = "";
97 for(p = storage, str = 0; str || nextstr; str = nextstr) {
Lev Walkinf15320b2004-06-03 03:38:44 +000098 int subst_made = 0;
Lev Walkina00d6b32006-03-21 03:40:38 +000099 nextstr = second ? second : va_arg(ap, char *);
100
101 if(str == 0) {
102 if(expr) {
103 str = expr->Identifier;
104 first = str;
105 second = 0;
106 } else {
107 first = nextstr;
108 continue;
109 }
110 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000111
112 if(str[0] == ' ' && str[1] == '\0') {
113 *p++ = ' ';
114 nodelimiter = 1; /* No delimiter */
115 continue;
116 }
117
Lev Walkin22b5ed42006-09-13 02:51:20 +0000118 if(str != first && !nodelimiter && !(flags & AMI_NODELIMITER))
Lev Walkinf15320b2004-06-03 03:38:44 +0000119 *p++ = '_'; /* Delimiter between tokens */
120 nodelimiter = 0;
121
Lev Walkin801fabc2005-01-28 12:18:50 +0000122 /*
123 * If it is a single argument, check that it does not clash
124 * with C/C++ language keywords.
125 */
126 if((flags & AMI_CHECK_RESERVED)
Lev Walkina00d6b32006-03-21 03:40:38 +0000127 && str == first && !nextstr && reserved_keyword(str)) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000128 *p++ = toupper(*str++);
129 /* Fall through */
130 }
131
Lev Walkinf15320b2004-06-03 03:38:44 +0000132 for(; *str; str++) {
133 if(isalnum(*str)) {
134 *p++ = *str;
135 subst_made = 0;
136 } else if(!subst_made++) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000137 if((flags & AMI_MASK_ONLY_SPACES)
138 && !isspace(*str)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000139 *p ++ = *str;
140 } else {
141 *p++ = '_';
142 }
143 }
144 }
145 }
146 va_end(ap);
147 *p = '\0';
148
149 assert((p - storage) <= storage_size);
150
151 return storage;
152}
153
Lev Walkinf15320b2004-06-03 03:38:44 +0000154char *
155asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
Lev Walkina00d6b32006-03-21 03:40:38 +0000156 asn1p_expr_t *exprid = 0;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000157 asn1p_expr_t *top_parent;
Lev Walkina00d6b32006-03-21 03:40:38 +0000158 asn1p_expr_t *terminal;
Lev Walkin22b5ed42006-09-13 02:51:20 +0000159 int stdname = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000160 char *typename;
161
Lev Walkin5a8219a2004-09-08 00:28:57 +0000162 /* Rewind to the topmost parent expression */
163 if((top_parent = expr->parent_expr))
164 while(top_parent->parent_expr)
165 top_parent = top_parent->parent_expr;
166
Lev Walkin725883b2006-10-09 12:07:58 +0000167 if(0) DEBUG("asn1c_type_name(%s: 0x%x)",
168 expr->Identifier, expr->expr_type);
Lev Walkinc2a75092006-03-14 11:52:12 +0000169
Lev Walkinf15320b2004-06-03 03:38:44 +0000170 switch(expr->expr_type) {
171 case A1TC_REFERENCE:
172 typename = expr->reference->components[
173 expr->reference->comp_count-1].name;
174 if(typename[0] == '&') {
175 arg_t tmp = *arg;
176
177 /*
178 * This is a reference to a type defined in a class.
179 * Resolve it and use instead.
180 */
Lev Walkinb85a8132005-08-18 13:38:19 +0000181 tmp.expr = asn1f_class_access_ex(arg->asn,
Lev Walkina00d6b32006-03-21 03:40:38 +0000182 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
Lev Walkinc2a75092006-03-14 11:52:12 +0000183 if(!tmp.expr) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000184
Lev Walkinf15320b2004-06-03 03:38:44 +0000185 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000186 }
187
Lev Walkina00d6b32006-03-21 03:40:38 +0000188 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
189
Lev Walkinc8285712005-03-04 22:18:20 +0000190 if(_format == TNF_RSAFE) {
Lev Walkinc8285712005-03-04 22:18:20 +0000191 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
192 typename = terminal->Identifier;
193 }
194 }
195
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000196 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000197 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000198 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000199 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000200 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000201 */
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000202 if(terminal && terminal == top_parent) {
203 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000204 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000205 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000206
207 if(terminal && terminal->spec_index != -1) {
208 exprid = terminal;
209 typename = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000210 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000211
Lev Walkinf15320b2004-06-03 03:38:44 +0000212 break;
213 case ASN_BASIC_INTEGER:
214 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000215 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-08-14 02:18:27 +0000216 if((expr->expr_type == ASN_BASIC_REAL
Lev Walkin2a744a72013-03-27 01:56:23 -0700217 && !(arg->flags & A1C_USE_WIDE_TYPES))
Lev Walkin082cadc2005-08-14 02:18:27 +0000218 || asn1c_type_fits_long(arg, expr)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000219 switch(_format) {
220 case TNF_CTYPE:
221 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000222 if(expr->expr_type == ASN_BASIC_REAL)
223 return "double";
Lev Walkin8bb57a22007-12-03 13:41:36 +0000224 else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN)
225 return "unsigned long";
Lev Walkinf15320b2004-06-03 03:38:44 +0000226 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000227 return "long";
Lev Walkin22b5ed42006-09-13 02:51:20 +0000228 default:
229 typename = 0;
230 switch(expr->expr_type) {
231 case ASN_BASIC_INTEGER:
232 typename = "NativeInteger"; break;
233 case ASN_BASIC_ENUMERATED:
234 typename = "NativeEnumerated"; break;
235 case ASN_BASIC_REAL:
236 typename = "NativeReal"; break;
237 default:
238 break;
239 }
240 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000241 }
Lev Walkin22b5ed42006-09-13 02:51:20 +0000242 if(typename) {
243 if(_format != TNF_INCLUDE)
244 return typename;
245 stdname = 1;
246 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000247 }
248 }
249 /* Fall through */
250 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000251 if(expr->expr_type
252 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000253 if(_format == TNF_RSAFE)
254 _format = TNF_CTYPE;
Lev Walkin22b5ed42006-09-13 02:51:20 +0000255 stdname = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000256 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
257 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000258 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000259 typename = expr->Identifier;
260 }
261 }
262
263 switch(_format) {
264 case TNF_UNMODIFIED:
Lev Walkina00d6b32006-03-21 03:40:38 +0000265 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES,
Vasil Velichkovfebd3d52016-07-18 20:24:49 +0300266 0, exprid ? exprid->Identifier : typename, (char*)0);
Lev Walkin22b5ed42006-09-13 02:51:20 +0000267 case TNF_INCLUDE:
268 return asn1c_make_identifier(
269 AMI_MASK_ONLY_SPACES | AMI_NODELIMITER,
Lev Walkinffd035e2010-10-16 01:26:57 -0700270 0, ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
271 ? "\"" : "<"),
Lev Walkin22b5ed42006-09-13 02:51:20 +0000272 exprid ? exprid->Identifier : typename,
Lev Walkinffd035e2010-10-16 01:26:57 -0700273 ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
Vasil Velichkovfebd3d52016-07-18 20:24:49 +0300274 ? ".h\"" : ".h>"), (char*)0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000275 case TNF_SAFE:
Vasil Velichkovfebd3d52016-07-18 20:24:49 +0300276 return asn1c_make_identifier(0, exprid, typename, (char*)0);
Lev Walkinc8285712005-03-04 22:18:20 +0000277 case TNF_CTYPE: /* C type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000278 return asn1c_make_identifier(0, exprid,
Vasil Velichkovfebd3d52016-07-18 20:24:49 +0300279 exprid?"t":typename, exprid?0:"t", (char*)0);
Lev Walkinc8285712005-03-04 22:18:20 +0000280 case TNF_RSAFE: /* Recursion-safe type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000281 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
Vasil Velichkovfebd3d52016-07-18 20:24:49 +0300282 "struct", " ", typename, (char*)0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000283 }
284
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000285 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000286 return typename;
287}
288
Lev Walkin082cadc2005-08-14 02:18:27 +0000289/*
290 * Check whether the specified INTEGER or ENUMERATED type can be represented
Lev Walkin8bb57a22007-12-03 13:41:36 +0000291 * using the generic 'long' or 'unsigned long' type.
Lev Walkin082cadc2005-08-14 02:18:27 +0000292 */
293enum asn1c_fitslong_e
294asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
295 asn1cnst_range_t *range = 0;
296 asn1cnst_edge_t left;
297 asn1cnst_edge_t right;
298 asn1p_expr_t *v;
299
300/*
301 * Since we don't know the sizeof(long) on the possible target platform
302 * which will be compiling the code generated by asn1c, let's play it
303 * simple: long's range is equal to or greater than int32_t.
Lev Walkin4c97bd62005-08-15 01:01:24 +0000304 * NOTE: the most negative integer cannot be written in C, as the C99
305 * standard will give it an unsigned type.
306 * It is defined here as a constant expression.
Lev Walkin082cadc2005-08-14 02:18:27 +0000307 */
Lev Walkinc08c3cf2005-08-15 01:04:48 +0000308#define RIGHTMAX 2147483647 /* of 32-bit integer type */
309#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
Lev Walkin082cadc2005-08-14 02:18:27 +0000310
311 /* Descend to the terminal type */
312 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
313 if(expr == 0) return FL_NOTFIT;
314
315 /* The "fits into long" operation is relevant only for integer types */
316 switch(expr->expr_type) {
317 case ASN_BASIC_INTEGER:
318 case ASN_BASIC_ENUMERATED:
319 break;
320 default:
321 return FL_NOTFIT;
322 }
323
324 /*
325 * First, evaluate the range of explicitly given identifiers.
326 */
327 TQ_FOR(v, &(expr->members), next) {
328 if(v->expr_type != A1TC_UNIVERVAL)
329 continue;
330 if(v->value->value.v_integer < LEFTMIN
331 || v->value->value.v_integer > RIGHTMAX)
332 return FL_NOTFIT;
333 }
334
Lev Walkin4b553412005-08-14 14:45:44 +0000335 if(!expr->combined_constraints)
Lev Walkin2a744a72013-03-27 01:56:23 -0700336 return (arg->flags & A1C_USE_WIDE_TYPES)
337 ? FL_NOTFIT : FL_PRESUMED;
Lev Walkin4b553412005-08-14 14:45:44 +0000338
Lev Walkin082cadc2005-08-14 02:18:27 +0000339 /*
Lev Walkin4b553412005-08-14 14:45:44 +0000340 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
341 * applied (non-standard! but we can deal with this) to the type.
342 * Check the range.
Lev Walkin082cadc2005-08-14 02:18:27 +0000343 */
Lev Walkin4b553412005-08-14 14:45:44 +0000344 range = asn1constraint_compute_PER_range(expr->expr_type,
345 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
346 CPR_simulate_fbless_SIZE);
347 if(range) {
348 if(!range->incompatible) {
349 right = range->right;
350 /* Use 4 instead of sizeof(long) is justified! */
351 if(right.type == ARE_VALUE && right.value <= 4)
Lev Walkin8bb57a22007-12-03 13:41:36 +0000352 return FL_FITS_SIGNED;
Lev Walkin4b553412005-08-14 14:45:44 +0000353 }
354 asn1constraint_range_free(range);
355 }
356
357 /*
358 * Third, pull up the PER visible range of the INTEGER.
359 */
360 range = asn1constraint_compute_PER_range(expr->expr_type,
361 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
Lev Walkine5086e32014-02-10 11:00:51 -0800362
Lev Walkin082cadc2005-08-14 02:18:27 +0000363 if(!range
Lev Walkine5086e32014-02-10 11:00:51 -0800364 /* Commenting out
365 || range->extensible
366 * because this may or may not indicate wide type.
367 */
Lev Walkin334d5cc2014-02-10 11:06:56 -0800368 || (range->extensible && (arg->flags & A1C_USE_WIDE_TYPES))
Lev Walkin082cadc2005-08-14 02:18:27 +0000369 || range->empty_constraint
Lev Walkin082cadc2005-08-14 02:18:27 +0000370 || range->incompatible
371 || range->not_PER_visible
372 ) {
373 asn1constraint_range_free(range);
Lev Walkin2a744a72013-03-27 01:56:23 -0700374 return (arg->flags & A1C_USE_WIDE_TYPES)
375 ? FL_NOTFIT : FL_PRESUMED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000376 }
377
378 left = range->left;
379 right = range->right;
380 asn1constraint_range_free(range);
381
Lev Walkin8bb57a22007-12-03 13:41:36 +0000382 /* Special case for unsigned */
383 if(left.type == ARE_VALUE
384 && left.value >= 0
385 && right.type == ARE_VALUE
386 && right.value > 2147483647
Lev Walkin1b3a1352016-01-10 13:15:02 -0800387 && right.value <= (asn1c_integer_t)(4294967295UL))
Lev Walkin8bb57a22007-12-03 13:41:36 +0000388 return FL_FITS_UNSIGN;
389
390
Lev Walkin082cadc2005-08-14 02:18:27 +0000391 /* If some fixed value is outside of target range, not fit */
392 if(left.type == ARE_VALUE
393 && (left.value < LEFTMIN || left.value > RIGHTMAX))
394 return FL_NOTFIT;
395 if(right.type == ARE_VALUE
396 && (right.value > RIGHTMAX || right.value < LEFTMIN))
397 return FL_NOTFIT;
398
Lev Walkin2a744a72013-03-27 01:56:23 -0700399 /* If the range is open, fits only unless -fwide-types is given */
Lev Walkin082cadc2005-08-14 02:18:27 +0000400 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
Lev Walkin2a744a72013-03-27 01:56:23 -0700401 return (arg->flags & A1C_USE_WIDE_TYPES)
402 ? FL_NOTFIT : FL_PRESUMED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000403 }
404
Lev Walkin8bb57a22007-12-03 13:41:36 +0000405 return FL_FITS_SIGNED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000406}
407