blob: f48ab081e3c8cc0b5f68ac69511d816ea4d28443 [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 Walkin3fe2e122005-03-03 21:29:27 +000012 "const", "auto", "register", "volatile", "restrict", "extern",
13 "static", "inline",
14 "signed", "unsigned",
15 "void", "char", "short", "int", "long", "float", "double",
16 "enum", "union", "struct", "typedef", "class",
17 "switch", "case", "default", "break", "continue",
18 "if", "else", "do", "for", "while", "goto",
19 "sizeof", "return"
20};
Lev Walkin801fabc2005-01-28 12:18:50 +000021static int
22reserved_keyword(const char *str) {
Lev Walkinc46b7cb2006-08-18 02:27:55 +000023 size_t i;
Lev Walkin801fabc2005-01-28 12:18:50 +000024 for(i = 0 ; i < sizeof(res_kwd)/sizeof(res_kwd[0]); i++) {
25 if(strcmp(str, res_kwd[i]) == 0)
26 return 1;
27 }
28 return 0;
29}
30
31/*
Lev Walkinf15320b2004-06-03 03:38:44 +000032 * Construct identifier from multiple parts.
33 * Convert unsafe characters to underscores.
34 */
35char *
Lev Walkina00d6b32006-03-21 03:40:38 +000036asn1c_make_identifier(enum ami_flags_e flags, asn1p_expr_t *expr, ...) {
Lev Walkinf15320b2004-06-03 03:38:44 +000037 static char *storage;
38 static int storage_size;
39 int nodelimiter = 0;
40 va_list ap;
41 char *str;
Lev Walkin801fabc2005-01-28 12:18:50 +000042 char *nextstr;
Lev Walkina00d6b32006-03-21 03:40:38 +000043 char *first = 0;
44 char *second = 0;
Lev Walkinc46b7cb2006-08-18 02:27:55 +000045 ssize_t size;
Lev Walkinf15320b2004-06-03 03:38:44 +000046 char *p;
47
Lev Walkina00d6b32006-03-21 03:40:38 +000048 if(expr) {
49 /*
50 * Estimate the necessary storage size
51 */
52 if(expr->Identifier == NULL)
53 return "Member";
54 size = strlen(expr->Identifier);
55 if(expr->spec_index != -1) {
56 static char buf[32];
57 second = buf;
58 size += 1 + snprintf(buf, sizeof buf, "%dP%d",
59 expr->_lineno, expr->spec_index);
60 }
61 } else {
62 size = -1;
63 }
Lev Walkinf15320b2004-06-03 03:38:44 +000064
Lev Walkina00d6b32006-03-21 03:40:38 +000065 va_start(ap, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +000066 while((str = va_arg(ap, char *)))
67 size += 1 + strlen(str);
68 va_end(ap);
Lev Walkina00d6b32006-03-21 03:40:38 +000069 if(size == -1) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +000070
71 /*
72 * Make sure we have this amount of storage.
73 */
74 if(storage_size <= size) {
75 if(storage) free(storage);
76 storage = malloc(size + 1);
77 if(storage) {
78 storage_size = size;
79 } else {
80 storage_size = 0;
81 return NULL;
82 }
83 }
84
85 /*
86 * Fill-in the storage.
87 */
Lev Walkina00d6b32006-03-21 03:40:38 +000088 va_start(ap, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +000089 p = storage;
Lev Walkina00d6b32006-03-21 03:40:38 +000090 nextstr = "";
91 for(p = storage, str = 0; str || nextstr; str = nextstr) {
Lev Walkinf15320b2004-06-03 03:38:44 +000092 int subst_made = 0;
Lev Walkina00d6b32006-03-21 03:40:38 +000093 nextstr = second ? second : va_arg(ap, char *);
94
95 if(str == 0) {
96 if(expr) {
97 str = expr->Identifier;
98 first = str;
99 second = 0;
100 } else {
101 first = nextstr;
102 continue;
103 }
104 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000105
106 if(str[0] == ' ' && str[1] == '\0') {
107 *p++ = ' ';
108 nodelimiter = 1; /* No delimiter */
109 continue;
110 }
111
Lev Walkin22b5ed42006-09-13 02:51:20 +0000112 if(str != first && !nodelimiter && !(flags & AMI_NODELIMITER))
Lev Walkinf15320b2004-06-03 03:38:44 +0000113 *p++ = '_'; /* Delimiter between tokens */
114 nodelimiter = 0;
115
Lev Walkin801fabc2005-01-28 12:18:50 +0000116 /*
117 * If it is a single argument, check that it does not clash
118 * with C/C++ language keywords.
119 */
120 if((flags & AMI_CHECK_RESERVED)
Lev Walkina00d6b32006-03-21 03:40:38 +0000121 && str == first && !nextstr && reserved_keyword(str)) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000122 *p++ = toupper(*str++);
123 /* Fall through */
124 }
125
Lev Walkinf15320b2004-06-03 03:38:44 +0000126 for(; *str; str++) {
127 if(isalnum(*str)) {
128 *p++ = *str;
129 subst_made = 0;
130 } else if(!subst_made++) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000131 if((flags & AMI_MASK_ONLY_SPACES)
132 && !isspace(*str)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000133 *p ++ = *str;
134 } else {
135 *p++ = '_';
136 }
137 }
138 }
139 }
140 va_end(ap);
141 *p = '\0';
142
143 assert((p - storage) <= storage_size);
144
145 return storage;
146}
147
Lev Walkinf15320b2004-06-03 03:38:44 +0000148char *
149asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
Lev Walkina00d6b32006-03-21 03:40:38 +0000150 asn1p_expr_t *exprid = 0;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000151 asn1p_expr_t *top_parent;
Lev Walkina00d6b32006-03-21 03:40:38 +0000152 asn1p_expr_t *terminal;
Lev Walkin22b5ed42006-09-13 02:51:20 +0000153 int stdname = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000154 char *typename;
155
Lev Walkin5a8219a2004-09-08 00:28:57 +0000156 /* Rewind to the topmost parent expression */
157 if((top_parent = expr->parent_expr))
158 while(top_parent->parent_expr)
159 top_parent = top_parent->parent_expr;
160
Lev Walkin725883b2006-10-09 12:07:58 +0000161 if(0) DEBUG("asn1c_type_name(%s: 0x%x)",
162 expr->Identifier, expr->expr_type);
Lev Walkinc2a75092006-03-14 11:52:12 +0000163
Lev Walkinf15320b2004-06-03 03:38:44 +0000164 switch(expr->expr_type) {
165 case A1TC_REFERENCE:
166 typename = expr->reference->components[
167 expr->reference->comp_count-1].name;
168 if(typename[0] == '&') {
169 arg_t tmp = *arg;
170
171 /*
172 * This is a reference to a type defined in a class.
173 * Resolve it and use instead.
174 */
Lev Walkinb85a8132005-08-18 13:38:19 +0000175 tmp.expr = asn1f_class_access_ex(arg->asn,
Lev Walkina00d6b32006-03-21 03:40:38 +0000176 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
Lev Walkinc2a75092006-03-14 11:52:12 +0000177 if(!tmp.expr) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000178
Lev Walkinf15320b2004-06-03 03:38:44 +0000179 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000180 }
181
Lev Walkina00d6b32006-03-21 03:40:38 +0000182 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
183
Lev Walkinc8285712005-03-04 22:18:20 +0000184 if(_format == TNF_RSAFE) {
Lev Walkinc8285712005-03-04 22:18:20 +0000185 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
186 typename = terminal->Identifier;
187 }
188 }
189
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000190 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000191 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000192 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000193 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000194 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000195 */
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000196 if(terminal && terminal == top_parent) {
197 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000198 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000199 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000200
201 if(terminal && terminal->spec_index != -1) {
202 exprid = terminal;
203 typename = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000204 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000205
Lev Walkinf15320b2004-06-03 03:38:44 +0000206 break;
207 case ASN_BASIC_INTEGER:
208 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000209 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-08-14 02:18:27 +0000210 if((expr->expr_type == ASN_BASIC_REAL
211 && (arg->flags & A1C_USE_NATIVE_TYPES))
212 || asn1c_type_fits_long(arg, expr)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000213 switch(_format) {
214 case TNF_CTYPE:
215 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000216 if(expr->expr_type == ASN_BASIC_REAL)
217 return "double";
Lev Walkin8bb57a22007-12-03 13:41:36 +0000218 else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN)
219 return "unsigned long";
Lev Walkinf15320b2004-06-03 03:38:44 +0000220 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000221 return "long";
Lev Walkin22b5ed42006-09-13 02:51:20 +0000222 default:
223 typename = 0;
224 switch(expr->expr_type) {
225 case ASN_BASIC_INTEGER:
226 typename = "NativeInteger"; break;
227 case ASN_BASIC_ENUMERATED:
228 typename = "NativeEnumerated"; break;
229 case ASN_BASIC_REAL:
230 typename = "NativeReal"; break;
231 default:
232 break;
233 }
234 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000235 }
Lev Walkin22b5ed42006-09-13 02:51:20 +0000236 if(typename) {
237 if(_format != TNF_INCLUDE)
238 return typename;
239 stdname = 1;
240 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000241 }
242 }
243 /* Fall through */
244 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000245 if(expr->expr_type
246 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000247 if(_format == TNF_RSAFE)
248 _format = TNF_CTYPE;
Lev Walkin22b5ed42006-09-13 02:51:20 +0000249 stdname = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000250 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
251 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000252 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000253 typename = expr->Identifier;
254 }
255 }
256
257 switch(_format) {
258 case TNF_UNMODIFIED:
Lev Walkina00d6b32006-03-21 03:40:38 +0000259 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES,
260 0, exprid ? exprid->Identifier : typename, 0);
Lev Walkin22b5ed42006-09-13 02:51:20 +0000261 case TNF_INCLUDE:
262 return asn1c_make_identifier(
263 AMI_MASK_ONLY_SPACES | AMI_NODELIMITER,
264 0, stdname ? "<" : "\"",
265 exprid ? exprid->Identifier : typename,
266 stdname ? ".h>" : ".h\"", 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000267 case TNF_SAFE:
Lev Walkina00d6b32006-03-21 03:40:38 +0000268 return asn1c_make_identifier(0, exprid, typename, 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000269 case TNF_CTYPE: /* C type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000270 return asn1c_make_identifier(0, exprid,
271 exprid?"t":typename, exprid?0:"t", 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000272 case TNF_RSAFE: /* Recursion-safe type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000273 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
Lev Walkinc8285712005-03-04 22:18:20 +0000274 "struct", " ", typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000275 }
276
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000277 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000278 return typename;
279}
280
Lev Walkin082cadc2005-08-14 02:18:27 +0000281/*
282 * Check whether the specified INTEGER or ENUMERATED type can be represented
Lev Walkin8bb57a22007-12-03 13:41:36 +0000283 * using the generic 'long' or 'unsigned long' type.
Lev Walkin082cadc2005-08-14 02:18:27 +0000284 */
285enum asn1c_fitslong_e
286asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
287 asn1cnst_range_t *range = 0;
288 asn1cnst_edge_t left;
289 asn1cnst_edge_t right;
290 asn1p_expr_t *v;
291
292/*
293 * Since we don't know the sizeof(long) on the possible target platform
294 * which will be compiling the code generated by asn1c, let's play it
295 * simple: long's range is equal to or greater than int32_t.
Lev Walkin4c97bd62005-08-15 01:01:24 +0000296 * NOTE: the most negative integer cannot be written in C, as the C99
297 * standard will give it an unsigned type.
298 * It is defined here as a constant expression.
Lev Walkin082cadc2005-08-14 02:18:27 +0000299 */
Lev Walkinc08c3cf2005-08-15 01:04:48 +0000300#define RIGHTMAX 2147483647 /* of 32-bit integer type */
301#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
Lev Walkin082cadc2005-08-14 02:18:27 +0000302
303 /* Descend to the terminal type */
304 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
305 if(expr == 0) return FL_NOTFIT;
306
307 /* The "fits into long" operation is relevant only for integer types */
308 switch(expr->expr_type) {
309 case ASN_BASIC_INTEGER:
310 case ASN_BASIC_ENUMERATED:
311 break;
312 default:
313 return FL_NOTFIT;
314 }
315
316 /*
317 * First, evaluate the range of explicitly given identifiers.
318 */
319 TQ_FOR(v, &(expr->members), next) {
320 if(v->expr_type != A1TC_UNIVERVAL)
321 continue;
322 if(v->value->value.v_integer < LEFTMIN
323 || v->value->value.v_integer > RIGHTMAX)
324 return FL_NOTFIT;
325 }
326
Lev Walkin4b553412005-08-14 14:45:44 +0000327 if(!expr->combined_constraints)
328 return (arg->flags & A1C_USE_NATIVE_TYPES)
329 ? FL_FORCED : FL_NOTFIT;
330
Lev Walkin082cadc2005-08-14 02:18:27 +0000331 /*
Lev Walkin4b553412005-08-14 14:45:44 +0000332 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
333 * applied (non-standard! but we can deal with this) to the type.
334 * Check the range.
Lev Walkin082cadc2005-08-14 02:18:27 +0000335 */
Lev Walkin4b553412005-08-14 14:45:44 +0000336 range = asn1constraint_compute_PER_range(expr->expr_type,
337 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
338 CPR_simulate_fbless_SIZE);
339 if(range) {
340 if(!range->incompatible) {
341 right = range->right;
342 /* Use 4 instead of sizeof(long) is justified! */
343 if(right.type == ARE_VALUE && right.value <= 4)
Lev Walkin8bb57a22007-12-03 13:41:36 +0000344 return FL_FITS_SIGNED;
Lev Walkin4b553412005-08-14 14:45:44 +0000345 }
346 asn1constraint_range_free(range);
347 }
348
349 /*
350 * Third, pull up the PER visible range of the INTEGER.
351 */
352 range = asn1constraint_compute_PER_range(expr->expr_type,
353 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
Lev Walkin082cadc2005-08-14 02:18:27 +0000354 if(!range
355 || range->empty_constraint
356 || range->extensible
357 || range->incompatible
358 || range->not_PER_visible
359 ) {
360 asn1constraint_range_free(range);
361 return (arg->flags & A1C_USE_NATIVE_TYPES)
362 ? FL_FORCED : FL_NOTFIT;
363 }
364
365 left = range->left;
366 right = range->right;
367 asn1constraint_range_free(range);
368
Lev Walkin8bb57a22007-12-03 13:41:36 +0000369 /* Special case for unsigned */
370 if(left.type == ARE_VALUE
371 && left.value >= 0
372 && right.type == ARE_VALUE
373 && right.value > 2147483647
374 && right.value <= 4294967295UL)
375 return FL_FITS_UNSIGN;
376
377
Lev Walkin082cadc2005-08-14 02:18:27 +0000378 /* If some fixed value is outside of target range, not fit */
379 if(left.type == ARE_VALUE
380 && (left.value < LEFTMIN || left.value > RIGHTMAX))
381 return FL_NOTFIT;
382 if(right.type == ARE_VALUE
383 && (right.value > RIGHTMAX || right.value < LEFTMIN))
384 return FL_NOTFIT;
385
386 /* If the range is open, fits only if -fnative-types is given */
387 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
388 return (arg->flags & A1C_USE_NATIVE_TYPES)
389 ? FL_FORCED : FL_NOTFIT;
390 }
391
Lev Walkin8bb57a22007-12-03 13:41:36 +0000392 return FL_FITS_SIGNED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000393}
394