#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; }