blob: c8adce66c87b1785bcfe9bb73ceb23cc1b0d6d9f [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) {
Lev Walkinc46b7cb2006-08-18 02:27:55 +000023 size_t i;
Lev Walkin801fabc2005-01-28 12:18:50 +000024 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 Walkinc46b7cb2006-08-18 02:27:55 +000045 ssize_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 Walkin22b5ed42006-09-13 02:51:20 +0000112 if(str != first && !nodelimiter && !(flags & AMI_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 Walkin22b5ed42006-09-13 02:51:20 +0000153 int stdname = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000154 char *typename;
155
Lev Walkin5a8219a2004-09-08 00:28:57 +0000156 /* Rewind to the topmost parent expression */
157 if((top_parent = expr->parent_expr))
158 while(top_parent->parent_expr)
159 top_parent = top_parent->parent_expr;
160
Lev Walkinc2a75092006-03-14 11:52:12 +0000161 DEBUG("asn1c_type_name(%s: 0x%x)", expr->Identifier, expr->expr_type);
162
Lev Walkinf15320b2004-06-03 03:38:44 +0000163 switch(expr->expr_type) {
164 case A1TC_REFERENCE:
165 typename = expr->reference->components[
166 expr->reference->comp_count-1].name;
167 if(typename[0] == '&') {
168 arg_t tmp = *arg;
169
170 /*
171 * This is a reference to a type defined in a class.
172 * Resolve it and use instead.
173 */
Lev Walkinb85a8132005-08-18 13:38:19 +0000174 tmp.expr = asn1f_class_access_ex(arg->asn,
Lev Walkina00d6b32006-03-21 03:40:38 +0000175 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
Lev Walkinc2a75092006-03-14 11:52:12 +0000176 if(!tmp.expr) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000177
Lev Walkinf15320b2004-06-03 03:38:44 +0000178 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000179 }
180
Lev Walkina00d6b32006-03-21 03:40:38 +0000181 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
182
Lev Walkinc8285712005-03-04 22:18:20 +0000183 if(_format == TNF_RSAFE) {
Lev Walkinc8285712005-03-04 22:18:20 +0000184 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
185 typename = terminal->Identifier;
186 }
187 }
188
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000189 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000190 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000191 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000192 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000193 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000194 */
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000195 if(terminal && terminal == top_parent) {
196 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000197 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000198 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000199
200 if(terminal && terminal->spec_index != -1) {
201 exprid = terminal;
202 typename = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000203 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000204
Lev Walkinf15320b2004-06-03 03:38:44 +0000205 break;
206 case ASN_BASIC_INTEGER:
207 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000208 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-08-14 02:18:27 +0000209 if((expr->expr_type == ASN_BASIC_REAL
210 && (arg->flags & A1C_USE_NATIVE_TYPES))
211 || asn1c_type_fits_long(arg, expr)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000212 switch(_format) {
213 case TNF_CTYPE:
214 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000215 if(expr->expr_type == ASN_BASIC_REAL)
216 return "double";
Lev Walkinf15320b2004-06-03 03:38:44 +0000217 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000218 return "long";
Lev Walkin22b5ed42006-09-13 02:51:20 +0000219 default:
220 typename = 0;
221 switch(expr->expr_type) {
222 case ASN_BASIC_INTEGER:
223 typename = "NativeInteger"; break;
224 case ASN_BASIC_ENUMERATED:
225 typename = "NativeEnumerated"; break;
226 case ASN_BASIC_REAL:
227 typename = "NativeReal"; break;
228 default:
229 break;
230 }
231 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000232 }
Lev Walkin22b5ed42006-09-13 02:51:20 +0000233 if(typename) {
234 if(_format != TNF_INCLUDE)
235 return typename;
236 stdname = 1;
237 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000238 }
239 }
240 /* Fall through */
241 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000242 if(expr->expr_type
243 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000244 if(_format == TNF_RSAFE)
245 _format = TNF_CTYPE;
Lev Walkin22b5ed42006-09-13 02:51:20 +0000246 stdname = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000247 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
248 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000249 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000250 typename = expr->Identifier;
251 }
252 }
253
254 switch(_format) {
255 case TNF_UNMODIFIED:
Lev Walkina00d6b32006-03-21 03:40:38 +0000256 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES,
257 0, exprid ? exprid->Identifier : typename, 0);
Lev Walkin22b5ed42006-09-13 02:51:20 +0000258 case TNF_INCLUDE:
259 return asn1c_make_identifier(
260 AMI_MASK_ONLY_SPACES | AMI_NODELIMITER,
261 0, stdname ? "<" : "\"",
262 exprid ? exprid->Identifier : typename,
263 stdname ? ".h>" : ".h\"", 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000264 case TNF_SAFE:
Lev Walkina00d6b32006-03-21 03:40:38 +0000265 return asn1c_make_identifier(0, exprid, typename, 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000266 case TNF_CTYPE: /* C type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000267 return asn1c_make_identifier(0, exprid,
268 exprid?"t":typename, exprid?0:"t", 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000269 case TNF_RSAFE: /* Recursion-safe type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000270 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
Lev Walkinc8285712005-03-04 22:18:20 +0000271 "struct", " ", typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000272 }
273
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000274 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000275 return typename;
276}
277
Lev Walkin082cadc2005-08-14 02:18:27 +0000278/*
279 * Check whether the specified INTEGER or ENUMERATED type can be represented
280 * using the generic 'long' type.
281 */
282enum asn1c_fitslong_e
283asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
284 asn1cnst_range_t *range = 0;
285 asn1cnst_edge_t left;
286 asn1cnst_edge_t right;
287 asn1p_expr_t *v;
288
289/*
290 * Since we don't know the sizeof(long) on the possible target platform
291 * which will be compiling the code generated by asn1c, let's play it
292 * simple: long's range is equal to or greater than int32_t.
Lev Walkin4c97bd62005-08-15 01:01:24 +0000293 * NOTE: the most negative integer cannot be written in C, as the C99
294 * standard will give it an unsigned type.
295 * It is defined here as a constant expression.
Lev Walkin082cadc2005-08-14 02:18:27 +0000296 */
Lev Walkinc08c3cf2005-08-15 01:04:48 +0000297#define RIGHTMAX 2147483647 /* of 32-bit integer type */
298#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
Lev Walkin082cadc2005-08-14 02:18:27 +0000299
300 /* Descend to the terminal type */
301 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
302 if(expr == 0) return FL_NOTFIT;
303
304 /* The "fits into long" operation is relevant only for integer types */
305 switch(expr->expr_type) {
306 case ASN_BASIC_INTEGER:
307 case ASN_BASIC_ENUMERATED:
308 break;
309 default:
310 return FL_NOTFIT;
311 }
312
313 /*
314 * First, evaluate the range of explicitly given identifiers.
315 */
316 TQ_FOR(v, &(expr->members), next) {
317 if(v->expr_type != A1TC_UNIVERVAL)
318 continue;
319 if(v->value->value.v_integer < LEFTMIN
320 || v->value->value.v_integer > RIGHTMAX)
321 return FL_NOTFIT;
322 }
323
Lev Walkin4b553412005-08-14 14:45:44 +0000324 if(!expr->combined_constraints)
325 return (arg->flags & A1C_USE_NATIVE_TYPES)
326 ? FL_FORCED : FL_NOTFIT;
327
Lev Walkin082cadc2005-08-14 02:18:27 +0000328 /*
Lev Walkin4b553412005-08-14 14:45:44 +0000329 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
330 * applied (non-standard! but we can deal with this) to the type.
331 * Check the range.
Lev Walkin082cadc2005-08-14 02:18:27 +0000332 */
Lev Walkin4b553412005-08-14 14:45:44 +0000333 range = asn1constraint_compute_PER_range(expr->expr_type,
334 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
335 CPR_simulate_fbless_SIZE);
336 if(range) {
337 if(!range->incompatible) {
338 right = range->right;
339 /* Use 4 instead of sizeof(long) is justified! */
340 if(right.type == ARE_VALUE && right.value <= 4)
341 return FL_FITSOK;
342 }
343 asn1constraint_range_free(range);
344 }
345
346 /*
347 * Third, pull up the PER visible range of the INTEGER.
348 */
349 range = asn1constraint_compute_PER_range(expr->expr_type,
350 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
Lev Walkin082cadc2005-08-14 02:18:27 +0000351 if(!range
352 || range->empty_constraint
353 || range->extensible
354 || range->incompatible
355 || range->not_PER_visible
356 ) {
357 asn1constraint_range_free(range);
358 return (arg->flags & A1C_USE_NATIVE_TYPES)
359 ? FL_FORCED : FL_NOTFIT;
360 }
361
362 left = range->left;
363 right = range->right;
364 asn1constraint_range_free(range);
365
366 /* If some fixed value is outside of target range, not fit */
367 if(left.type == ARE_VALUE
368 && (left.value < LEFTMIN || left.value > RIGHTMAX))
369 return FL_NOTFIT;
370 if(right.type == ARE_VALUE
371 && (right.value > RIGHTMAX || right.value < LEFTMIN))
372 return FL_NOTFIT;
373
374 /* If the range is open, fits only if -fnative-types is given */
375 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
376 return (arg->flags & A1C_USE_NATIVE_TYPES)
377 ? FL_FORCED : FL_NOTFIT;
378 }
379
380 return FL_FITSOK;
381}
382