blob: f98ccb04400018eefea4be4a3367e62769474cf1 [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,
Lev Walkinffd035e2010-10-16 01:26:57 -0700264 0, ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
265 ? "\"" : "<"),
Lev Walkin22b5ed42006-09-13 02:51:20 +0000266 exprid ? exprid->Identifier : typename,
Lev Walkinffd035e2010-10-16 01:26:57 -0700267 ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
268 ? ".h\"" : ".h>"), 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000269 case TNF_SAFE:
Lev Walkina00d6b32006-03-21 03:40:38 +0000270 return asn1c_make_identifier(0, exprid, typename, 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000271 case TNF_CTYPE: /* C type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000272 return asn1c_make_identifier(0, exprid,
273 exprid?"t":typename, exprid?0:"t", 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000274 case TNF_RSAFE: /* Recursion-safe type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000275 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
Lev Walkinc8285712005-03-04 22:18:20 +0000276 "struct", " ", typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000277 }
278
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000279 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000280 return typename;
281}
282
Lev Walkin082cadc2005-08-14 02:18:27 +0000283/*
284 * Check whether the specified INTEGER or ENUMERATED type can be represented
Lev Walkin8bb57a22007-12-03 13:41:36 +0000285 * using the generic 'long' or 'unsigned long' type.
Lev Walkin082cadc2005-08-14 02:18:27 +0000286 */
287enum asn1c_fitslong_e
288asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
289 asn1cnst_range_t *range = 0;
290 asn1cnst_edge_t left;
291 asn1cnst_edge_t right;
292 asn1p_expr_t *v;
293
294/*
295 * Since we don't know the sizeof(long) on the possible target platform
296 * which will be compiling the code generated by asn1c, let's play it
297 * simple: long's range is equal to or greater than int32_t.
Lev Walkin4c97bd62005-08-15 01:01:24 +0000298 * NOTE: the most negative integer cannot be written in C, as the C99
299 * standard will give it an unsigned type.
300 * It is defined here as a constant expression.
Lev Walkin082cadc2005-08-14 02:18:27 +0000301 */
Lev Walkinc08c3cf2005-08-15 01:04:48 +0000302#define RIGHTMAX 2147483647 /* of 32-bit integer type */
303#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
Lev Walkin082cadc2005-08-14 02:18:27 +0000304
305 /* Descend to the terminal type */
306 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
307 if(expr == 0) return FL_NOTFIT;
308
309 /* The "fits into long" operation is relevant only for integer types */
310 switch(expr->expr_type) {
311 case ASN_BASIC_INTEGER:
312 case ASN_BASIC_ENUMERATED:
313 break;
314 default:
315 return FL_NOTFIT;
316 }
317
318 /*
319 * First, evaluate the range of explicitly given identifiers.
320 */
321 TQ_FOR(v, &(expr->members), next) {
322 if(v->expr_type != A1TC_UNIVERVAL)
323 continue;
324 if(v->value->value.v_integer < LEFTMIN
325 || v->value->value.v_integer > RIGHTMAX)
326 return FL_NOTFIT;
327 }
328
Lev Walkin4b553412005-08-14 14:45:44 +0000329 if(!expr->combined_constraints)
330 return (arg->flags & A1C_USE_NATIVE_TYPES)
331 ? FL_FORCED : FL_NOTFIT;
332
Lev Walkin082cadc2005-08-14 02:18:27 +0000333 /*
Lev Walkin4b553412005-08-14 14:45:44 +0000334 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
335 * applied (non-standard! but we can deal with this) to the type.
336 * Check the range.
Lev Walkin082cadc2005-08-14 02:18:27 +0000337 */
Lev Walkin4b553412005-08-14 14:45:44 +0000338 range = asn1constraint_compute_PER_range(expr->expr_type,
339 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
340 CPR_simulate_fbless_SIZE);
341 if(range) {
342 if(!range->incompatible) {
343 right = range->right;
344 /* Use 4 instead of sizeof(long) is justified! */
345 if(right.type == ARE_VALUE && right.value <= 4)
Lev Walkin8bb57a22007-12-03 13:41:36 +0000346 return FL_FITS_SIGNED;
Lev Walkin4b553412005-08-14 14:45:44 +0000347 }
348 asn1constraint_range_free(range);
349 }
350
351 /*
352 * Third, pull up the PER visible range of the INTEGER.
353 */
354 range = asn1constraint_compute_PER_range(expr->expr_type,
355 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
Lev Walkin082cadc2005-08-14 02:18:27 +0000356 if(!range
357 || range->empty_constraint
358 || range->extensible
359 || range->incompatible
360 || range->not_PER_visible
361 ) {
362 asn1constraint_range_free(range);
363 return (arg->flags & A1C_USE_NATIVE_TYPES)
364 ? FL_FORCED : FL_NOTFIT;
365 }
366
367 left = range->left;
368 right = range->right;
369 asn1constraint_range_free(range);
370
Lev Walkin8bb57a22007-12-03 13:41:36 +0000371 /* Special case for unsigned */
372 if(left.type == ARE_VALUE
373 && left.value >= 0
374 && right.type == ARE_VALUE
375 && right.value > 2147483647
376 && right.value <= 4294967295UL)
377 return FL_FITS_UNSIGN;
378
379
Lev Walkin082cadc2005-08-14 02:18:27 +0000380 /* If some fixed value is outside of target range, not fit */
381 if(left.type == ARE_VALUE
382 && (left.value < LEFTMIN || left.value > RIGHTMAX))
383 return FL_NOTFIT;
384 if(right.type == ARE_VALUE
385 && (right.value > RIGHTMAX || right.value < LEFTMIN))
386 return FL_NOTFIT;
387
388 /* If the range is open, fits only if -fnative-types is given */
389 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
390 return (arg->flags & A1C_USE_NATIVE_TYPES)
391 ? FL_FORCED : FL_NOTFIT;
392 }
393
Lev Walkin8bb57a22007-12-03 13:41:36 +0000394 return FL_FITS_SIGNED;
Lev Walkin082cadc2005-08-14 02:18:27 +0000395}
396