blob: 6b752792e1bcf921f672224b25a0e6dd7f9fe437 [file] [log] [blame]
vlmfa67ddc2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
2
vlm93226382005-03-20 11:27:19 +00003enum ftt_what {
4 FTT_TYPE, /* Find the type of the given expression */
5 FTT_VALUE, /* Find the value of the given expression */
6};
7
8static asn1p_expr_t *asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, enum ftt_what);
vlmfa67ddc2004-06-03 03:38:44 +00009static int asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name);
10
11
12/*
13 * Lookup a child by its name.
14 */
15asn1p_expr_t *
16asn1f_lookup_child(asn1p_expr_t *tc, const char *name) {
17 asn1p_expr_t *child_tc;
18
19 TQ_FOR(child_tc, &(tc->members), next) {
20 if(child_tc->Identifier
21 && strcmp(child_tc->Identifier, name) == 0) {
22 return child_tc;
23 }
24 }
25
26 errno = ESRCH;
27 return NULL;
28}
29
30asn1p_module_t *
vlmf98e07a2004-09-15 11:46:47 +000031asn1f_lookup_in_imports(arg_t *arg, asn1p_module_t *mod, const char *name) {
vlmfa67ddc2004-06-03 03:38:44 +000032 asn1p_xports_t *xp;
33 asn1p_expr_t *tc;
34
35 /*
36 * Search in which exactly module this name is defined.
37 */
vlmf98e07a2004-09-15 11:46:47 +000038 TQ_FOR(xp, &(mod->imports), xp_next) {
vlmfa67ddc2004-06-03 03:38:44 +000039 TQ_FOR(tc, &(xp->members), next) {
40 if(strcmp(name, tc->Identifier) == 0)
41 break;
42 }
43 if(tc) break;
44 }
45 if(xp == NULL) {
46 errno = ESRCH;
47 return NULL;
48 }
49
50 /*
51 * Okay, right now we have a module name and, hopefully, an OID.
52 * Search the arg->asn for the specified module.
53 */
54 mod = asn1f_lookup_module(arg, xp->from, xp->from_oid);
55 if(mod == NULL) {
vlmf1d86c92005-03-18 05:20:39 +000056 /* Conditional debug */
57 if(!(arg->expr->_mark & TM_BROKEN)) {
58 arg->expr->_mark |= TM_BROKEN;
59 FATAL("Cannot find module %s "
60 "mentioned for %s at line %d",
61 xp->from, name, arg->expr->_lineno);
62 }
vlmfa67ddc2004-06-03 03:38:44 +000063 /* ENOENT/ETOOMANYREFS */
64 return NULL;
65 }
66
67 /*
68 * Check that the EXPORTS section of this module contains
69 * the symbol we care about, or it is EXPORTS ALL.
70 */
71 if(asn1f_compatible_with_exports(arg, mod, name)) {
72 errno = EPERM;
73 return NULL;
74 }
75
76 return mod;
77}
78
79asn1p_module_t *
80asn1f_lookup_module(arg_t *arg, const char *module_name, asn1p_oid_t *oid) {
81 asn1p_module_t *mod;
82
83 assert(module_name);
84
85 /*
86 * If OID is given, the module_name is unused.
87 * If OID is not given, the module_name may mean
88 * either the real module's name, or the symbol which is the
89 * result of renaming. Check this first.
90 */
91 if(oid == 0) {
92 asn1p_xports_t *xp;
93 /*
94 * Check inside the IMPORTS section for possible renaming.
95 * Renaming practically means that a module_name is mentioned
96 * somewhere in the IMPORTS section AND OID is given.
97 */
98 TQ_FOR(xp, &(arg->mod->imports), xp_next) {
99 if(strcmp(module_name, xp->from))
100 continue;
101 if(oid) {
102 FATAL("Ambiguous reference: "
103 "%s "
104 "matches several modules",
105 module_name);
106 errno = ETOOMANYREFS;
107 return NULL;
108 }
109 /*
110 * Yes, there is a renaming.
111 * Make lookup use OID instead.
112 */
113 oid = xp->from_oid;
114 }
115 }
116
117 /*
118 * Perform lookup using OID or module_name.
119 */
120 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
121 if(oid) {
122 if(mod->module_oid) {
123 if(asn1p_oid_compare(oid,
124 mod->module_oid)) {
125 continue;
126 } else {
127 /* Match! Even if name doesn't. */
128 return mod;
129 }
130 } else {
131 /* Not match, even if name is the same. */
132 continue;
133 }
134 }
135
136 if(strcmp(module_name, mod->Identifier) == 0)
137 return mod;
138 }
139
140 DEBUG("\tModule \"%s\" not found", module_name);
141
142 errno = ENOENT;
143 return NULL;
144}
145
146
147
148asn1p_expr_t *
vlm2e0c1942004-08-22 03:10:23 +0000149asn1f_lookup_symbol(arg_t *arg, asn1p_module_t *mod, asn1p_ref_t *ref) {
vlmfa67ddc2004-06-03 03:38:44 +0000150 asn1p_expr_t *ref_tc; /* Referenced tc */
vlmf98e07a2004-09-15 11:46:47 +0000151 asn1p_module_t *imports_from;
vlmfa67ddc2004-06-03 03:38:44 +0000152 char *modulename;
153 char *identifier;
154
155 /*
156 * First of all, a reference to a symbol may be specified
157 * using several possible forms:
158 * a) simple identifier
159 * v INTEGER ::= value
160 * b) external reference
161 * v INTEGER ::= Module1.value
162 * c) class-related stuff (the most complex stuff)
163 * v ::= <[A-Z][A-Z0-9a-z-]*>.&<[A-Z0-9a-z-]+>.
164 * All other forms are not implemented at this moment.
165 */
166
vlmfd245932005-03-10 10:02:50 +0000167 DEBUG("(%s) in %s for line %d",
vlmfa67ddc2004-06-03 03:38:44 +0000168 asn1f_printable_reference(ref),
vlm2e0c1942004-08-22 03:10:23 +0000169 mod->Identifier,
vlmfa67ddc2004-06-03 03:38:44 +0000170 ref->_lineno);
171
172 if(ref->comp_count == 1) {
173 modulename = NULL;
174 identifier = ref->components[0].name;
175 } else if(ref->comp_count == 2
176 && ref->components[1].name[0] != '&') {
177 modulename = ref->components[0].name;
178 identifier = ref->components[1].name;
179 } else if(ref->comp_count > 1
180 && isupper(ref->components[0].name[0])
181 && ref->components[1].name[0] == '&') {
182 asn1p_expr_t *extract;
183 /*
184 * This is a reference to a CLASS-related stuff.
185 * Employ a separate function for that.
186 */
vlm2e0c1942004-08-22 03:10:23 +0000187 extract = asn1f_class_access(arg, mod, ref);
vlmfa67ddc2004-06-03 03:38:44 +0000188
189 return extract;
190 } else {
191 DEBUG("\tToo many components: %d", ref->comp_count);
192 errno = EINVAL;
193 return NULL;
194 }
195
196 /*
197 * If module name is specified explicitly
198 * OR the current module's IMPORTS clause contains the identifier,
199 * fetch that module.
200 */
201 if(modulename) {
vlmf98e07a2004-09-15 11:46:47 +0000202 imports_from = asn1f_lookup_module(arg, modulename, 0);
203 if(imports_from == NULL) {
vlmfa67ddc2004-06-03 03:38:44 +0000204 FATAL("Module \"%s\" "
205 "mentioned at line %d is not found",
206 modulename, ref->_lineno);
207 return NULL;
208 }
209
210 /*
211 * Check that the EXPORTS section of this module contains
212 * the symbol we care about, or it is EXPORTS ALL.
213 */
vlmf98e07a2004-09-15 11:46:47 +0000214 if(asn1f_compatible_with_exports(arg,imports_from,identifier)) {
vlmfa67ddc2004-06-03 03:38:44 +0000215 errno = EPERM;
216 return NULL;
217 }
218 } else {
vlmf98e07a2004-09-15 11:46:47 +0000219 imports_from = asn1f_lookup_in_imports(arg, mod, identifier);
220 if(imports_from == NULL && errno != ESRCH) {
vlmfa67ddc2004-06-03 03:38:44 +0000221 /*
222 * Return only of the name was not found.
223 * If module was not found or more serious error
224 * encountered, just return preserving the errno.
225 */
226 return NULL;
227 }
228 }
229
vlmf98e07a2004-09-15 11:46:47 +0000230 /*
231 * The symbol is being imported from another module.
232 */
233 if(imports_from) {
234 asn1p_ref_t tmpref = *ref;
vlmf1d86c92005-03-18 05:20:39 +0000235 asn1p_expr_t *expr;
vlmf98e07a2004-09-15 11:46:47 +0000236 if(modulename) {
237 /*
238 * The modulename is specified inside this reference.
239 * To avoid recursion, reformat the reference
240 * as it were local to that module.
241 */
242 tmpref.components++; /* Hide the first element */
243 tmpref.comp_count--;
244 assert(tmpref.comp_count > 0);
245 }
vlmf1d86c92005-03-18 05:20:39 +0000246
247 expr = asn1f_lookup_symbol(arg, imports_from, &tmpref);
248 if(!expr && !(arg->expr->_mark & TM_BROKEN)) {
249 arg->expr->_mark |= TM_BROKEN;
250 if(modulename) {
251 FATAL("Module %s referred by %s in module %s "
252 "does not contain the requested symbol",
253 imports_from->Identifier,
254 asn1f_printable_reference(ref),
255 mod->Identifier);
256 } else {
257 FATAL("Module %s referred in IMPORTS section "
258 "for %s of module %s does not contain "
259 "the requested symbol",
260 imports_from->Identifier,
261 asn1f_printable_reference(ref),
262 mod->Identifier);
263 }
264 }
265 return expr;
vlmf98e07a2004-09-15 11:46:47 +0000266 }
vlmfa67ddc2004-06-03 03:38:44 +0000267
268 /*
vlmf98e07a2004-09-15 11:46:47 +0000269 * Now we know where to search for a value: in the current module.
vlmfa67ddc2004-06-03 03:38:44 +0000270 */
vlmf98e07a2004-09-15 11:46:47 +0000271 TQ_FOR(ref_tc, &(mod->members), next) {
vlmfa67ddc2004-06-03 03:38:44 +0000272 if(ref_tc->Identifier)
273 if(strcmp(ref_tc->Identifier, identifier) == 0)
274 break;
275 }
276 if(ref_tc == NULL) {
277 DEBUG("Module \"%s\" does not contain \"%s\" "
vlmd9cd3f92004-06-28 21:21:24 +0000278 "mentioned at line %d: %s",
vlmf98e07a2004-09-15 11:46:47 +0000279 mod->Identifier,
vlmfa67ddc2004-06-03 03:38:44 +0000280 identifier,
vlmd9cd3f92004-06-28 21:21:24 +0000281 ref->_lineno,
282 strerror(errno)
vlmfa67ddc2004-06-03 03:38:44 +0000283 );
vlmd9cd3f92004-06-28 21:21:24 +0000284 if(asn1f_check_known_external_type(identifier) == 0) {
285 errno = EEXIST; /* Exists somewhere */
286 } else {
287 errno = ESRCH;
288 }
vlmfa67ddc2004-06-03 03:38:44 +0000289 return NULL;
290 }
291
vlmfa67ddc2004-06-03 03:38:44 +0000292 return ref_tc;
293}
294
295
296asn1p_expr_t *
vlm2e0c1942004-08-22 03:10:23 +0000297asn1f_find_terminal_type(arg_t *arg, asn1p_expr_t *expr) {
vlm93226382005-03-20 11:27:19 +0000298 return asn1f_find_terminal_thing(arg, expr, FTT_TYPE);
vlmfa67ddc2004-06-03 03:38:44 +0000299}
300
301asn1p_expr_t *
vlm2e0c1942004-08-22 03:10:23 +0000302asn1f_find_terminal_value(arg_t *arg, asn1p_expr_t *expr) {
vlm93226382005-03-20 11:27:19 +0000303 return asn1f_find_terminal_thing(arg, expr, FTT_VALUE);
vlmfa67ddc2004-06-03 03:38:44 +0000304}
305
306static asn1p_expr_t *
vlm93226382005-03-20 11:27:19 +0000307asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, enum ftt_what what) {
vlm2fb3f752005-03-20 13:17:48 +0000308 asn1p_ref_t *ref = 0;
vlmfa67ddc2004-06-03 03:38:44 +0000309 asn1p_expr_t *tc;
310
vlm93226382005-03-20 11:27:19 +0000311 switch(what) {
312 case FTT_TYPE:
313 /* Expression may be a terminal type itself */
314 if(expr->expr_type != A1TC_REFERENCE)
315 return expr;
316 ref = expr->reference;
317 break;
318 case FTT_VALUE:
vlmfa67ddc2004-06-03 03:38:44 +0000319 assert(expr->meta_type == AMT_VALUE);
320 assert(expr->value);
vlm2e0c1942004-08-22 03:10:23 +0000321 /* Expression may be a terminal type itself */
322 if(expr->value->type != ATV_REFERENCED)
vlmfa67ddc2004-06-03 03:38:44 +0000323 return expr;
vlmfa67ddc2004-06-03 03:38:44 +0000324 ref = expr->value->value.reference;
vlm93226382005-03-20 11:27:19 +0000325 break;
vlmfa67ddc2004-06-03 03:38:44 +0000326 }
327
vlmfd245932005-03-10 10:02:50 +0000328 DEBUG("%s(%s->%s) for line %d",
vlm93226382005-03-20 11:27:19 +0000329 (what == FTT_VALUE)?"VALUE":"TYPE",
vlmfa67ddc2004-06-03 03:38:44 +0000330 expr->Identifier, asn1f_printable_reference(ref),
331 expr->_lineno);
332
333 assert(ref);
334
335 /*
336 * Lookup inside the type itself (ENUMERATED, INTEGER, etc).
337 */
vlm93226382005-03-20 11:27:19 +0000338 if(what == FTT_VALUE) {
vlmfa67ddc2004-06-03 03:38:44 +0000339 asn1p_expr_t *val_type_tc;
vlm2e0c1942004-08-22 03:10:23 +0000340 val_type_tc = asn1f_find_terminal_type(arg, expr);
vlmfa67ddc2004-06-03 03:38:44 +0000341 if(val_type_tc
342 && asn1f_look_value_in_type(arg, val_type_tc, expr))
343 return NULL;
344 if(expr->value->type != ATV_REFERENCED) {
vlmfa67ddc2004-06-03 03:38:44 +0000345 return expr;
346 }
347 assert(ref == expr->value->value.reference);
348 ref = expr->value->value.reference;
349 }
350
351 /*
vlmf1d86c92005-03-18 05:20:39 +0000352 * Lookup inside the default module and its IMPORTS section.
vlmfa67ddc2004-06-03 03:38:44 +0000353 */
vlm2e0c1942004-08-22 03:10:23 +0000354 tc = asn1f_lookup_symbol(arg, expr->module, ref);
vlmfa67ddc2004-06-03 03:38:44 +0000355 if(tc == NULL) {
vlmd9cd3f92004-06-28 21:21:24 +0000356 DEBUG("\tSymbol \"%s\" not found: %s",
357 asn1f_printable_reference(ref),
358 strerror(errno));
vlmfa67ddc2004-06-03 03:38:44 +0000359 return NULL;
360 }
361
362 /*
363 * Recursive loops detection.
364 */
365 if(tc->_mark & TM_RECURSION) {
366 DEBUG("Recursion loop detected for %s at line %d",
367 asn1f_printable_reference(ref), ref->_lineno);
368 errno = EPERM;
369 return NULL;
370 }
371
372 tc->_mark |= TM_RECURSION;
vlm2e0c1942004-08-22 03:10:23 +0000373 WITH_MODULE(tc->module,
vlm93226382005-03-20 11:27:19 +0000374 expr = asn1f_find_terminal_thing(arg, tc, what));
vlmfa67ddc2004-06-03 03:38:44 +0000375 tc->_mark &= ~TM_RECURSION;
376
377 return expr;
378}
379
380/*
381 * Make sure that the specified name is present or otherwise does
382 * not contradict with the EXPORTS clause of the specified module.
383 */
384static int
385asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name) {
386 asn1p_xports_t *exports;
387 asn1p_expr_t *item;
388
389 assert(mod);
390 assert(name);
391
392 exports = TQ_FIRST(&(mod->exports));
393 if(exports == NULL) {
394 /* No EXPORTS section or EXPORTS ALL; */
395 return 0;
396 }
397
398 TQ_FOR(item, &(exports->members), next) {
399 if(strcmp(item->Identifier, name) == 0)
400 return 0;
401 }
402
vlmf1d86c92005-03-18 05:20:39 +0000403 /* Conditional debug */
404 if(!(arg->expr->_mark & TM_BROKEN)) {
405 arg->expr->_mark |= TM_BROKEN;
406 FATAL("EXPORTS section of module %s in %s "
407 "does not mention %s at line %d",
408 mod->Identifier, mod->source_file_name, name,
409 arg->expr->_lineno);
410 }
vlmfa67ddc2004-06-03 03:38:44 +0000411
412 errno = ESRCH;
413 return -1;
414}