diff options
Diffstat (limited to 'libasn1fix/asn1fix_param.c')
-rw-r--r-- | libasn1fix/asn1fix_param.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/libasn1fix/asn1fix_param.c b/libasn1fix/asn1fix_param.c new file mode 100644 index 00000000..0c838cc5 --- /dev/null +++ b/libasn1fix/asn1fix_param.c @@ -0,0 +1,165 @@ +#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 asn1p_expr_t *_referenced_argument(asn1p_ref_t *ref, 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\" { %s }) for line %d", + __func__, 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->reference, 0); + 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; \ + tmp = *(to); \ + *(to) = *(from); \ + *(from) = tmp; \ + (to)->next = tmp.next; \ + memset(&((from)->next), 0, \ + sizeof((from)->next)); \ + asn1p_expr_free(from); \ + } 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; + + /* + * 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. + */ + + nex = asn1p_expr_clone(ptype); + if(nex == NULL) return -1; + + /* + * Cleanup the new expression so there is no ptype-related + * stuff hanging around. + */ + 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; + + ra = _referenced_argument(child->reference, ptype, actargs); + if(ra == NULL) continue; + + 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); + 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; +} + +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; +} |