#include "asn1fix_internal.h" typedef struct resolver_arg { asn1p_expr_t *(*resolver)(asn1p_expr_t *, void *arg); arg_t *arg; asn1p_expr_t *original_expr; asn1p_paramlist_t *lhs_params; asn1p_expr_t *rhs_pspecs; } resolver_arg_t; static asn1p_expr_t *resolve_expr(asn1p_expr_t *, void *resolver_arg); static int compare_specializations(arg_t *, asn1p_expr_t *a, asn1p_expr_t *b); static asn1p_expr_t *find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref); static asn1p_expr_t *find_target_specialization_bystr(resolver_arg_t *rarg, char *str); asn1p_expr_t * asn1f_parameterization_fork(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *rhs_pspecs) { resolver_arg_t rarg; /* resolver argument */ asn1p_expr_t *exc; /* expr clone */ asn1p_expr_t *rpc; /* rhs_pspecs clone */ void *p; struct asn1p_pspec_s *pspec; int npspecs; assert(rhs_pspecs); assert(expr->lhs_params); assert(expr->parent_expr == 0); DEBUG("Forking parameterization at %d for %s (%d alr)", rhs_pspecs->_lineno, expr->Identifier, expr->specializations.pspecs_count); /* * Find if this exact specialization has been used already. */ for(npspecs = 0; npspecs < expr->specializations.pspecs_count; npspecs++) { if(compare_specializations(arg, rhs_pspecs, expr->specializations.pspec[npspecs].rhs_pspecs) == 0) { DEBUG("Reused parameterization for %s", expr->Identifier); return expr->specializations.pspec[npspecs].my_clone; } } rarg.resolver = resolve_expr; rarg.arg = arg; rarg.original_expr = expr; rarg.lhs_params = expr->lhs_params; rarg.rhs_pspecs = rhs_pspecs; exc = asn1p_expr_clone_with_resolver(expr, resolve_expr, &rarg); if(!exc) return NULL; rpc = asn1p_expr_clone(rhs_pspecs, 0); assert(rpc); /* * Create a new specialization. */ npspecs = expr->specializations.pspecs_count; p = realloc(expr->specializations.pspec, (npspecs + 1) * sizeof(expr->specializations.pspec[0])); assert(p); expr->specializations.pspec = p; pspec = &expr->specializations.pspec[npspecs]; memset(pspec, 0, sizeof *pspec); pspec->rhs_pspecs = rpc; pspec->my_clone = exc; exc->spec_index = npspecs; DEBUG("Forked new parameterization for %s", expr->Identifier); /* Commit */ expr->specializations.pspecs_count = npspecs + 1; return exc; } static int compare_specializations(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) { asn1p_expr_t *ac = TQ_FIRST(&a->members); asn1p_expr_t *bc = TQ_FIRST(&b->members); for(;ac && bc; ac = TQ_NEXT(ac, next), bc = TQ_NEXT(bc, next)) { retry: if(ac == bc) continue; if(ac->meta_type != bc->meta_type) break; if(ac->expr_type != bc->expr_type) break; if(!ac->reference && !bc->reference) continue; if(ac->reference) { ac = asn1f_lookup_symbol(arg, ac->module, ac->rhs_pspecs, ac->reference); if(!ac) break; } if(bc->reference) { bc = asn1f_lookup_symbol(arg, bc->module, bc->rhs_pspecs, bc->reference); if(!bc) break; } goto retry; } if(ac || bc) /* Specializations do not match: different size option sets */ return -1; return 0; } static asn1p_expr_t * resolve_expr(asn1p_expr_t *expr_to_resolve, void *resolver_arg) { resolver_arg_t *rarg = resolver_arg; arg_t *arg = rarg->arg; asn1p_expr_t *expr; asn1p_expr_t *nex; DEBUG("Resolving %s (meta %d)", expr_to_resolve->Identifier, expr_to_resolve->meta_type); if(expr_to_resolve->meta_type == AMT_TYPEREF) { expr = find_target_specialization_byref(rarg, expr_to_resolve->reference); if(!expr) return NULL; } else if(expr_to_resolve->meta_type == AMT_VALUE) { assert(expr_to_resolve->value); expr = find_target_specialization_bystr(rarg, expr_to_resolve->Identifier); if(!expr) return NULL; } else { errno = ESRCH; return NULL; } DEBUG("Found target %s (%d/%x)", expr->Identifier, expr->meta_type, expr->expr_type); if(expr->meta_type == AMT_TYPE || expr->meta_type == AMT_VALUE || expr->meta_type == AMT_TYPEREF || expr->meta_type == AMT_VALUESET) { DEBUG("Target is a simple type %s", ASN_EXPR_TYPE2STR(expr->expr_type)); nex = asn1p_expr_clone(expr, 0); free(nex->Identifier); nex->Identifier = expr_to_resolve->Identifier ? strdup(expr_to_resolve->Identifier) : 0; return nex; } else { FATAL("Feature not implemented for %s (%d/%x), " "please contact the asn1c author", rarg->original_expr->Identifier, expr->meta_type, expr->expr_type); errno = EPERM; return NULL; } return NULL; } static asn1p_expr_t * find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref) { char *refstr; if(!ref || ref->comp_count != 1) { errno = ESRCH; return NULL; } refstr = ref->components[0].name; /* T */ return find_target_specialization_bystr(rarg, refstr); } static asn1p_expr_t * find_target_specialization_bystr(resolver_arg_t *rarg, char *refstr) { arg_t *arg = rarg->arg; asn1p_expr_t *target; int i; target = TQ_FIRST(&rarg->rhs_pspecs->members); for(i = 0; i < rarg->lhs_params->params_count; i++, target = TQ_NEXT(target, next)) { struct asn1p_param_s *param = &rarg->lhs_params->params[i]; if(!target) break; if(strcmp(param->argument, refstr)) continue; return target; } if(i != rarg->lhs_params->params_count) { FATAL("Parameterization of %s failed: " "parameters number mismatch", rarg->original_expr->Identifier); errno = EPERM; return NULL; } errno = ESRCH; return NULL; }