blob: 779426aaf1126eaa7ee81088530fd45843a27394 [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 *
vlmaf841972005-01-28 12:18:50 +000036asn1c_make_identifier(enum ami_flags_e flags, char *arg1, ...) {
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;
vlm8a09e0f2005-02-25 14:20:30 +000043 size_t size;
vlmfa67ddc2004-06-03 03:38:44 +000044 char *p;
45
46 if(arg1 == NULL)
47 return NULL;
48
49 /*
50 * Estimate the necessary storage size
51 */
52 size = strlen(arg1);
53 va_start(ap, arg1);
54 while((str = va_arg(ap, char *)))
55 size += 1 + strlen(str);
56 va_end(ap);
57
58 /*
59 * Make sure we have this amount of storage.
60 */
61 if(storage_size <= size) {
62 if(storage) free(storage);
63 storage = malloc(size + 1);
64 if(storage) {
65 storage_size = size;
66 } else {
67 storage_size = 0;
68 return NULL;
69 }
70 }
71
72 /*
73 * Fill-in the storage.
74 */
75 va_start(ap, arg1);
76 str = arg1;
77 p = storage;
vlmaf841972005-01-28 12:18:50 +000078 for(str = arg1; str; str = nextstr) {
vlmfa67ddc2004-06-03 03:38:44 +000079 int subst_made = 0;
vlmaf841972005-01-28 12:18:50 +000080 nextstr = va_arg(ap, char *);
vlmfa67ddc2004-06-03 03:38:44 +000081
82 if(str[0] == ' ' && str[1] == '\0') {
83 *p++ = ' ';
84 nodelimiter = 1; /* No delimiter */
85 continue;
86 }
87
88 if(str != arg1 && !nodelimiter)
89 *p++ = '_'; /* Delimiter between tokens */
90 nodelimiter = 0;
91
vlmaf841972005-01-28 12:18:50 +000092 /*
93 * If it is a single argument, check that it does not clash
94 * with C/C++ language keywords.
95 */
96 if((flags & AMI_CHECK_RESERVED)
97 && str == arg1 && !nextstr && reserved_keyword(str)) {
98 *p++ = toupper(*str++);
99 /* Fall through */
100 }
101
vlmfa67ddc2004-06-03 03:38:44 +0000102 for(; *str; str++) {
103 if(isalnum(*str)) {
104 *p++ = *str;
105 subst_made = 0;
106 } else if(!subst_made++) {
vlmaf841972005-01-28 12:18:50 +0000107 if((flags & AMI_MASK_ONLY_SPACES)
108 && !isspace(*str)) {
vlmfa67ddc2004-06-03 03:38:44 +0000109 *p ++ = *str;
110 } else {
111 *p++ = '_';
112 }
113 }
114 }
115 }
116 va_end(ap);
117 *p = '\0';
118
119 assert((p - storage) <= storage_size);
120
121 return storage;
122}
123
vlmfa67ddc2004-06-03 03:38:44 +0000124char *
125asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
vlmfb41dbb2004-09-08 00:28:57 +0000126 asn1p_expr_t *top_parent;
vlmfa67ddc2004-06-03 03:38:44 +0000127 char *typename;
128
vlmfb41dbb2004-09-08 00:28:57 +0000129 /* Rewind to the topmost parent expression */
130 if((top_parent = expr->parent_expr))
131 while(top_parent->parent_expr)
132 top_parent = top_parent->parent_expr;
133
vlmfa67ddc2004-06-03 03:38:44 +0000134 switch(expr->expr_type) {
135 case A1TC_REFERENCE:
136 typename = expr->reference->components[
137 expr->reference->comp_count-1].name;
138 if(typename[0] == '&') {
139 arg_t tmp = *arg;
140
141 /*
142 * This is a reference to a type defined in a class.
143 * Resolve it and use instead.
144 */
vlm6c4a8502005-08-18 13:38:19 +0000145 tmp.expr = asn1f_class_access_ex(arg->asn,
146 arg->expr->module, arg->expr, expr->reference);
vlmfa67ddc2004-06-03 03:38:44 +0000147 if(tmp.expr) return NULL;
148
vlmfa67ddc2004-06-03 03:38:44 +0000149 return asn1c_type_name(&tmp, tmp.expr, _format);
vlmfb41dbb2004-09-08 00:28:57 +0000150 }
151
vlm0b567bf2005-03-04 22:18:20 +0000152 if(_format == TNF_RSAFE) {
153 asn1p_expr_t *terminal;
154 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
155 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
156 typename = terminal->Identifier;
157 }
158 }
159
vlmb47f48e2004-09-17 06:32:12 +0000160 if(_format == TNF_CTYPE) {
vlmfa67ddc2004-06-03 03:38:44 +0000161 /*
vlmb47f48e2004-09-17 06:32:12 +0000162 * If the component references the type itself,
vlm0b567bf2005-03-04 22:18:20 +0000163 * switch to a recursion-safe type naming
vlmb47f48e2004-09-17 06:32:12 +0000164 * ("struct foo" instead of "foo_t").
vlmfa67ddc2004-06-03 03:38:44 +0000165 */
166 asn1p_expr_t *terminal;
vlmcbebb812004-09-22 16:05:13 +0000167 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
vlmb47f48e2004-09-17 06:32:12 +0000168 if(terminal && terminal == top_parent) {
169 _format = TNF_RSAFE;
vlmfb41dbb2004-09-08 00:28:57 +0000170 }
vlmfa67ddc2004-06-03 03:38:44 +0000171 }
172 break;
vlmc161f0c2004-08-25 02:03:26 +0000173#if 0
vlmfa67ddc2004-06-03 03:38:44 +0000174 case ASN_CONSTR_SEQUENCE_OF:
175 case ASN_CONSTR_SET_OF:
176 if(expr->Identifier) {
177 typename = expr->Identifier;
178 } else {
179 asn1p_expr_t *child;
180 child = TQ_FIRST(&(expr->members));
181 typename = asn1c_type_name(arg, child, _format);
182 if(typename)
183 return typename;
184 _format = TNF_SAFE;
185 typename = child->Identifier;
186 }
187 break;
vlmc161f0c2004-08-25 02:03:26 +0000188#endif
vlmfa67ddc2004-06-03 03:38:44 +0000189 case ASN_BASIC_INTEGER:
190 case ASN_BASIC_ENUMERATED:
vlmf9d178d2004-09-14 12:47:45 +0000191 case ASN_BASIC_REAL:
vlm75b3a532005-08-14 02:18:27 +0000192 if((expr->expr_type == ASN_BASIC_REAL
193 && (arg->flags & A1C_USE_NATIVE_TYPES))
194 || asn1c_type_fits_long(arg, expr)) {
vlmfa67ddc2004-06-03 03:38:44 +0000195 switch(_format) {
196 case TNF_CTYPE:
197 case TNF_RSAFE:
vlmf9d178d2004-09-14 12:47:45 +0000198 if(expr->expr_type == ASN_BASIC_REAL)
199 return "double";
vlmfa67ddc2004-06-03 03:38:44 +0000200 else
vlm909b6c62005-02-25 12:09:55 +0000201 return "long";
vlmf9d178d2004-09-14 12:47:45 +0000202 default: break;
203 }
204 switch(expr->expr_type) {
205 case ASN_BASIC_INTEGER:
206 return "NativeInteger";
207 case ASN_BASIC_ENUMERATED:
208 return "NativeEnumerated";
209 case ASN_BASIC_REAL:
210 return "NativeReal";
211 default: break;
vlmfa67ddc2004-06-03 03:38:44 +0000212 }
213 }
214 /* Fall through */
215 default:
vlmc161f0c2004-08-25 02:03:26 +0000216 if(expr->expr_type
217 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
vlmfa67ddc2004-06-03 03:38:44 +0000218 if(_format == TNF_RSAFE)
219 _format = TNF_CTYPE;
220 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
221 } else {
vlmb47f48e2004-09-17 06:32:12 +0000222 _format = TNF_RSAFE;
vlmfa67ddc2004-06-03 03:38:44 +0000223 typename = expr->Identifier;
224 }
225 }
226
227 switch(_format) {
228 case TNF_UNMODIFIED:
229 case TNF_INCLUDE:
vlm0b567bf2005-03-04 22:18:20 +0000230 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES, typename, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000231 case TNF_SAFE:
vlm0b567bf2005-03-04 22:18:20 +0000232 return asn1c_make_identifier(0, typename, 0);
233 case TNF_CTYPE: /* C type */
234 return asn1c_make_identifier(0, typename, "t", 0);
235 case TNF_RSAFE: /* Recursion-safe type */
236 return asn1c_make_identifier(AMI_CHECK_RESERVED,
237 "struct", " ", typename, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000238 }
239
vlmb47f48e2004-09-17 06:32:12 +0000240 assert(!"unreachable");
vlmfa67ddc2004-06-03 03:38:44 +0000241 return typename;
242}
243
vlm75b3a532005-08-14 02:18:27 +0000244/*
245 * Check whether the specified INTEGER or ENUMERATED type can be represented
246 * using the generic 'long' type.
247 */
248enum asn1c_fitslong_e
249asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
250 asn1cnst_range_t *range = 0;
251 asn1cnst_edge_t left;
252 asn1cnst_edge_t right;
253 asn1p_expr_t *v;
254
255/*
256 * Since we don't know the sizeof(long) on the possible target platform
257 * which will be compiling the code generated by asn1c, let's play it
258 * simple: long's range is equal to or greater than int32_t.
vlm87ae6f92005-08-15 01:01:24 +0000259 * NOTE: the most negative integer cannot be written in C, as the C99
260 * standard will give it an unsigned type.
261 * It is defined here as a constant expression.
vlm75b3a532005-08-14 02:18:27 +0000262 */
vlm856b94c2005-08-15 01:04:48 +0000263#define RIGHTMAX 2147483647 /* of 32-bit integer type */
264#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
vlm75b3a532005-08-14 02:18:27 +0000265
266 /* Descend to the terminal type */
267 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
268 if(expr == 0) return FL_NOTFIT;
269
270 /* The "fits into long" operation is relevant only for integer types */
271 switch(expr->expr_type) {
272 case ASN_BASIC_INTEGER:
273 case ASN_BASIC_ENUMERATED:
274 break;
275 default:
276 return FL_NOTFIT;
277 }
278
279 /*
280 * First, evaluate the range of explicitly given identifiers.
281 */
282 TQ_FOR(v, &(expr->members), next) {
283 if(v->expr_type != A1TC_UNIVERVAL)
284 continue;
285 if(v->value->value.v_integer < LEFTMIN
286 || v->value->value.v_integer > RIGHTMAX)
287 return FL_NOTFIT;
288 }
289
vlm27028582005-08-14 14:45:44 +0000290 if(!expr->combined_constraints)
291 return (arg->flags & A1C_USE_NATIVE_TYPES)
292 ? FL_FORCED : FL_NOTFIT;
293
vlm75b3a532005-08-14 02:18:27 +0000294 /*
vlm27028582005-08-14 14:45:44 +0000295 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
296 * applied (non-standard! but we can deal with this) to the type.
297 * Check the range.
vlm75b3a532005-08-14 02:18:27 +0000298 */
vlm27028582005-08-14 14:45:44 +0000299 range = asn1constraint_compute_PER_range(expr->expr_type,
300 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
301 CPR_simulate_fbless_SIZE);
302 if(range) {
303 if(!range->incompatible) {
304 right = range->right;
305 /* Use 4 instead of sizeof(long) is justified! */
306 if(right.type == ARE_VALUE && right.value <= 4)
307 return FL_FITSOK;
308 }
309 asn1constraint_range_free(range);
310 }
311
312 /*
313 * Third, pull up the PER visible range of the INTEGER.
314 */
315 range = asn1constraint_compute_PER_range(expr->expr_type,
316 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
vlm75b3a532005-08-14 02:18:27 +0000317 if(!range
318 || range->empty_constraint
319 || range->extensible
320 || range->incompatible
321 || range->not_PER_visible
322 ) {
323 asn1constraint_range_free(range);
324 return (arg->flags & A1C_USE_NATIVE_TYPES)
325 ? FL_FORCED : FL_NOTFIT;
326 }
327
328 left = range->left;
329 right = range->right;
330 asn1constraint_range_free(range);
331
332 /* If some fixed value is outside of target range, not fit */
333 if(left.type == ARE_VALUE
334 && (left.value < LEFTMIN || left.value > RIGHTMAX))
335 return FL_NOTFIT;
336 if(right.type == ARE_VALUE
337 && (right.value > RIGHTMAX || right.value < LEFTMIN))
338 return FL_NOTFIT;
339
340 /* If the range is open, fits only if -fnative-types is given */
341 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
342 return (arg->flags & A1C_USE_NATIVE_TYPES)
343 ? FL_FORCED : FL_NOTFIT;
344 }
345
346 return FL_FITSOK;
347}
348