blob: f2f91d5c98a3a5b0267d367f84b9b83cead4a088 [file] [log] [blame]
vlmfa67ddc2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
2
3static asn1p_expr_t *asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, asn1p_module_t **optm, int type_or_value);
4static int asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name);
5
6
7/*
8 * Lookup a child by its name.
9 */
10asn1p_expr_t *
11asn1f_lookup_child(asn1p_expr_t *tc, const char *name) {
12 asn1p_expr_t *child_tc;
13
14 TQ_FOR(child_tc, &(tc->members), next) {
15 if(child_tc->Identifier
16 && strcmp(child_tc->Identifier, name) == 0) {
17 return child_tc;
18 }
19 }
20
21 errno = ESRCH;
22 return NULL;
23}
24
25asn1p_module_t *
26asn1f_lookup_in_imports(arg_t *arg, const char *name) {
27 asn1p_module_t *mod;
28 asn1p_xports_t *xp;
29 asn1p_expr_t *tc;
30
31 /*
32 * Search in which exactly module this name is defined.
33 */
34 TQ_FOR(xp, &(arg->mod->imports), xp_next) {
35 TQ_FOR(tc, &(xp->members), next) {
36 if(strcmp(name, tc->Identifier) == 0)
37 break;
38 }
39 if(tc) break;
40 }
41 if(xp == NULL) {
42 errno = ESRCH;
43 return NULL;
44 }
45
46 /*
47 * Okay, right now we have a module name and, hopefully, an OID.
48 * Search the arg->asn for the specified module.
49 */
50 mod = asn1f_lookup_module(arg, xp->from, xp->from_oid);
51 if(mod == NULL) {
52 /* ENOENT/ETOOMANYREFS */
53 return NULL;
54 }
55
56 /*
57 * Check that the EXPORTS section of this module contains
58 * the symbol we care about, or it is EXPORTS ALL.
59 */
60 if(asn1f_compatible_with_exports(arg, mod, name)) {
61 errno = EPERM;
62 return NULL;
63 }
64
65 return mod;
66}
67
68asn1p_module_t *
69asn1f_lookup_module(arg_t *arg, const char *module_name, asn1p_oid_t *oid) {
70 asn1p_module_t *mod;
71
72 assert(module_name);
73
74 /*
75 * If OID is given, the module_name is unused.
76 * If OID is not given, the module_name may mean
77 * either the real module's name, or the symbol which is the
78 * result of renaming. Check this first.
79 */
80 if(oid == 0) {
81 asn1p_xports_t *xp;
82 /*
83 * Check inside the IMPORTS section for possible renaming.
84 * Renaming practically means that a module_name is mentioned
85 * somewhere in the IMPORTS section AND OID is given.
86 */
87 TQ_FOR(xp, &(arg->mod->imports), xp_next) {
88 if(strcmp(module_name, xp->from))
89 continue;
90 if(oid) {
91 FATAL("Ambiguous reference: "
92 "%s "
93 "matches several modules",
94 module_name);
95 errno = ETOOMANYREFS;
96 return NULL;
97 }
98 /*
99 * Yes, there is a renaming.
100 * Make lookup use OID instead.
101 */
102 oid = xp->from_oid;
103 }
104 }
105
106 /*
107 * Perform lookup using OID or module_name.
108 */
109 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
110 if(oid) {
111 if(mod->module_oid) {
112 if(asn1p_oid_compare(oid,
113 mod->module_oid)) {
114 continue;
115 } else {
116 /* Match! Even if name doesn't. */
117 return mod;
118 }
119 } else {
120 /* Not match, even if name is the same. */
121 continue;
122 }
123 }
124
125 if(strcmp(module_name, mod->Identifier) == 0)
126 return mod;
127 }
128
129 DEBUG("\tModule \"%s\" not found", module_name);
130
131 errno = ENOENT;
132 return NULL;
133}
134
135
136
137asn1p_expr_t *
138asn1f_lookup_symbol(arg_t *arg, asn1p_ref_t *ref, asn1p_module_t **module_r) {
139 asn1p_expr_t *ref_tc; /* Referenced tc */
140 asn1p_module_t *src_mod;
141 char *modulename;
142 char *identifier;
143
144 /*
145 * First of all, a reference to a symbol may be specified
146 * using several possible forms:
147 * a) simple identifier
148 * v INTEGER ::= value
149 * b) external reference
150 * v INTEGER ::= Module1.value
151 * c) class-related stuff (the most complex stuff)
152 * v ::= <[A-Z][A-Z0-9a-z-]*>.&<[A-Z0-9a-z-]+>.
153 * All other forms are not implemented at this moment.
154 */
155
156 DEBUG("%s(%s) in %s for line %d", __func__,
157 asn1f_printable_reference(ref),
158 arg->mod->Identifier,
159 ref->_lineno);
160
161 if(ref->comp_count == 1) {
162 modulename = NULL;
163 identifier = ref->components[0].name;
164 } else if(ref->comp_count == 2
165 && ref->components[1].name[0] != '&') {
166 modulename = ref->components[0].name;
167 identifier = ref->components[1].name;
168 } else if(ref->comp_count > 1
169 && isupper(ref->components[0].name[0])
170 && ref->components[1].name[0] == '&') {
171 asn1p_expr_t *extract;
172 /*
173 * This is a reference to a CLASS-related stuff.
174 * Employ a separate function for that.
175 */
176 extract = asn1f_class_access(arg, ref, module_r);
177
178 return extract;
179 } else {
180 DEBUG("\tToo many components: %d", ref->comp_count);
181 errno = EINVAL;
182 return NULL;
183 }
184
185 /*
186 * If module name is specified explicitly
187 * OR the current module's IMPORTS clause contains the identifier,
188 * fetch that module.
189 */
190 if(modulename) {
191 src_mod = asn1f_lookup_module(arg, modulename, 0);
192 if(src_mod == NULL) {
193 FATAL("Module \"%s\" "
194 "mentioned at line %d is not found",
195 modulename, ref->_lineno);
196 return NULL;
197 }
198
199 /*
200 * Check that the EXPORTS section of this module contains
201 * the symbol we care about, or it is EXPORTS ALL.
202 */
203 if(asn1f_compatible_with_exports(arg, src_mod, identifier)) {
204 errno = EPERM;
205 return NULL;
206 }
207 } else {
208 src_mod = asn1f_lookup_in_imports(arg, identifier);
209 if(src_mod == NULL && errno != ESRCH) {
210 /*
211 * Return only of the name was not found.
212 * If module was not found or more serious error
213 * encountered, just return preserving the errno.
214 */
215 return NULL;
216 }
217 }
218
219 if(src_mod == 0) src_mod = arg->mod;
220
221 /*
222 * Now we know where to search for a value.
223 */
224 TQ_FOR(ref_tc, &(src_mod->members), next) {
225 if(ref_tc->Identifier)
226 if(strcmp(ref_tc->Identifier, identifier) == 0)
227 break;
228 }
229 if(ref_tc == NULL) {
230 DEBUG("Module \"%s\" does not contain \"%s\" "
vlmd9cd3f92004-06-28 21:21:24 +0000231 "mentioned at line %d: %s",
vlmfa67ddc2004-06-03 03:38:44 +0000232 src_mod->Identifier,
233 identifier,
vlmd9cd3f92004-06-28 21:21:24 +0000234 ref->_lineno,
235 strerror(errno)
vlmfa67ddc2004-06-03 03:38:44 +0000236 );
vlmd9cd3f92004-06-28 21:21:24 +0000237 if(asn1f_check_known_external_type(identifier) == 0) {
238 errno = EEXIST; /* Exists somewhere */
239 } else {
240 errno = ESRCH;
241 }
vlmfa67ddc2004-06-03 03:38:44 +0000242 return NULL;
243 }
244
245 if(module_r)
246 *module_r = src_mod;
247
248 return ref_tc;
249}
250
251
252asn1p_expr_t *
253asn1f_find_terminal_type(arg_t *arg, asn1p_expr_t *expr,
254 asn1p_module_t **optm) {
255 return asn1f_find_terminal_thing(arg, expr, optm, 0);
256}
257
258asn1p_expr_t *
259asn1f_find_terminal_value(arg_t *arg, asn1p_expr_t *expr,
260 asn1p_module_t **optm) {
261 return asn1f_find_terminal_thing(arg, expr, optm, 1);
262}
263
264static asn1p_expr_t *
265asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr,
266 asn1p_module_t **optm, int type_or_value) {
267 asn1p_module_t *mod;
268 asn1p_ref_t *ref;
269 asn1p_expr_t *tc;
270
271 if(type_or_value) {
272 /* VALUE */
273 assert(expr->meta_type == AMT_VALUE);
274 assert(expr->value);
275 if(expr->value->type != ATV_REFERENCED) {
276 /* Expression is a terminal value itself */
277 if(optm) *optm = arg->mod;
278 return expr;
279 }
280 ref = expr->value->value.reference;
281 } else {
282 /* TYPE */
283 if(expr->expr_type != A1TC_REFERENCE) {
284 /* Expression is a terminal type itself */
285 if(optm) *optm = arg->mod;
286 return expr;
287 }
288 ref = expr->reference;
289 }
290
291 DEBUG("%s:%s(%s->%s) for line %d",
292 __func__, type_or_value?"VALUE":"TYPE",
293 expr->Identifier, asn1f_printable_reference(ref),
294 expr->_lineno);
295
296 assert(ref);
297
298 /*
299 * Lookup inside the type itself (ENUMERATED, INTEGER, etc).
300 */
301 if(type_or_value) {
302 asn1p_expr_t *val_type_tc;
303 val_type_tc = asn1f_find_terminal_type(arg, expr, 0);
304 if(val_type_tc
305 && asn1f_look_value_in_type(arg, val_type_tc, expr))
306 return NULL;
307 if(expr->value->type != ATV_REFERENCED) {
308 if(optm) *optm = arg->mod;
309 return expr;
310 }
311 assert(ref == expr->value->value.reference);
312 ref = expr->value->value.reference;
313 }
314
315 /*
316 * Lookup inside the default module.
317 */
318 tc = asn1f_lookup_symbol(arg, ref, &mod);
319 if(tc == NULL) {
vlmd9cd3f92004-06-28 21:21:24 +0000320 DEBUG("\tSymbol \"%s\" not found: %s",
321 asn1f_printable_reference(ref),
322 strerror(errno));
vlmfa67ddc2004-06-03 03:38:44 +0000323 return NULL;
324 }
325
326 /*
327 * Recursive loops detection.
328 */
329 if(tc->_mark & TM_RECURSION) {
330 DEBUG("Recursion loop detected for %s at line %d",
331 asn1f_printable_reference(ref), ref->_lineno);
332 errno = EPERM;
333 return NULL;
334 }
335
336 tc->_mark |= TM_RECURSION;
337 WITH_MODULE(mod,
338 expr = asn1f_find_terminal_thing(arg, tc, optm, type_or_value));
339 tc->_mark &= ~TM_RECURSION;
340
341 return expr;
342}
343
344/*
345 * Make sure that the specified name is present or otherwise does
346 * not contradict with the EXPORTS clause of the specified module.
347 */
348static int
349asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name) {
350 asn1p_xports_t *exports;
351 asn1p_expr_t *item;
352
353 assert(mod);
354 assert(name);
355
356 exports = TQ_FIRST(&(mod->exports));
357 if(exports == NULL) {
358 /* No EXPORTS section or EXPORTS ALL; */
359 return 0;
360 }
361
362 TQ_FOR(item, &(exports->members), next) {
363 if(strcmp(item->Identifier, name) == 0)
364 return 0;
365 }
366
367 DEBUG("Symbol \"%s\" contradicts with EXPORTS of module %s",
368 name, mod->Identifier);
369
370 errno = ESRCH;
371 return -1;
372}