static FnCallResult CallFunction(EvalContext *ctx, const Policy *policy, const FnCall *fp, const Rlist *expargs) { const Rlist *rp = fp->args; const FnCallType *fncall_type = FnCallTypeGet(fp->name); int argnum = 0; for (argnum = 0; rp != NULL && fncall_type->args[argnum].pattern != NULL; argnum++) { if (rp->val.type != RVAL_TYPE_FNCALL) { /* Nested functions will not match to lval so don't bother checking */ SyntaxTypeMatch err = CheckConstraintTypeMatch(fp->name, rp->val, fncall_type->args[argnum].dtype, fncall_type->args[argnum].pattern, 1); if (err != SYNTAX_TYPE_MATCH_OK && err != SYNTAX_TYPE_MATCH_ERROR_UNEXPANDED) { FatalError(ctx, "In function '%s', error in variable '%s', '%s'", fp->name, (const char *)rp->val.item, SyntaxTypeMatchToString(err)); } } rp = rp->next; } if (argnum != RlistLen(expargs) && !(fncall_type->options & FNCALL_OPTION_VARARG)) { char *args_str = RlistToString(expargs); Log(LOG_LEVEL_ERR, "Argument template mismatch handling function %s(%s)", fp->name, args_str); free(args_str); rp = expargs; for (int i = 0; i < argnum; i++) { if (rp != NULL) { char *rval_str = RvalToString(rp->val); Log(LOG_LEVEL_ERR, " arg[%d] range %s\t %s ", i, fncall_type->args[i].pattern, rval_str); free(rval_str); } else { Log(LOG_LEVEL_ERR, " arg[%d] range %s\t ? ", i, fncall_type->args[i].pattern); } } FatalError(ctx, "Bad arguments"); } return (*fncall_type->impl) (ctx, policy, fp, expargs); }
/** * @brief Flattens an Rlist by expanding naked scalar list-variable * members. Flattening is only one-level deep. */ void RlistFlatten(EvalContext *ctx, Rlist **list) { Rlist *next; for (Rlist *rp = *list; rp != NULL; rp = next) { next = rp->next; if (rp->val.type == RVAL_TYPE_SCALAR && IsNakedVar(RlistScalarValue(rp), '@')) { char naked[CF_MAXVARSIZE]; GetNaked(naked, RlistScalarValue(rp)); /* Make sure there are no inner expansions to take place, like if * rp was "@{blah_$(blue)}". */ if (!IsExpandable(naked)) { Log(LOG_LEVEL_DEBUG, "Flattening slist: %s", RlistScalarValue(rp)); VarRef *ref = VarRefParse(naked); DataType value_type; const void *value = EvalContextVariableGet(ctx, ref, &value_type); VarRefDestroy(ref); if (value_type == CF_DATA_TYPE_NONE) { assert(value == NULL); continue; /* undefined variable */ } if (DataTypeToRvalType(value_type) != RVAL_TYPE_LIST) { Log(LOG_LEVEL_WARNING, "'%s' failed - variable is not list but %s", RlistScalarValue(rp), DataTypeToString(value_type)); continue; } /* NOTE: Remember that value can be NULL as an empty Rlist. */ /* at_node: just a mnemonic name for the list node with @{blah}. */ Rlist *at_node = rp; Rlist *insert_after = at_node; for (const Rlist *rp2 = value; rp2 != NULL; rp2 = rp2->next) { assert(insert_after != NULL); RlistInsertAfter(insert_after, RvalCopy(rp2->val)); insert_after = insert_after->next; } /* Make sure we won't miss any element. */ assert(insert_after->next == next); RlistDestroyEntry(list, at_node); /* Delete @{blah} entry */ char *list_s = RlistToString(*list); Log(LOG_LEVEL_DEBUG, "Flattened slist: %s", list_s); free(list_s); } } } }