typedef struct {
TALLOC_CTX *ctx; //!< to allocate boxes and values in.
TALLOC_CTX *event_ctx; //!< for temporary events
- xlat_exp_t const *exp;
+ xlat_exp_t const *head; //!< of the xlat list
+ xlat_exp_t const *exp; //!< current one we're evaluating
fr_dcursor_t values; //!< Values aggregated so far.
/*
* For func and alternate
*/
- fr_value_box_list_t rhead; //!< Head of the result of a nested
+ fr_value_box_list_t out; //!< Head of the result of a nested
///< expansion.
bool alternate; //!< record which alternate branch we
///< previously took.
ev->request = request;
ev->fd = -1;
ev->timeout = callback;
+ fr_assert(state->exp->type == XLAT_FUNC);
ev->inst = state->exp->call.inst;
ev->thread = xlat_thread_instance_find(state->exp);
ev->rctx = rctx;
* Allocate its state, and setup a cursor for the xlat nodes
*/
MEM(frame->state = state = talloc_zero(stack, unlang_frame_state_xlat_t));
- state->exp = talloc_get_type_abort_const(exp, xlat_exp_t); /* Ensure the node is valid */
+ state->head = talloc_get_type_abort_const(exp, xlat_exp_t); /* Ensure the node is valid */
+ state->exp = state->head;
state->success = p_success;
state->ctx = ctx;
* Initialise the input and output lists
*/
fr_dcursor_init(&state->values, out);
- fr_value_box_list_init(&state->rhead);
+ fr_value_box_list_init(&state->out);
return 0;
}
xlat_exp_t const *child = NULL;
xa = xlat_frame_eval_repeat(state->ctx, &state->values, &child,
- &state->alternate, request, &state->exp, &state->rhead);
+ &state->alternate, request, state->head, &state->exp, &state->out);
switch (xa) {
case XLAT_ACTION_PUSH_CHILD:
fr_assert(child);
* at this level. A frame may be used to evaluate
* multiple sibling nodes.
*/
- fr_dlist_talloc_free(&state->rhead);
- if (unlang_xlat_push(state->ctx, state->success, &state->rhead, request, child, false) < 0) {
+ fr_dlist_talloc_free(&state->out);
+ if (unlang_xlat_push(state->ctx, state->success, &state->out, request, child, false) < 0) {
*p_result = RLM_MODULE_FAIL;
return UNLANG_ACTION_STOP_PROCESSING;
}
xlat_action_t xa;
xlat_exp_t const *child = NULL;
- xa = xlat_frame_eval(state->ctx, &state->values, &child, request, &state->exp);
+ xa = xlat_frame_eval(state->ctx, &state->values, &child, request, state->head, &state->exp);
switch (xa) {
case XLAT_ACTION_PUSH_CHILD:
fr_assert(child);
* at this level. A frame may be used to evaluate
* multiple sibling nodes.
*/
- fr_dlist_talloc_free(&state->rhead);
- if (unlang_xlat_push(state->ctx, state->success, &state->rhead, request, child, false) < 0) {
+ fr_dlist_talloc_free(&state->out);
+ if (unlang_xlat_push(state->ctx, state->success, &state->out, request, child, false) < 0) {
*p_result = RLM_MODULE_FAIL;
return UNLANG_ACTION_STOP_PROCESSING;
}
xa = xlat_frame_eval_resume(state->ctx, &state->values,
state->resume, state->exp,
- request, &state->rhead, state->rctx);
+ request, &state->out, state->rctx);
switch (xa) {
case XLAT_ACTION_YIELD:
repeatable_set(frame);
/*
* No arguments, just print an empty function.
*/
- if (!node->call.args) return talloc_asprintf(ctx, "%%%c%s:%c", open, node->call.func->name, close);
+ if (!xlat_exp_head(node->call.args)) return talloc_asprintf(ctx, "%%%c%s:%c", open, node->call.func->name, close);
out = talloc_asprintf(ctx, "%%%c%s:", open, node->call.func->name);
pool = talloc_pool(NULL, 128); /* Size of a single child (probably ok...) */
* we print the concatenated arguments list as
* well as the original fmt string.
*/
- if ((node->type == XLAT_FUNC) && !xlat_is_literal(node->call.args)) {
+ if ((node->type == XLAT_FUNC) && !xlat_is_literal(xlat_exp_head(node->call.args))) {
RDEBUG2(" (%%%c%s:%pM%c)",
(node->call.func->input_type == XLAT_INPUT_ARGS) ? '(' : '{',
node->call.func->name, args,
* @param[in] ctx to allocate value boxes in.
* @param[out] out a list of #fr_value_box_t to append to.
* @param[in] resume function to call.
- * @param[in] exp Xlat node currently being processed.
* @param[in] request the current request.
* @param[in] result Previously expanded arguments to this xlat function.
* @param[in] rctx Opaque (to us), resume ctx provided by xlat function
* @param[in,out] alternate Whether we processed, or have previously processed
* the alternate.
* @param[in] request the current request.
+ * @param[in] head of the list to evaluate
* @param[in,out] in xlat node to evaluate. Advanced as we process
* additional #xlat_exp_t.
* @param[in] result of a previous nested evaluation.
*/
xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out,
xlat_exp_t const **child, bool *alternate,
- request_t *request, xlat_exp_t const **in,
+ request_t *request, xlat_exp_t const *head, xlat_exp_t const **in,
fr_value_box_list_t *result)
{
xlat_exp_t const *node = *in;
/*
* It's easier if we get xlat_frame_eval to continue evaluating the frame.
*/
- *in = (*in)->next; /* advance */
- return xlat_frame_eval(ctx, out, child, request, in);
+ *in = xlat_exp_next(head, *in); /* advance */
+ return xlat_frame_eval(ctx, out, child, request, head, in);
}
/** Converts xlat nodes to value boxes
* should call us with the same #xlat_exp_t and the
* result of the nested evaluation in result.
* @param[in] request the current request.
+ * @param[in] head of the list to evaluate
* @param[in,out] in xlat node to evaluate. Advanced as we process
* additional #xlat_exp_t.
* @return
* - XLAT_ACTION_FAIL an xlat module failed.
*/
xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_t const **child,
- request_t *request, xlat_exp_t const **in)
+ request_t *request, xlat_exp_t const *head, xlat_exp_t const **in)
{
- xlat_exp_t const *node = *in;
xlat_action_t xa = XLAT_ACTION_DONE;
+ xlat_exp_t const *node;
fr_value_box_list_t result; /* tmp list so debug works correctly */
fr_value_box_list_init(&result);
*child = NULL;
- if (!node) return XLAT_ACTION_DONE;
+ if (!*in) return XLAT_ACTION_DONE;
XLAT_DEBUG("** [%i] %s >> entered", unlang_interpret_stack_depth(request), __FUNCTION__);
- for (node = *in; node; node = (*in)->next) {
+ for (node = *in; node; node = xlat_exp_next(head, node)) {
*in = node; /* Update node in our caller */
fr_dcursor_tail(out); /* Needed for debugging */
VALUE_BOX_TALLOC_LIST_VERIFY(out->dlist);
* If they're found anywhere else the xlat
* parser has an error.
*/
- fr_assert(((node == *in) && !node->next) || (talloc_array_length(node->fmt) > 1));
+ fr_assert(((node == *in) && !xlat_exp_next(head, node)) || (talloc_array_length(node->fmt) > 1));
/*
* We unfortunately need to dup the buffer
* Hand back the child node to the caller
* for evaluation.
*/
- if (node->call.args) {
- *child = node->call.args;
+ if (xlat_exp_head(node->call.args)) {
+ *child = xlat_exp_head(node->call.args);
xa = XLAT_ACTION_PUSH_CHILD;
goto finish;
}
* If there's no children we can just
* call the function directly.
*/
- xa = xlat_frame_eval_repeat(ctx, out, child, NULL, request, in, &result);
+ xa = xlat_frame_eval_repeat(ctx, out, child, NULL, request, head, in, &result);
if (xa != XLAT_ACTION_DONE || (!*in)) goto finish;
continue;
/*
* Now evaluate the function's arguments
*/
- if (node->call.args) {
+ if (xlat_exp_head(node->call.args)) {
ret = xlat_eval_walk(node->call.args, walker, type, uctx);
if (ret < 0) return ret;
}
/*
* Now evaluate the function's arguments
*/
- if (node->call.args) {
+ if (xlat_exp_head(node->call.args)) {
ret = xlat_eval_walk(node->call.args, walker, type, uctx);
if (ret < 0) return ret;
}
size_t at_in = fr_sbuff_used_total(out);
FR_SBUFF_IN_STRCPY_RETURN(out, fr_tokens[node->call.func->token]);
- xlat_print_node(out, node->call.args, e_rules);
+ xlat_print_node(out, xlat_exp_head(node->call.args), e_rules);
return fr_sbuff_used_total(out) - at_in;
}
size_t at_in = fr_sbuff_used_total(out);
FR_SBUFF_IN_CHAR_RETURN(out, '(');
- xlat_print_node(out, node->call.args, e_rules); /* prints a space after the first argument */
+ xlat_print_node(out, xlat_exp_head(node->call.args), e_rules); /* prints a space after the first argument */
/*
* @todo - when things like "+" support more than 2 arguments, print them all out
*/
FR_SBUFF_IN_STRCPY_RETURN(out, fr_tokens[node->call.func->token]);
FR_SBUFF_IN_CHAR_RETURN(out, ' ');
- xlat_print_node(out, node->call.args->next, e_rules);
+ xlat_print_node(out, xlat_exp_next(node->call.args, xlat_exp_head(node->call.args)), e_rules);
FR_SBUFF_IN_CHAR_RETURN(out, ')');
{
int rcode = -1;
xlat_t const *func;
- xlat_exp_t *arg;
fr_value_box_t *dst = NULL, *box;
xlat_arg_parser_t const *arg_p;
xlat_action_t xa;
/*
* A child isn't a value-box. We leave it alone.
*/
- for (arg = node->call.args; arg != NULL; arg = arg->next) {
+ xlat_exp_foreach(node->call.args, arg) {
fr_assert(arg->type == XLAT_GROUP);
if (!xlat_is_box(arg->group)) return 0;
- if (arg->group->next) return 0;
+
+ if (xlat_exp_next(arg->group, xlat_exp_head(arg->group))) return 0;
}
fr_value_box_list_init(&input);
* have to cast the box to the correct data type (or copy
* it), and then add the box to the source list.
*/
- for (arg = node->call.args, arg_p = func->args;
- arg != NULL;
- arg = arg->next, arg_p++) {
+ arg_p = func->args;
+ xlat_exp_foreach(node->call.args, arg) {
MEM(box = fr_value_box_alloc_null(node));
if ((arg_p->type != FR_TYPE_VOID) && (arg_p->type != box->type)) {
* cast / copy over-writes the list fields.
*/
fr_dlist_insert_tail(&input, box);
+ arg_p++;
}
/*
goto cleanup;
}
- while ((arg = node->call.args) != NULL) {
- node->call.args = arg->next;
- talloc_free(arg);
- }
+ xlat_exp_free(&node->call.args);
dst = fr_dcursor_head(&cursor);
fr_assert(dst != NULL);
{
size_t at_in = fr_sbuff_used_total(out);
xlat_logical_inst_t *inst = instance;
- xlat_exp_t *current = inst->args;
+ xlat_exp_t *head = inst->args;
/*
* We might get called before the node is instantiated.
*/
- if (!inst->args) current = node->call.args;
+ if (!head) head = node->call.args;
- fr_assert(current != NULL);
+ fr_assert(head != NULL);
FR_SBUFF_IN_CHAR_RETURN(out, '(');
- while (current) {
- xlat_print_node(out, current, e_rules);
+ xlat_exp_foreach(head, child) {
+ xlat_print_node(out, child, e_rules);
- if (!current->next) break;
+ if (!xlat_exp_next(head, child)) break;
FR_SBUFF_IN_STRCPY_RETURN(out, fr_tokens[node->call.func->token]);
FR_SBUFF_IN_CHAR_RETURN(out, ' ');
- current = current->next;
}
FR_SBUFF_IN_CHAR_RETURN(out, ')');
while (isspace((int) *fr_sbuff_current(_x))) fr_sbuff_advance(_x, 1); \
} while (0)
-#if 0
-static xlat_exp_t *xlat_exp_func_alloc_args(TALLOC_CTX *ctx, char const *name, size_t namelen, int argc)
-{
- int i;
- xlat_exp_t *node, *arg, **last;
-
- MEM(node = xlat_exp_alloc(ctx, XLAT_FUNC, name, namelen));
-
- last = &node->call.args;
- for (i = 0; i < argc; i++) {
- MEM(arg = xlat_exp_alloc_null(node));
- xlat_exp_set_type(arg, XLAT_GROUP);
- arg->quote = T_BARE_WORD;
- *last = arg;
- last = &arg->next;
- }
-
- return node;
-}
-#endif
-
static ssize_t tokenize_expression(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules,
fr_token_t prev, fr_sbuff_parse_rules_t const *bracket_rules);
xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out,
xlat_exp_t const **child, bool *alternate,
- request_t *request, xlat_exp_t const **in,
+ request_t *request, xlat_exp_t const *head, xlat_exp_t const **in,
fr_value_box_list_t *result) CC_HINT(nonnull(1,2,3,5,6));
xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_t const **child,
- request_t *request, xlat_exp_t const **in);
+ request_t *request, xlat_exp_t const *head, xlat_exp_t const **in);
int xlat_eval_walk(xlat_exp_t *exp, xlat_walker_t walker, xlat_type_t type, void *uctx);
{
fr_assert(node->type == XLAT_FUNC);
- if (node->call.func->args && node->call.func->args->required && !node->call.args) {
+ if (node->call.func->args && node->call.func->args->required && !xlat_exp_head(node->call.args)) {
fr_strerror_const("Missing required input");
return -1;
}
int xlat_validate_function_args(xlat_exp_t *node)
{
xlat_arg_parser_t const *arg_p;
- xlat_exp_t *arg = node->call.args;
+ xlat_exp_t *arg = xlat_exp_head(node->call.args);
fr_assert(node->type == XLAT_FUNC);
case XLAT_FUNC:
fr_assert(node->call.func != NULL);
INFO_INDENT("xlat (%s)", node->call.func->name);
- if (node->call.args) {
+ if (xlat_exp_head(node->call.args)) {
INFO_INDENT("{");
_xlat_debug(node->call.args, depth + 1);
INFO_INDENT("}");
case XLAT_FUNC_UNRESOLVED:
INFO_INDENT("xlat-unresolved (%s)", node->fmt);
- if (node->call.args) {
+ if (xlat_exp_head(node->call.args)) {
INFO_INDENT("{");
_xlat_debug(node->call.args, depth + 1);
INFO_INDENT("}");
FR_SBUFF_IN_BSTRCPY_BUFFER_RETURN(out, node->call.func->name);
FR_SBUFF_IN_CHAR_RETURN(out, ':');
- if (node->call.args) {
+ if (xlat_exp_head(node->call.args)) {
slen = xlat_print(out, node->call.args, &xlat_escape);
if (slen < 0) goto error;
}
FR_SBUFF_IN_BSTRCPY_BUFFER_RETURN(out, node->fmt);
FR_SBUFF_IN_CHAR_RETURN(out, ':');
- if (node->call.args) {
+ if (xlat_exp_head(node->call.args)) {
slen = xlat_print(out, node->call.args, &xlat_escape);
if (slen < 0) goto error;
}