blob: f96b3896a804f1c0ee2dbe3c7d9aa99826b05ad1 [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 Walkina00d6b32006-03-21 03:40:38 +000036asn1c_make_identifier(enum ami_flags_e flags, asn1p_expr_t *expr, ...) {
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 Walkina00d6b32006-03-21 03:40:38 +000043 char *first = 0;
44 char *second = 0;
Lev Walkin4efbfb72005-02-25 14:20:30 +000045 size_t size;
Lev Walkinf15320b2004-06-03 03:38:44 +000046 char *p;
47
Lev Walkina00d6b32006-03-21 03:40:38 +000048 if(expr) {
49 /*
50 * Estimate the necessary storage size
51 */
52 if(expr->Identifier == NULL)
53 return "Member";
54 size = strlen(expr->Identifier);
55 if(expr->spec_index != -1) {
56 static char buf[32];
57 second = buf;
58 size += 1 + snprintf(buf, sizeof buf, "%dP%d",
59 expr->_lineno, expr->spec_index);
60 }
61 } else {
62 size = -1;
63 }
Lev Walkinf15320b2004-06-03 03:38:44 +000064
Lev Walkina00d6b32006-03-21 03:40:38 +000065 va_start(ap, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +000066 while((str = va_arg(ap, char *)))
67 size += 1 + strlen(str);
68 va_end(ap);
Lev Walkina00d6b32006-03-21 03:40:38 +000069 if(size == -1) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +000070
71 /*
72 * Make sure we have this amount of storage.
73 */
74 if(storage_size <= size) {
75 if(storage) free(storage);
76 storage = malloc(size + 1);
77 if(storage) {
78 storage_size = size;
79 } else {
80 storage_size = 0;
81 return NULL;
82 }
83 }
84
85 /*
86 * Fill-in the storage.
87 */
Lev Walkina00d6b32006-03-21 03:40:38 +000088 va_start(ap, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +000089 p = storage;
Lev Walkina00d6b32006-03-21 03:40:38 +000090 nextstr = "";
91 for(p = storage, str = 0; str || nextstr; str = nextstr) {
Lev Walkinf15320b2004-06-03 03:38:44 +000092 int subst_made = 0;
Lev Walkina00d6b32006-03-21 03:40:38 +000093 nextstr = second ? second : va_arg(ap, char *);
94
95 if(str == 0) {
96 if(expr) {
97 str = expr->Identifier;
98 first = str;
99 second = 0;
100 } else {
101 first = nextstr;
102 continue;
103 }
104 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000105
106 if(str[0] == ' ' && str[1] == '\0') {
107 *p++ = ' ';
108 nodelimiter = 1; /* No delimiter */
109 continue;
110 }
111
Lev Walkina00d6b32006-03-21 03:40:38 +0000112 if(str != first && !nodelimiter)
Lev Walkinf15320b2004-06-03 03:38:44 +0000113 *p++ = '_'; /* Delimiter between tokens */
114 nodelimiter = 0;
115
Lev Walkin801fabc2005-01-28 12:18:50 +0000116 /*
117 * If it is a single argument, check that it does not clash
118 * with C/C++ language keywords.
119 */
120 if((flags & AMI_CHECK_RESERVED)
Lev Walkina00d6b32006-03-21 03:40:38 +0000121 && str == first && !nextstr && reserved_keyword(str)) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000122 *p++ = toupper(*str++);
123 /* Fall through */
124 }
125
Lev Walkinf15320b2004-06-03 03:38:44 +0000126 for(; *str; str++) {
127 if(isalnum(*str)) {
128 *p++ = *str;
129 subst_made = 0;
130 } else if(!subst_made++) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000131 if((flags & AMI_MASK_ONLY_SPACES)
132 && !isspace(*str)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000133 *p ++ = *str;
134 } else {
135 *p++ = '_';
136 }
137 }
138 }
139 }
140 va_end(ap);
141 *p = '\0';
142
143 assert((p - storage) <= storage_size);
144
145 return storage;
146}
147
Lev Walkinf15320b2004-06-03 03:38:44 +0000148char *
149asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
Lev Walkina00d6b32006-03-21 03:40:38 +0000150 asn1p_expr_t *exprid = 0;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000151 asn1p_expr_t *top_parent;
Lev Walkina00d6b32006-03-21 03:40:38 +0000152 asn1p_expr_t *terminal;
Lev Walkinf15320b2004-06-03 03:38:44 +0000153 char *typename;
154
Lev Walkin5a8219a2004-09-08 00:28:57 +0000155 /* Rewind to the topmost parent expression */
156 if((top_parent = expr->parent_expr))
157 while(top_parent->parent_expr)
158 top_parent = top_parent->parent_expr;
159
Lev Walkinc2a75092006-03-14 11:52:12 +0000160 DEBUG("asn1c_type_name(%s: 0x%x)", expr->Identifier, expr->expr_type);
161
Lev Walkinf15320b2004-06-03 03:38:44 +0000162 switch(expr->expr_type) {
163 case A1TC_REFERENCE:
164 typename = expr->reference->components[
165 expr->reference->comp_count-1].name;
166 if(typename[0] == '&') {
167 arg_t tmp = *arg;
168
169 /*
170 * This is a reference to a type defined in a class.
171 * Resolve it and use instead.
172 */
Lev Walkinb85a8132005-08-18 13:38:19 +0000173 tmp.expr = asn1f_class_access_ex(arg->asn,
Lev Walkina00d6b32006-03-21 03:40:38 +0000174 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
Lev Walkinc2a75092006-03-14 11:52:12 +0000175 if(!tmp.expr) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000176
Lev Walkinf15320b2004-06-03 03:38:44 +0000177 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000178 }
179
Lev Walkina00d6b32006-03-21 03:40:38 +0000180 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
181
Lev Walkinc8285712005-03-04 22:18:20 +0000182 if(_format == TNF_RSAFE) {
Lev Walkinc8285712005-03-04 22:18:20 +0000183 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
184 typename = terminal->Identifier;
185 }
186 }
187
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000188 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000189 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000190 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000191 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000192 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000193 */
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000194 if(terminal && terminal == top_parent) {
195 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000196 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000197 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000198
199 if(terminal && terminal->spec_index != -1) {
200 exprid = terminal;
201 typename = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000202 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000203
Lev Walkinf15320b2004-06-03 03:38:44 +0000204 break;
205 case ASN_BASIC_INTEGER:
206 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000207 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-08-14 02:18:27 +0000208 if((expr->expr_type == ASN_BASIC_REAL
209 && (arg->flags & A1C_USE_NATIVE_TYPES))
210 || asn1c_type_fits_long(arg, expr)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000211 switch(_format) {
212 case TNF_CTYPE:
213 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000214 if(expr->expr_type == ASN_BASIC_REAL)
215 return "double";
Lev Walkinf15320b2004-06-03 03:38:44 +0000216 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000217 return "long";
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000218 default: break;
219 }
220 switch(expr->expr_type) {
221 case ASN_BASIC_INTEGER:
222 return "NativeInteger";
223 case ASN_BASIC_ENUMERATED:
224 return "NativeEnumerated";
225 case ASN_BASIC_REAL:
226 return "NativeReal";
227 default: break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000228 }
229 }
230 /* Fall through */
231 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000232 if(expr->expr_type
233 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000234 if(_format == TNF_RSAFE)
235 _format = TNF_CTYPE;
236 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
237 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000238 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000239 typename = expr->Identifier;
240 }
241 }
242
243 switch(_format) {
244 case TNF_UNMODIFIED:
245 case TNF_INCLUDE:
Lev Walkina00d6b32006-03-21 03:40:38 +0000246 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES,
247 0, exprid ? exprid->Identifier : typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000248 case TNF_SAFE:
Lev Walkina00d6b32006-03-21 03:40:38 +0000249 return asn1c_make_identifier(0, exprid, typename, 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000250 case TNF_CTYPE: /* C type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000251 return asn1c_make_identifier(0, exprid,
252 exprid?"t":typename, exprid?0:"t", 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000253 case TNF_RSAFE: /* Recursion-safe type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000254 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
Lev Walkinc8285712005-03-04 22:18:20 +0000255 "struct", " ", typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000256 }
257
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000258 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000259 return typename;
260}
261
Lev Walkin082cadc2005-08-14 02:18:27 +0000262/*
263 * Check whether the specified INTEGER or ENUMERATED type can be represented
264 * using the generic 'long' type.
265 */
266enum asn1c_fitslong_e
267asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
268 asn1cnst_range_t *range = 0;
269 asn1cnst_edge_t left;
270 asn1cnst_edge_t right;
271 asn1p_expr_t *v;
272
273/*
274 * Since we don't know the sizeof(long) on the possible target platform
275 * which will be compiling the code generated by asn1c, let's play it
276 * simple: long's range is equal to or greater than int32_t.
Lev Walkin4c97bd62005-08-15 01:01:24 +0000277 * NOTE: the most negative integer cannot be written in C, as the C99
278 * standard will give it an unsigned type.
279 * It is defined here as a constant expression.
Lev Walkin082cadc2005-08-14 02:18:27 +0000280 */
Lev Walkinc08c3cf2005-08-15 01:04:48 +0000281#define RIGHTMAX 2147483647 /* of 32-bit integer type */
282#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
Lev Walkin082cadc2005-08-14 02:18:27 +0000283
284 /* Descend to the terminal type */
285 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
286 if(expr == 0) return FL_NOTFIT;
287
288 /* The "fits into long" operation is relevant only for integer types */
289 switch(expr->expr_type) {
290 case ASN_BASIC_INTEGER:
291 case ASN_BASIC_ENUMERATED:
292 break;
293 default:
294 return FL_NOTFIT;
295 }
296
297 /*
298 * First, evaluate the range of explicitly given identifiers.
299 */
300 TQ_FOR(v, &(expr->members), next) {
301 if(v->expr_type != A1TC_UNIVERVAL)
302 continue;
303 if(v->value->value.v_integer < LEFTMIN
304 || v->value->value.v_integer > RIGHTMAX)
305 return FL_NOTFIT;
306 }
307
Lev Walkin4b553412005-08-14 14:45:44 +0000308 if(!expr->combined_constraints)
309 return (arg->flags & A1C_USE_NATIVE_TYPES)
310 ? FL_FORCED : FL_NOTFIT;
311
Lev Walkin082cadc2005-08-14 02:18:27 +0000312 /*
Lev Walkin4b553412005-08-14 14:45:44 +0000313 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
314 * applied (non-standard! but we can deal with this) to the type.
315 * Check the range.
Lev Walkin082cadc2005-08-14 02:18:27 +0000316 */
Lev Walkin4b553412005-08-14 14:45:44 +0000317 range = asn1constraint_compute_PER_range(expr->expr_type,
318 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
319 CPR_simulate_fbless_SIZE);
320 if(range) {
321 if(!range->incompatible) {
322 right = range->right;
323 /* Use 4 instead of sizeof(long) is justified! */
324 if(right.type == ARE_VALUE && right.value <= 4)
325 return FL_FITSOK;
326 }
327 asn1constraint_range_free(range);
328 }
329
330 /*
331 * Third, pull up the PER visible range of the INTEGER.
332 */
333 range = asn1constraint_compute_PER_range(expr->expr_type,
334 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
Lev Walkin082cadc2005-08-14 02:18:27 +0000335 if(!range
336 || range->empty_constraint
337 || range->extensible
338 || range->incompatible
339 || range->not_PER_visible
340 ) {
341 asn1constraint_range_free(range);
342 return (arg->flags & A1C_USE_NATIVE_TYPES)
343 ? FL_FORCED : FL_NOTFIT;
344 }
345
346 left = range->left;
347 right = range->right;
348 asn1constraint_range_free(range);
349
350 /* If some fixed value is outside of target range, not fit */
351 if(left.type == ARE_VALUE
352 && (left.value < LEFTMIN || left.value > RIGHTMAX))
353 return FL_NOTFIT;
354 if(right.type == ARE_VALUE
355 && (right.value > RIGHTMAX || right.value < LEFTMIN))
356 return FL_NOTFIT;
357
358 /* If the range is open, fits only if -fnative-types is given */
359 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
360 return (arg->flags & A1C_USE_NATIVE_TYPES)
361 ? FL_FORCED : FL_NOTFIT;
362 }
363
364 return FL_FITSOK;
365}
366