blob: cbf6baeee0910d73d0750b0108865cbda3fb8f6e [file] [log] [blame]
vlmfa67ddc2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
2
vlm2e0c1942004-08-22 03:10:23 +00003static asn1p_expr_t *asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, int type_or_value);
vlmfa67ddc2004-06-03 03:38:44 +00004static 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 *
vlmf98e07a2004-09-15 11:46:47 +000026asn1f_lookup_in_imports(arg_t *arg, asn1p_module_t *mod, const char *name) {
vlmfa67ddc2004-06-03 03:38:44 +000027 asn1p_xports_t *xp;
28 asn1p_expr_t *tc;
29
30 /*
31 * Search in which exactly module this name is defined.
32 */
vlmf98e07a2004-09-15 11:46:47 +000033 TQ_FOR(xp, &(mod->imports), xp_next) {
vlmfa67ddc2004-06-03 03:38:44 +000034 TQ_FOR(tc, &(xp->members), next) {
35 if(strcmp(name, tc->Identifier) == 0)
36 break;
37 }
38 if(tc) break;
39 }
40 if(xp == NULL) {
41 errno = ESRCH;
42 return NULL;
43 }
44
45 /*
46 * Okay, right now we have a module name and, hopefully, an OID.
47 * Search the arg->asn for the specified module.
48 */
49 mod = asn1f_lookup_module(arg, xp->from, xp->from_oid);
50 if(mod == NULL) {
51 /* ENOENT/ETOOMANYREFS */
52 return NULL;
53 }
54
55 /*
56 * Check that the EXPORTS section of this module contains
57 * the symbol we care about, or it is EXPORTS ALL.
58 */
59 if(asn1f_compatible_with_exports(arg, mod, name)) {
60 errno = EPERM;
61 return NULL;
62 }
63
64 return mod;
65}
66
67asn1p_module_t *
68asn1f_lookup_module(arg_t *arg, const char *module_name, asn1p_oid_t *oid) {
69 asn1p_module_t *mod;
70
71 assert(module_name);
72
73 /*
74 * If OID is given, the module_name is unused.
75 * If OID is not given, the module_name may mean
76 * either the real module's name, or the symbol which is the
77 * result of renaming. Check this first.
78 */
79 if(oid == 0) {
80 asn1p_xports_t *xp;
81 /*
82 * Check inside the IMPORTS section for possible renaming.
83 * Renaming practically means that a module_name is mentioned
84 * somewhere in the IMPORTS section AND OID is given.
85 */
86 TQ_FOR(xp, &(arg->mod->imports), xp_next) {
87 if(strcmp(module_name, xp->from))
88 continue;
89 if(oid) {
90 FATAL("Ambiguous reference: "
91 "%s "
92 "matches several modules",
93 module_name);
94 errno = ETOOMANYREFS;
95 return NULL;
96 }
97 /*
98 * Yes, there is a renaming.
99 * Make lookup use OID instead.
100 */
101 oid = xp->from_oid;
102 }
103 }
104
105 /*
106 * Perform lookup using OID or module_name.
107 */
108 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
109 if(oid) {
110 if(mod->module_oid) {
111 if(asn1p_oid_compare(oid,
112 mod->module_oid)) {
113 continue;
114 } else {
115 /* Match! Even if name doesn't. */
116 return mod;
117 }
118 } else {
119 /* Not match, even if name is the same. */
120 continue;
121 }
122 }
123
124 if(strcmp(module_name, mod->Identifier) == 0)
125 return mod;
126 }
127
128 DEBUG("\tModule \"%s\" not found", module_name);
129
130 errno = ENOENT;
131 return NULL;
132}
133
134
135
136asn1p_expr_t *
vlm2e0c1942004-08-22 03:10:23 +0000137asn1f_lookup_symbol(arg_t *arg, asn1p_module_t *mod, asn1p_ref_t *ref) {
vlmfa67ddc2004-06-03 03:38:44 +0000138 asn1p_expr_t *ref_tc; /* Referenced tc */
vlmf98e07a2004-09-15 11:46:47 +0000139 asn1p_module_t *imports_from;
vlmfa67ddc2004-06-03 03:38:44 +0000140 char *modulename;
141 char *identifier;
142
143 /*
144 * First of all, a reference to a symbol may be specified
145 * using several possible forms:
146 * a) simple identifier
147 * v INTEGER ::= value
148 * b) external reference
149 * v INTEGER ::= Module1.value
150 * c) class-related stuff (the most complex stuff)
151 * v ::= <[A-Z][A-Z0-9a-z-]*>.&<[A-Z0-9a-z-]+>.
152 * All other forms are not implemented at this moment.
153 */
154
vlmfd245932005-03-10 10:02:50 +0000155 DEBUG("(%s) in %s for line %d",
vlmfa67ddc2004-06-03 03:38:44 +0000156 asn1f_printable_reference(ref),
vlm2e0c1942004-08-22 03:10:23 +0000157 mod->Identifier,
vlmfa67ddc2004-06-03 03:38:44 +0000158 ref->_lineno);
159
160 if(ref->comp_count == 1) {
161 modulename = NULL;
162 identifier = ref->components[0].name;
163 } else if(ref->comp_count == 2
164 && ref->components[1].name[0] != '&') {
165 modulename = ref->components[0].name;
166 identifier = ref->components[1].name;
167 } else if(ref->comp_count > 1
168 && isupper(ref->components[0].name[0])
169 && ref->components[1].name[0] == '&') {
170 asn1p_expr_t *extract;
171 /*
172 * This is a reference to a CLASS-related stuff.
173 * Employ a separate function for that.
174 */
vlm2e0c1942004-08-22 03:10:23 +0000175 extract = asn1f_class_access(arg, mod, ref);
vlmfa67ddc2004-06-03 03:38:44 +0000176
177 return extract;
178 } else {
179 DEBUG("\tToo many components: %d", ref->comp_count);
180 errno = EINVAL;
181 return NULL;
182 }
183
184 /*
185 * If module name is specified explicitly
186 * OR the current module's IMPORTS clause contains the identifier,
187 * fetch that module.
188 */
189 if(modulename) {
vlmf98e07a2004-09-15 11:46:47 +0000190 imports_from = asn1f_lookup_module(arg, modulename, 0);
191 if(imports_from == NULL) {
vlmfa67ddc2004-06-03 03:38:44 +0000192 FATAL("Module \"%s\" "
193 "mentioned at line %d is not found",
194 modulename, ref->_lineno);
195 return NULL;
196 }
197
198 /*
199 * Check that the EXPORTS section of this module contains
200 * the symbol we care about, or it is EXPORTS ALL.
201 */
vlmf98e07a2004-09-15 11:46:47 +0000202 if(asn1f_compatible_with_exports(arg,imports_from,identifier)) {
vlmfa67ddc2004-06-03 03:38:44 +0000203 errno = EPERM;
204 return NULL;
205 }
206 } else {
vlmf98e07a2004-09-15 11:46:47 +0000207 imports_from = asn1f_lookup_in_imports(arg, mod, identifier);
208 if(imports_from == NULL && errno != ESRCH) {
vlmfa67ddc2004-06-03 03:38:44 +0000209 /*
210 * Return only of the name was not found.
211 * If module was not found or more serious error
212 * encountered, just return preserving the errno.
213 */
214 return NULL;
215 }
216 }
217
vlmf98e07a2004-09-15 11:46:47 +0000218 /*
219 * The symbol is being imported from another module.
220 */
221 if(imports_from) {
222 asn1p_ref_t tmpref = *ref;
223 if(modulename) {
224 /*
225 * The modulename is specified inside this reference.
226 * To avoid recursion, reformat the reference
227 * as it were local to that module.
228 */
229 tmpref.components++; /* Hide the first element */
230 tmpref.comp_count--;
231 assert(tmpref.comp_count > 0);
232 }
233 return asn1f_lookup_symbol(arg, imports_from, &tmpref);
234 }
vlmfa67ddc2004-06-03 03:38:44 +0000235
236 /*
vlmf98e07a2004-09-15 11:46:47 +0000237 * Now we know where to search for a value: in the current module.
vlmfa67ddc2004-06-03 03:38:44 +0000238 */
vlmf98e07a2004-09-15 11:46:47 +0000239 TQ_FOR(ref_tc, &(mod->members), next) {
vlmfa67ddc2004-06-03 03:38:44 +0000240 if(ref_tc->Identifier)
241 if(strcmp(ref_tc->Identifier, identifier) == 0)
242 break;
243 }
244 if(ref_tc == NULL) {
245 DEBUG("Module \"%s\" does not contain \"%s\" "
vlmd9cd3f92004-06-28 21:21:24 +0000246 "mentioned at line %d: %s",
vlmf98e07a2004-09-15 11:46:47 +0000247 mod->Identifier,
vlmfa67ddc2004-06-03 03:38:44 +0000248 identifier,
vlmd9cd3f92004-06-28 21:21:24 +0000249 ref->_lineno,
250 strerror(errno)
vlmfa67ddc2004-06-03 03:38:44 +0000251 );
vlmd9cd3f92004-06-28 21:21:24 +0000252 if(asn1f_check_known_external_type(identifier) == 0) {
253 errno = EEXIST; /* Exists somewhere */
254 } else {
255 errno = ESRCH;
256 }
vlmfa67ddc2004-06-03 03:38:44 +0000257 return NULL;
258 }
259
vlmfa67ddc2004-06-03 03:38:44 +0000260 return ref_tc;
261}
262
263
264asn1p_expr_t *
vlm2e0c1942004-08-22 03:10:23 +0000265asn1f_find_terminal_type(arg_t *arg, asn1p_expr_t *expr) {
266 return asn1f_find_terminal_thing(arg, expr, 0);
vlmfa67ddc2004-06-03 03:38:44 +0000267}
268
269asn1p_expr_t *
vlm2e0c1942004-08-22 03:10:23 +0000270asn1f_find_terminal_value(arg_t *arg, asn1p_expr_t *expr) {
271 return asn1f_find_terminal_thing(arg, expr, 1);
vlmfa67ddc2004-06-03 03:38:44 +0000272}
273
274static asn1p_expr_t *
vlm2e0c1942004-08-22 03:10:23 +0000275asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, int type_or_value) {
vlmfa67ddc2004-06-03 03:38:44 +0000276 asn1p_ref_t *ref;
277 asn1p_expr_t *tc;
278
279 if(type_or_value) {
280 /* VALUE */
281 assert(expr->meta_type == AMT_VALUE);
282 assert(expr->value);
vlm2e0c1942004-08-22 03:10:23 +0000283 /* Expression may be a terminal type itself */
284 if(expr->value->type != ATV_REFERENCED)
vlmfa67ddc2004-06-03 03:38:44 +0000285 return expr;
vlmfa67ddc2004-06-03 03:38:44 +0000286 ref = expr->value->value.reference;
287 } else {
288 /* TYPE */
vlm2e0c1942004-08-22 03:10:23 +0000289 /* Expression may be a terminal type itself */
290 if(expr->expr_type != A1TC_REFERENCE)
vlmfa67ddc2004-06-03 03:38:44 +0000291 return expr;
vlmfa67ddc2004-06-03 03:38:44 +0000292 ref = expr->reference;
293 }
294
vlmfd245932005-03-10 10:02:50 +0000295 DEBUG("%s(%s->%s) for line %d",
296 type_or_value?"VALUE":"TYPE",
vlmfa67ddc2004-06-03 03:38:44 +0000297 expr->Identifier, asn1f_printable_reference(ref),
298 expr->_lineno);
299
300 assert(ref);
301
302 /*
303 * Lookup inside the type itself (ENUMERATED, INTEGER, etc).
304 */
305 if(type_or_value) {
306 asn1p_expr_t *val_type_tc;
vlm2e0c1942004-08-22 03:10:23 +0000307 val_type_tc = asn1f_find_terminal_type(arg, expr);
vlmfa67ddc2004-06-03 03:38:44 +0000308 if(val_type_tc
309 && asn1f_look_value_in_type(arg, val_type_tc, expr))
310 return NULL;
311 if(expr->value->type != ATV_REFERENCED) {
vlmfa67ddc2004-06-03 03:38:44 +0000312 return expr;
313 }
314 assert(ref == expr->value->value.reference);
315 ref = expr->value->value.reference;
316 }
317
318 /*
319 * Lookup inside the default module.
320 */
vlm2e0c1942004-08-22 03:10:23 +0000321 tc = asn1f_lookup_symbol(arg, expr->module, ref);
vlmfa67ddc2004-06-03 03:38:44 +0000322 if(tc == NULL) {
vlmd9cd3f92004-06-28 21:21:24 +0000323 DEBUG("\tSymbol \"%s\" not found: %s",
324 asn1f_printable_reference(ref),
325 strerror(errno));
vlmfa67ddc2004-06-03 03:38:44 +0000326 return NULL;
327 }
328
329 /*
330 * Recursive loops detection.
331 */
332 if(tc->_mark & TM_RECURSION) {
333 DEBUG("Recursion loop detected for %s at line %d",
334 asn1f_printable_reference(ref), ref->_lineno);
335 errno = EPERM;
336 return NULL;
337 }
338
339 tc->_mark |= TM_RECURSION;
vlm2e0c1942004-08-22 03:10:23 +0000340 WITH_MODULE(tc->module,
341 expr = asn1f_find_terminal_thing(arg, tc, type_or_value));
vlmfa67ddc2004-06-03 03:38:44 +0000342 tc->_mark &= ~TM_RECURSION;
343
344 return expr;
345}
346
347/*
348 * Make sure that the specified name is present or otherwise does
349 * not contradict with the EXPORTS clause of the specified module.
350 */
351static int
352asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name) {
353 asn1p_xports_t *exports;
354 asn1p_expr_t *item;
355
356 assert(mod);
357 assert(name);
358
359 exports = TQ_FIRST(&(mod->exports));
360 if(exports == NULL) {
361 /* No EXPORTS section or EXPORTS ALL; */
362 return 0;
363 }
364
365 TQ_FOR(item, &(exports->members), next) {
366 if(strcmp(item->Identifier, name) == 0)
367 return 0;
368 }
369
370 DEBUG("Symbol \"%s\" contradicts with EXPORTS of module %s",
371 name, mod->Identifier);
372
373 errno = ESRCH;
374 return -1;
375}