blob: c8cd2e70cc00b7c15fb9dfcbeff9a286dd511c3b [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 */
145 tmp.expr = asn1f_class_access_ex(arg->asn, arg->mod,
Lev Walkin065a74b2004-08-22 03:23:15 +0000146 arg->expr, expr->reference);
Lev Walkinf15320b2004-06-03 03:38:44 +0000147 if(tmp.expr) return NULL;
148
Lev Walkin065a74b2004-08-22 03:23:15 +0000149 tmp.mod = tmp.expr->module;
Lev Walkinf15320b2004-06-03 03:38:44 +0000150 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000151 }
152
Lev Walkinc8285712005-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
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000161 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000162 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000163 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000164 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000165 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000166 */
167 asn1p_expr_t *terminal;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000168 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000169 if(terminal && terminal == top_parent) {
170 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000171 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000172 }
173 break;
Lev Walkin0e22b982004-08-25 02:03:26 +0000174#if 0
Lev Walkinf15320b2004-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;
Lev Walkin0e22b982004-08-25 02:03:26 +0000189#endif
Lev Walkinf15320b2004-06-03 03:38:44 +0000190 case ASN_BASIC_INTEGER:
191 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000192 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-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)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000196 switch(_format) {
197 case TNF_CTYPE:
198 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000199 if(expr->expr_type == ASN_BASIC_REAL)
200 return "double";
Lev Walkinf15320b2004-06-03 03:38:44 +0000201 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000202 return "long";
Lev Walkinc78cbfb2004-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;
Lev Walkinf15320b2004-06-03 03:38:44 +0000213 }
214 }
215 /* Fall through */
216 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000217 if(expr->expr_type
218 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000219 if(_format == TNF_RSAFE)
220 _format = TNF_CTYPE;
221 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
222 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000223 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000224 typename = expr->Identifier;
225 }
226 }
227
228 switch(_format) {
229 case TNF_UNMODIFIED:
230 case TNF_INCLUDE:
Lev Walkinc8285712005-03-04 22:18:20 +0000231 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES, typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000232 case TNF_SAFE:
Lev Walkinc8285712005-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);
Lev Walkinf15320b2004-06-03 03:38:44 +0000239 }
240
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000241 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000242 return typename;
243}
244
Lev Walkin082cadc2005-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.
Lev Walkin4c97bd62005-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.
Lev Walkin082cadc2005-08-14 02:18:27 +0000263 */
Lev Walkin4c97bd62005-08-15 01:01:24 +0000264#define LEFTMIN 2147483647
265#define RIGHTMAX (-LEFTMIN-1)
Lev Walkin082cadc2005-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
Lev Walkin4b553412005-08-14 14:45:44 +0000291 if(!expr->combined_constraints)
292 return (arg->flags & A1C_USE_NATIVE_TYPES)
293 ? FL_FORCED : FL_NOTFIT;
294
Lev Walkin082cadc2005-08-14 02:18:27 +0000295 /*
Lev Walkin4b553412005-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.
Lev Walkin082cadc2005-08-14 02:18:27 +0000299 */
Lev Walkin4b553412005-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);
Lev Walkin082cadc2005-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