blob: f48ab081e3c8cc0b5f68ac69511d816ea4d28443 [file] [log] [blame]
vlmfa67ddc2004-06-03 03:38:44 +00001#include "asn1c_internal.h"
vlmb2839012004-08-20 13:37:01 +00002#include "asn1c_misc.h"
3
vlm75b3a532005-08-14 02:18:27 +00004#include <asn1fix_crange.h> /* constraint groker from libasn1fix */
5#include <asn1fix_export.h> /* other exportable stuff from libasn1fix */
vlmfa67ddc2004-06-03 03:38:44 +00006
vlmfa67ddc2004-06-03 03:38:44 +00007/*
vlmaf841972005-01-28 12:18:50 +00008 * Checks that the given string is not a reserved C/C++ keyword.
vlm4bf55512005-03-03 21:29:27 +00009 * ISO/IEC 9899:1999 (C99), A.1.2
vlmaf841972005-01-28 12:18:50 +000010 */
11static char *res_kwd[] = {
vlm4bf55512005-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};
vlmaf841972005-01-28 12:18:50 +000021static int
22reserved_keyword(const char *str) {
vlm1fcf7592006-08-18 02:27:55 +000023 size_t i;
vlmaf841972005-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/*
vlmfa67ddc2004-06-03 03:38:44 +000032 * Construct identifier from multiple parts.
33 * Convert unsafe characters to underscores.
34 */
35char *
vlm0c6d3812006-03-21 03:40:38 +000036asn1c_make_identifier(enum ami_flags_e flags, asn1p_expr_t *expr, ...) {
vlmfa67ddc2004-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;
vlmaf841972005-01-28 12:18:50 +000042 char *nextstr;
vlm0c6d3812006-03-21 03:40:38 +000043 char *first = 0;
44 char *second = 0;
vlm1fcf7592006-08-18 02:27:55 +000045 ssize_t size;
vlmfa67ddc2004-06-03 03:38:44 +000046 char *p;
47
vlm0c6d3812006-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 }
vlmfa67ddc2004-06-03 03:38:44 +000064
vlm0c6d3812006-03-21 03:40:38 +000065 va_start(ap, expr);
vlmfa67ddc2004-06-03 03:38:44 +000066 while((str = va_arg(ap, char *)))
67 size += 1 + strlen(str);
68 va_end(ap);
vlm0c6d3812006-03-21 03:40:38 +000069 if(size == -1) return NULL;
vlmfa67ddc2004-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 */
vlm0c6d3812006-03-21 03:40:38 +000088 va_start(ap, expr);
vlmfa67ddc2004-06-03 03:38:44 +000089 p = storage;
vlm0c6d3812006-03-21 03:40:38 +000090 nextstr = "";
91 for(p = storage, str = 0; str || nextstr; str = nextstr) {
vlmfa67ddc2004-06-03 03:38:44 +000092 int subst_made = 0;
vlm0c6d3812006-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 }
vlmfa67ddc2004-06-03 03:38:44 +0000105
106 if(str[0] == ' ' && str[1] == '\0') {
107 *p++ = ' ';
108 nodelimiter = 1; /* No delimiter */
109 continue;
110 }
111
vlmea226772006-09-13 02:51:20 +0000112 if(str != first && !nodelimiter && !(flags & AMI_NODELIMITER))
vlmfa67ddc2004-06-03 03:38:44 +0000113 *p++ = '_'; /* Delimiter between tokens */
114 nodelimiter = 0;
115
vlmaf841972005-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)
vlm0c6d3812006-03-21 03:40:38 +0000121 && str == first && !nextstr && reserved_keyword(str)) {
vlmaf841972005-01-28 12:18:50 +0000122 *p++ = toupper(*str++);
123 /* Fall through */
124 }
125
vlmfa67ddc2004-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++) {
vlmaf841972005-01-28 12:18:50 +0000131 if((flags & AMI_MASK_ONLY_SPACES)
132 && !isspace(*str)) {
vlmfa67ddc2004-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
vlmfa67ddc2004-06-03 03:38:44 +0000148char *
149asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
vlm0c6d3812006-03-21 03:40:38 +0000150 asn1p_expr_t *exprid = 0;
vlmfb41dbb2004-09-08 00:28:57 +0000151 asn1p_expr_t *top_parent;
vlm0c6d3812006-03-21 03:40:38 +0000152 asn1p_expr_t *terminal;
vlmea226772006-09-13 02:51:20 +0000153 int stdname = 0;
vlmfa67ddc2004-06-03 03:38:44 +0000154 char *typename;
155
vlmfb41dbb2004-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
vlm86380d32006-10-09 12:07:58 +0000161 if(0) DEBUG("asn1c_type_name(%s: 0x%x)",
162 expr->Identifier, expr->expr_type);
vlm5fbaa132006-03-14 11:52:12 +0000163
vlmfa67ddc2004-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 */
vlm6c4a8502005-08-18 13:38:19 +0000175 tmp.expr = asn1f_class_access_ex(arg->asn,
vlm0c6d3812006-03-21 03:40:38 +0000176 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
vlm5fbaa132006-03-14 11:52:12 +0000177 if(!tmp.expr) return NULL;
vlmfa67ddc2004-06-03 03:38:44 +0000178
vlmfa67ddc2004-06-03 03:38:44 +0000179 return asn1c_type_name(&tmp, tmp.expr, _format);
vlmfb41dbb2004-09-08 00:28:57 +0000180 }
181
vlm0c6d3812006-03-21 03:40:38 +0000182 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
183
vlm0b567bf2005-03-04 22:18:20 +0000184 if(_format == TNF_RSAFE) {
vlm0b567bf2005-03-04 22:18:20 +0000185 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
186 typename = terminal->Identifier;
187 }
188 }
189
vlmb47f48e2004-09-17 06:32:12 +0000190 if(_format == TNF_CTYPE) {
vlmfa67ddc2004-06-03 03:38:44 +0000191 /*
vlmb47f48e2004-09-17 06:32:12 +0000192 * If the component references the type itself,
vlm0b567bf2005-03-04 22:18:20 +0000193 * switch to a recursion-safe type naming
vlmb47f48e2004-09-17 06:32:12 +0000194 * ("struct foo" instead of "foo_t").
vlmfa67ddc2004-06-03 03:38:44 +0000195 */
vlmb47f48e2004-09-17 06:32:12 +0000196 if(terminal && terminal == top_parent) {
197 _format = TNF_RSAFE;
vlmfb41dbb2004-09-08 00:28:57 +0000198 }
vlmfa67ddc2004-06-03 03:38:44 +0000199 }
vlm0c6d3812006-03-21 03:40:38 +0000200
201 if(terminal && terminal->spec_index != -1) {
202 exprid = terminal;
203 typename = 0;
vlmfa67ddc2004-06-03 03:38:44 +0000204 }
vlm0c6d3812006-03-21 03:40:38 +0000205
vlmfa67ddc2004-06-03 03:38:44 +0000206 break;
207 case ASN_BASIC_INTEGER:
208 case ASN_BASIC_ENUMERATED:
vlmf9d178d2004-09-14 12:47:45 +0000209 case ASN_BASIC_REAL:
vlm75b3a532005-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)) {
vlmfa67ddc2004-06-03 03:38:44 +0000213 switch(_format) {
214 case TNF_CTYPE:
215 case TNF_RSAFE:
vlmf9d178d2004-09-14 12:47:45 +0000216 if(expr->expr_type == ASN_BASIC_REAL)
217 return "double";
vlm12164c42007-12-03 13:41:36 +0000218 else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN)
219 return "unsigned long";
vlmfa67ddc2004-06-03 03:38:44 +0000220 else
vlm909b6c62005-02-25 12:09:55 +0000221 return "long";
vlmea226772006-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;
vlmf9d178d2004-09-14 12:47:45 +0000235 }
vlmea226772006-09-13 02:51:20 +0000236 if(typename) {
237 if(_format != TNF_INCLUDE)
238 return typename;
239 stdname = 1;
240 break;
vlmfa67ddc2004-06-03 03:38:44 +0000241 }
242 }
243 /* Fall through */
244 default:
vlmc161f0c2004-08-25 02:03:26 +0000245 if(expr->expr_type
246 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
vlmfa67ddc2004-06-03 03:38:44 +0000247 if(_format == TNF_RSAFE)
248 _format = TNF_CTYPE;
vlmea226772006-09-13 02:51:20 +0000249 stdname = 1;
vlmfa67ddc2004-06-03 03:38:44 +0000250 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
251 } else {
vlmb47f48e2004-09-17 06:32:12 +0000252 _format = TNF_RSAFE;
vlmfa67ddc2004-06-03 03:38:44 +0000253 typename = expr->Identifier;
254 }
255 }
256
257 switch(_format) {
258 case TNF_UNMODIFIED:
vlm0c6d3812006-03-21 03:40:38 +0000259 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES,
260 0, exprid ? exprid->Identifier : typename, 0);
vlmea226772006-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);
vlmfa67ddc2004-06-03 03:38:44 +0000267 case TNF_SAFE:
vlm0c6d3812006-03-21 03:40:38 +0000268 return asn1c_make_identifier(0, exprid, typename, 0);
vlm0b567bf2005-03-04 22:18:20 +0000269 case TNF_CTYPE: /* C type */
vlm0c6d3812006-03-21 03:40:38 +0000270 return asn1c_make_identifier(0, exprid,
271 exprid?"t":typename, exprid?0:"t", 0);
vlm0b567bf2005-03-04 22:18:20 +0000272 case TNF_RSAFE: /* Recursion-safe type */
vlm0c6d3812006-03-21 03:40:38 +0000273 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
vlm0b567bf2005-03-04 22:18:20 +0000274 "struct", " ", typename, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000275 }
276
vlmb47f48e2004-09-17 06:32:12 +0000277 assert(!"unreachable");
vlmfa67ddc2004-06-03 03:38:44 +0000278 return typename;
279}
280
vlm75b3a532005-08-14 02:18:27 +0000281/*
282 * Check whether the specified INTEGER or ENUMERATED type can be represented
vlm12164c42007-12-03 13:41:36 +0000283 * using the generic 'long' or 'unsigned long' type.
vlm75b3a532005-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.
vlm87ae6f92005-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.
vlm75b3a532005-08-14 02:18:27 +0000299 */
vlm856b94c2005-08-15 01:04:48 +0000300#define RIGHTMAX 2147483647 /* of 32-bit integer type */
301#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
vlm75b3a532005-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
vlm27028582005-08-14 14:45:44 +0000327 if(!expr->combined_constraints)
328 return (arg->flags & A1C_USE_NATIVE_TYPES)
329 ? FL_FORCED : FL_NOTFIT;
330
vlm75b3a532005-08-14 02:18:27 +0000331 /*
vlm27028582005-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.
vlm75b3a532005-08-14 02:18:27 +0000335 */
vlm27028582005-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)
vlm12164c42007-12-03 13:41:36 +0000344 return FL_FITS_SIGNED;
vlm27028582005-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);
vlm75b3a532005-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
vlm12164c42007-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
vlm75b3a532005-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
vlm12164c42007-12-03 13:41:36 +0000392 return FL_FITS_SIGNED;
vlm75b3a532005-08-14 02:18:27 +0000393}
394