blob: bcf062f348a8eb4b6c98fe6ba0c741e760ccb55e [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 Walkin801fabc2005-01-28 12:18:50 +000036asn1c_make_identifier(enum ami_flags_e flags, char *arg1, ...) {
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 Walkin4efbfb72005-02-25 14:20:30 +000043 size_t size;
Lev Walkinf15320b2004-06-03 03:38:44 +000044 char *p;
45
46 if(arg1 == NULL)
47 return NULL;
48
49 /*
50 * Estimate the necessary storage size
51 */
52 size = strlen(arg1);
53 va_start(ap, arg1);
54 while((str = va_arg(ap, char *)))
55 size += 1 + strlen(str);
56 va_end(ap);
57
58 /*
59 * Make sure we have this amount of storage.
60 */
61 if(storage_size <= size) {
62 if(storage) free(storage);
63 storage = malloc(size + 1);
64 if(storage) {
65 storage_size = size;
66 } else {
67 storage_size = 0;
68 return NULL;
69 }
70 }
71
72 /*
73 * Fill-in the storage.
74 */
75 va_start(ap, arg1);
76 str = arg1;
77 p = storage;
Lev Walkin801fabc2005-01-28 12:18:50 +000078 for(str = arg1; str; str = nextstr) {
Lev Walkinf15320b2004-06-03 03:38:44 +000079 int subst_made = 0;
Lev Walkin801fabc2005-01-28 12:18:50 +000080 nextstr = va_arg(ap, char *);
Lev Walkinf15320b2004-06-03 03:38:44 +000081
82 if(str[0] == ' ' && str[1] == '\0') {
83 *p++ = ' ';
84 nodelimiter = 1; /* No delimiter */
85 continue;
86 }
87
88 if(str != arg1 && !nodelimiter)
89 *p++ = '_'; /* Delimiter between tokens */
90 nodelimiter = 0;
91
Lev Walkin801fabc2005-01-28 12:18:50 +000092 /*
93 * If it is a single argument, check that it does not clash
94 * with C/C++ language keywords.
95 */
96 if((flags & AMI_CHECK_RESERVED)
97 && str == arg1 && !nextstr && reserved_keyword(str)) {
98 *p++ = toupper(*str++);
99 /* Fall through */
100 }
101
Lev Walkinf15320b2004-06-03 03:38:44 +0000102 for(; *str; str++) {
103 if(isalnum(*str)) {
104 *p++ = *str;
105 subst_made = 0;
106 } else if(!subst_made++) {
Lev Walkin801fabc2005-01-28 12:18:50 +0000107 if((flags & AMI_MASK_ONLY_SPACES)
108 && !isspace(*str)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000109 *p ++ = *str;
110 } else {
111 *p++ = '_';
112 }
113 }
114 }
115 }
116 va_end(ap);
117 *p = '\0';
118
119 assert((p - storage) <= storage_size);
120
121 return storage;
122}
123
Lev Walkinf15320b2004-06-03 03:38:44 +0000124char *
125asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
Lev Walkin5a8219a2004-09-08 00:28:57 +0000126 asn1p_expr_t *top_parent;
Lev Walkinf15320b2004-06-03 03:38:44 +0000127 char *typename;
128
Lev Walkin5a8219a2004-09-08 00:28:57 +0000129 /* Rewind to the topmost parent expression */
130 if((top_parent = expr->parent_expr))
131 while(top_parent->parent_expr)
132 top_parent = top_parent->parent_expr;
133
Lev Walkinf15320b2004-06-03 03:38:44 +0000134 switch(expr->expr_type) {
135 case A1TC_REFERENCE:
136 typename = expr->reference->components[
137 expr->reference->comp_count-1].name;
138 if(typename[0] == '&') {
139 arg_t tmp = *arg;
140
141 /*
142 * This is a reference to a type defined in a class.
143 * Resolve it and use instead.
144 */
145 tmp.expr = asn1f_class_access_ex(arg->asn, arg->mod,
Lev Walkin065a74b2004-08-22 03:23:15 +0000146 arg->expr, expr->reference);
Lev Walkinf15320b2004-06-03 03:38:44 +0000147 if(tmp.expr) return NULL;
148
Lev Walkin065a74b2004-08-22 03:23:15 +0000149 tmp.mod = tmp.expr->module;
Lev Walkinf15320b2004-06-03 03:38:44 +0000150 return asn1c_type_name(&tmp, tmp.expr, _format);
Lev Walkin5a8219a2004-09-08 00:28:57 +0000151 }
152
Lev Walkinc8285712005-03-04 22:18:20 +0000153 if(_format == TNF_RSAFE) {
154 asn1p_expr_t *terminal;
155 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
156 if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
157 typename = terminal->Identifier;
158 }
159 }
160
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000161 if(_format == TNF_CTYPE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000162 /*
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000163 * If the component references the type itself,
Lev Walkinc8285712005-03-04 22:18:20 +0000164 * switch to a recursion-safe type naming
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000165 * ("struct foo" instead of "foo_t").
Lev Walkinf15320b2004-06-03 03:38:44 +0000166 */
167 asn1p_expr_t *terminal;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000168 terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000169 if(terminal && terminal == top_parent) {
170 _format = TNF_RSAFE;
Lev Walkin5a8219a2004-09-08 00:28:57 +0000171 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000172 }
173 break;
Lev Walkin0e22b982004-08-25 02:03:26 +0000174#if 0
Lev Walkinf15320b2004-06-03 03:38:44 +0000175 case ASN_CONSTR_SEQUENCE_OF:
176 case ASN_CONSTR_SET_OF:
177 if(expr->Identifier) {
178 typename = expr->Identifier;
179 } else {
180 asn1p_expr_t *child;
181 child = TQ_FIRST(&(expr->members));
182 typename = asn1c_type_name(arg, child, _format);
183 if(typename)
184 return typename;
185 _format = TNF_SAFE;
186 typename = child->Identifier;
187 }
188 break;
Lev Walkin0e22b982004-08-25 02:03:26 +0000189#endif
Lev Walkinf15320b2004-06-03 03:38:44 +0000190 case ASN_BASIC_INTEGER:
191 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000192 case ASN_BASIC_REAL:
Lev Walkin082cadc2005-08-14 02:18:27 +0000193 if((expr->expr_type == ASN_BASIC_REAL
194 && (arg->flags & A1C_USE_NATIVE_TYPES))
195 || asn1c_type_fits_long(arg, expr)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000196 switch(_format) {
197 case TNF_CTYPE:
198 case TNF_RSAFE:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000199 if(expr->expr_type == ASN_BASIC_REAL)
200 return "double";
Lev Walkinf15320b2004-06-03 03:38:44 +0000201 else
Lev Walkin475d91f2005-02-25 12:09:55 +0000202 return "long";
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000203 default: break;
204 }
205 switch(expr->expr_type) {
206 case ASN_BASIC_INTEGER:
207 return "NativeInteger";
208 case ASN_BASIC_ENUMERATED:
209 return "NativeEnumerated";
210 case ASN_BASIC_REAL:
211 return "NativeReal";
212 default: break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000213 }
214 }
215 /* Fall through */
216 default:
Lev Walkin0e22b982004-08-25 02:03:26 +0000217 if(expr->expr_type
218 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000219 if(_format == TNF_RSAFE)
220 _format = TNF_CTYPE;
221 typename = ASN_EXPR_TYPE2STR(expr->expr_type);
222 } else {
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000223 _format = TNF_RSAFE;
Lev Walkinf15320b2004-06-03 03:38:44 +0000224 typename = expr->Identifier;
225 }
226 }
227
228 switch(_format) {
229 case TNF_UNMODIFIED:
230 case TNF_INCLUDE:
Lev Walkinc8285712005-03-04 22:18:20 +0000231 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES, typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000232 case TNF_SAFE:
Lev Walkinc8285712005-03-04 22:18:20 +0000233 return asn1c_make_identifier(0, typename, 0);
234 case TNF_CTYPE: /* C type */
235 return asn1c_make_identifier(0, typename, "t", 0);
236 case TNF_RSAFE: /* Recursion-safe type */
237 return asn1c_make_identifier(AMI_CHECK_RESERVED,
238 "struct", " ", typename, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000239 }
240
Lev Walkin8dd0eed2004-09-17 06:32:12 +0000241 assert(!"unreachable");
Lev Walkinf15320b2004-06-03 03:38:44 +0000242 return typename;
243}
244
Lev Walkin082cadc2005-08-14 02:18:27 +0000245/*
246 * Check whether the specified INTEGER or ENUMERATED type can be represented
247 * using the generic 'long' type.
248 */
249enum asn1c_fitslong_e
250asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
251 asn1cnst_range_t *range = 0;
252 asn1cnst_edge_t left;
253 asn1cnst_edge_t right;
254 asn1p_expr_t *v;
255
256/*
257 * Since we don't know the sizeof(long) on the possible target platform
258 * which will be compiling the code generated by asn1c, let's play it
259 * simple: long's range is equal to or greater than int32_t.
260 */
261#define LEFTMIN INT32_MIN
262#define RIGHTMAX INT32_MAX
263
264 /* Descend to the terminal type */
265 expr = asn1f_find_terminal_type_ex(arg->asn, expr);
266 if(expr == 0) return FL_NOTFIT;
267
268 /* The "fits into long" operation is relevant only for integer types */
269 switch(expr->expr_type) {
270 case ASN_BASIC_INTEGER:
271 case ASN_BASIC_ENUMERATED:
272 break;
273 default:
274 return FL_NOTFIT;
275 }
276
277 /*
278 * First, evaluate the range of explicitly given identifiers.
279 */
280 TQ_FOR(v, &(expr->members), next) {
281 if(v->expr_type != A1TC_UNIVERVAL)
282 continue;
283 if(v->value->value.v_integer < LEFTMIN
284 || v->value->value.v_integer > RIGHTMAX)
285 return FL_NOTFIT;
286 }
287
288 /*
289 * Second, pull up the PER visible range of the INTEGER.
290 */
291 if(expr->combined_constraints)
292 range = asn1constraint_compute_PER_range(expr->expr_type,
293 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
294 if(!range
295 || range->empty_constraint
296 || range->extensible
297 || range->incompatible
298 || range->not_PER_visible
299 ) {
300 asn1constraint_range_free(range);
301 return (arg->flags & A1C_USE_NATIVE_TYPES)
302 ? FL_FORCED : FL_NOTFIT;
303 }
304
305 left = range->left;
306 right = range->right;
307 asn1constraint_range_free(range);
308
309 /* If some fixed value is outside of target range, not fit */
310 if(left.type == ARE_VALUE
311 && (left.value < LEFTMIN || left.value > RIGHTMAX))
312 return FL_NOTFIT;
313 if(right.type == ARE_VALUE
314 && (right.value > RIGHTMAX || right.value < LEFTMIN))
315 return FL_NOTFIT;
316
317 /* If the range is open, fits only if -fnative-types is given */
318 if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
319 return (arg->flags & A1C_USE_NATIVE_TYPES)
320 ? FL_FORCED : FL_NOTFIT;
321 }
322
323 return FL_FITSOK;
324}
325