blob: 779426aaf1126eaa7ee81088530fd45843a27394 [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) {
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/*
Lev Walkinf15320b2004-06-03 03:38:44 +000032 * Construct identifier from multiple parts.
33 * Convert unsafe characters to underscores.
34 */
35char *
Lev Walkin801fabc2005-01-28 12:18:50 +000036asn1c_make_identifier(enum ami_flags_e flags, char *arg1, ...) {
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 Walkin4efbfb72005-02-25 14:20:30 +000043 size_t size;
Lev Walkinf15320b2004-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;
Lev Walkin801fabc2005-01-28 12:18:50 +000078 for(str = arg1; str; str = nextstr) {
Lev Walkinf15320b2004-06-03 03:38:44 +000079 int subst_made = 0;
Lev Walkin801fabc2005-01-28 12:18:50 +000080 nextstr = va_arg(ap, char *);
Lev Walkinf15320b2004-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
Lev Walkin801fabc2005-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
Lev Walkinf15320b2004-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++) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000107 if((flags & AMI_MASK_ONLY_SPACES)
108 && !isspace(*str)) {
Lev Walkinf15320b2004-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
Lev Walkinf15320b2004-06-03 03:38:44 +0000124char *
125asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
Lev Walkin5a8219a2004-09-08 00:28:57 +0000126 asn1p_expr_t *top_parent;
Lev Walkinf15320b2004-06-03 03:38:44 +0000127 char *typename;
128
Lev Walkin5a8219a2004-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
Lev Walkinf15320b2004-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 */
Lev Walkinb85a8132005-08-18 13:38:19 +0000145 tmp.expr = asn1f_class_access_ex(arg->asn,
146 arg->expr->module, arg->expr, expr->reference);
Lev Walkinf15320b2004-06-03 03:38:44 +0000147 if(tmp.expr) return NULL;
148
Lev Walkinf15320b2004-06-03 03:38:44 +0000149 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000150 }
151
Lev Walkinc8285712005-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
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000160 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000161 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000162 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000163 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000164 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000165 */
166 asn1p_expr_t *terminal;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000167 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000168 if(terminal && terminal == top_parent) {
169 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000170 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000171 }
172 break;
Lev Walkin0e22b982004-08-25 02:03:26 +0000173#if 0
Lev Walkinf15320b2004-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;
Lev Walkin0e22b982004-08-25 02:03:26 +0000188#endif
Lev Walkinf15320b2004-06-03 03:38:44 +0000189 case ASN_BASIC_INTEGER:
190 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000191 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-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)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000195 switch(_format) {
196 case TNF_CTYPE:
197 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000198 if(expr->expr_type == ASN_BASIC_REAL)
199 return "double";
Lev Walkinf15320b2004-06-03 03:38:44 +0000200 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000201 return "long";
Lev Walkinc78cbfb2004-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;
Lev Walkinf15320b2004-06-03 03:38:44 +0000212 }
213 }
214 /* Fall through */
215 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000216 if(expr->expr_type
217 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000218 if(_format == TNF_RSAFE)
219 _format = TNF_CTYPE;
220 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
221 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000222 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000223 typename = expr->Identifier;
224 }
225 }
226
227 switch(_format) {
228 case TNF_UNMODIFIED:
229 case TNF_INCLUDE:
Lev Walkinc8285712005-03-04 22:18:20 +0000230 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES, typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000231 case TNF_SAFE:
Lev Walkinc8285712005-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);
Lev Walkinf15320b2004-06-03 03:38:44 +0000238 }
239
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000240 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000241 return typename;
242}
243
Lev Walkin082cadc2005-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.
Lev Walkin4c97bd62005-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.
Lev Walkin082cadc2005-08-14 02:18:27 +0000262 */
Lev Walkinc08c3cf2005-08-15 01:04:48 +0000263#define RIGHTMAX 2147483647 /* of 32-bit integer type */
264#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
Lev Walkin082cadc2005-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
Lev Walkin4b553412005-08-14 14:45:44 +0000290 if(!expr->combined_constraints)
291 return (arg->flags & A1C_USE_NATIVE_TYPES)
292 ? FL_FORCED : FL_NOTFIT;
293
Lev Walkin082cadc2005-08-14 02:18:27 +0000294 /*
Lev Walkin4b553412005-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.
Lev Walkin082cadc2005-08-14 02:18:27 +0000298 */
Lev Walkin4b553412005-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);
Lev Walkin082cadc2005-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