blob: 8805347b33e4eb1972a37eb219e78bd0cfdd66be [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 Walkinc2a75092006-03-14 11:52:12 +0000134 DEBUG("asn1c_type_name(%s: 0x%x)", expr->Identifier, expr->expr_type);
135
Lev Walkinf15320b2004-06-03 03:38:44 +0000136 switch(expr->expr_type) {
137 case A1TC_REFERENCE:
138 typename = expr->reference->components[
139 expr->reference->comp_count-1].name;
140 if(typename[0] == '&') {
141 arg_t tmp = *arg;
142
143 /*
144 * This is a reference to a type defined in a class.
145 * Resolve it and use instead.
146 */
Lev Walkinb85a8132005-08-18 13:38:19 +0000147 tmp.expr = asn1f_class_access_ex(arg->asn,
148 arg->expr->module, arg->expr, expr->reference);
Lev Walkinc2a75092006-03-14 11:52:12 +0000149 if(!tmp.expr) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000150
Lev Walkinf15320b2004-06-03 03:38:44 +0000151 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000152 }
153
Lev Walkinc8285712005-03-04 22:18:20 +0000154 if(_format == TNF_RSAFE) {
155 asn1p_expr_t *terminal;
156 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
157 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
158 typename = terminal->Identifier;
159 }
160 }
161
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000162 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000163 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000164 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000165 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000166 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000167 */
168 asn1p_expr_t *terminal;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000169 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000170 if(terminal && terminal == top_parent) {
171 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000172 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000173 }
174 break;
Lev Walkin0e22b982004-08-25 02:03:26 +0000175#if 0
Lev Walkinf15320b2004-06-03 03:38:44 +0000176 case ASN_CONSTR_SEQUENCE_OF:
177 case ASN_CONSTR_SET_OF:
178 if(expr->Identifier) {
179 typename = expr->Identifier;
180 } else {
181 asn1p_expr_t *child;
182 child = TQ_FIRST(&(expr->members));
183 typename = asn1c_type_name(arg, child, _format);
184 if(typename)
185 return typename;
186 _format = TNF_SAFE;
187 typename = child->Identifier;
188 }
189 break;
Lev Walkin0e22b982004-08-25 02:03:26 +0000190#endif
Lev Walkinf15320b2004-06-03 03:38:44 +0000191 case ASN_BASIC_INTEGER:
192 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000193 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-08-14 02:18:27 +0000194 if((expr->expr_type == ASN_BASIC_REAL
195 && (arg->flags & A1C_USE_NATIVE_TYPES))
196 || asn1c_type_fits_long(arg, expr)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000197 switch(_format) {
198 case TNF_CTYPE:
199 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000200 if(expr->expr_type == ASN_BASIC_REAL)
201 return "double";
Lev Walkinf15320b2004-06-03 03:38:44 +0000202 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000203 return "long";
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000204 default: break;
205 }
206 switch(expr->expr_type) {
207 case ASN_BASIC_INTEGER:
208 return "NativeInteger";
209 case ASN_BASIC_ENUMERATED:
210 return "NativeEnumerated";
211 case ASN_BASIC_REAL:
212 return "NativeReal";
213 default: break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000214 }
215 }
216 /* Fall through */
217 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000218 if(expr->expr_type
219 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000220 if(_format == TNF_RSAFE)
221 _format = TNF_CTYPE;
222 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
223 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000224 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000225 typename = expr->Identifier;
226 }
227 }
228
229 switch(_format) {
230 case TNF_UNMODIFIED:
231 case TNF_INCLUDE:
Lev Walkinc8285712005-03-04 22:18:20 +0000232 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES, typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000233 case TNF_SAFE:
Lev Walkinc8285712005-03-04 22:18:20 +0000234 return asn1c_make_identifier(0, typename, 0);
235 case TNF_CTYPE: /* C type */
236 return asn1c_make_identifier(0, typename, "t", 0);
237 case TNF_RSAFE: /* Recursion-safe type */
238 return asn1c_make_identifier(AMI_CHECK_RESERVED,
239 "struct", " ", typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000240 }
241
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000242 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000243 return typename;
244}
245
Lev Walkin082cadc2005-08-14 02:18:27 +0000246/*
247 * Check whether the specified INTEGER or ENUMERATED type can be represented
248 * using the generic 'long' type.
249 */
250enum asn1c_fitslong_e
251asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
252 asn1cnst_range_t *range = 0;
253 asn1cnst_edge_t left;
254 asn1cnst_edge_t right;
255 asn1p_expr_t *v;
256
257/*
258 * Since we don't know the sizeof(long) on the possible target platform
259 * which will be compiling the code generated by asn1c, let's play it
260 * simple: long's range is equal to or greater than int32_t.
Lev Walkin4c97bd62005-08-15 01:01:24 +0000261 * NOTE: the most negative integer cannot be written in C, as the C99
262 * standard will give it an unsigned type.
263 * It is defined here as a constant expression.
Lev Walkin082cadc2005-08-14 02:18:27 +0000264 */
Lev Walkinc08c3cf2005-08-15 01:04:48 +0000265#define RIGHTMAX 2147483647 /* of 32-bit integer type */
266#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
Lev Walkin082cadc2005-08-14 02:18:27 +0000267
268 /* Descend to the terminal type */
269 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
270 if(expr == 0) return FL_NOTFIT;
271
272 /* The "fits into long" operation is relevant only for integer types */
273 switch(expr->expr_type) {
274 case ASN_BASIC_INTEGER:
275 case ASN_BASIC_ENUMERATED:
276 break;
277 default:
278 return FL_NOTFIT;
279 }
280
281 /*
282 * First, evaluate the range of explicitly given identifiers.
283 */
284 TQ_FOR(v, &(expr->members), next) {
285 if(v->expr_type != A1TC_UNIVERVAL)
286 continue;
287 if(v->value->value.v_integer < LEFTMIN
288 || v->value->value.v_integer > RIGHTMAX)
289 return FL_NOTFIT;
290 }
291
Lev Walkin4b553412005-08-14 14:45:44 +0000292 if(!expr->combined_constraints)
293 return (arg->flags & A1C_USE_NATIVE_TYPES)
294 ? FL_FORCED : FL_NOTFIT;
295
Lev Walkin082cadc2005-08-14 02:18:27 +0000296 /*
Lev Walkin4b553412005-08-14 14:45:44 +0000297 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
298 * applied (non-standard! but we can deal with this) to the type.
299 * Check the range.
Lev Walkin082cadc2005-08-14 02:18:27 +0000300 */
Lev Walkin4b553412005-08-14 14:45:44 +0000301 range = asn1constraint_compute_PER_range(expr->expr_type,
302 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
303 CPR_simulate_fbless_SIZE);
304 if(range) {
305 if(!range->incompatible) {
306 right = range->right;
307 /* Use 4 instead of sizeof(long) is justified! */
308 if(right.type == ARE_VALUE && right.value <= 4)
309 return FL_FITSOK;
310 }
311 asn1constraint_range_free(range);
312 }
313
314 /*
315 * Third, pull up the PER visible range of the INTEGER.
316 */
317 range = asn1constraint_compute_PER_range(expr->expr_type,
318 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
Lev Walkin082cadc2005-08-14 02:18:27 +0000319 if(!range
320 || range->empty_constraint
321 || range->extensible
322 || range->incompatible
323 || range->not_PER_visible
324 ) {
325 asn1constraint_range_free(range);
326 return (arg->flags & A1C_USE_NATIVE_TYPES)
327 ? FL_FORCED : FL_NOTFIT;
328 }
329
330 left = range->left;
331 right = range->right;
332 asn1constraint_range_free(range);
333
334 /* If some fixed value is outside of target range, not fit */
335 if(left.type == ARE_VALUE
336 && (left.value < LEFTMIN || left.value > RIGHTMAX))
337 return FL_NOTFIT;
338 if(right.type == ARE_VALUE
339 && (right.value > RIGHTMAX || right.value < LEFTMIN))
340 return FL_NOTFIT;
341
342 /* If the range is open, fits only if -fnative-types is given */
343 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
344 return (arg->flags & A1C_USE_NATIVE_TYPES)
345 ? FL_FORCED : FL_NOTFIT;
346 }
347
348 return FL_FITSOK;
349}
350