asn1c/libasn1fix/asn1fix_param.c

307 lines
7.9 KiB
C

#include "asn1fix_internal.h"
static int asn1f_parametrize(arg_t *arg, asn1p_expr_t *ex, asn1p_expr_t *ptype);
static int asn1f_param_process_recursive(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
static int asn1f_param_process_constraints(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
static asn1p_expr_t *_referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
static int _process_constraints(arg_t *arg, asn1p_constraint_t *ct, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
int
asn1f_fix_parametrized_assignment(arg_t *arg) {
asn1p_expr_t *expr = arg->expr;
asn1p_expr_t *ptype;
assert(expr->expr_type == A1TC_PARAMETRIZED);
assert(expr->reference);
DEBUG("(\"%s\" ::= \"%s\" { %s }) for line %d",
expr->Identifier,
asn1f_printable_reference(expr->reference),
asn1f_printable_value(expr->value),
expr->_lineno);
/*
* Find the corresponding parametrized type definition.
*/
DEBUG("Looking for parametrized type definition \"%s\"",
asn1f_printable_reference(expr->reference));
ptype = asn1f_lookup_symbol(arg, expr->module, expr->reference);
if(ptype == NULL) {
DEBUG("%s: missing parametrized type declaration",
asn1f_printable_reference(expr->reference));
return -1;
}
/*
* Check that the number of arguments which are expected by
* the parametrized type declaration is consistent with the
* number of arguments supplied by the parametrized assignment.
*/
if(asn1f_count_children(expr) != ptype->params->params_count) {
FATAL("Number of actual arguments %d in %s at line %d "
"is not equal to number of expected arguments "
"%d in %s at line %d",
asn1f_count_children(expr),
asn1f_printable_reference(expr->reference),
expr->_lineno,
ptype->params->params_count,
ptype->Identifier,
ptype->_lineno
);
return -1;
}
/*
* Perform an expansion of a parametrized assignment.
*/
return asn1f_parametrize(arg, expr, ptype);
}
#define SUBSTITUTE(to, from) do { \
asn1p_expr_t tmp, *__v; \
if((to)->tag.tag_class \
&& (from)->tag.tag_class) { \
FATAL("Layered tagging in parametrization " \
"is not yet supported, " \
"contact asn1c author for assistance " \
"with line %d", (to)->_lineno); \
return -1; \
} \
/* This code shall not be invoked too early */ \
assert((to)->combined_constraints == NULL); \
assert((from)->combined_constraints == NULL); \
/* Copy stuff, and merge some parameters */ \
tmp = *(to); \
*(to) = *(from); \
TQ_MOVE(&(to)->members, &(from)->members); \
*(from) = tmp; \
(to)->next = tmp.next; \
(to)->parent_expr = tmp.parent_expr; \
assert((to)->marker.flags == EM_NOMARK); \
(to)->marker = tmp.marker; \
if(tmp.tag.tag_class) \
(to)->tag = tmp.tag; \
if(tmp.constraints) { \
if((to)->constraints) { \
asn1p_constraint_t *ct; \
ct = asn1p_constraint_new( \
(to)->constraints->_lineno); \
ct->type = ACT_CA_SET; \
asn1p_constraint_insert(ct, \
(to)->constraints); \
asn1p_constraint_insert(ct, \
tmp.constraints); \
(to)->constraints = ct; \
} else { \
(to)->constraints = tmp.constraints; \
} \
} \
(from)->constraints = 0; \
(from)->marker.default_value = 0; \
memset(&((from)->next), 0, sizeof((from)->next)); \
memset(&((from)->members), 0, sizeof((from)->members)); \
asn1p_expr_free(from); \
TQ_FOR(__v, &((to)->members), next) { \
assert(__v->parent_expr == (from)); \
__v->parent_expr = (to); \
} \
} while(0)
static int
asn1f_parametrize(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype) {
asn1p_expr_t *nex;
void *p;
int ret;
DEBUG("asn1f_parametrize(%s <= %s)",
expr->Identifier, ptype->Identifier);
/*
* The algorithm goes like that:
* 1. Replace the expression's type with parametrized type.
* 2. For every child in the parametrized type, import it
* as a child of the expression, replacing all occurences of
* symbols which are defined as parametrized type arguments
* with the actual values.
* 3. Don't forget to parametrize the subtype constraints.
*/
nex = asn1p_expr_clone(ptype, 0);
if(nex == NULL) return -1;
/*
* Cleanup the new expression so there is no ptype-related
* stuff hanging around.
*/
if(expr->Identifier) {
p = strdup(expr->Identifier);
if(p) {
free(nex->Identifier);
nex->Identifier = p;
} else {
asn1p_expr_free(nex);
return -1;
}
}
asn1p_paramlist_free(nex->params);
nex->params = NULL;
nex->meta_type = expr->meta_type;
ret = asn1f_param_process_recursive(arg, nex, ptype, expr);
if(ret != 0) {
asn1p_expr_free(nex);
return ret;
}
SUBSTITUTE(expr, nex);
return ret;
}
static int
asn1f_param_process_recursive(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
asn1p_expr_t *child;
TQ_FOR(child, &(expr->members), next) {
asn1p_expr_t *ra;
asn1p_expr_t *ne; /* new expression (clone) */
if(asn1f_param_process_constraints(arg, child, ptype, actargs))
return -1;
ra = _referenced_argument(child->reference, ptype, actargs);
if(ra) {
DEBUG("Substituting parameter for %s %s at line %d",
child->Identifier,
asn1f_printable_reference(child->reference),
child->_lineno
);
assert(child->meta_type == AMT_TYPEREF);
assert(child->expr_type == A1TC_REFERENCE);
ne = asn1p_expr_clone(ra, 0);
if(ne == NULL) return -1;
assert(ne->Identifier == 0);
ne->Identifier = strdup(child->Identifier);
if(ne->Identifier == 0) {
asn1p_expr_free(ne);
return -1;
}
SUBSTITUTE(child, ne);
}
}
return 0;
}
/*
* Check that the given ref looks like an argument of a parametrized type.
*/
static asn1p_expr_t *
_referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
asn1p_expr_t *aa;
int i;
if(ref == NULL || ref->comp_count != 1)
return NULL;
aa = TQ_FIRST(&(actargs->members));
for(i = 0; i < ptype->params->params_count;
i++, aa = TQ_NEXT(aa, next)) {
if(strcmp(ref->components[0].name,
ptype->params->params[i].argument) == 0)
return aa;
}
return NULL;
}
/*
* Search for parameters inside constraints.
*/
static int
asn1f_param_process_constraints(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
asn1p_constraint_t *cts;
int ret;
if(!expr->constraints) return 0;
cts = asn1p_constraint_clone(expr->constraints);
assert(cts);
ret = _process_constraints(arg, cts, ptype, actargs);
if(ret == 1) {
asn1p_constraint_free(expr->constraints);
expr->constraints = cts;
ret = 0;
} else {
asn1p_constraint_free(cts);
}
return ret;
}
static int
_process_constraints(arg_t *arg, asn1p_constraint_t *ct, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
asn1p_value_t *values[3];
int rvalue = 0;
size_t i;
values[0] = ct->value;
values[1] = ct->range_start;
values[2] = ct->range_stop;
for(i = 0; i < sizeof(values)/sizeof(values[0]); i++) {
asn1p_value_t *v = values[i];
asn1p_expr_t *ra;
asn1p_ref_t *ref;
char *str;
if(!v || v->type != ATV_REFERENCED) continue;
ref = v->value.reference;
ra = _referenced_argument(ref, ptype, actargs);
if(!ra) continue;
DEBUG("_process_constraints(%s), ra=%s",
asn1f_printable_reference(ref), ra->Identifier);
if(ra->expr_type == A1TC_PARAMETRIZED) {
DEBUG("Double %s", "parametrization");
}
assert(ra->Identifier);
str = strdup(ra->Identifier);
if(!str) return -1;
assert(ref->comp_count == 1);
ref = asn1p_ref_new(ref->_lineno);
if(!ref) { free(str); return -1; }
if(asn1p_ref_add_component(ref, str, 0)) {
free(str);
return -1;
}
asn1p_ref_free(v->value.reference);
v->value.reference = ref;
rvalue = 1;
}
/* Process the rest of constraints recursively */
for(i = 0; i < ct->el_count; i++) {
int ret = _process_constraints(arg, ct->elements[i],
ptype, actargs);
if(ret == -1)
rvalue = -1;
else if(ret == 1 && rvalue != -1)
rvalue = 1;
}
return rvalue;
}