blob: 543a165b36e46f2bd193acb078f167adf5da2538 [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 Walkin725883b2006-10-09 12:07:58 +0000161 if(0) DEBUG("asn1c_type_name(%s: 0x%x)",
162 expr->Identifier, expr->expr_type);
Lev Walkinc2a75092006-03-14 11:52:12 +0000163
Lev Walkinf15320b2004-06-03 03:38:44 +0000164 switch(expr->expr_type) {
165 case A1TC_REFERENCE:
166 typename = expr->reference->components[
167 expr->reference->comp_count-1].name;
168 if(typename[0] == '&') {
169 arg_t tmp = *arg;
170
171 /*
172 * This is a reference to a type defined in a class.
173 * Resolve it and use instead.
174 */
Lev Walkinb85a8132005-08-18 13:38:19 +0000175 tmp.expr = asn1f_class_access_ex(arg->asn,
Lev Walkina00d6b32006-03-21 03:40:38 +0000176 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
Lev Walkinc2a75092006-03-14 11:52:12 +0000177 if(!tmp.expr) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000178
Lev Walkinf15320b2004-06-03 03:38:44 +0000179 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000180 }
181
Lev Walkina00d6b32006-03-21 03:40:38 +0000182 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
183
Lev Walkinc8285712005-03-04 22:18:20 +0000184 if(_format == TNF_RSAFE) {
Lev Walkinc8285712005-03-04 22:18:20 +0000185 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
186 typename = terminal->Identifier;
187 }
188 }
189
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000190 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000191 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000192 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000193 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000194 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000195 */
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000196 if(terminal && terminal == top_parent) {
197 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000198 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000199 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000200
201 if(terminal && terminal->spec_index != -1) {
202 exprid = terminal;
203 typename = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000204 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000205
Lev Walkinf15320b2004-06-03 03:38:44 +0000206 break;
207 case ASN_BASIC_INTEGER:
208 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000209 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-08-14 02:18:27 +0000210 if((expr->expr_type == ASN_BASIC_REAL
211 && (arg->flags & A1C_USE_NATIVE_TYPES))
212 || asn1c_type_fits_long(arg, expr)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000213 switch(_format) {
214 case TNF_CTYPE:
215 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000216 if(expr->expr_type == ASN_BASIC_REAL)
217 return "double";
Lev Walkinf15320b2004-06-03 03:38:44 +0000218 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000219 return "long";
Lev Walkin22b5ed42006-09-13 02:51:20 +0000220 default:
221 typename = 0;
222 switch(expr->expr_type) {
223 case ASN_BASIC_INTEGER:
224 typename = "NativeInteger"; break;
225 case ASN_BASIC_ENUMERATED:
226 typename = "NativeEnumerated"; break;
227 case ASN_BASIC_REAL:
228 typename = "NativeReal"; break;
229 default:
230 break;
231 }
232 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000233 }
Lev Walkin22b5ed42006-09-13 02:51:20 +0000234 if(typename) {
235 if(_format != TNF_INCLUDE)
236 return typename;
237 stdname = 1;
238 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000239 }
240 }
241 /* Fall through */
242 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000243 if(expr->expr_type
244 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000245 if(_format == TNF_RSAFE)
246 _format = TNF_CTYPE;
Lev Walkin22b5ed42006-09-13 02:51:20 +0000247 stdname = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000248 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
249 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000250 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000251 typename = expr->Identifier;
252 }
253 }
254
255 switch(_format) {
256 case TNF_UNMODIFIED:
Lev Walkina00d6b32006-03-21 03:40:38 +0000257 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES,
258 0, exprid ? exprid->Identifier : typename, 0);
Lev Walkin22b5ed42006-09-13 02:51:20 +0000259 case TNF_INCLUDE:
260 return asn1c_make_identifier(
261 AMI_MASK_ONLY_SPACES | AMI_NODELIMITER,
262 0, stdname ? "<" : "\"",
263 exprid ? exprid->Identifier : typename,
264 stdname ? ".h>" : ".h\"", 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000265 case TNF_SAFE:
Lev Walkina00d6b32006-03-21 03:40:38 +0000266 return asn1c_make_identifier(0, exprid, typename, 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000267 case TNF_CTYPE: /* C type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000268 return asn1c_make_identifier(0, exprid,
269 exprid?"t":typename, exprid?0:"t", 0);
Lev Walkinc8285712005-03-04 22:18:20 +0000270 case TNF_RSAFE: /* Recursion-safe type */
Lev Walkina00d6b32006-03-21 03:40:38 +0000271 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
Lev Walkinc8285712005-03-04 22:18:20 +0000272 "struct", " ", typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000273 }
274
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000275 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000276 return typename;
277}
278
Lev Walkin082cadc2005-08-14 02:18:27 +0000279/*
280 * Check whether the specified INTEGER or ENUMERATED type can be represented
281 * using the generic 'long' type.
282 */
283enum asn1c_fitslong_e
284asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
285 asn1cnst_range_t *range = 0;
286 asn1cnst_edge_t left;
287 asn1cnst_edge_t right;
288 asn1p_expr_t *v;
289
290/*
291 * Since we don't know the sizeof(long) on the possible target platform
292 * which will be compiling the code generated by asn1c, let's play it
293 * simple: long's range is equal to or greater than int32_t.
Lev Walkin4c97bd62005-08-15 01:01:24 +0000294 * NOTE: the most negative integer cannot be written in C, as the C99
295 * standard will give it an unsigned type.
296 * It is defined here as a constant expression.
Lev Walkin082cadc2005-08-14 02:18:27 +0000297 */
Lev Walkinc08c3cf2005-08-15 01:04:48 +0000298#define RIGHTMAX 2147483647 /* of 32-bit integer type */
299#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
Lev Walkin082cadc2005-08-14 02:18:27 +0000300
301 /* Descend to the terminal type */
302 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
303 if(expr == 0) return FL_NOTFIT;
304
305 /* The "fits into long" operation is relevant only for integer types */
306 switch(expr->expr_type) {
307 case ASN_BASIC_INTEGER:
308 case ASN_BASIC_ENUMERATED:
309 break;
310 default:
311 return FL_NOTFIT;
312 }
313
314 /*
315 * First, evaluate the range of explicitly given identifiers.
316 */
317 TQ_FOR(v, &(expr->members), next) {
318 if(v->expr_type != A1TC_UNIVERVAL)
319 continue;
320 if(v->value->value.v_integer < LEFTMIN
321 || v->value->value.v_integer > RIGHTMAX)
322 return FL_NOTFIT;
323 }
324
Lev Walkin4b553412005-08-14 14:45:44 +0000325 if(!expr->combined_constraints)
326 return (arg->flags & A1C_USE_NATIVE_TYPES)
327 ? FL_FORCED : FL_NOTFIT;
328
Lev Walkin082cadc2005-08-14 02:18:27 +0000329 /*
Lev Walkin4b553412005-08-14 14:45:44 +0000330 * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
331 * applied (non-standard! but we can deal with this) to the type.
332 * Check the range.
Lev Walkin082cadc2005-08-14 02:18:27 +0000333 */
Lev Walkin4b553412005-08-14 14:45:44 +0000334 range = asn1constraint_compute_PER_range(expr->expr_type,
335 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
336 CPR_simulate_fbless_SIZE);
337 if(range) {
338 if(!range->incompatible) {
339 right = range->right;
340 /* Use 4 instead of sizeof(long) is justified! */
341 if(right.type == ARE_VALUE && right.value <= 4)
342 return FL_FITSOK;
343 }
344 asn1constraint_range_free(range);
345 }
346
347 /*
348 * Third, pull up the PER visible range of the INTEGER.
349 */
350 range = asn1constraint_compute_PER_range(expr->expr_type,
351 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
Lev Walkin082cadc2005-08-14 02:18:27 +0000352 if(!range
353 || range->empty_constraint
354 || range->extensible
355 || range->incompatible
356 || range->not_PER_visible
357 ) {
358 asn1constraint_range_free(range);
359 return (arg->flags & A1C_USE_NATIVE_TYPES)
360 ? FL_FORCED : FL_NOTFIT;
361 }
362
363 left = range->left;
364 right = range->right;
365 asn1constraint_range_free(range);
366
367 /* If some fixed value is outside of target range, not fit */
368 if(left.type == ARE_VALUE
369 && (left.value < LEFTMIN || left.value > RIGHTMAX))
370 return FL_NOTFIT;
371 if(right.type == ARE_VALUE
372 && (right.value > RIGHTMAX || right.value < LEFTMIN))
373 return FL_NOTFIT;
374
375 /* If the range is open, fits only if -fnative-types is given */
376 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
377 return (arg->flags & A1C_USE_NATIVE_TYPES)
378 ? FL_FORCED : FL_NOTFIT;
379 }
380
381 return FL_FITSOK;
382}
383