blob: 161e0da10e77e774b577dc6dc1d67e77ea07d718 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
2
Lev Walkin33f63f82005-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);
Lev Walkinf15320b2004-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 *
Lev Walkin163db362004-09-15 11:46:47 +000031asn1f_lookup_in_imports(arg_t *arg, asn1p_module_t *mod, const char *name) {
Lev Walkinf15320b2004-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 */
Lev Walkin163db362004-09-15 11:46:47 +000038 TQ_FOR(xp, &(mod->imports), xp_next) {
Lev Walkinf15320b2004-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 */
Lev Walkinb36317c2005-08-12 10:09:10 +000054 mod = asn1f_lookup_module(arg, xp->fromModuleName, xp->identifier.oid);
Lev Walkinf15320b2004-06-03 03:38:44 +000055 if(mod == NULL) {
Lev Walkind8095522005-03-18 05:20:39 +000056 /* Conditional debug */
57 if(!(arg->expr->_mark & TM_BROKEN)) {
58 arg->expr->_mark |= TM_BROKEN;
Lev Walkin9e366ba2005-04-12 17:46:30 +000059 FATAL("Cannot find external module \"%s\" "
60 "mentioned for "
61 "\"%s\" at line %d",
Lev Walkinb36317c2005-08-12 10:09:10 +000062 xp->fromModuleName, name, arg->expr->_lineno);
Lev Walkind8095522005-03-18 05:20:39 +000063 }
Lev Walkinf15320b2004-06-03 03:38:44 +000064 /* ENOENT/ETOOMANYREFS */
65 return NULL;
66 }
67
68 /*
69 * Check that the EXPORTS section of this module contains
70 * the symbol we care about, or it is EXPORTS ALL.
71 */
72 if(asn1f_compatible_with_exports(arg, mod, name)) {
73 errno = EPERM;
74 return NULL;
75 }
76
77 return mod;
78}
79
80asn1p_module_t *
81asn1f_lookup_module(arg_t *arg, const char *module_name, asn1p_oid_t *oid) {
82 asn1p_module_t *mod;
83
84 assert(module_name);
85
86 /*
87 * If OID is given, the module_name is unused.
88 * If OID is not given, the module_name may mean
89 * either the real module's name, or the symbol which is the
90 * result of renaming. Check this first.
91 */
92 if(oid == 0) {
93 asn1p_xports_t *xp;
94 /*
95 * Check inside the IMPORTS section for possible renaming.
96 * Renaming practically means that a module_name is mentioned
97 * somewhere in the IMPORTS section AND OID is given.
98 */
99 TQ_FOR(xp, &(arg->mod->imports), xp_next) {
Lev Walkinb36317c2005-08-12 10:09:10 +0000100 if(strcmp(module_name, xp->fromModuleName))
Lev Walkinf15320b2004-06-03 03:38:44 +0000101 continue;
102 if(oid) {
103 FATAL("Ambiguous reference: "
104 "%s "
105 "matches several modules",
106 module_name);
107 errno = ETOOMANYREFS;
108 return NULL;
109 }
110 /*
111 * Yes, there is a renaming.
112 * Make lookup use OID instead.
113 */
Lev Walkinb36317c2005-08-12 10:09:10 +0000114 oid = xp->identifier.oid;
Lev Walkinf15320b2004-06-03 03:38:44 +0000115 }
116 }
117
118 /*
119 * Perform lookup using OID or module_name.
120 */
121 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
122 if(oid) {
123 if(mod->module_oid) {
124 if(asn1p_oid_compare(oid,
125 mod->module_oid)) {
126 continue;
127 } else {
128 /* Match! Even if name doesn't. */
129 return mod;
130 }
131 } else {
132 /* Not match, even if name is the same. */
133 continue;
134 }
135 }
136
Lev Walkinb36317c2005-08-12 10:09:10 +0000137 if(strcmp(module_name, mod->ModuleName) == 0)
Lev Walkinf15320b2004-06-03 03:38:44 +0000138 return mod;
139 }
140
141 DEBUG("\tModule \"%s\" not found", module_name);
142
143 errno = ENOENT;
144 return NULL;
145}
146
147
148
149asn1p_expr_t *
Lev Walkin6fec44d2004-08-22 03:10:23 +0000150asn1f_lookup_symbol(arg_t *arg, asn1p_module_t *mod, asn1p_ref_t *ref) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000151 asn1p_expr_t *ref_tc; /* Referenced tc */
Lev Walkin163db362004-09-15 11:46:47 +0000152 asn1p_module_t *imports_from;
Lev Walkinf15320b2004-06-03 03:38:44 +0000153 char *modulename;
154 char *identifier;
155
156 /*
157 * First of all, a reference to a symbol may be specified
158 * using several possible forms:
159 * a) simple identifier
160 * v INTEGER ::= value
161 * b) external reference
162 * v INTEGER ::= Module1.value
163 * c) class-related stuff (the most complex stuff)
164 * v ::= <[A-Z][A-Z0-9a-z-]*>.&<[A-Z0-9a-z-]+>.
165 * All other forms are not implemented at this moment.
166 */
167
Lev Walkin03850182005-03-10 10:02:50 +0000168 DEBUG("(%s) in %s for line %d",
Lev Walkinf15320b2004-06-03 03:38:44 +0000169 asn1f_printable_reference(ref),
Lev Walkinb36317c2005-08-12 10:09:10 +0000170 mod->ModuleName,
Lev Walkinf15320b2004-06-03 03:38:44 +0000171 ref->_lineno);
172
173 if(ref->comp_count == 1) {
174 modulename = NULL;
175 identifier = ref->components[0].name;
176 } else if(ref->comp_count == 2
177 && ref->components[1].name[0] != '&') {
178 modulename = ref->components[0].name;
179 identifier = ref->components[1].name;
180 } else if(ref->comp_count > 1
181 && isupper(ref->components[0].name[0])
182 && ref->components[1].name[0] == '&') {
183 asn1p_expr_t *extract;
184 /*
185 * This is a reference to a CLASS-related stuff.
186 * Employ a separate function for that.
187 */
Lev Walkin6fec44d2004-08-22 03:10:23 +0000188 extract = asn1f_class_access(arg, mod, ref);
Lev Walkinf15320b2004-06-03 03:38:44 +0000189
190 return extract;
191 } else {
192 DEBUG("\tToo many components: %d", ref->comp_count);
193 errno = EINVAL;
194 return NULL;
195 }
196
197 /*
198 * If module name is specified explicitly
199 * OR the current module's IMPORTS clause contains the identifier,
200 * fetch that module.
201 */
202 if(modulename) {
Lev Walkin163db362004-09-15 11:46:47 +0000203 imports_from = asn1f_lookup_module(arg, modulename, 0);
204 if(imports_from == NULL) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000205 FATAL("Module \"%s\" "
206 "mentioned at line %d is not found",
207 modulename, ref->_lineno);
208 return NULL;
209 }
210
211 /*
212 * Check that the EXPORTS section of this module contains
213 * the symbol we care about, or it is EXPORTS ALL.
214 */
Lev Walkin163db362004-09-15 11:46:47 +0000215 if(asn1f_compatible_with_exports(arg,imports_from,identifier)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000216 errno = EPERM;
217 return NULL;
218 }
219 } else {
Lev Walkin6b3ff542006-03-06 14:51:00 +0000220 /* Search inside the IMPORTS section of the current module */
Lev Walkin163db362004-09-15 11:46:47 +0000221 imports_from = asn1f_lookup_in_imports(arg, mod, identifier);
222 if(imports_from == NULL && errno != ESRCH) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000223 /*
224 * Return only of the name was not found.
225 * If module was not found or more serious error
226 * encountered, just return preserving the errno.
227 */
228 return NULL;
229 }
230 }
231
Lev Walkin163db362004-09-15 11:46:47 +0000232 /*
233 * The symbol is being imported from another module.
234 */
Lev Walkin6b3ff542006-03-06 14:51:00 +0000235 importing:
Lev Walkin163db362004-09-15 11:46:47 +0000236 if(imports_from) {
237 asn1p_ref_t tmpref = *ref;
Lev Walkind8095522005-03-18 05:20:39 +0000238 asn1p_expr_t *expr;
Lev Walkin163db362004-09-15 11:46:47 +0000239 if(modulename) {
240 /*
241 * The modulename is specified inside this reference.
242 * To avoid recursion, reformat the reference
243 * as it were local to that module.
244 */
245 tmpref.components++; /* Hide the first element */
246 tmpref.comp_count--;
247 assert(tmpref.comp_count > 0);
248 }
Lev Walkind8095522005-03-18 05:20:39 +0000249
250 expr = asn1f_lookup_symbol(arg, imports_from, &tmpref);
251 if(!expr && !(arg->expr->_mark & TM_BROKEN)) {
252 arg->expr->_mark |= TM_BROKEN;
253 if(modulename) {
254 FATAL("Module %s referred by %s in module %s "
255 "does not contain the requested symbol",
Lev Walkinb36317c2005-08-12 10:09:10 +0000256 imports_from->ModuleName,
Lev Walkind8095522005-03-18 05:20:39 +0000257 asn1f_printable_reference(ref),
Lev Walkinb36317c2005-08-12 10:09:10 +0000258 mod->ModuleName);
Lev Walkind8095522005-03-18 05:20:39 +0000259 } else {
260 FATAL("Module %s referred in IMPORTS section "
261 "for %s of module %s does not contain "
262 "the requested symbol",
Lev Walkinb36317c2005-08-12 10:09:10 +0000263 imports_from->ModuleName,
Lev Walkind8095522005-03-18 05:20:39 +0000264 asn1f_printable_reference(ref),
Lev Walkinb36317c2005-08-12 10:09:10 +0000265 mod->ModuleName);
Lev Walkind8095522005-03-18 05:20:39 +0000266 }
267 }
268 return expr;
Lev Walkin163db362004-09-15 11:46:47 +0000269 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000270
271 /*
Lev Walkin163db362004-09-15 11:46:47 +0000272 * Now we know where to search for a value: in the current module.
Lev Walkinf15320b2004-06-03 03:38:44 +0000273 */
Lev Walkin163db362004-09-15 11:46:47 +0000274 TQ_FOR(ref_tc, &(mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000275 if(ref_tc->Identifier)
276 if(strcmp(ref_tc->Identifier, identifier) == 0)
277 break;
278 }
Lev Walkin6b3ff542006-03-06 14:51:00 +0000279 if(ref_tc)
280 return ref_tc;
281
282 {
283 /* Search inside standard module */
284 static asn1p_oid_t *uioc_oid;
285 if(!uioc_oid) {
286 asn1p_oid_arc_t arcs[] = {
287 { 1, "iso" },
288 { 3, "org" },
289 { 6, "dod" },
290 { 1, "internet" },
291 { 4, "private" },
292 { 1, "enterprise" },
293 { 9363, "spelio" },
294 { 1, "software" },
295 { 5, "asn1c" },
296 { 3, "standard-modules" },
297 { 0, "auto-imported" },
298 { 1, 0 }
299 };
300 uioc_oid = asn1p_oid_construct(arcs,
301 sizeof(arcs)/sizeof(arcs[0]));
Lev Walkin97bdee22004-06-28 21:21:24 +0000302 }
Lev Walkin6b3ff542006-03-06 14:51:00 +0000303 if(!imports_from && mod->module_oid
304 && asn1p_oid_compare(mod->module_oid, uioc_oid)) {
305 imports_from = asn1f_lookup_module(arg,
306 "ASN1C-UsefulInformationObjectClasses",
307 uioc_oid);
308 if(imports_from) goto importing;
309 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000310 }
311
Lev Walkin6b3ff542006-03-06 14:51:00 +0000312 DEBUG("Module \"%s\" does not contain \"%s\" "
313 "mentioned at line %d: %s",
314 mod->ModuleName,
315 identifier,
316 ref->_lineno,
317 strerror(errno));
318
319 if(asn1f_check_known_external_type(identifier) == 0) {
320 errno = EEXIST; /* Exists somewhere */
321 } else {
322 errno = ESRCH;
323 }
324 return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000325}
326
327
328asn1p_expr_t *
Lev Walkin6fec44d2004-08-22 03:10:23 +0000329asn1f_find_terminal_type(arg_t *arg, asn1p_expr_t *expr) {
Lev Walkin33f63f82005-03-20 11:27:19 +0000330 return asn1f_find_terminal_thing(arg, expr, FTT_TYPE);
Lev Walkinf15320b2004-06-03 03:38:44 +0000331}
332
333asn1p_expr_t *
Lev Walkin6fec44d2004-08-22 03:10:23 +0000334asn1f_find_terminal_value(arg_t *arg, asn1p_expr_t *expr) {
Lev Walkin33f63f82005-03-20 11:27:19 +0000335 return asn1f_find_terminal_thing(arg, expr, FTT_VALUE);
Lev Walkinf15320b2004-06-03 03:38:44 +0000336}
337
338static asn1p_expr_t *
Lev Walkin33f63f82005-03-20 11:27:19 +0000339asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, enum ftt_what what) {
Lev Walkin039a09e2005-03-20 13:17:48 +0000340 asn1p_ref_t *ref = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000341 asn1p_expr_t *tc;
342
Lev Walkin33f63f82005-03-20 11:27:19 +0000343 switch(what) {
344 case FTT_TYPE:
345 /* Expression may be a terminal type itself */
346 if(expr->expr_type != A1TC_REFERENCE)
347 return expr;
348 ref = expr->reference;
349 break;
350 case FTT_VALUE:
Lev Walkinf15320b2004-06-03 03:38:44 +0000351 assert(expr->meta_type == AMT_VALUE);
352 assert(expr->value);
Lev Walkin6fec44d2004-08-22 03:10:23 +0000353 /* Expression may be a terminal type itself */
354 if(expr->value->type != ATV_REFERENCED)
Lev Walkinf15320b2004-06-03 03:38:44 +0000355 return expr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000356 ref = expr->value->value.reference;
Lev Walkin33f63f82005-03-20 11:27:19 +0000357 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000358 }
359
Lev Walkin03850182005-03-10 10:02:50 +0000360 DEBUG("%s(%s->%s) for line %d",
Lev Walkin33f63f82005-03-20 11:27:19 +0000361 (what == FTT_VALUE)?"VALUE":"TYPE",
Lev Walkinf15320b2004-06-03 03:38:44 +0000362 expr->Identifier, asn1f_printable_reference(ref),
363 expr->_lineno);
364
365 assert(ref);
366
367 /*
368 * Lookup inside the type itself (ENUMERATED, INTEGER, etc).
369 */
Lev Walkin33f63f82005-03-20 11:27:19 +0000370 if(what == FTT_VALUE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000371 asn1p_expr_t *val_type_tc;
Lev Walkin6fec44d2004-08-22 03:10:23 +0000372 val_type_tc = asn1f_find_terminal_type(arg, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +0000373 if(val_type_tc
374 && asn1f_look_value_in_type(arg, val_type_tc, expr))
375 return NULL;
376 if(expr->value->type != ATV_REFERENCED) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000377 return expr;
378 }
379 assert(ref == expr->value->value.reference);
380 ref = expr->value->value.reference;
381 }
382
383 /*
Lev Walkind8095522005-03-18 05:20:39 +0000384 * Lookup inside the default module and its IMPORTS section.
Lev Walkinf15320b2004-06-03 03:38:44 +0000385 */
Lev Walkin6fec44d2004-08-22 03:10:23 +0000386 tc = asn1f_lookup_symbol(arg, expr->module, ref);
Lev Walkinf15320b2004-06-03 03:38:44 +0000387 if(tc == NULL) {
Lev Walkin97bdee22004-06-28 21:21:24 +0000388 DEBUG("\tSymbol \"%s\" not found: %s",
389 asn1f_printable_reference(ref),
390 strerror(errno));
Lev Walkinf15320b2004-06-03 03:38:44 +0000391 return NULL;
392 }
393
394 /*
395 * Recursive loops detection.
396 */
397 if(tc->_mark & TM_RECURSION) {
398 DEBUG("Recursion loop detected for %s at line %d",
399 asn1f_printable_reference(ref), ref->_lineno);
400 errno = EPERM;
401 return NULL;
402 }
403
Lev Walkin59b176e2005-11-26 11:25:14 +0000404 tc->_type_referenced = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000405 tc->_mark |= TM_RECURSION;
Lev Walkin6fec44d2004-08-22 03:10:23 +0000406 WITH_MODULE(tc->module,
Lev Walkin33f63f82005-03-20 11:27:19 +0000407 expr = asn1f_find_terminal_thing(arg, tc, what));
Lev Walkinf15320b2004-06-03 03:38:44 +0000408 tc->_mark &= ~TM_RECURSION;
409
410 return expr;
411}
412
413/*
414 * Make sure that the specified name is present or otherwise does
415 * not contradict with the EXPORTS clause of the specified module.
416 */
417static int
418asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name) {
419 asn1p_xports_t *exports;
420 asn1p_expr_t *item;
421
422 assert(mod);
423 assert(name);
424
425 exports = TQ_FIRST(&(mod->exports));
426 if(exports == NULL) {
427 /* No EXPORTS section or EXPORTS ALL; */
428 return 0;
429 }
430
431 TQ_FOR(item, &(exports->members), next) {
432 if(strcmp(item->Identifier, name) == 0)
433 return 0;
434 }
435
Lev Walkind8095522005-03-18 05:20:39 +0000436 /* Conditional debug */
437 if(!(arg->expr->_mark & TM_BROKEN)) {
438 arg->expr->_mark |= TM_BROKEN;
439 FATAL("EXPORTS section of module %s in %s "
440 "does not mention %s at line %d",
Lev Walkinb36317c2005-08-12 10:09:10 +0000441 mod->ModuleName, mod->source_file_name, name,
Lev Walkind8095522005-03-18 05:20:39 +0000442 arg->expr->_lineno);
443 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000444
445 errno = ESRCH;
446 return -1;
447}