blob: fe98081a3aabc5b684108a0fa61f285ea6127909 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
2
Lev Walkina00d6b32006-03-21 03:40:38 +00003typedef struct resolver_arg {
4 asn1p_expr_t *(*resolver)(asn1p_expr_t *, void *arg);
5 arg_t *arg;
6 asn1p_expr_t *original_expr;
7 asn1p_paramlist_t *lhs_params;
8 asn1p_expr_t *rhs_pspecs;
9} resolver_arg_t;
Lev Walkind541c252004-09-05 10:36:22 +000010
Lev Walkina00d6b32006-03-21 03:40:38 +000011static asn1p_expr_t *resolve_expr(asn1p_expr_t *, void *resolver_arg);
12static int compare_specializations(arg_t *, asn1p_expr_t *a, asn1p_expr_t *b);
13static asn1p_expr_t *find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref);
14static asn1p_expr_t *find_target_specialization_bystr(resolver_arg_t *rarg, char *str);
Lev Walkinf15320b2004-06-03 03:38:44 +000015
Lev Walkina00d6b32006-03-21 03:40:38 +000016asn1p_expr_t *
17asn1f_parameterization_fork(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *rhs_pspecs) {
18 resolver_arg_t rarg; /* resolver argument */
19 asn1p_expr_t *exc; /* expr clone */
20 asn1p_expr_t *rpc; /* rhs_pspecs clone */
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +080021 asn1p_expr_t *m; /* expr members */
Lev Walkinf15320b2004-06-03 03:38:44 +000022 void *p;
Lev Walkina00d6b32006-03-21 03:40:38 +000023 struct asn1p_pspec_s *pspec;
24 int npspecs;
Lev Walkinf15320b2004-06-03 03:38:44 +000025
Lev Walkina00d6b32006-03-21 03:40:38 +000026 assert(rhs_pspecs);
27 assert(expr->lhs_params);
28 assert(expr->parent_expr == 0);
29
30 DEBUG("Forking parameterization at %d for %s (%d alr)",
31 rhs_pspecs->_lineno, expr->Identifier,
32 expr->specializations.pspecs_count);
Lev Walkinf593f102005-02-22 07:59:59 +000033
Lev Walkinf15320b2004-06-03 03:38:44 +000034 /*
Lev Walkina00d6b32006-03-21 03:40:38 +000035 * Find if this exact specialization has been used already.
Lev Walkinf15320b2004-06-03 03:38:44 +000036 */
Lev Walkina00d6b32006-03-21 03:40:38 +000037 for(npspecs = 0;
38 npspecs < expr->specializations.pspecs_count;
39 npspecs++) {
40 if(compare_specializations(arg, rhs_pspecs,
41 expr->specializations.pspec[npspecs].rhs_pspecs) == 0) {
42 DEBUG("Reused parameterization for %s",
43 expr->Identifier);
44 return expr->specializations.pspec[npspecs].my_clone;
Lev Walkind5947712005-11-05 12:28:14 +000045 }
Lev Walkinf15320b2004-06-03 03:38:44 +000046 }
Lev Walkinf15320b2004-06-03 03:38:44 +000047
Lev Walkina00d6b32006-03-21 03:40:38 +000048 rarg.resolver = resolve_expr;
49 rarg.arg = arg;
50 rarg.original_expr = expr;
51 rarg.lhs_params = expr->lhs_params;
52 rarg.rhs_pspecs = rhs_pspecs;
53 exc = asn1p_expr_clone_with_resolver(expr, resolve_expr, &rarg);
Lev Walkinc5a5d222007-06-23 17:35:56 +000054 if(!exc) return NULL;
Lev Walkina00d6b32006-03-21 03:40:38 +000055 rpc = asn1p_expr_clone(rhs_pspecs, 0);
Lev Walkinc5a5d222007-06-23 17:35:56 +000056 assert(rpc);
Lev Walkina00d6b32006-03-21 03:40:38 +000057
58 /*
59 * Create a new specialization.
60 */
61 npspecs = expr->specializations.pspecs_count;
62 p = realloc(expr->specializations.pspec,
63 (npspecs + 1) * sizeof(expr->specializations.pspec[0]));
64 assert(p);
65 expr->specializations.pspec = p;
66 pspec = &expr->specializations.pspec[npspecs];
67 memset(pspec, 0, sizeof *pspec);
68
69 pspec->rhs_pspecs = rpc;
70 pspec->my_clone = exc;
71 exc->spec_index = npspecs;
72
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +080073 /* Passing arguments to members and type references */
74 exc->rhs_pspecs = expr->rhs_pspecs ? expr->rhs_pspecs : rhs_pspecs;
75 if(exc->rhs_pspecs)
76 exc->rhs_pspecs->ref_cnt++;
77
78 TQ_FOR(m, &exc->members, next) {
79 m->rhs_pspecs = exc->rhs_pspecs;
80 if (exc->rhs_pspecs)
81 exc->rhs_pspecs->ref_cnt++;
82 }
83
Lev Walkina00d6b32006-03-21 03:40:38 +000084 DEBUG("Forked new parameterization for %s", expr->Identifier);
Lev Walkinf15320b2004-06-03 03:38:44 +000085
Lev Walkina00d6b32006-03-21 03:40:38 +000086 /* Commit */
87 expr->specializations.pspecs_count = npspecs + 1;
88 return exc;
Lev Walkinf15320b2004-06-03 03:38:44 +000089}
90
91static int
Lev Walkina00d6b32006-03-21 03:40:38 +000092compare_specializations(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
93 asn1p_expr_t *ac = TQ_FIRST(&a->members);
94 asn1p_expr_t *bc = TQ_FIRST(&b->members);
Lev Walkinf15320b2004-06-03 03:38:44 +000095
Lev Walkina00d6b32006-03-21 03:40:38 +000096 for(;ac && bc; ac = TQ_NEXT(ac, next), bc = TQ_NEXT(bc, next)) {
97 retry:
98 if(ac == bc) continue;
99 if(ac->meta_type != bc->meta_type) break;
100 if(ac->expr_type != bc->expr_type) break;
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800101 /* Maybe different object sets */
102 if(ac->constraints && bc->constraints
103 && ac->constraints->containedSubtype
104 && bc->constraints->containedSubtype
105 && ac->constraints->containedSubtype->type == ATV_REFERENCED
106 && bc->constraints->containedSubtype->type == ATV_REFERENCED
107 && strcmp(ac->constraints->containedSubtype->value.reference->components[0].name,
108 bc->constraints->containedSubtype->value.reference->components[0].name))
109 break;
Lev Walkina00d6b32006-03-21 03:40:38 +0000110 if(!ac->reference && !bc->reference)
111 continue;
Lev Walkind541c252004-09-05 10:36:22 +0000112
Lev Walkina00d6b32006-03-21 03:40:38 +0000113 if(ac->reference) {
114 ac = asn1f_lookup_symbol(arg,
115 ac->module, ac->rhs_pspecs, ac->reference);
116 if(!ac) break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000117 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000118 if(bc->reference) {
119 bc = asn1f_lookup_symbol(arg,
120 bc->module, bc->rhs_pspecs, bc->reference);
121 if(!bc) break;
122 }
123 goto retry;
Lev Walkinf15320b2004-06-03 03:38:44 +0000124 }
125
Lev Walkina00d6b32006-03-21 03:40:38 +0000126 if(ac || bc)
127 /* Specializations do not match: different size option sets */
128 return -1;
129
Lev Walkinf15320b2004-06-03 03:38:44 +0000130 return 0;
131}
132
133static asn1p_expr_t *
Lev Walkina00d6b32006-03-21 03:40:38 +0000134resolve_expr(asn1p_expr_t *expr_to_resolve, void *resolver_arg) {
135 resolver_arg_t *rarg = resolver_arg;
136 arg_t *arg = rarg->arg;
137 asn1p_expr_t *expr;
138 asn1p_expr_t *nex;
Lev Walkinf15320b2004-06-03 03:38:44 +0000139
Lev Walkina00d6b32006-03-21 03:40:38 +0000140 DEBUG("Resolving %s (meta %d)",
141 expr_to_resolve->Identifier, expr_to_resolve->meta_type);
142
143 if(expr_to_resolve->meta_type == AMT_TYPEREF) {
144 expr = find_target_specialization_byref(rarg,
145 expr_to_resolve->reference);
146 if(!expr) return NULL;
147 } else if(expr_to_resolve->meta_type == AMT_VALUE) {
148 assert(expr_to_resolve->value);
149 expr = find_target_specialization_bystr(rarg,
150 expr_to_resolve->Identifier);
151 if(!expr) return NULL;
152 } else {
153 errno = ESRCH;
Lev Walkinf15320b2004-06-03 03:38:44 +0000154 return NULL;
Lev Walkina00d6b32006-03-21 03:40:38 +0000155 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000156
Lev Walkin5045dfa2006-03-21 09:41:28 +0000157 DEBUG("Found target %s (%d/%x)",
158 expr->Identifier, expr->meta_type, expr->expr_type);
Lev Walkina00d6b32006-03-21 03:40:38 +0000159 if(expr->meta_type == AMT_TYPE
Lev Walkin5045dfa2006-03-21 09:41:28 +0000160 || expr->meta_type == AMT_VALUE
Lev Walkinc5a5d222007-06-23 17:35:56 +0000161 || expr->meta_type == AMT_TYPEREF
Lev Walkin5045dfa2006-03-21 09:41:28 +0000162 || expr->meta_type == AMT_VALUESET) {
Lev Walkina00d6b32006-03-21 03:40:38 +0000163 DEBUG("Target is a simple type %s",
164 ASN_EXPR_TYPE2STR(expr->expr_type));
165 nex = asn1p_expr_clone(expr, 0);
166 free(nex->Identifier);
167 nex->Identifier = expr_to_resolve->Identifier
168 ? strdup(expr_to_resolve->Identifier) : 0;
169 return nex;
170 } else {
Lev Walkin5045dfa2006-03-21 09:41:28 +0000171 FATAL("Feature not implemented for %s (%d/%x), "
172 "please contact the asn1c author",
173 rarg->original_expr->Identifier,
174 expr->meta_type, expr->expr_type);
Lev Walkina00d6b32006-03-21 03:40:38 +0000175 errno = EPERM;
176 return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000177 }
178
179 return NULL;
180}
Lev Walkind541c252004-09-05 10:36:22 +0000181
Lev Walkina00d6b32006-03-21 03:40:38 +0000182static asn1p_expr_t *
183find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref) {
184 char *refstr;
Lev Walkind541c252004-09-05 10:36:22 +0000185
Lev Walkina00d6b32006-03-21 03:40:38 +0000186 if(!ref || ref->comp_count != 1) {
187 errno = ESRCH;
188 return NULL;
Lev Walkind541c252004-09-05 10:36:22 +0000189 }
190
Lev Walkina00d6b32006-03-21 03:40:38 +0000191 refstr = ref->components[0].name; /* T */
192
193 return find_target_specialization_bystr(rarg, refstr);
Lev Walkind541c252004-09-05 10:36:22 +0000194}
195
Lev Walkina00d6b32006-03-21 03:40:38 +0000196static asn1p_expr_t *
197find_target_specialization_bystr(resolver_arg_t *rarg, char *refstr) {
198 arg_t *arg = rarg->arg;
199 asn1p_expr_t *target;
200 int i;
Lev Walkind541c252004-09-05 10:36:22 +0000201
Lev Walkina00d6b32006-03-21 03:40:38 +0000202 target = TQ_FIRST(&rarg->rhs_pspecs->members);
203 for(i = 0; i < rarg->lhs_params->params_count;
204 i++, target = TQ_NEXT(target, next)) {
205 struct asn1p_param_s *param = &rarg->lhs_params->params[i];
206 if(!target) break;
Lev Walkind541c252004-09-05 10:36:22 +0000207
Lev Walkina00d6b32006-03-21 03:40:38 +0000208 if(strcmp(param->argument, refstr))
209 continue;
Lev Walkind541c252004-09-05 10:36:22 +0000210
Lev Walkina00d6b32006-03-21 03:40:38 +0000211 return target;
212 }
213 if(i != rarg->lhs_params->params_count) {
214 FATAL("Parameterization of %s failed: "
215 "parameters number mismatch",
216 rarg->original_expr->Identifier);
217 errno = EPERM;
218 return NULL;
Lev Walkind541c252004-09-05 10:36:22 +0000219 }
220
Lev Walkina00d6b32006-03-21 03:40:38 +0000221 errno = ESRCH;
222 return NULL;
Lev Walkind541c252004-09-05 10:36:22 +0000223}