blob: 543a165b36e46f2bd193acb078f167adf5da2538 [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
vlm86380d32006-10-09 12:07:58 +0000161 if(0) DEBUG("asn1c_type_name(%s: 0x%x)",
162 expr->Identifier, expr->expr_type);
vlm5fbaa132006-03-14 11:52:12 +0000163
vlmfa67ddc2004-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 */
vlm6c4a8502005-08-18 13:38:19 +0000175 tmp.expr = asn1f_class_access_ex(arg->asn,
vlm0c6d3812006-03-21 03:40:38 +0000176 arg->expr->module, arg->expr, expr->rhs_pspecs, expr->reference);
vlm5fbaa132006-03-14 11:52:12 +0000177 if(!tmp.expr) return NULL;
vlmfa67ddc2004-06-03 03:38:44 +0000178
vlmfa67ddc2004-06-03 03:38:44 +0000179 return asn1c_type_name(&tmp, tmp.expr, _format);
vlmfb41dbb2004-09-08 00:28:57 +0000180 }
181
vlm0c6d3812006-03-21 03:40:38 +0000182 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
183
vlm0b567bf2005-03-04 22:18:20 +0000184 if(_format == TNF_RSAFE) {
vlm0b567bf2005-03-04 22:18:20 +0000185 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
186 typename = terminal->Identifier;
187 }
188 }
189
vlmb47f48e2004-09-17 06:32:12 +0000190 if(_format == TNF_CTYPE) {
vlmfa67ddc2004-06-03 03:38:44 +0000191 /*
vlmb47f48e2004-09-17 06:32:12 +0000192 * If the component references the type itself,
vlm0b567bf2005-03-04 22:18:20 +0000193 * switch to a recursion-safe type naming
vlmb47f48e2004-09-17 06:32:12 +0000194 * ("struct foo" instead of "foo_t").
vlmfa67ddc2004-06-03 03:38:44 +0000195 */
vlmb47f48e2004-09-17 06:32:12 +0000196 if(terminal && terminal == top_parent) {
197 _format = TNF_RSAFE;
vlmfb41dbb2004-09-08 00:28:57 +0000198 }
vlmfa67ddc2004-06-03 03:38:44 +0000199 }
vlm0c6d3812006-03-21 03:40:38 +0000200
201 if(terminal && terminal->spec_index != -1) {
202 exprid = terminal;
203 typename = 0;
vlmfa67ddc2004-06-03 03:38:44 +0000204 }
vlm0c6d3812006-03-21 03:40:38 +0000205
vlmfa67ddc2004-06-03 03:38:44 +0000206 break;
207 case ASN_BASIC_INTEGER:
208 case ASN_BASIC_ENUMERATED:
vlmf9d178d2004-09-14 12:47:45 +0000209 case ASN_BASIC_REAL:
vlm75b3a532005-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)) {
vlmfa67ddc2004-06-03 03:38:44 +0000213 switch(_format) {
214 case TNF_CTYPE:
215 case TNF_RSAFE:
vlmf9d178d2004-09-14 12:47:45 +0000216 if(expr->expr_type == ASN_BASIC_REAL)
217 return "double";
vlmfa67ddc2004-06-03 03:38:44 +0000218 else
vlm909b6c62005-02-25 12:09:55 +0000219 return "long";
vlmea226772006-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;
vlmf9d178d2004-09-14 12:47:45 +0000233 }
vlmea226772006-09-13 02:51:20 +0000234 if(typename) {
235 if(_format != TNF_INCLUDE)
236 return typename;
237 stdname = 1;
238 break;
vlmfa67ddc2004-06-03 03:38:44 +0000239 }
240 }
241 /* Fall through */
242 default:
vlmc161f0c2004-08-25 02:03:26 +0000243 if(expr->expr_type
244 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
vlmfa67ddc2004-06-03 03:38:44 +0000245 if(_format == TNF_RSAFE)
246 _format = TNF_CTYPE;
vlmea226772006-09-13 02:51:20 +0000247 stdname = 1;
vlmfa67ddc2004-06-03 03:38:44 +0000248 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
249 } else {
vlmb47f48e2004-09-17 06:32:12 +0000250 _format = TNF_RSAFE;
vlmfa67ddc2004-06-03 03:38:44 +0000251 typename = expr->Identifier;
252 }
253 }
254
255 switch(_format) {
256 case TNF_UNMODIFIED:
vlm0c6d3812006-03-21 03:40:38 +0000257 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES,
258 0, exprid ? exprid->Identifier : typename, 0);
vlmea226772006-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);
vlmfa67ddc2004-06-03 03:38:44 +0000265 case TNF_SAFE:
vlm0c6d3812006-03-21 03:40:38 +0000266 return asn1c_make_identifier(0, exprid, typename, 0);
vlm0b567bf2005-03-04 22:18:20 +0000267 case TNF_CTYPE: /* C type */
vlm0c6d3812006-03-21 03:40:38 +0000268 return asn1c_make_identifier(0, exprid,
269 exprid?"t":typename, exprid?0:"t", 0);
vlm0b567bf2005-03-04 22:18:20 +0000270 case TNF_RSAFE: /* Recursion-safe type */
vlm0c6d3812006-03-21 03:40:38 +0000271 return asn1c_make_identifier(AMI_CHECK_RESERVED, 0,
vlm0b567bf2005-03-04 22:18:20 +0000272 "struct", " ", typename, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000273 }
274
vlmb47f48e2004-09-17 06:32:12 +0000275 assert(!"unreachable");
vlmfa67ddc2004-06-03 03:38:44 +0000276 return typename;
277}
278
vlm75b3a532005-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.
vlm87ae6f92005-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.
vlm75b3a532005-08-14 02:18:27 +0000297 */
vlm856b94c2005-08-15 01:04:48 +0000298#define RIGHTMAX 2147483647 /* of 32-bit integer type */
299#define LEFTMIN (-RIGHTMAX-1) /* of 32-bit integer type */
vlm75b3a532005-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
vlm27028582005-08-14 14:45:44 +0000325 if(!expr->combined_constraints)
326 return (arg->flags & A1C_USE_NATIVE_TYPES)
327 ? FL_FORCED : FL_NOTFIT;
328
vlm75b3a532005-08-14 02:18:27 +0000329 /*
vlm27028582005-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.
vlm75b3a532005-08-14 02:18:27 +0000333 */
vlm27028582005-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);
vlm75b3a532005-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