blob: c8cd2e70cc00b7c15fb9dfcbeff9a286dd511c3b [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 */
145 tmp.expr = asn1f_class_access_ex(arg->asn, arg->mod,
vlmb179d312004-08-22 03:23:15 +0000146 arg->expr, expr->reference);
vlmfa67ddc2004-06-03 03:38:44 +0000147 if(tmp.expr) return NULL;
148
vlmb179d312004-08-22 03:23:15 +0000149 tmp.mod = tmp.expr->module;
vlmfa67ddc2004-06-03 03:38:44 +0000150 return asn1c_type_name(&tmp, tmp.expr, _format);
vlmfb41dbb2004-09-08 00:28:57 +0000151 }
152
vlm0b567bf2005-03-04 22:18:20 +0000153 if(_format == TNF_RSAFE) {
154 asn1p_expr_t *terminal;
155 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
156 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
157 typename = terminal->Identifier;
158 }
159 }
160
vlmb47f48e2004-09-17 06:32:12 +0000161 if(_format == TNF_CTYPE) {
vlmfa67ddc2004-06-03 03:38:44 +0000162 /*
vlmb47f48e2004-09-17 06:32:12 +0000163 * If the component references the type itself,
vlm0b567bf2005-03-04 22:18:20 +0000164 * switch to a recursion-safe type naming
vlmb47f48e2004-09-17 06:32:12 +0000165 * ("struct foo" instead of "foo_t").
vlmfa67ddc2004-06-03 03:38:44 +0000166 */
167 asn1p_expr_t *terminal;
vlmcbebb812004-09-22 16:05:13 +0000168 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
vlmb47f48e2004-09-17 06:32:12 +0000169 if(terminal && terminal == top_parent) {
170 _format = TNF_RSAFE;
vlmfb41dbb2004-09-08 00:28:57 +0000171 }
vlmfa67ddc2004-06-03 03:38:44 +0000172 }
173 break;
vlmc161f0c2004-08-25 02:03:26 +0000174#if 0
vlmfa67ddc2004-06-03 03:38:44 +0000175 case ASN_CONSTR_SEQUENCE_OF:
176 case ASN_CONSTR_SET_OF:
177 if(expr->Identifier) {
178 typename = expr->Identifier;
179 } else {
180 asn1p_expr_t *child;
181 child = TQ_FIRST(&(expr->members));
182 typename = asn1c_type_name(arg, child, _format);
183 if(typename)
184 return typename;
185 _format = TNF_SAFE;
186 typename = child->Identifier;
187 }
188 break;
vlmc161f0c2004-08-25 02:03:26 +0000189#endif
vlmfa67ddc2004-06-03 03:38:44 +0000190 case ASN_BASIC_INTEGER:
191 case ASN_BASIC_ENUMERATED:
vlmf9d178d2004-09-14 12:47:45 +0000192 case ASN_BASIC_REAL:
vlm75b3a532005-08-14 02:18:27 +0000193 if((expr->expr_type == ASN_BASIC_REAL
194 && (arg->flags & A1C_USE_NATIVE_TYPES))
195 || asn1c_type_fits_long(arg, expr)) {
vlmfa67ddc2004-06-03 03:38:44 +0000196 switch(_format) {
197 case TNF_CTYPE:
198 case TNF_RSAFE:
vlmf9d178d2004-09-14 12:47:45 +0000199 if(expr->expr_type == ASN_BASIC_REAL)
200 return "double";
vlmfa67ddc2004-06-03 03:38:44 +0000201 else
vlm909b6c62005-02-25 12:09:55 +0000202 return "long";
vlmf9d178d2004-09-14 12:47:45 +0000203 default: break;
204 }
205 switch(expr->expr_type) {
206 case ASN_BASIC_INTEGER:
207 return "NativeInteger";
208 case ASN_BASIC_ENUMERATED:
209 return "NativeEnumerated";
210 case ASN_BASIC_REAL:
211 return "NativeReal";
212 default: break;
vlmfa67ddc2004-06-03 03:38:44 +0000213 }
214 }
215 /* Fall through */
216 default:
vlmc161f0c2004-08-25 02:03:26 +0000217 if(expr->expr_type
218 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
vlmfa67ddc2004-06-03 03:38:44 +0000219 if(_format == TNF_RSAFE)
220 _format = TNF_CTYPE;
221 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
222 } else {
vlmb47f48e2004-09-17 06:32:12 +0000223 _format = TNF_RSAFE;
vlmfa67ddc2004-06-03 03:38:44 +0000224 typename = expr->Identifier;
225 }
226 }
227
228 switch(_format) {
229 case TNF_UNMODIFIED:
230 case TNF_INCLUDE:
vlm0b567bf2005-03-04 22:18:20 +0000231 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES, typename, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000232 case TNF_SAFE:
vlm0b567bf2005-03-04 22:18:20 +0000233 return asn1c_make_identifier(0, typename, 0);
234 case TNF_CTYPE: /* C type */
235 return asn1c_make_identifier(0, typename, "t", 0);
236 case TNF_RSAFE: /* Recursion-safe type */
237 return asn1c_make_identifier(AMI_CHECK_RESERVED,
238 "struct", " ", typename, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000239 }
240
vlmb47f48e2004-09-17 06:32:12 +0000241 assert(!"unreachable");
vlmfa67ddc2004-06-03 03:38:44 +0000242 return typename;
243}
244
vlm75b3a532005-08-14 02:18:27 +0000245/*
246 * Check whether the specified INTEGER or ENUMERATED type can be represented
247 * using the generic 'long' type.
248 */
249enum asn1c_fitslong_e
250asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
251 asn1cnst_range_t *range = 0;
252 asn1cnst_edge_t left;
253 asn1cnst_edge_t right;
254 asn1p_expr_t *v;
255
256/*
257 * Since we don't know the sizeof(long) on the possible target platform
258 * which will be compiling the code generated by asn1c, let's play it
259 * simple: long's range is equal to or greater than int32_t.
vlm87ae6f92005-08-15 01:01:24 +0000260 * NOTE: the most negative integer cannot be written in C, as the C99
261 * standard will give it an unsigned type.
262 * It is defined here as a constant expression.
vlm75b3a532005-08-14 02:18:27 +0000263 */
vlm87ae6f92005-08-15 01:01:24 +0000264#define LEFTMIN 2147483647
265#define RIGHTMAX (-LEFTMIN-1)
vlm75b3a532005-08-14 02:18:27 +0000266
267 /* Descend to the terminal type */
268 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
269 if(expr == 0) return FL_NOTFIT;
270
271 /* The "fits into long" operation is relevant only for integer types */
272 switch(expr->expr_type) {
273 case ASN_BASIC_INTEGER:
274 case ASN_BASIC_ENUMERATED:
275 break;
276 default:
277 return FL_NOTFIT;
278 }
279
280 /*
281 * First, evaluate the range of explicitly given identifiers.
282 */
283 TQ_FOR(v, &(expr->members), next) {
284 if(v->expr_type != A1TC_UNIVERVAL)
285 continue;
286 if(v->value->value.v_integer < LEFTMIN
287 || v->value->value.v_integer > RIGHTMAX)
288 return FL_NOTFIT;
289 }
290
vlm27028582005-08-14 14:45:44 +0000291 if(!expr->combined_constraints)
292 return (arg->flags & A1C_USE_NATIVE_TYPES)
293 ? FL_FORCED : FL_NOTFIT;
294
vlm75b3a532005-08-14 02:18:27 +0000295 /*
vlm27028582005-08-14 14:45:44 +0000296 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
297 * applied (non-standard! but we can deal with this) to the type.
298 * Check the range.
vlm75b3a532005-08-14 02:18:27 +0000299 */
vlm27028582005-08-14 14:45:44 +0000300 range = asn1constraint_compute_PER_range(expr->expr_type,
301 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
302 CPR_simulate_fbless_SIZE);
303 if(range) {
304 if(!range->incompatible) {
305 right = range->right;
306 /* Use 4 instead of sizeof(long) is justified! */
307 if(right.type == ARE_VALUE && right.value <= 4)
308 return FL_FITSOK;
309 }
310 asn1constraint_range_free(range);
311 }
312
313 /*
314 * Third, pull up the PER visible range of the INTEGER.
315 */
316 range = asn1constraint_compute_PER_range(expr->expr_type,
317 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
vlm75b3a532005-08-14 02:18:27 +0000318 if(!range
319 || range->empty_constraint
320 || range->extensible
321 || range->incompatible
322 || range->not_PER_visible
323 ) {
324 asn1constraint_range_free(range);
325 return (arg->flags & A1C_USE_NATIVE_TYPES)
326 ? FL_FORCED : FL_NOTFIT;
327 }
328
329 left = range->left;
330 right = range->right;
331 asn1constraint_range_free(range);
332
333 /* If some fixed value is outside of target range, not fit */
334 if(left.type == ARE_VALUE
335 && (left.value < LEFTMIN || left.value > RIGHTMAX))
336 return FL_NOTFIT;
337 if(right.type == ARE_VALUE
338 && (right.value > RIGHTMAX || right.value < LEFTMIN))
339 return FL_NOTFIT;
340
341 /* If the range is open, fits only if -fnative-types is given */
342 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
343 return (arg->flags & A1C_USE_NATIVE_TYPES)
344 ? FL_FORCED : FL_NOTFIT;
345 }
346
347 return FL_FITSOK;
348}
349