blob: c8adce66c87b1785bcfe9bb73ceb23cc1b0d6d9f [file] [log] [blame]
vlmfa67ddc2004-06-03 03:38:44 +00001#include "asn1c_internal.h"
vlmb2839012004-08-20 13:37:01 +00002#include "asn1c_misc.h"
3
vlm75b3a532005-08-14 02:18:27 +00004#include <asn1fix_crange.h> /* constraint groker from libasn1fix */
5#include <asn1fix_export.h> /* other exportable stuff from libasn1fix */
vlmfa67ddc2004-06-03 03:38:44 +00006
vlmfa67ddc2004-06-03 03:38:44 +00007/*
vlmaf841972005-01-28 12:18:50 +00008 * Checks that the given string is not a reserved C/C++ keyword.
vlm4bf55512005-03-03 21:29:27 +00009 * ISO/IEC 9899:1999 (C99), A.1.2
vlmaf841972005-01-28 12:18:50 +000010 */
11static char *res_kwd[] = {
vlm4bf55512005-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};
vlmaf841972005-01-28 12:18:50 +000021static int
22reserved_keyword(const char *str) {
vlm1fcf7592006-08-18 02:27:55 +000023 size_t i;
vlmaf841972005-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/*
vlmfa67ddc2004-06-03 03:38:44 +000032 * Construct identifier from multiple parts.
33 * Convert unsafe characters to underscores.
34 */
35char *
vlm0c6d3812006-03-21 03:40:38 +000036asn1c_make_identifier(enum ami_flags_e flags, asn1p_expr_t *expr, ...) {
vlmfa67ddc2004-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;
vlmaf841972005-01-28 12:18:50 +000042 char *nextstr;
vlm0c6d3812006-03-21 03:40:38 +000043 char *first = 0;
44 char *second = 0;
vlm1fcf7592006-08-18 02:27:55 +000045 ssize_t size;
vlmfa67ddc2004-06-03 03:38:44 +000046 char *p;
47
vlm0c6d3812006-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 }
vlmfa67ddc2004-06-03 03:38:44 +000064
vlm0c6d3812006-03-21 03:40:38 +000065 va_start(ap, expr);
vlmfa67ddc2004-06-03 03:38:44 +000066 while((str = va_arg(ap, char *)))
67 size += 1 + strlen(str);
68 va_end(ap);
vlm0c6d3812006-03-21 03:40:38 +000069 if(size == -1) return NULL;
vlmfa67ddc2004-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 */
vlm0c6d3812006-03-21 03:40:38 +000088 va_start(ap, expr);
vlmfa67ddc2004-06-03 03:38:44 +000089 p = storage;
vlm0c6d3812006-03-21 03:40:38 +000090 nextstr = "";
91 for(p = storage, str = 0; str || nextstr; str = nextstr) {
vlmfa67ddc2004-06-03 03:38:44 +000092 int subst_made = 0;
vlm0c6d3812006-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 }
vlmfa67ddc2004-06-03 03:38:44 +0000105
106 if(str[0] == ' ' && str[1] == '\0') {
107 *p++ = ' ';
108 nodelimiter = 1; /* No delimiter */
109 continue;
110 }
111
vlmea226772006-09-13 02:51:20 +0000112 if(str != first && !nodelimiter && !(flags & AMI_NODELIMITER))
vlmfa67ddc2004-06-03 03:38:44 +0000113 *p++ = '_'; /* Delimiter between tokens */
114 nodelimiter = 0;
115
vlmaf841972005-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)
vlm0c6d3812006-03-21 03:40:38 +0000121 && str == first && !nextstr && reserved_keyword(str)) {
vlmaf841972005-01-28 12:18:50 +0000122 *p++ = toupper(*str++);
123 /* Fall through */
124 }
125
vlmfa67ddc2004-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++) {
vlmaf841972005-01-28 12:18:50 +0000131 if((flags & AMI_MASK_ONLY_SPACES)
132 && !isspace(*str)) {
vlmfa67ddc2004-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
vlmfa67ddc2004-06-03 03:38:44 +0000148char *
149asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
vlm0c6d3812006-03-21 03:40:38 +0000150 asn1p_expr_t *exprid = 0;
vlmfb41dbb2004-09-08 00:28:57 +0000151 asn1p_expr_t *top_parent;
vlm0c6d3812006-03-21 03:40:38 +0000152 asn1p_expr_t *terminal;
vlmea226772006-09-13 02:51:20 +0000153 int stdname = 0;
vlmfa67ddc2004-06-03 03:38:44 +0000154 char *typename;
155
vlmfb41dbb2004-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
vlm5fbaa132006-03-14 11:52:12 +0000161 DEBUG("asn1c_type_name(%s: 0x%x)", expr->Identifier, expr->expr_type);
162
vlmfa67ddc2004-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 */
vlm6c4a8502005-08-18 13:38:19 +0000174 tmp.expr = asn1f_class_access_ex(arg->asn,
vlm0c6d3812006-03-21 03:40:38 +0000175 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
vlm5fbaa132006-03-14 11:52:12 +0000176 if(!tmp.expr) return NULL;
vlmfa67ddc2004-06-03 03:38:44 +0000177
vlmfa67ddc2004-06-03 03:38:44 +0000178 return asn1c_type_name(&tmp, tmp.expr, _format);
vlmfb41dbb2004-09-08 00:28:57 +0000179 }
180
vlm0c6d3812006-03-21 03:40:38 +0000181 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
182
vlm0b567bf2005-03-04 22:18:20 +0000183 if(_format == TNF_RSAFE) {
vlm0b567bf2005-03-04 22:18:20 +0000184 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
185 typename = terminal->Identifier;
186 }
187 }
188
vlmb47f48e2004-09-17 06:32:12 +0000189 if(_format == TNF_CTYPE) {
vlmfa67ddc2004-06-03 03:38:44 +0000190 /*
vlmb47f48e2004-09-17 06:32:12 +0000191 * If the component references the type itself,
vlm0b567bf2005-03-04 22:18:20 +0000192 * switch to a recursion-safe type naming
vlmb47f48e2004-09-17 06:32:12 +0000193 * ("struct foo" instead of "foo_t").
vlmfa67ddc2004-06-03 03:38:44 +0000194 */
vlmb47f48e2004-09-17 06:32:12 +0000195 if(terminal && terminal == top_parent) {
196 _format = TNF_RSAFE;
vlmfb41dbb2004-09-08 00:28:57 +0000197 }
vlmfa67ddc2004-06-03 03:38:44 +0000198 }
vlm0c6d3812006-03-21 03:40:38 +0000199
200 if(terminal && terminal->spec_index != -1) {
201 exprid = terminal;
202 typename = 0;
vlmfa67ddc2004-06-03 03:38:44 +0000203 }
vlm0c6d3812006-03-21 03:40:38 +0000204
vlmfa67ddc2004-06-03 03:38:44 +0000205 break;
206 case ASN_BASIC_INTEGER:
207 case ASN_BASIC_ENUMERATED:
vlmf9d178d2004-09-14 12:47:45 +0000208 case ASN_BASIC_REAL:
vlm75b3a532005-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)) {
vlmfa67ddc2004-06-03 03:38:44 +0000212 switch(_format) {
213 case TNF_CTYPE:
214 case TNF_RSAFE:
vlmf9d178d2004-09-14 12:47:45 +0000215 if(expr->expr_type == ASN_BASIC_REAL)
216 return "double";
vlmfa67ddc2004-06-03 03:38:44 +0000217 else
vlm909b6c62005-02-25 12:09:55 +0000218 return "long";
vlmea226772006-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;
vlmf9d178d2004-09-14 12:47:45 +0000232 }
vlmea226772006-09-13 02:51:20 +0000233 if(typename) {
234 if(_format != TNF_INCLUDE)
235 return typename;
236 stdname = 1;
237 break;
vlmfa67ddc2004-06-03 03:38:44 +0000238 }
239 }
240 /* Fall through */
241 default:
vlmc161f0c2004-08-25 02:03:26 +0000242 if(expr->expr_type
243 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
vlmfa67ddc2004-06-03 03:38:44 +0000244 if(_format == TNF_RSAFE)
245 _format = TNF_CTYPE;
vlmea226772006-09-13 02:51:20 +0000246 stdname = 1;
vlmfa67ddc2004-06-03 03:38:44 +0000247 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
248 } else {
vlmb47f48e2004-09-17 06:32:12 +0000249 _format = TNF_RSAFE;
vlmfa67ddc2004-06-03 03:38:44 +0000250 typename = expr->Identifier;
251 }
252 }
253
254 switch(_format) {
255 case TNF_UNMODIFIED:
vlm0c6d3812006-03-21 03:40:38 +0000256 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES,
257 0, exprid ? exprid->Identifier : typename, 0);
vlmea226772006-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);
vlmfa67ddc2004-06-03 03:38:44 +0000264 case TNF_SAFE:
vlm0c6d3812006-03-21 03:40:38 +0000265 return asn1c_make_identifier(0, exprid, typename, 0);
vlm0b567bf2005-03-04 22:18:20 +0000266 case TNF_CTYPE: /* C type */
vlm0c6d3812006-03-21 03:40:38 +0000267 return asn1c_make_identifier(0, exprid,
268 exprid?"t":typename, exprid?0:"t", 0);
vlm0b567bf2005-03-04 22:18:20 +0000269 case TNF_RSAFE: /* Recursion-safe type */
vlm0c6d3812006-03-21 03:40:38 +0000270 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
vlm0b567bf2005-03-04 22:18:20 +0000271 "struct", " ", typename, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000272 }
273
vlmb47f48e2004-09-17 06:32:12 +0000274 assert(!"unreachable");
vlmfa67ddc2004-06-03 03:38:44 +0000275 return typename;
276}
277
vlm75b3a532005-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.
vlm87ae6f92005-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.
vlm75b3a532005-08-14 02:18:27 +0000296 */
vlm856b94c2005-08-15 01:04:48 +0000297#define RIGHTMAX 2147483647 /* of 32-bit integer type */
298#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
vlm75b3a532005-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
vlm27028582005-08-14 14:45:44 +0000324 if(!expr->combined_constraints)
325 return (arg->flags & A1C_USE_NATIVE_TYPES)
326 ? FL_FORCED : FL_NOTFIT;
327
vlm75b3a532005-08-14 02:18:27 +0000328 /*
vlm27028582005-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.
vlm75b3a532005-08-14 02:18:27 +0000332 */
vlm27028582005-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);
vlm75b3a532005-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