blob: 5a2d2b9c4f3f0883aa86658cb0c654d28a7a6a42 [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;
Harald Welteaa37b8c2015-09-10 09:31:18 +020053 char *prefix = NULL;
54
55 if (flags & AMI_USE_PREFIX)
56 prefix = getenv("ASN1C_PREFIX");
Lev Walkinf15320b2004-06-03 03:38:44 +000057
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
Harald Welteaa37b8c2015-09-10 09:31:18 +020081 if(prefix)
82 size += 1 + strlen(prefix);
Lev Walkinf15320b2004-06-03 03:38:44 +000083 /*
84 * Make sure we have this amount of storage.
85 */
86 if(storage_size <= size) {
87 if(storage) free(storage);
88 storage = malloc(size + 1);
89 if(storage) {
90 storage_size = size;
91 } else {
92 storage_size = 0;
93 return NULL;
94 }
95 }
96
97 /*
98 * Fill-in the storage.
99 */
Lev Walkina00d6b32006-03-21 03:40:38 +0000100 va_start(ap, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +0000101 p = storage;
Harald Welteaa37b8c2015-09-10 09:31:18 +0200102 if(prefix) {
103 strcpy(storage, prefix);
104 p += strlen(prefix);
105 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000106 nextstr = "";
Harald Welteaa37b8c2015-09-10 09:31:18 +0200107 for(str = 0; str || nextstr; str = nextstr) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000108 int subst_made = 0;
Lev Walkina00d6b32006-03-21 03:40:38 +0000109 nextstr = second ? second : va_arg(ap, char *);
110
111 if(str == 0) {
112 if(expr) {
113 str = expr->Identifier;
114 first = str;
115 second = 0;
116 } else {
117 first = nextstr;
118 continue;
119 }
120 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000121
122 if(str[0] == ' ' && str[1] == '\0') {
123 *p++ = ' ';
124 nodelimiter = 1; /* No delimiter */
125 continue;
126 }
127
Lev Walkin22b5ed42006-09-13 02:51:20 +0000128 if(str != first && !nodelimiter && !(flags & AMI_NODELIMITER))
Lev Walkinf15320b2004-06-03 03:38:44 +0000129 *p++ = '_'; /* Delimiter between tokens */
130 nodelimiter = 0;
131
Lev Walkin801fabc2005-01-28 12:18:50 +0000132 /*
133 * If it is a single argument, check that it does not clash
134 * with C/C++ language keywords.
135 */
136 if((flags & AMI_CHECK_RESERVED)
Lev Walkina00d6b32006-03-21 03:40:38 +0000137 && str == first && !nextstr && reserved_keyword(str)) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000138 *p++ = toupper(*str++);
139 /* Fall through */
140 }
141
Lev Walkinf15320b2004-06-03 03:38:44 +0000142 for(; *str; str++) {
143 if(isalnum(*str)) {
144 *p++ = *str;
145 subst_made = 0;
146 } else if(!subst_made++) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000147 if((flags & AMI_MASK_ONLY_SPACES)
148 && !isspace(*str)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000149 *p ++ = *str;
150 } else {
151 *p++ = '_';
152 }
153 }
154 }
155 }
156 va_end(ap);
157 *p = '\0';
158
159 assert((p - storage) <= storage_size);
160
161 return storage;
162}
163
Lev Walkinf15320b2004-06-03 03:38:44 +0000164char *
165asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
Lev Walkina00d6b32006-03-21 03:40:38 +0000166 asn1p_expr_t *exprid = 0;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000167 asn1p_expr_t *top_parent;
Lev Walkina00d6b32006-03-21 03:40:38 +0000168 asn1p_expr_t *terminal;
Lev Walkin22b5ed42006-09-13 02:51:20 +0000169 int stdname = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000170 char *typename;
171
Lev Walkin5a8219a2004-09-08 00:28:57 +0000172 /* Rewind to the topmost parent expression */
173 if((top_parent = expr->parent_expr))
174 while(top_parent->parent_expr)
175 top_parent = top_parent->parent_expr;
176
Lev Walkin725883b2006-10-09 12:07:58 +0000177 if(0) DEBUG("asn1c_type_name(%s: 0x%x)",
178 expr->Identifier, expr->expr_type);
Lev Walkinc2a75092006-03-14 11:52:12 +0000179
Lev Walkinf15320b2004-06-03 03:38:44 +0000180 switch(expr->expr_type) {
181 case A1TC_REFERENCE:
182 typename = expr->reference->components[
183 expr->reference->comp_count-1].name;
184 if(typename[0] == '&') {
185 arg_t tmp = *arg;
186
187 /*
188 * This is a reference to a type defined in a class.
189 * Resolve it and use instead.
190 */
Lev Walkinb85a8132005-08-18 13:38:19 +0000191 tmp.expr = asn1f_class_access_ex(arg->asn,
Lev Walkina00d6b32006-03-21 03:40:38 +0000192 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
Lev Walkinc2a75092006-03-14 11:52:12 +0000193 if(!tmp.expr) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000194
Lev Walkinf15320b2004-06-03 03:38:44 +0000195 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000196 }
197
Lev Walkina00d6b32006-03-21 03:40:38 +0000198 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
199
Lev Walkinc8285712005-03-04 22:18:20 +0000200 if(_format == TNF_RSAFE) {
Lev Walkinc8285712005-03-04 22:18:20 +0000201 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
202 typename = terminal->Identifier;
203 }
204 }
205
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000206 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000207 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000208 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000209 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000210 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000211 */
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000212 if(terminal && terminal == top_parent) {
213 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000214 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000215 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000216
217 if(terminal && terminal->spec_index != -1) {
218 exprid = terminal;
219 typename = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000220 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000221
Lev Walkinf15320b2004-06-03 03:38:44 +0000222 break;
223 case ASN_BASIC_INTEGER:
224 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000225 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-08-14 02:18:27 +0000226 if((expr->expr_type == ASN_BASIC_REAL
Lev Walkin2a744a72013-03-27 01:56:23 -0700227 && !(arg->flags & A1C_USE_WIDE_TYPES))
Lev Walkin082cadc2005-08-14 02:18:27 +0000228 || asn1c_type_fits_long(arg, expr)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000229 switch(_format) {
230 case TNF_CTYPE:
231 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000232 if(expr->expr_type == ASN_BASIC_REAL)
233 return "double";
Lev Walkin8bb57a22007-12-03 13:41:36 +0000234 else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN)
235 return "unsigned long";
Lev Walkinf15320b2004-06-03 03:38:44 +0000236 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000237 return "long";
Lev Walkin22b5ed42006-09-13 02:51:20 +0000238 default:
239 typename = 0;
240 switch(expr->expr_type) {
241 case ASN_BASIC_INTEGER:
242 typename = "NativeInteger"; break;
243 case ASN_BASIC_ENUMERATED:
244 typename = "NativeEnumerated"; break;
245 case ASN_BASIC_REAL:
246 typename = "NativeReal"; break;
247 default:
248 break;
249 }
250 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000251 }
Lev Walkin22b5ed42006-09-13 02:51:20 +0000252 if(typename) {
253 if(_format != TNF_INCLUDE)
254 return typename;
255 stdname = 1;
256 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000257 }
258 }
259 /* Fall through */
260 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000261 if(expr->expr_type
262 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000263 if(_format == TNF_RSAFE)
264 _format = TNF_CTYPE;
Lev Walkin22b5ed42006-09-13 02:51:20 +0000265 stdname = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000266 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
267 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000268 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000269 typename = expr->Identifier;
270 }
271 }
272
273 switch(_format) {
274 case TNF_UNMODIFIED:
Harald Welteaa37b8c2015-09-10 09:31:18 +0200275 return asn1c_make_identifier(stdname ? AMI_MASK_ONLY_SPACES :
276 AMI_MASK_ONLY_SPACES | AMI_USE_PREFIX,
Lev Walkina00d6b32006-03-21 03:40:38 +0000277 0, exprid ? exprid->Identifier : typename, 0);
Harald Welteaa37b8c2015-09-10 09:31:18 +0200278 case TNF_INCLUDE: {
279 /* as we have the quote marks " or < preceding the type
280 * name, we cannot simply have asn1c_make_identifier
281 * generate the prefix. Then we would end up with
282 * strings like PREFIX_<foo.h>" */
283 char *prefix = getenv("ASN1C_PREFIX");
284 if (!prefix)
285 prefix = "";
Lev Walkin22b5ed42006-09-13 02:51:20 +0000286 return asn1c_make_identifier(
287 AMI_MASK_ONLY_SPACES | AMI_NODELIMITER,
Lev Walkinffd035e2010-10-16 01:26:57 -0700288 0, ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
Harald Welteaa37b8c2015-09-10 09:31:18 +0200289 ? "\"" : "<"), stdname ? "" : prefix,
Lev Walkin22b5ed42006-09-13 02:51:20 +0000290 exprid ? exprid->Identifier : typename,
Lev Walkinffd035e2010-10-16 01:26:57 -0700291 ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
292 ? ".h\"" : ".h>"), 0);
Harald Welteaa37b8c2015-09-10 09:31:18 +0200293 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000294 case TNF_SAFE:
Harald Welteaa37b8c2015-09-10 09:31:18 +0200295 return asn1c_make_identifier(stdname ? 0 : AMI_USE_PREFIX,
296 exprid, typename, 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000297 case TNF_CTYPE: /* C type */
Harald Welteaa37b8c2015-09-10 09:31:18 +0200298 return asn1c_make_identifier(stdname ? 0 : AMI_USE_PREFIX,
299 exprid, exprid?"t":typename, exprid?0:"t", 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000300 case TNF_RSAFE: /* Recursion-safe type */
Harald Welteaa37b8c2015-09-10 09:31:18 +0200301 return asn1c_make_identifier(stdname ? AMI_CHECK_RESERVED :
302 AMI_CHECK_RESERVED | AMI_USE_PREFIX, 0,
Lev Walkinc8285712005-03-04 22:18:20 +0000303 "struct", " ", typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000304 }
305
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000306 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000307 return typename;
308}
309
Lev Walkin082cadc2005-08-14 02:18:27 +0000310/*
311 * Check whether the specified INTEGER or ENUMERATED type can be represented
Lev Walkin8bb57a22007-12-03 13:41:36 +0000312 * using the generic 'long' or 'unsigned long' type.
Lev Walkin082cadc2005-08-14 02:18:27 +0000313 */
314enum asn1c_fitslong_e
315asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
316 asn1cnst_range_t *range = 0;
317 asn1cnst_edge_t left;
318 asn1cnst_edge_t right;
319 asn1p_expr_t *v;
320
321/*
322 * Since we don't know the sizeof(long) on the possible target platform
323 * which will be compiling the code generated by asn1c, let's play it
324 * simple: long's range is equal to or greater than int32_t.
Lev Walkin4c97bd62005-08-15 01:01:24 +0000325 * NOTE: the most negative integer cannot be written in C, as the C99
326 * standard will give it an unsigned type.
327 * It is defined here as a constant expression.
Lev Walkin082cadc2005-08-14 02:18:27 +0000328 */
Lev Walkinc08c3cf2005-08-15 01:04:48 +0000329#define RIGHTMAX 2147483647 /* of 32-bit integer type */
330#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
Lev Walkin082cadc2005-08-14 02:18:27 +0000331
332 /* Descend to the terminal type */
333 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
334 if(expr == 0) return FL_NOTFIT;
335
336 /* The "fits into long" operation is relevant only for integer types */
337 switch(expr->expr_type) {
338 case ASN_BASIC_INTEGER:
339 case ASN_BASIC_ENUMERATED:
340 break;
341 default:
342 return FL_NOTFIT;
343 }
344
345 /*
346 * First, evaluate the range of explicitly given identifiers.
347 */
348 TQ_FOR(v, &(expr->members), next) {
349 if(v->expr_type != A1TC_UNIVERVAL)
350 continue;
351 if(v->value->value.v_integer < LEFTMIN
352 || v->value->value.v_integer > RIGHTMAX)
353 return FL_NOTFIT;
354 }
355
Lev Walkin4b553412005-08-14 14:45:44 +0000356 if(!expr->combined_constraints)
Lev Walkin2a744a72013-03-27 01:56:23 -0700357 return (arg->flags & A1C_USE_WIDE_TYPES)
358 ? FL_NOTFIT : FL_PRESUMED;
Lev Walkin4b553412005-08-14 14:45:44 +0000359
Lev Walkin082cadc2005-08-14 02:18:27 +0000360 /*
Lev Walkin4b553412005-08-14 14:45:44 +0000361 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
362 * applied (non-standard! but we can deal with this) to the type.
363 * Check the range.
Lev Walkin082cadc2005-08-14 02:18:27 +0000364 */
Lev Walkin4b553412005-08-14 14:45:44 +0000365 range = asn1constraint_compute_PER_range(expr->expr_type,
366 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
367 CPR_simulate_fbless_SIZE);
368 if(range) {
369 if(!range->incompatible) {
370 right = range->right;
371 /* Use 4 instead of sizeof(long) is justified! */
372 if(right.type == ARE_VALUE && right.value <= 4)
Lev Walkin8bb57a22007-12-03 13:41:36 +0000373 return FL_FITS_SIGNED;
Lev Walkin4b553412005-08-14 14:45:44 +0000374 }
375 asn1constraint_range_free(range);
376 }
377
378 /*
379 * Third, pull up the PER visible range of the INTEGER.
380 */
381 range = asn1constraint_compute_PER_range(expr->expr_type,
382 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
Lev Walkine5086e32014-02-10 11:00:51 -0800383
Lev Walkin082cadc2005-08-14 02:18:27 +0000384 if(!range
Lev Walkine5086e32014-02-10 11:00:51 -0800385 /* Commenting out
386 || range->extensible
387 * because this may or may not indicate wide type.
388 */
Lev Walkin334d5cc2014-02-10 11:06:56 -0800389 || (range->extensible && (arg->flags & A1C_USE_WIDE_TYPES))
Lev Walkin082cadc2005-08-14 02:18:27 +0000390 || range->empty_constraint
Lev Walkin082cadc2005-08-14 02:18:27 +0000391 || range->incompatible
392 || range->not_PER_visible
393 ) {
394 asn1constraint_range_free(range);
Lev Walkin2a744a72013-03-27 01:56:23 -0700395 return (arg->flags & A1C_USE_WIDE_TYPES)
396 ? FL_NOTFIT : FL_PRESUMED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000397 }
398
399 left = range->left;
400 right = range->right;
401 asn1constraint_range_free(range);
402
Lev Walkin8bb57a22007-12-03 13:41:36 +0000403 /* Special case for unsigned */
404 if(left.type == ARE_VALUE
405 && left.value >= 0
406 && right.type == ARE_VALUE
Harald Welte498c9712015-08-30 16:33:07 +0200407 && right.value > 2147483647L
Lev Walkine5086e32014-02-10 11:00:51 -0800408 && right.value <= 4294967295UL)
Lev Walkin8bb57a22007-12-03 13:41:36 +0000409 return FL_FITS_UNSIGN;
410
411
Lev Walkin082cadc2005-08-14 02:18:27 +0000412 /* If some fixed value is outside of target range, not fit */
413 if(left.type == ARE_VALUE
414 && (left.value < LEFTMIN || left.value > RIGHTMAX))
415 return FL_NOTFIT;
416 if(right.type == ARE_VALUE
417 && (right.value > RIGHTMAX || right.value < LEFTMIN))
418 return FL_NOTFIT;
419
Lev Walkin2a744a72013-03-27 01:56:23 -0700420 /* If the range is open, fits only unless -fwide-types is given */
Lev Walkin082cadc2005-08-14 02:18:27 +0000421 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
Lev Walkin2a744a72013-03-27 01:56:23 -0700422 return (arg->flags & A1C_USE_WIDE_TYPES)
423 ? FL_NOTFIT : FL_PRESUMED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000424 }
425
Lev Walkin8bb57a22007-12-03 13:41:36 +0000426 return FL_FITS_SIGNED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000427}
428