blob: 86540b9405cc5506f27fa3f598799895618fafb1 [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 "
Lev Walkin41635d32006-03-18 05:06:57 +000061 "\"%s\" at line %d. "
62 "Obtain this module and instruct compiler to process it too.",
Lev Walkinb36317c2005-08-12 10:09:10 +000063 xp->fromModuleName, name, arg->expr->_lineno);
Lev Walkind8095522005-03-18 05:20:39 +000064 }
Lev Walkinf15320b2004-06-03 03:38:44 +000065 /* ENOENT/ETOOMANYREFS */
66 return NULL;
67 }
68
69 /*
70 * Check that the EXPORTS section of this module contains
71 * the symbol we care about, or it is EXPORTS ALL.
72 */
73 if(asn1f_compatible_with_exports(arg, mod, name)) {
74 errno = EPERM;
75 return NULL;
76 }
77
78 return mod;
79}
80
81asn1p_module_t *
82asn1f_lookup_module(arg_t *arg, const char *module_name, asn1p_oid_t *oid) {
83 asn1p_module_t *mod;
84
85 assert(module_name);
86
87 /*
88 * If OID is given, the module_name is unused.
89 * If OID is not given, the module_name may mean
90 * either the real module's name, or the symbol which is the
91 * result of renaming. Check this first.
92 */
93 if(oid == 0) {
94 asn1p_xports_t *xp;
95 /*
96 * Check inside the IMPORTS section for possible renaming.
97 * Renaming practically means that a module_name is mentioned
98 * somewhere in the IMPORTS section AND OID is given.
99 */
100 TQ_FOR(xp, &(arg->mod->imports), xp_next) {
Lev Walkinb36317c2005-08-12 10:09:10 +0000101 if(strcmp(module_name, xp->fromModuleName))
Lev Walkinf15320b2004-06-03 03:38:44 +0000102 continue;
103 if(oid) {
104 FATAL("Ambiguous reference: "
105 "%s "
106 "matches several modules",
107 module_name);
108 errno = ETOOMANYREFS;
109 return NULL;
110 }
111 /*
112 * Yes, there is a renaming.
113 * Make lookup use OID instead.
114 */
Lev Walkinb36317c2005-08-12 10:09:10 +0000115 oid = xp->identifier.oid;
Lev Walkinf15320b2004-06-03 03:38:44 +0000116 }
117 }
118
119 /*
120 * Perform lookup using OID or module_name.
121 */
122 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
123 if(oid) {
124 if(mod->module_oid) {
125 if(asn1p_oid_compare(oid,
126 mod->module_oid)) {
127 continue;
128 } else {
129 /* Match! Even if name doesn't. */
130 return mod;
131 }
132 } else {
133 /* Not match, even if name is the same. */
134 continue;
135 }
136 }
137
Lev Walkinb36317c2005-08-12 10:09:10 +0000138 if(strcmp(module_name, mod->ModuleName) == 0)
Lev Walkinf15320b2004-06-03 03:38:44 +0000139 return mod;
140 }
141
142 DEBUG("\tModule \"%s\" not found", module_name);
143
144 errno = ENOENT;
145 return NULL;
146}
147
Lev Walkin41635d32006-03-18 05:06:57 +0000148static asn1p_expr_t *
Lev Walkina00d6b32006-03-21 03:40:38 +0000149asn1f_lookup_symbol_impl(arg_t *arg, asn1p_module_t *mod, asn1p_expr_t *rhs_pspecs, asn1p_ref_t *ref, int recursion_depth) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000150 asn1p_expr_t *ref_tc; /* Referenced tc */
Lev Walkin163db362004-09-15 11:46:47 +0000151 asn1p_module_t *imports_from;
Lev Walkinf15320b2004-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
Lev Walkin03850182005-03-10 10:02:50 +0000167 DEBUG("(%s) in %s for line %d",
Lev Walkinf15320b2004-06-03 03:38:44 +0000168 asn1f_printable_reference(ref),
Lev Walkinb36317c2005-08-12 10:09:10 +0000169 mod->ModuleName,
Lev Walkinf15320b2004-06-03 03:38:44 +0000170 ref->_lineno);
171
Lev Walkin41635d32006-03-18 05:06:57 +0000172 if(recursion_depth++ > 30 /* Arbitrary constant */) {
173 FATAL("Excessive circular referencing detected in module %s for %s at line %d",
174 mod->ModuleName,
175 asn1f_printable_reference(ref),
176 ref->_lineno);
177 errno = ETOOMANYREFS;
178 return NULL;
179 }
180
Lev Walkinf15320b2004-06-03 03:38:44 +0000181 if(ref->comp_count == 1) {
182 modulename = NULL;
183 identifier = ref->components[0].name;
184 } else if(ref->comp_count == 2
185 && ref->components[1].name[0] != '&') {
186 modulename = ref->components[0].name;
187 identifier = ref->components[1].name;
188 } else if(ref->comp_count > 1
189 && isupper(ref->components[0].name[0])
190 && ref->components[1].name[0] == '&') {
191 asn1p_expr_t *extract;
192 /*
193 * This is a reference to a CLASS-related stuff.
194 * Employ a separate function for that.
195 */
Lev Walkina00d6b32006-03-21 03:40:38 +0000196 extract = asn1f_class_access(arg, mod, rhs_pspecs, ref);
Lev Walkinf15320b2004-06-03 03:38:44 +0000197
198 return extract;
199 } else {
200 DEBUG("\tToo many components: %d", ref->comp_count);
201 errno = EINVAL;
202 return NULL;
203 }
204
205 /*
206 * If module name is specified explicitly
207 * OR the current module's IMPORTS clause contains the identifier,
208 * fetch that module.
209 */
210 if(modulename) {
Lev Walkin163db362004-09-15 11:46:47 +0000211 imports_from = asn1f_lookup_module(arg, modulename, 0);
212 if(imports_from == NULL) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000213 FATAL("Module \"%s\" "
214 "mentioned at line %d is not found",
215 modulename, ref->_lineno);
216 return NULL;
217 }
218
219 /*
220 * Check that the EXPORTS section of this module contains
221 * the symbol we care about, or it is EXPORTS ALL.
222 */
Lev Walkin163db362004-09-15 11:46:47 +0000223 if(asn1f_compatible_with_exports(arg,imports_from,identifier)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000224 errno = EPERM;
225 return NULL;
226 }
227 } else {
Lev Walkin6b3ff542006-03-06 14:51:00 +0000228 /* Search inside the IMPORTS section of the current module */
Lev Walkin163db362004-09-15 11:46:47 +0000229 imports_from = asn1f_lookup_in_imports(arg, mod, identifier);
230 if(imports_from == NULL && errno != ESRCH) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000231 /*
232 * Return only of the name was not found.
233 * If module was not found or more serious error
234 * encountered, just return preserving the errno.
235 */
236 return NULL;
237 }
238 }
239
Lev Walkin163db362004-09-15 11:46:47 +0000240 /*
241 * The symbol is being imported from another module.
242 */
Lev Walkin6b3ff542006-03-06 14:51:00 +0000243 importing:
Lev Walkin163db362004-09-15 11:46:47 +0000244 if(imports_from) {
245 asn1p_ref_t tmpref = *ref;
Lev Walkind8095522005-03-18 05:20:39 +0000246 asn1p_expr_t *expr;
Lev Walkin163db362004-09-15 11:46:47 +0000247 if(modulename) {
248 /*
249 * The modulename is specified inside this reference.
250 * To avoid recursion, reformat the reference
251 * as it were local to that module.
252 */
253 tmpref.components++; /* Hide the first element */
254 tmpref.comp_count--;
255 assert(tmpref.comp_count > 0);
256 }
Lev Walkind8095522005-03-18 05:20:39 +0000257
Lev Walkina00d6b32006-03-21 03:40:38 +0000258 expr = asn1f_lookup_symbol_impl(arg, imports_from,
259 rhs_pspecs, &tmpref, recursion_depth);
Lev Walkindc4376d2006-03-16 11:04:55 +0000260 if(!expr && !(arg->expr->_mark & TM_BROKEN)
261 && !(imports_from->_tags & MT_STANDARD_MODULE)) {
Lev Walkind8095522005-03-18 05:20:39 +0000262 arg->expr->_mark |= TM_BROKEN;
263 if(modulename) {
264 FATAL("Module %s referred by %s in module %s "
265 "does not contain the requested symbol",
Lev Walkinb36317c2005-08-12 10:09:10 +0000266 imports_from->ModuleName,
Lev Walkind8095522005-03-18 05:20:39 +0000267 asn1f_printable_reference(ref),
Lev Walkinb36317c2005-08-12 10:09:10 +0000268 mod->ModuleName);
Lev Walkind8095522005-03-18 05:20:39 +0000269 } else {
270 FATAL("Module %s referred in IMPORTS section "
271 "for %s of module %s does not contain "
272 "the requested symbol",
Lev Walkinb36317c2005-08-12 10:09:10 +0000273 imports_from->ModuleName,
Lev Walkind8095522005-03-18 05:20:39 +0000274 asn1f_printable_reference(ref),
Lev Walkinb36317c2005-08-12 10:09:10 +0000275 mod->ModuleName);
Lev Walkind8095522005-03-18 05:20:39 +0000276 }
277 }
278 return expr;
Lev Walkin163db362004-09-15 11:46:47 +0000279 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000280
281 /*
Lev Walkin163db362004-09-15 11:46:47 +0000282 * Now we know where to search for a value: in the current module.
Lev Walkinf15320b2004-06-03 03:38:44 +0000283 */
Lev Walkin163db362004-09-15 11:46:47 +0000284 TQ_FOR(ref_tc, &(mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000285 if(ref_tc->Identifier)
286 if(strcmp(ref_tc->Identifier, identifier) == 0)
287 break;
288 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000289 if(ref_tc) {
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800290 /* It is acceptable that we don't use input parameters */
Lev Walkina00d6b32006-03-21 03:40:38 +0000291 if(rhs_pspecs && !ref_tc->lhs_params) {
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800292 WARNING("Parameterized type %s expected "
Lev Walkina00d6b32006-03-21 03:40:38 +0000293 "for %s at line %d",
294 ref_tc->Identifier,
295 asn1f_printable_reference(ref),
296 ref->_lineno);
Lev Walkina00d6b32006-03-21 03:40:38 +0000297 }
298 if(!rhs_pspecs && ref_tc->lhs_params) {
299 FATAL("Type %s expects specialization "
300 "from %s at line %d",
301 ref_tc->Identifier,
302 asn1f_printable_reference(ref),
303 ref->_lineno);
304 errno = EPERM;
305 return NULL;
306 }
307 if(rhs_pspecs && ref_tc->lhs_params) {
308 /* Specialize the target */
309 ref_tc = asn1f_parameterization_fork(arg,
310 ref_tc, rhs_pspecs);
311 }
Lev Walkin6b3ff542006-03-06 14:51:00 +0000312
Lev Walkina00d6b32006-03-21 03:40:38 +0000313 return ref_tc;
314 }
315
316 /*
317 * Not found in the current module.
318 * Search in our default standard module.
319 */
Lev Walkin6b3ff542006-03-06 14:51:00 +0000320 {
321 /* Search inside standard module */
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800322 asn1p_oid_t *uioc_oid;
323 asn1p_oid_arc_t arcs[] = {
324 { 1, "iso" },
325 { 3, "org" },
326 { 6, "dod" },
327 { 1, "internet" },
328 { 4, "private" },
329 { 1, "enterprise" },
330 { 9363, "spelio" },
331 { 1, "software" },
332 { 5, "asn1c" },
333 { 3, "standard-modules" },
334 { 0, "auto-imported" },
335 { 1, 0 }
336 };
337
338 if(!imports_from) {
Lev Walkin6b3ff542006-03-06 14:51:00 +0000339 uioc_oid = asn1p_oid_construct(arcs,
340 sizeof(arcs)/sizeof(arcs[0]));
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800341
342 if(!mod->module_oid
343 || asn1p_oid_compare(mod->module_oid, uioc_oid))
344 imports_from = asn1f_lookup_module(arg,
345 "ASN1C-UsefulInformationObjectClasses",
346 uioc_oid);
347
348 asn1p_oid_free(uioc_oid);
Lev Walkin6b3ff542006-03-06 14:51:00 +0000349 if(imports_from) goto importing;
350 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000351 }
352
Lev Walkin6b3ff542006-03-06 14:51:00 +0000353 DEBUG("Module \"%s\" does not contain \"%s\" "
354 "mentioned at line %d: %s",
355 mod->ModuleName,
356 identifier,
357 ref->_lineno,
358 strerror(errno));
359
360 if(asn1f_check_known_external_type(identifier) == 0) {
361 errno = EEXIST; /* Exists somewhere */
362 } else {
363 errno = ESRCH;
364 }
365 return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000366}
367
368
369asn1p_expr_t *
Lev Walkina00d6b32006-03-21 03:40:38 +0000370asn1f_lookup_symbol(arg_t *arg,
371 asn1p_module_t *mod, asn1p_expr_t *rhs_pspecs, asn1p_ref_t *ref) {
372 return asn1f_lookup_symbol_impl(arg, mod, rhs_pspecs, ref, 0);
Lev Walkin41635d32006-03-18 05:06:57 +0000373}
374
375asn1p_expr_t *
Lev Walkin6fec44d2004-08-22 03:10:23 +0000376asn1f_find_terminal_type(arg_t *arg, asn1p_expr_t *expr) {
Lev Walkin33f63f82005-03-20 11:27:19 +0000377 return asn1f_find_terminal_thing(arg, expr, FTT_TYPE);
Lev Walkinf15320b2004-06-03 03:38:44 +0000378}
379
380asn1p_expr_t *
Lev Walkin6fec44d2004-08-22 03:10:23 +0000381asn1f_find_terminal_value(arg_t *arg, asn1p_expr_t *expr) {
Lev Walkin33f63f82005-03-20 11:27:19 +0000382 return asn1f_find_terminal_thing(arg, expr, FTT_VALUE);
Lev Walkinf15320b2004-06-03 03:38:44 +0000383}
384
385static asn1p_expr_t *
Lev Walkin33f63f82005-03-20 11:27:19 +0000386asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, enum ftt_what what) {
Lev Walkin039a09e2005-03-20 13:17:48 +0000387 asn1p_ref_t *ref = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000388 asn1p_expr_t *tc;
389
Lev Walkin33f63f82005-03-20 11:27:19 +0000390 switch(what) {
391 case FTT_TYPE:
392 /* Expression may be a terminal type itself */
393 if(expr->expr_type != A1TC_REFERENCE)
394 return expr;
395 ref = expr->reference;
396 break;
397 case FTT_VALUE:
Lev Walkinf15320b2004-06-03 03:38:44 +0000398 assert(expr->meta_type == AMT_VALUE);
399 assert(expr->value);
Lev Walkin6fec44d2004-08-22 03:10:23 +0000400 /* Expression may be a terminal type itself */
401 if(expr->value->type != ATV_REFERENCED)
Lev Walkinf15320b2004-06-03 03:38:44 +0000402 return expr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000403 ref = expr->value->value.reference;
Lev Walkin33f63f82005-03-20 11:27:19 +0000404 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000405 }
406
Lev Walkin03850182005-03-10 10:02:50 +0000407 DEBUG("%s(%s->%s) for line %d",
Lev Walkin33f63f82005-03-20 11:27:19 +0000408 (what == FTT_VALUE)?"VALUE":"TYPE",
Lev Walkinf15320b2004-06-03 03:38:44 +0000409 expr->Identifier, asn1f_printable_reference(ref),
410 expr->_lineno);
411
412 assert(ref);
413
414 /*
415 * Lookup inside the type itself (ENUMERATED, INTEGER, etc).
416 */
Lev Walkin33f63f82005-03-20 11:27:19 +0000417 if(what == FTT_VALUE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000418 asn1p_expr_t *val_type_tc;
Lev Walkin6fec44d2004-08-22 03:10:23 +0000419 val_type_tc = asn1f_find_terminal_type(arg, expr);
Lev Walkinf15320b2004-06-03 03:38:44 +0000420 if(val_type_tc
421 && asn1f_look_value_in_type(arg, val_type_tc, expr))
422 return NULL;
423 if(expr->value->type != ATV_REFERENCED) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000424 return expr;
425 }
426 assert(ref == expr->value->value.reference);
427 ref = expr->value->value.reference;
428 }
429
430 /*
Lev Walkind8095522005-03-18 05:20:39 +0000431 * Lookup inside the default module and its IMPORTS section.
Lev Walkinf15320b2004-06-03 03:38:44 +0000432 */
Lev Walkina00d6b32006-03-21 03:40:38 +0000433 tc = asn1f_lookup_symbol(arg, expr->module, expr->rhs_pspecs, ref);
Lev Walkinf15320b2004-06-03 03:38:44 +0000434 if(tc == NULL) {
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800435 /*
436 * Lookup inside the ref's module and its IMPORTS section.
437 */
438 tc = asn1f_lookup_symbol(arg, ref->module, expr->rhs_pspecs, ref);
439 if(tc == NULL) {
440 DEBUG("\tSymbol \"%s\" not found: %s",
441 asn1f_printable_reference(ref),
442 strerror(errno));
443 return NULL;
444 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000445 }
446
447 /*
448 * Recursive loops detection.
449 */
450 if(tc->_mark & TM_RECURSION) {
451 DEBUG("Recursion loop detected for %s at line %d",
452 asn1f_printable_reference(ref), ref->_lineno);
453 errno = EPERM;
454 return NULL;
455 }
456
Lev Walkin59b176e2005-11-26 11:25:14 +0000457 tc->_type_referenced = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000458 tc->_mark |= TM_RECURSION;
Lev Walkin6fec44d2004-08-22 03:10:23 +0000459 WITH_MODULE(tc->module,
Lev Walkin33f63f82005-03-20 11:27:19 +0000460 expr = asn1f_find_terminal_thing(arg, tc, what));
Lev Walkinf15320b2004-06-03 03:38:44 +0000461 tc->_mark &= ~TM_RECURSION;
462
463 return expr;
464}
465
466/*
467 * Make sure that the specified name is present or otherwise does
468 * not contradict with the EXPORTS clause of the specified module.
469 */
470static int
471asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name) {
472 asn1p_xports_t *exports;
473 asn1p_expr_t *item;
474
475 assert(mod);
476 assert(name);
477
478 exports = TQ_FIRST(&(mod->exports));
479 if(exports == NULL) {
480 /* No EXPORTS section or EXPORTS ALL; */
481 return 0;
482 }
483
484 TQ_FOR(item, &(exports->members), next) {
485 if(strcmp(item->Identifier, name) == 0)
486 return 0;
487 }
488
Lev Walkind8095522005-03-18 05:20:39 +0000489 /* Conditional debug */
490 if(!(arg->expr->_mark & TM_BROKEN)) {
491 arg->expr->_mark |= TM_BROKEN;
492 FATAL("EXPORTS section of module %s in %s "
493 "does not mention %s at line %d",
Lev Walkinb36317c2005-08-12 10:09:10 +0000494 mod->ModuleName, mod->source_file_name, name,
Lev Walkind8095522005-03-18 05:20:39 +0000495 arg->expr->_lineno);
496 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000497
498 errno = ESRCH;
499 return -1;
500}