blob: 6b3a62940d985b1ee11fa6bd6eaaa2ddd8386070 [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 */
Lev Walkinf15320b2004-06-03 03:38:44 +000021 void *p;
Lev Walkina00d6b32006-03-21 03:40:38 +000022 struct asn1p_pspec_s *pspec;
23 int npspecs;
Lev Walkinf15320b2004-06-03 03:38:44 +000024
Lev Walkina00d6b32006-03-21 03:40:38 +000025 assert(rhs_pspecs);
26 assert(expr->lhs_params);
27 assert(expr->parent_expr == 0);
28
29 DEBUG("Forking parameterization at %d for %s (%d alr)",
30 rhs_pspecs->_lineno, expr->Identifier,
31 expr->specializations.pspecs_count);
Lev Walkinf593f102005-02-22 07:59:59 +000032
Lev Walkinf15320b2004-06-03 03:38:44 +000033 /*
Lev Walkina00d6b32006-03-21 03:40:38 +000034 * Find if this exact specialization has been used already.
Lev Walkinf15320b2004-06-03 03:38:44 +000035 */
Lev Walkina00d6b32006-03-21 03:40:38 +000036 for(npspecs = 0;
37 npspecs < expr->specializations.pspecs_count;
38 npspecs++) {
39 if(compare_specializations(arg, 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;
Lev Walkind5947712005-11-05 12:28:14 +000044 }
Lev Walkinf15320b2004-06-03 03:38:44 +000045 }
Lev Walkinf15320b2004-06-03 03:38:44 +000046
Lev Walkina00d6b32006-03-21 03:40:38 +000047 rarg.resolver = resolve_expr;
48 rarg.arg = arg;
49 rarg.original_expr = expr;
50 rarg.lhs_params = expr->lhs_params;
51 rarg.rhs_pspecs = rhs_pspecs;
52 exc = asn1p_expr_clone_with_resolver(expr, resolve_expr, &rarg);
53 rpc = asn1p_expr_clone(rhs_pspecs, 0);
54 assert(exc && rpc);
55
56 /*
57 * Create a new specialization.
58 */
59 npspecs = expr->specializations.pspecs_count;
60 p = realloc(expr->specializations.pspec,
61 (npspecs + 1) * sizeof(expr->specializations.pspec[0]));
62 assert(p);
63 expr->specializations.pspec = p;
64 pspec = &expr->specializations.pspec[npspecs];
65 memset(pspec, 0, sizeof *pspec);
66
67 pspec->rhs_pspecs = rpc;
68 pspec->my_clone = exc;
69 exc->spec_index = npspecs;
70
Lev Walkina00d6b32006-03-21 03:40:38 +000071 DEBUG("Forked new parameterization for %s", expr->Identifier);
Lev Walkinf15320b2004-06-03 03:38:44 +000072
Lev Walkina00d6b32006-03-21 03:40:38 +000073 /* Commit */
74 expr->specializations.pspecs_count = npspecs + 1;
75 return exc;
Lev Walkinf15320b2004-06-03 03:38:44 +000076}
77
78static int
Lev Walkina00d6b32006-03-21 03:40:38 +000079compare_specializations(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
80 asn1p_expr_t *ac = TQ_FIRST(&a->members);
81 asn1p_expr_t *bc = TQ_FIRST(&b->members);
Lev Walkinf15320b2004-06-03 03:38:44 +000082
Lev Walkina00d6b32006-03-21 03:40:38 +000083 for(;ac && bc; ac = TQ_NEXT(ac, next), bc = TQ_NEXT(bc, next)) {
84 retry:
85 if(ac == bc) continue;
86 if(ac->meta_type != bc->meta_type) break;
87 if(ac->expr_type != bc->expr_type) break;
Lev Walkinf593f102005-02-22 07:59:59 +000088
Lev Walkina00d6b32006-03-21 03:40:38 +000089 if(!ac->reference && !bc->reference)
90 continue;
Lev Walkind541c252004-09-05 10:36:22 +000091
Lev Walkina00d6b32006-03-21 03:40:38 +000092 if(ac->reference) {
93 ac = asn1f_lookup_symbol(arg,
94 ac->module, ac->rhs_pspecs, ac->reference);
95 if(!ac) break;
Lev Walkinf15320b2004-06-03 03:38:44 +000096 }
Lev Walkina00d6b32006-03-21 03:40:38 +000097 if(bc->reference) {
98 bc = asn1f_lookup_symbol(arg,
99 bc->module, bc->rhs_pspecs, bc->reference);
100 if(!bc) break;
101 }
102 goto retry;
Lev Walkinf15320b2004-06-03 03:38:44 +0000103 }
104
Lev Walkina00d6b32006-03-21 03:40:38 +0000105 if(ac || bc)
106 /* Specializations do not match: different size option sets */
107 return -1;
108
Lev Walkinf15320b2004-06-03 03:38:44 +0000109 return 0;
110}
111
112static asn1p_expr_t *
Lev Walkina00d6b32006-03-21 03:40:38 +0000113resolve_expr(asn1p_expr_t *expr_to_resolve, void *resolver_arg) {
114 resolver_arg_t *rarg = resolver_arg;
115 arg_t *arg = rarg->arg;
116 asn1p_expr_t *expr;
117 asn1p_expr_t *nex;
Lev Walkinf15320b2004-06-03 03:38:44 +0000118
Lev Walkina00d6b32006-03-21 03:40:38 +0000119 DEBUG("Resolving %s (meta %d)",
120 expr_to_resolve->Identifier, expr_to_resolve->meta_type);
121
122 if(expr_to_resolve->meta_type == AMT_TYPEREF) {
123 expr = find_target_specialization_byref(rarg,
124 expr_to_resolve->reference);
125 if(!expr) return NULL;
126 } else if(expr_to_resolve->meta_type == AMT_VALUE) {
127 assert(expr_to_resolve->value);
128 expr = find_target_specialization_bystr(rarg,
129 expr_to_resolve->Identifier);
130 if(!expr) return NULL;
131 } else {
132 errno = ESRCH;
Lev Walkinf15320b2004-06-03 03:38:44 +0000133 return NULL;
Lev Walkina00d6b32006-03-21 03:40:38 +0000134 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000135
Lev Walkin5045dfa2006-03-21 09:41:28 +0000136 DEBUG("Found target %s (%d/%x)",
137 expr->Identifier, expr->meta_type, expr->expr_type);
Lev Walkina00d6b32006-03-21 03:40:38 +0000138 if(expr->meta_type == AMT_TYPE
Lev Walkin5045dfa2006-03-21 09:41:28 +0000139 || expr->meta_type == AMT_VALUE
140 || expr->meta_type == AMT_VALUESET) {
Lev Walkina00d6b32006-03-21 03:40:38 +0000141 DEBUG("Target is a simple type %s",
142 ASN_EXPR_TYPE2STR(expr->expr_type));
143 nex = asn1p_expr_clone(expr, 0);
144 free(nex->Identifier);
145 nex->Identifier = expr_to_resolve->Identifier
146 ? strdup(expr_to_resolve->Identifier) : 0;
147 return nex;
148 } else {
Lev Walkin5045dfa2006-03-21 09:41:28 +0000149 FATAL("Feature not implemented for %s (%d/%x), "
150 "please contact the asn1c author",
151 rarg->original_expr->Identifier,
152 expr->meta_type, expr->expr_type);
Lev Walkina00d6b32006-03-21 03:40:38 +0000153 errno = EPERM;
154 return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000155 }
156
157 return NULL;
158}
Lev Walkind541c252004-09-05 10:36:22 +0000159
Lev Walkina00d6b32006-03-21 03:40:38 +0000160static asn1p_expr_t *
161find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref) {
162 char *refstr;
Lev Walkind541c252004-09-05 10:36:22 +0000163
Lev Walkina00d6b32006-03-21 03:40:38 +0000164 if(!ref || ref->comp_count != 1) {
165 errno = ESRCH;
166 return NULL;
Lev Walkind541c252004-09-05 10:36:22 +0000167 }
168
Lev Walkina00d6b32006-03-21 03:40:38 +0000169 refstr = ref->components[0].name; /* T */
170
171 return find_target_specialization_bystr(rarg, refstr);
Lev Walkind541c252004-09-05 10:36:22 +0000172}
173
Lev Walkina00d6b32006-03-21 03:40:38 +0000174static asn1p_expr_t *
175find_target_specialization_bystr(resolver_arg_t *rarg, char *refstr) {
176 arg_t *arg = rarg->arg;
177 asn1p_expr_t *target;
178 int i;
Lev Walkind541c252004-09-05 10:36:22 +0000179
Lev Walkina00d6b32006-03-21 03:40:38 +0000180 target = TQ_FIRST(&rarg->rhs_pspecs->members);
181 for(i = 0; i < rarg->lhs_params->params_count;
182 i++, target = TQ_NEXT(target, next)) {
183 struct asn1p_param_s *param = &rarg->lhs_params->params[i];
184 if(!target) break;
Lev Walkind541c252004-09-05 10:36:22 +0000185
Lev Walkina00d6b32006-03-21 03:40:38 +0000186 if(strcmp(param->argument, refstr))
187 continue;
Lev Walkind541c252004-09-05 10:36:22 +0000188
Lev Walkina00d6b32006-03-21 03:40:38 +0000189 return target;
190 }
191 if(i != rarg->lhs_params->params_count) {
192 FATAL("Parameterization of %s failed: "
193 "parameters number mismatch",
194 rarg->original_expr->Identifier);
195 errno = EPERM;
196 return NULL;
Lev Walkind541c252004-09-05 10:36:22 +0000197 }
198
Lev Walkina00d6b32006-03-21 03:40:38 +0000199 errno = ESRCH;
200 return NULL;
Lev Walkind541c252004-09-05 10:36:22 +0000201}