894f42ae405ea7aff793f16c67ba25f1e36644db
[com/asn1c.git] / libasn1fix / asn1fix_param.c
1 #include "asn1fix_internal.h"
2
3 typedef 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         char              *resolved_name;
10 } resolver_arg_t;
11
12 static asn1p_expr_t *resolve_expr(asn1p_expr_t *, void *resolver_arg);
13 static int compare_specializations(const asn1p_expr_t *a, const asn1p_expr_t *b);
14 static asn1p_expr_t *find_target_specialization_byvalueset(resolver_arg_t *rarg, asn1p_constraint_t *ct);
15 static asn1p_expr_t *find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref);
16 static asn1p_expr_t *find_target_specialization_bystr(resolver_arg_t *rarg, char *str);
17
18 asn1p_expr_t *
19 asn1f_parameterization_fork(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *rhs_pspecs) {
20         resolver_arg_t rarg;    /* resolver argument */
21         asn1p_expr_t *exc;      /* expr clone */
22         asn1p_expr_t *rpc;      /* rhs_pspecs clone */
23         asn1p_expr_t *m;        /* expr members */
24         asn1p_expr_t *target;
25         void *p;
26         struct asn1p_pspec_s *pspec;
27         int npspecs;
28
29         assert(rhs_pspecs);
30         assert(expr->lhs_params);
31         assert(expr->parent_expr == 0);
32
33         /*
34          * Find if this exact specialization has been used already.
35          */
36         for(npspecs = 0;
37                 npspecs < expr->specializations.pspecs_count;
38                         npspecs++) {
39                 if(compare_specializations(rhs_pspecs,
40                         expr->specializations.pspec[npspecs].rhs_pspecs) == 0) {
41                         DEBUG("Reused parameterization for %s",
42                                 expr->Identifier);
43                         return expr->specializations.pspec[npspecs].my_clone;
44                 }
45         }
46
47         DEBUG("Forking parameterization at %d for %s (%d alr)",
48                 rhs_pspecs->_lineno, expr->Identifier,
49                 expr->specializations.pspecs_count);
50
51         rarg.resolver = resolve_expr;
52         rarg.arg = arg;
53         rarg.original_expr = expr;
54         rarg.lhs_params = expr->lhs_params;
55         rarg.rhs_pspecs = rhs_pspecs;
56         rarg.resolved_name = NULL;
57         exc = asn1p_expr_clone_with_resolver(expr, resolve_expr, &rarg);
58         if(!exc) return NULL;
59         if(rarg.resolved_name) {
60                 free(exc->Identifier);
61                 exc->Identifier = strdup(rarg.resolved_name);
62                 exc->_lineno = 0;
63         }
64         rpc = asn1p_expr_clone(rhs_pspecs, 0);
65         assert(rpc);
66
67         /*
68          * Create a new specialization.
69          */
70         npspecs = expr->specializations.pspecs_count;
71         p = realloc(expr->specializations.pspec,
72                         (npspecs + 1) * sizeof(expr->specializations.pspec[0]));
73         assert(p);
74         expr->specializations.pspec = p;
75         pspec = &expr->specializations.pspec[npspecs];
76         memset(pspec, 0, sizeof *pspec);
77
78         pspec->rhs_pspecs = rpc;
79         pspec->my_clone = exc;
80         exc->spec_index = npspecs;
81         exc->rhs_pspecs = asn1p_expr_clone_with_resolver(expr->rhs_pspecs ?
82                                         expr->rhs_pspecs : rhs_pspecs,
83                                         resolve_expr, &rarg);
84
85         /* Passing arguments to members and type references */
86
87         target = TQ_FIRST(&expr->members);
88         TQ_FOR(m, &exc->members, next) {
89                 m->rhs_pspecs = asn1p_expr_clone_with_resolver(target->rhs_pspecs ?
90                                                 target->rhs_pspecs : exc->rhs_pspecs,
91                                                 resolve_expr, &rarg);
92                 target = TQ_NEXT(target, next);
93         }
94
95         DEBUG("Forked new parameterization for %s", expr->Identifier);
96
97         /* Commit */
98         expr->specializations.pspecs_count = npspecs + 1;
99         return exc;
100 }
101
102 static int
103 compare_specializations(const asn1p_expr_t *a, const asn1p_expr_t *b) {
104     return asn1p_expr_compare(a, b);
105 }
106
107 static asn1p_expr_t *
108 resolve_expr(asn1p_expr_t *expr_to_resolve, void *resolver_arg) {
109         resolver_arg_t *rarg = resolver_arg;
110         arg_t *arg = rarg->arg;
111         asn1p_expr_t *expr;
112         asn1p_expr_t *nex;
113
114         DEBUG("Resolving %s (meta %d)",
115                 expr_to_resolve->Identifier, expr_to_resolve->meta_type);
116
117         if(expr_to_resolve->meta_type == AMT_TYPEREF) {
118                 expr = find_target_specialization_byref(rarg,
119                                 expr_to_resolve->reference);
120                 if(!expr) return NULL;
121         } else if(expr_to_resolve->meta_type == AMT_VALUE) {
122                 if(!expr_to_resolve->value) return NULL;
123                 expr = find_target_specialization_bystr(rarg,
124                                 expr_to_resolve->Identifier);
125                 if(!expr) return NULL;
126         } else if(expr_to_resolve->meta_type == AMT_VALUESET) {
127                 assert(expr_to_resolve->constraints);
128                 expr = find_target_specialization_byvalueset(rarg,
129                                 expr_to_resolve->constraints);
130                 if(!expr) return NULL;
131         } else {
132                 errno = ESRCH;
133                 return NULL;
134         }
135
136         DEBUG("Found target %s (%d/%x)",
137                 expr->Identifier, expr->meta_type, expr->expr_type);
138         if(expr->meta_type == AMT_TYPE
139         || expr->meta_type == AMT_VALUE
140         || expr->meta_type == AMT_TYPEREF
141         || expr->meta_type == AMT_VALUESET) {
142                 DEBUG("Target is a simple type %s",
143                         ASN_EXPR_TYPE2STR(expr->expr_type));
144                 nex = asn1p_expr_clone(expr, 0);
145                 free(nex->Identifier);
146                 nex->Identifier = expr_to_resolve->Identifier
147                         ? strdup(expr_to_resolve->Identifier) : 0;
148                 if(expr->meta_type == AMT_TYPEREF) {
149                         asn1p_ref_t *ref = expr->reference;
150                         rarg->resolved_name = ref->components[ref->comp_count - 1].name;
151                 } else if(expr->meta_type == AMT_VALUESET) {
152                         asn1p_constraint_t *ct = expr->constraints;
153                         if(ct->type == ACT_EL_TYPE) {
154                                 asn1p_ref_t *ref = ct->containedSubtype->value.v_type->reference;
155                                 rarg->resolved_name = ref->components[ref->comp_count - 1].name;
156                         }
157                 }
158                 return nex;
159         } else {
160                 FATAL("Feature not implemented for %s (%d/%x), "
161                         "please contact the asn1c author",
162                         rarg->original_expr->Identifier,
163                         expr->meta_type, expr->expr_type);
164                 errno = EPERM;
165                 return NULL;
166         }
167
168         return NULL;
169 }
170
171 static asn1p_expr_t *
172 find_target_specialization_byvalueset(resolver_arg_t *rarg, asn1p_constraint_t *ct) {
173         asn1p_ref_t *ref;
174
175         if (ct->type != ACT_EL_TYPE) return NULL;
176
177         ref = ct->containedSubtype->value.v_type->reference;
178
179         return find_target_specialization_byref(rarg, ref);
180 }
181
182 static asn1p_expr_t *
183 find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref) {
184         char *refstr;
185
186         if(!ref || ref->comp_count != 1) {
187                 errno = ESRCH;
188                 return NULL;
189         }
190
191         refstr = ref->components[0].name;       /* T */
192
193         return find_target_specialization_bystr(rarg, refstr);
194 }
195
196 static asn1p_expr_t *
197 find_target_specialization_bystr(resolver_arg_t *rarg, char *refstr) {
198         arg_t *arg = rarg->arg;
199         asn1p_expr_t *target;
200         int i;
201
202         if(!refstr) return NULL;
203
204         target = TQ_FIRST(&rarg->rhs_pspecs->members);
205         for(i = 0; i < rarg->lhs_params->params_count;
206                         i++, target = TQ_NEXT(target, next)) {
207                 struct asn1p_param_s *param = &rarg->lhs_params->params[i];
208                 if(!target) break;
209
210                 if(strcmp(param->argument, refstr))
211                         continue;
212
213                 return target;
214         }
215         if(i != rarg->lhs_params->params_count) {
216                 FATAL("Parameterization of %s failed: "
217                         "parameters number mismatch",
218                                 rarg->original_expr->Identifier);
219                 errno = EPERM;
220                 return NULL;
221         }
222
223         errno = ESRCH;
224         return NULL;
225 }