blob: f96b3896a804f1c0ee2dbe3c7d9aa99826b05ad1 [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) {
23 int i;
24 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;
vlm8a09e0f2005-02-25 14:20:30 +000045 size_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
vlm0c6d3812006-03-21 03:40:38 +0000112 if(str != first && !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;
vlmfa67ddc2004-06-03 03:38:44 +0000153 char *typename;
154
vlmfb41dbb2004-09-08 00:28:57 +0000155 /* Rewind to the topmost parent expression */
156 if((top_parent = expr->parent_expr))
157 while(top_parent->parent_expr)
158 top_parent = top_parent->parent_expr;
159
vlm5fbaa132006-03-14 11:52:12 +0000160 DEBUG("asn1c_type_name(%s: 0x%x)", expr->Identifier, expr->expr_type);
161
vlmfa67ddc2004-06-03 03:38:44 +0000162 switch(expr->expr_type) {
163 case A1TC_REFERENCE:
164 typename = expr->reference->components[
165 expr->reference->comp_count-1].name;
166 if(typename[0] == '&') {
167 arg_t tmp = *arg;
168
169 /*
170 * This is a reference to a type defined in a class.
171 * Resolve it and use instead.
172 */
vlm6c4a8502005-08-18 13:38:19 +0000173 tmp.expr = asn1f_class_access_ex(arg->asn,
vlm0c6d3812006-03-21 03:40:38 +0000174 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
vlm5fbaa132006-03-14 11:52:12 +0000175 if(!tmp.expr) return NULL;
vlmfa67ddc2004-06-03 03:38:44 +0000176
vlmfa67ddc2004-06-03 03:38:44 +0000177 return asn1c_type_name(&tmp, tmp.expr, _format);
vlmfb41dbb2004-09-08 00:28:57 +0000178 }
179
vlm0c6d3812006-03-21 03:40:38 +0000180 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
181
vlm0b567bf2005-03-04 22:18:20 +0000182 if(_format == TNF_RSAFE) {
vlm0b567bf2005-03-04 22:18:20 +0000183 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
184 typename = terminal->Identifier;
185 }
186 }
187
vlmb47f48e2004-09-17 06:32:12 +0000188 if(_format == TNF_CTYPE) {
vlmfa67ddc2004-06-03 03:38:44 +0000189 /*
vlmb47f48e2004-09-17 06:32:12 +0000190 * If the component references the type itself,
vlm0b567bf2005-03-04 22:18:20 +0000191 * switch to a recursion-safe type naming
vlmb47f48e2004-09-17 06:32:12 +0000192 * ("struct foo" instead of "foo_t").
vlmfa67ddc2004-06-03 03:38:44 +0000193 */
vlmb47f48e2004-09-17 06:32:12 +0000194 if(terminal && terminal == top_parent) {
195 _format = TNF_RSAFE;
vlmfb41dbb2004-09-08 00:28:57 +0000196 }
vlmfa67ddc2004-06-03 03:38:44 +0000197 }
vlm0c6d3812006-03-21 03:40:38 +0000198
199 if(terminal && terminal->spec_index != -1) {
200 exprid = terminal;
201 typename = 0;
vlmfa67ddc2004-06-03 03:38:44 +0000202 }
vlm0c6d3812006-03-21 03:40:38 +0000203
vlmfa67ddc2004-06-03 03:38:44 +0000204 break;
205 case ASN_BASIC_INTEGER:
206 case ASN_BASIC_ENUMERATED:
vlmf9d178d2004-09-14 12:47:45 +0000207 case ASN_BASIC_REAL:
vlm75b3a532005-08-14 02:18:27 +0000208 if((expr->expr_type == ASN_BASIC_REAL
209 && (arg->flags & A1C_USE_NATIVE_TYPES))
210 || asn1c_type_fits_long(arg, expr)) {
vlmfa67ddc2004-06-03 03:38:44 +0000211 switch(_format) {
212 case TNF_CTYPE:
213 case TNF_RSAFE:
vlmf9d178d2004-09-14 12:47:45 +0000214 if(expr->expr_type == ASN_BASIC_REAL)
215 return "double";
vlmfa67ddc2004-06-03 03:38:44 +0000216 else
vlm909b6c62005-02-25 12:09:55 +0000217 return "long";
vlmf9d178d2004-09-14 12:47:45 +0000218 default: break;
219 }
220 switch(expr->expr_type) {
221 case ASN_BASIC_INTEGER:
222 return "NativeInteger";
223 case ASN_BASIC_ENUMERATED:
224 return "NativeEnumerated";
225 case ASN_BASIC_REAL:
226 return "NativeReal";
227 default: break;
vlmfa67ddc2004-06-03 03:38:44 +0000228 }
229 }
230 /* Fall through */
231 default:
vlmc161f0c2004-08-25 02:03:26 +0000232 if(expr->expr_type
233 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
vlmfa67ddc2004-06-03 03:38:44 +0000234 if(_format == TNF_RSAFE)
235 _format = TNF_CTYPE;
236 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
237 } else {
vlmb47f48e2004-09-17 06:32:12 +0000238 _format = TNF_RSAFE;
vlmfa67ddc2004-06-03 03:38:44 +0000239 typename = expr->Identifier;
240 }
241 }
242
243 switch(_format) {
244 case TNF_UNMODIFIED:
245 case TNF_INCLUDE:
vlm0c6d3812006-03-21 03:40:38 +0000246 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES,
247 0, exprid ? exprid->Identifier : typename, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000248 case TNF_SAFE:
vlm0c6d3812006-03-21 03:40:38 +0000249 return asn1c_make_identifier(0, exprid, typename, 0);
vlm0b567bf2005-03-04 22:18:20 +0000250 case TNF_CTYPE: /* C type */
vlm0c6d3812006-03-21 03:40:38 +0000251 return asn1c_make_identifier(0, exprid,
252 exprid?"t":typename, exprid?0:"t", 0);
vlm0b567bf2005-03-04 22:18:20 +0000253 case TNF_RSAFE: /* Recursion-safe type */
vlm0c6d3812006-03-21 03:40:38 +0000254 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
vlm0b567bf2005-03-04 22:18:20 +0000255 "struct", " ", typename, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000256 }
257
vlmb47f48e2004-09-17 06:32:12 +0000258 assert(!"unreachable");
vlmfa67ddc2004-06-03 03:38:44 +0000259 return typename;
260}
261
vlm75b3a532005-08-14 02:18:27 +0000262/*
263 * Check whether the specified INTEGER or ENUMERATED type can be represented
264 * using the generic 'long' type.
265 */
266enum asn1c_fitslong_e
267asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
268 asn1cnst_range_t *range = 0;
269 asn1cnst_edge_t left;
270 asn1cnst_edge_t right;
271 asn1p_expr_t *v;
272
273/*
274 * Since we don't know the sizeof(long) on the possible target platform
275 * which will be compiling the code generated by asn1c, let's play it
276 * simple: long's range is equal to or greater than int32_t.
vlm87ae6f92005-08-15 01:01:24 +0000277 * NOTE: the most negative integer cannot be written in C, as the C99
278 * standard will give it an unsigned type.
279 * It is defined here as a constant expression.
vlm75b3a532005-08-14 02:18:27 +0000280 */
vlm856b94c2005-08-15 01:04:48 +0000281#define RIGHTMAX 2147483647 /* of 32-bit integer type */
282#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
vlm75b3a532005-08-14 02:18:27 +0000283
284 /* Descend to the terminal type */
285 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
286 if(expr == 0) return FL_NOTFIT;
287
288 /* The "fits into long" operation is relevant only for integer types */
289 switch(expr->expr_type) {
290 case ASN_BASIC_INTEGER:
291 case ASN_BASIC_ENUMERATED:
292 break;
293 default:
294 return FL_NOTFIT;
295 }
296
297 /*
298 * First, evaluate the range of explicitly given identifiers.
299 */
300 TQ_FOR(v, &(expr->members), next) {
301 if(v->expr_type != A1TC_UNIVERVAL)
302 continue;
303 if(v->value->value.v_integer < LEFTMIN
304 || v->value->value.v_integer > RIGHTMAX)
305 return FL_NOTFIT;
306 }
307
vlm27028582005-08-14 14:45:44 +0000308 if(!expr->combined_constraints)
309 return (arg->flags & A1C_USE_NATIVE_TYPES)
310 ? FL_FORCED : FL_NOTFIT;
311
vlm75b3a532005-08-14 02:18:27 +0000312 /*
vlm27028582005-08-14 14:45:44 +0000313 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
314 * applied (non-standard! but we can deal with this) to the type.
315 * Check the range.
vlm75b3a532005-08-14 02:18:27 +0000316 */
vlm27028582005-08-14 14:45:44 +0000317 range = asn1constraint_compute_PER_range(expr->expr_type,
318 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
319 CPR_simulate_fbless_SIZE);
320 if(range) {
321 if(!range->incompatible) {
322 right = range->right;
323 /* Use 4 instead of sizeof(long) is justified! */
324 if(right.type == ARE_VALUE && right.value <= 4)
325 return FL_FITSOK;
326 }
327 asn1constraint_range_free(range);
328 }
329
330 /*
331 * Third, pull up the PER visible range of the INTEGER.
332 */
333 range = asn1constraint_compute_PER_range(expr->expr_type,
334 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
vlm75b3a532005-08-14 02:18:27 +0000335 if(!range
336 || range->empty_constraint
337 || range->extensible
338 || range->incompatible
339 || range->not_PER_visible
340 ) {
341 asn1constraint_range_free(range);
342 return (arg->flags & A1C_USE_NATIVE_TYPES)
343 ? FL_FORCED : FL_NOTFIT;
344 }
345
346 left = range->left;
347 right = range->right;
348 asn1constraint_range_free(range);
349
350 /* If some fixed value is outside of target range, not fit */
351 if(left.type == ARE_VALUE
352 && (left.value < LEFTMIN || left.value > RIGHTMAX))
353 return FL_NOTFIT;
354 if(right.type == ARE_VALUE
355 && (right.value > RIGHTMAX || right.value < LEFTMIN))
356 return FL_NOTFIT;
357
358 /* If the range is open, fits only if -fnative-types is given */
359 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
360 return (arg->flags & A1C_USE_NATIVE_TYPES)
361 ? FL_FORCED : FL_NOTFIT;
362 }
363
364 return FL_FITSOK;
365}
366