continue;
}
- if (xlat_resolve(&head, &flags, NULL) < 0) {
+ if (xlat_resolve(head, &flags, NULL) < 0) {
talloc_free(xlat_ctx);
snprintf(output, sizeof(output), "ERROR resolving xlat: %s", fr_strerror());
continue;
* the string for conversion later.
*/
if (xlat_to_string(vpt, &str, &head)) {
- xlat_exp_free(&head); /* Free up any memory */
+ TALLOC_FREE(head);
tmpl_init(vpt, TMPL_TYPE_UNRESOLVED, quote,
fr_sbuff_start(&our_in), slen, t_rules);
static inline CC_HINT(always_inline)
int tmpl_xlat_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules)
{
- if (xlat_resolve(&vpt->data.xlat.ex, &vpt->data.xlat.flags,
+ if (xlat_resolve(vpt->data.xlat.ex, &vpt->data.xlat.flags,
&(xlat_res_rules_t){
.tr_rules = tr_rules,
.allow_unresolved = false
case TMPL_TYPE_EXEC_UNRESOLVED:
case TMPL_TYPE_XLAT_UNRESOLVED:
case TMPL_TYPE_REGEX_XLAT_UNRESOLVED:
- xlat_exp_free(&vpt->data.xlat.ex);
+ TALLOC_FREE(vpt->data.xlat.ex);
break;
case TMPL_TYPE_REGEX:
* - UNLANG_ACTION_YIELD
*/
unlang_action_t unlang_module_yield_to_xlat(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out,
- request_t *request, xlat_exp_t const *exp,
+ request_t *request, xlat_exp_head_t const *exp,
unlang_module_resume_t resume,
unlang_module_signal_t signal, void *rctx)
{
unlang_module_signal_t signal, void *rctx);
unlang_action_t unlang_module_yield_to_xlat(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out,
- request_t *request, xlat_exp_t const *xlat,
+ request_t *request, xlat_exp_head_t const *xlat,
unlang_module_resume_t resume,
unlang_module_signal_t signal, void *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->head = talloc_get_type_abort_const(xlat, xlat_exp_t); /* Ensure the node is valid */
+ state->head = talloc_get_type_abort_const(xlat, xlat_exp_head_t); /* Ensure the node is valid */
state->exp = xlat_exp_head(state->head);
state->success = p_success;
state->ctx = ctx;
bool xlat_to_string(TALLOC_CTX *ctx, char **str, xlat_exp_head_t **head);
-int xlat_resolve(xlat_exp_head_t **head, xlat_flags_t *flags, xlat_res_rules_t const *xr_rules);
+int xlat_resolve(xlat_exp_head_t *head, xlat_flags_t *flags, xlat_res_rules_t const *xr_rules);
xlat_t *xlat_register_module(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx,
char const *name, xlat_func_t func, xlat_flags_t const *flags);
int xlat_from_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *flags, tmpl_t **vpt_p);
-int xlat_copy(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_exp_t const *in);
+int xlat_copy(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_exp_head_t const *in);
/*
* xlat_inst.c
int xlat_bootstrap_func(xlat_exp_t *node);
-int xlat_bootstrap(xlat_exp_t *root);
+int xlat_bootstrap(xlat_exp_head_t *root);
void xlat_instances_free(void);
typedef struct {
xlat_redundant_t *xr; //!< Information about the redundant xlat.
- xlat_exp_t **ex; //!< Array of xlat expressions created by
+ xlat_exp_head_t **ex; //!< Array of xlat expressions created by
///< tokenizing the arguments to the redundant
///< xlat, then duplicating them multiple times,
///< one for each xlat function that may be called.
typedef struct {
bool last_success; //!< Did the last call succeed?
- xlat_exp_t **first; //!< First function called.
+ xlat_exp_head_t **first; //!< First function called.
///< Used for redundant-load-balance.
- xlat_exp_t **current; //!< Last function called, used for redundant xlats.
+ xlat_exp_head_t **current; //!< Last function called, used for redundant xlats.
} xlat_redundant_rctx_t;
/** Pass back the result from a single redundant child call
xlat_redundant_t *xr = talloc_get_type_abort(xctx->uctx, xlat_redundant_t);
xlat_redundant_inst_t *xri = talloc_get_type_abort(xctx->inst, xlat_redundant_inst_t);
unsigned int num = 0;
- xlat_redundant_func_t const *head;
+ xlat_redundant_func_t const *first;
- MEM(xri->ex = talloc_array(xri, xlat_exp_t *, fr_dlist_num_elements(&xr->funcs)));
+ MEM(xri->ex = talloc_array(xri, xlat_exp_head_t *, fr_dlist_num_elements(&xr->funcs)));
xri->xr = xr;
- head = talloc_get_type_abort(fr_dlist_head(&xr->funcs), xlat_redundant_func_t);
+ first = talloc_get_type_abort(fr_dlist_head(&xr->funcs), xlat_redundant_func_t);
/*
* Check the calling style matches the first
break;
case XLAT_INPUT_MONO:
- if (head->func->input_type == XLAT_INPUT_ARGS) {
+ if (first->func->input_type == XLAT_INPUT_ARGS) {
PERROR("Expansion function \"%s\" takes defined arguments and should "
"be called using %%(func:args) syntax",
xctx->ex->call.func->name);
break;
case XLAT_INPUT_ARGS:
- if (head->func->input_type == XLAT_INPUT_MONO) {
+ if (first->func->input_type == XLAT_INPUT_MONO) {
PERROR("Expansion function \"%s\" should be called using %%{func:arg} syntax",
xctx->ex->call.func->name);
return -1;
*/
fr_dlist_foreach(&xr->funcs, xlat_redundant_func_t, xrf) {
xlat_exp_t *node;
+ xlat_exp_head_t *head;
/*
* We have to do this here as it only
* becomes an error when the user tries
* to use the redundant xlat.
*/
- if (head->func->input_type != xrf->func->input_type) {
+ if (first->func->input_type != xrf->func->input_type) {
cf_log_err(xr->cs, "Expansion functions \"%s\" and \"%s\" use different argument styles "
- "cannot be used in the same redundant section", head->func->name, xrf->func->name);
+ "cannot be used in the same redundant section", first->func->name, xrf->func->name);
error:
talloc_free(xri->ex);
return -1;
* for the new node can operate
* correctly.
*/
- MEM(node = xlat_exp_func_alloc(xri->ex, xrf->func, xctx->ex->call.args));
+ MEM(head = xlat_exp_head_alloc(xri->ex));
+ MEM(head->next = node = xlat_exp_func_alloc(head, xrf->func, xctx->ex->call.args));
switch (xrf->func->input_type) {
case XLAT_INPUT_UNPROCESSED:
* they'll get called at some point after
* we return.
*/
- xlat_bootstrap(node);
- xri->ex[num++] = node;
+ xlat_bootstrap(head);
+ xri->ex[num++] = head;
}
/*
typedef struct {
bool last_success;
- xlat_exp_t *ex;
+ xlat_exp_head_t *ex;
} xlat_eval_rctx_t;
/** Just serves to push the result up the stack
* unresolved.
*/
if (flags.needs_resolving &&
- (xlat_resolve(&rctx->ex, &flags, &(xlat_res_rules_t){ .allow_unresolved = false }) < 0)) {
+ (xlat_resolve(rctx->ex, &flags, &(xlat_res_rules_t){ .allow_unresolved = false }) < 0)) {
RPEDEBUG("Unresolved expansion functions in expansion");
goto error;
/* So we don't need to include xlat.h */
typedef struct xlat_exp xlat_exp_t;
-typedef struct xlat_exp xlat_exp_head_t;
+typedef struct xlat_exp_head xlat_exp_head_t;
/** An xlat calling ctx
*
char **my_argv;
size_t count;
- if (!xlat_exp_is_head(head)) return -1;
-
count = 0;
xlat_exp_foreach(head, node) {
count++;
xlat_exp_head_t const **my_argv;
size_t count;
- if (!xlat_exp_is_head(head)) return -1;
-
count = 0;
xlat_exp_foreach(head, node) {
count++;
#include <freeradius-devel/unlang/xlat_priv.h>
#include <freeradius-devel/util/calc.h>
+#undef XLAT_DEBUG
+#ifdef DEBUG_XLAT
+# define XLAT_DEBUG(_fmt, ...) DEBUG3("%s[%i] "_fmt, __FILE__, __LINE__, ##__VA_ARGS__)
+#else
+# define XLAT_DEBUG(...)
+#endif
+
/*
* The new tokenizer accepts most things which are accepted by the old one. Many of the errors will be
* different, though.
static fr_slen_t xlat_expr_print_binary(fr_sbuff_t *out, xlat_exp_t const *node, UNUSED void *inst, fr_sbuff_escape_rules_t const *e_rules)
{
size_t at_in = fr_sbuff_used_total(out);
+ xlat_exp_t *child = xlat_exp_head(node->call.args);
FR_SBUFF_IN_CHAR_RETURN(out, '(');
- xlat_print_node(out, node->call.args, xlat_exp_head(node->call.args), e_rules); /* prints a space after the first argument */
+ xlat_print_node(out, node->call.args, child, 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, xlat_exp_next(node->call.args, xlat_exp_head(node->call.args)), e_rules);
+ child = xlat_exp_next(node->call.args, child);
+ xlat_print_node(out, node->call.args, child, e_rules);
FR_SBUFF_IN_CHAR_RETURN(out, ')');
xlat_exp_foreach(node->call.args, arg) {
fr_assert(arg->type == XLAT_GROUP);
- if (!xlat_is_box(arg->group)) return 0;
+ if (!xlat_is_box(xlat_exp_head(arg->group))) return 0;
if (xlat_exp_next(arg->group, xlat_exp_head(arg->group))) return 0;
}
MEM(box = fr_value_box_alloc_null(node));
if ((arg_p->type != FR_TYPE_VOID) && (arg_p->type != box->type)) {
- if (fr_value_box_cast(node, box, arg_p->type, NULL, xlat_box(arg->group)) < 0) goto fail;
+ if (fr_value_box_cast(node, box, arg_p->type, NULL, xlat_box(xlat_exp_head(arg->group))) < 0) goto fail;
- } else if (fr_value_box_copy(node, box, xlat_box(arg->group)) < 0) {
+ } else if (fr_value_box_copy(node, box, xlat_box(xlat_exp_head(arg->group))) < 0) {
fail:
talloc_free(box);
goto cleanup;
group->quote = T_BARE_WORD;
group->fmt = node->fmt; /* not entirely correct, but good enough for now */
- group->group = talloc_steal(group, node);
+ MEM(group->group = xlat_exp_head_alloc(group));
+ group->group->next = talloc_steal(group->group, node);
group->flags = node->flags;
if (node->next) {
return group;
}
-/*
- * Any function requires each argument to be in it's own XLAT_GROUP. But we can't create an XLAT_GROUP
- * from the start of parsing, as we might need to return an XLAT_FUNC, or another type of xlat. Instead,
- * we just work on the bare nodes, and then later groupify them. For now, it's just easier to do it this way.
- */
-static void xlat_groupify_expr(xlat_exp_t *node)
-{
- xlat_t const *func;
-
- if (node->type != XLAT_FUNC) return;
-
- func = node->call.func;
-
- if (!func->internal) return;
-
- if (func->token == T_INVALID) return;
-
- /*
- * It's already been groupified, don't do anything.
- */
- if (node->call.args->type == XLAT_GROUP) return;
-
- node->call.args = xlat_groupify_node(node, node->call.args);
-}
static xlat_arg_parser_t const binary_op_xlat_args[] = {
{ .required = true, .type = FR_TYPE_VOID },
}
typedef struct {
- xlat_exp_t *args;
bool sense;
+ int argc;
+ xlat_exp_head_t **argv;
} xlat_logical_inst_t;
typedef struct {
bool last_success;
- xlat_exp_t *current;
+ int current;
fr_value_box_list_t list;
} xlat_logical_rctx_t;
{
size_t at_in = fr_sbuff_used_total(out);
xlat_logical_inst_t *inst = instance;
- xlat_exp_head_t *head = inst->args;
+ xlat_exp_head_t *head;
+
+ FR_SBUFF_IN_CHAR_RETURN(out, '(');
/*
* We might get called before the node is instantiated.
*/
- if (!head) head = node->call.args;
+ if (!inst->argv) {
+ head = node->call.args;
- fr_assert(head != NULL);
+ fr_assert(head != NULL);
- FR_SBUFF_IN_CHAR_RETURN(out, '(');
+ xlat_exp_foreach(head, child) {
+ xlat_print_node(out, head, child, e_rules);
- xlat_exp_foreach(head, child) {
- xlat_print_node(out, head, child, e_rules);
+ 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, ' ');
+ }
+ } else {
+ int i;
- if (!xlat_exp_next(head, child)) break;
+ for (i = 0; i < inst->argc; i++) {
+ xlat_print(out, inst->argv[i], e_rules);
+ if (i == (inst->argc - 1)) break;
- FR_SBUFF_IN_STRCPY_RETURN(out, fr_tokens[node->call.func->token]);
- FR_SBUFF_IN_CHAR_RETURN(out, ' ');
+ FR_SBUFF_IN_STRCPY_RETURN(out, fr_tokens[node->call.func->token]);
+ FR_SBUFF_IN_CHAR_RETURN(out, ' ');
+ }
}
FR_SBUFF_IN_CHAR_RETURN(out, ')');
return fr_sbuff_used_total(out) - at_in;
}
+/*
+ * Each argument is it's own head, because we do NOT always want
+ * to go to the next argument.
+ */
static int xlat_logical_instantiate(xlat_inst_ctx_t const *xctx)
{
xlat_logical_inst_t *inst = talloc_get_type_abort(xctx->inst, xlat_logical_inst_t);
+ int i;
+
+ xlat_exp_foreach(xctx->ex->call.args, arg) {
+ inst->argc++;
+ }
+
+ inst->argv = talloc_array(inst, xlat_exp_head_t *, inst->argc);
+
+ i = 0;
+ xlat_exp_foreach(xctx->ex->call.args, arg) {
+ MEM(inst->argv[i] = xlat_exp_head_alloc(inst->argv));
+ inst->argv[i++]->next = talloc_steal(inst->argv[i], arg);
+ fr_assert(arg->type == XLAT_GROUP);
+ }
+
+ /*
+ * The arguments are in a linked list, so unlink them,
+ */
+ for (i = 0; i < inst->argc; i++) {
+ inst->argv[i]->next->next = NULL;
+ }
- inst->args = xctx->ex->call.args;
- xctx->ex->call.args = NULL;
+ xctx->ex->call.args->next = NULL;
+ TALLOC_FREE(xctx->ex->call.args);
inst->sense = (xctx->ex->call.func->token == T_LOR);
return 0;
}
fr_dlist_talloc_free(&rctx->list);
- rctx->current = rctx->current->next;
+ rctx->current++;
/*
* Nothing to expand, return the final value we saw.
*/
- if (!rctx->current) goto done;
+ if (rctx->current >= inst->argc) goto done;
/*
* Push the xlat onto the stack for expansion.
if (unlang_xlat_yield(request, xlat_logical_resume, NULL, rctx) != XLAT_ACTION_YIELD) goto fail;
if (unlang_xlat_push(rctx, &rctx->last_success, &rctx->list,
- request, rctx->current, UNLANG_SUB_FRAME) < 0) goto fail;
+ request, inst->argv[rctx->current], UNLANG_SUB_FRAME) < 0) goto fail;
return XLAT_ACTION_PUSH_UNLANG;
}
xlat_logical_rctx_t *rctx;
MEM(rctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), xlat_logical_rctx_t));
- rctx->current = inst->args;
+ rctx->current = 0;
fr_value_box_list_init(&rctx->list);
if (unlang_xlat_yield(request, xlat_logical_resume, NULL, rctx) != XLAT_ACTION_YIELD) {
}
if (unlang_xlat_push(ctx, &rctx->last_success, &rctx->list,
- request, rctx->current, UNLANG_SUB_FRAME) < 0) goto fail;
+ request, inst->argv[rctx->current], UNLANG_SUB_FRAME) < 0) goto fail;
return XLAT_ACTION_PUSH_UNLANG;
}
while (isspace((int) *fr_sbuff_current(_x))) fr_sbuff_advance(_x, 1); \
} while (0)
-static ssize_t tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+static ssize_t tokenize_expression(TALLOC_CTX *ctx, xlat_exp_t **out, 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);
static size_t expr_quote_table_len = NUM_ELEMENTS(expr_quote_table);
#ifdef HAVE_REGEX
-static ssize_t tokenize_regex(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+static ssize_t tokenize_regex(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_flags_t *flags, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
{
ssize_t slen;
if (slen <= 0) goto error;
}
- *head = node;
+ *out = node;
xlat_flags_merge(flags, &node->flags);
return fr_sbuff_used(&our_in);
* to parse the next thing we get. Otherwise, parse the thing as
* int64_t.
*/
-static ssize_t tokenize_field(TALLOC_CTX *input_ctx, xlat_exp_head_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+static ssize_t tokenize_field(TALLOC_CTX *input_ctx, xlat_exp_t **out, xlat_flags_t *flags, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules,
fr_sbuff_parse_rules_t const *bracket_rules)
{
tmpl_t *vpt;
fr_token_t quote;
+ XLAT_DEBUG("FIELD <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in)));
+
/*
* Handle !-~ by adding a unary function to the xlat
* node, with the first argument being the _next_ thing
* @todo - purify the node.
*/
if (unary) {
- unary->call.args = node;
+ xlat_exp_head_t *head;
+
+ MEM(head = xlat_exp_head_alloc(unary));
+
+ unary->call.args = head;
+ head->next = xlat_groupify_node(unary, node);
xlat_flags_merge(&unary->flags, &node->flags);
node = unary;
}
- *head = node;
+ *out = node;
xlat_flags_merge(flags, &node->flags);
return fr_sbuff_set(in, &our_in);
* !EXPR
* A OP B
*/
-static ssize_t tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+static ssize_t tokenize_expression(TALLOC_CTX *ctx, xlat_exp_t **out, 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)
{
ssize_t slen;
fr_sbuff_marker_t marker;
fr_sbuff_t our_in = FR_SBUFF(in);
+ xlat_exp_head_t *head;
+
+ XLAT_DEBUG("EXPRESSION <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in)));
fr_sbuff_skip_whitespace(&our_in);
*/
if (fr_sbuff_extend(&our_in) == 0) {
done:
- *head = lhs;
+ *out = lhs;
return fr_sbuff_set(in, &our_in);
}
/*
* Get the operator.
*/
+ XLAT_DEBUG(" operator <-- %pV", fr_box_strvalue_len(fr_sbuff_current(&our_in), fr_sbuff_remaining(&our_in)));
fr_sbuff_out_by_longest_prefix(&slen, &op, expr_assignment_op_table, &our_in, T_INVALID);
if (op == T_INVALID) {
talloc_free(lhs);
/*
* We now parse the RHS, allowing a (perhaps different) cast on the RHS.
*/
+ XLAT_DEBUG(" recurse RHS <-- %pV", fr_box_strvalue_len(fr_sbuff_current(&our_in), fr_sbuff_remaining(&our_in)));
slen = tokenize_expression(ctx, &rhs, flags, &our_in, p_rules, t_rules, op, bracket_rules);
if (slen <= 0) {
talloc_free(lhs);
fr_assert(lhs->call.func == func);
node = xlat_groupify_node(lhs, rhs);
- last = &lhs->call.args;
+
+ fr_assert(lhs->call.args != NULL);
+ last = &lhs->call.args->next;
/*
* Find the last child.
node->call.func = func;
node->flags = func->flags;
- node->call.args = xlat_groupify_node(node, lhs);
+ MEM(node->call.args = head = xlat_exp_head_alloc(node));
+ head->next = xlat_groupify_node(node, lhs);
node->call.args->flags = lhs->flags;
- node->call.args->next = xlat_groupify_node(node, rhs);
- node->call.args->next->flags = rhs->flags;
+ head->next->next = xlat_groupify_node(node, rhs);
+ head->next->next->flags = rhs->flags;
xlat_flags_merge(&node->flags, &lhs->flags);
xlat_flags_merge(&node->flags, &rhs->flags);
}
}
- /*
- * Ensure that the various nodes are grouped properly.
- */
- xlat_groupify_expr(node);
-
lhs = node;
goto redo;
}
L("<"),
);
-ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_flags_t *flags, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
{
ssize_t slen;
fr_sbuff_parse_rules_t *terminal_rules = NULL;
xlat_flags_t my_flags = { };
tmpl_rules_t my_rules = { };
+ xlat_exp_head_t *head;
/*
* Whatever the caller passes, ensure that we have a
if (!t_rules) t_rules = &my_rules;
- *head = NULL;
+ MEM(head = xlat_exp_head_alloc(ctx));
- slen = tokenize_expression(ctx, head, flags, in, terminal_rules, t_rules, T_INVALID, bracket_rules);
+ slen = tokenize_expression(head, &head->next, flags, in, terminal_rules, t_rules, T_INVALID, bracket_rules);
talloc_free(bracket_rules);
talloc_free(terminal_rules);
/*
* Zero length expansion, return a zero length node.
*/
- if (!*head) {
- *head = xlat_exp_alloc(ctx, XLAT_BOX, "", 0);
+ if (!head->next) {
+ *out = head;
return 0;
}
* Add nodes that need to be bootstrapped to
* the registry.
*/
- if (xlat_bootstrap(*head) < 0) {
- TALLOC_FREE(*head);
+ if (xlat_bootstrap(head) < 0) {
+ talloc_free(head);
return 0;
}
+ *out = head;
return slen;
}
* expressions are integrated into the main xlat parser.
*
* @param[in] ctx to allocate dynamic buffers in.
- * @param[out] head the head of the xlat list / tree structure.
+ * @param[out] out the head of the xlat list / tree structure.
* @param[in] el for registering any I/O handlers.
* @param[out] flags indicating the state of the ephemeral tree.
* @param[in] in the format string to expand.
* - 0 and *head != NULL - Zero length expansion
* - <0 the negative offset of the parse failure.
*/
-ssize_t xlat_tokenize_ephemeral_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head,
+ssize_t xlat_tokenize_ephemeral_expression(TALLOC_CTX *ctx, xlat_exp_head_t **out,
fr_event_list_t *el,
xlat_flags_t *flags, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
fr_sbuff_parse_rules_t *terminal_rules = NULL;
xlat_flags_t my_flags = { };
tmpl_rules_t my_rules = { };
+ xlat_exp_head_t *head;
/*
* Whatever the caller passes, ensure that we have a
}
my_rules.xlat.runtime_el = el;
- *head = NULL;
+ MEM(head = xlat_exp_head_alloc(ctx));
- slen = tokenize_expression(ctx, head, flags, in, terminal_rules, &my_rules, T_INVALID, bracket_rules);
+ slen = tokenize_expression(head, &head->next, flags, in, terminal_rules, &my_rules, T_INVALID, bracket_rules);
talloc_free(bracket_rules);
talloc_free(terminal_rules);
/*
* Zero length expansion, return a zero length node.
*/
- if (!*head) {
- *head = xlat_exp_alloc(ctx, XLAT_BOX, "", 0);
+ if (!head->next) {
+ *out = head;
return 0;
}
/*
* Create ephemeral instance data for the xlat
*/
- if (xlat_instantiate_ephemeral(*head, el) < 0) {
+ if (xlat_instantiate_ephemeral(head, el) < 0) {
fr_strerror_const("Failed performing ephemeral instantiation for xlat");
- TALLOC_FREE(*head);
+ talloc_free(head);
return 0;
}
+ *out = head;
return slen;
}
* IF THIS IS CALLED FOR XLATS TOKENIZED AT RUNTIME YOU WILL LEAK LARGE AMOUNTS OF MEMORY.
* USE xlat_instantiate_request() INSTEAD.
*
- * @param[in] root of xlat tree to create instance data for.
+ * @param[in] head of xlat tree to create instance data for.
*/
-int xlat_bootstrap(xlat_exp_t *root)
+int xlat_bootstrap(xlat_exp_head_t *head)
{
/*
* If thread instantiate has been called, it's too late to
* Walk an expression registering all the function calls
* so that we can instantiate them later.
*/
- return xlat_eval_walk(root, _xlat_bootstrap_walker, XLAT_FUNC, NULL);
+ return xlat_eval_walk(head, _xlat_bootstrap_walker, XLAT_FUNC, NULL);
}
/** Walk over all registered instance data and free them explicitly
};
};
+struct xlat_exp_head {
+ char const *fmt; //!< The original format string (a talloced buffer).
+ xlat_flags_t flags; //!< Flags that control resolution and evaluation.
+ xlat_exp_t *next; //!< Next in the list.
+};
+
+
typedef struct {
char const *out; //!< Output data.
size_t len; //!< Length of the output string.
/*
* xlat_tokenize.c
*/
-int xlat_tokenize_expansion(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+int xlat_tokenize_expansion(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_flags_t *flags, fr_sbuff_t *in,
tmpl_attr_rules_t const *t_rules);
-int xlat_tokenize_function_args(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+int xlat_tokenize_function_args(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_flags_t *flags, fr_sbuff_t *in,
tmpl_attr_rules_t const *rules);
ssize_t xlat_print_node(fr_sbuff_t *out, xlat_exp_head_t const *head, xlat_exp_t const *node, fr_sbuff_escape_rules_t const *e_rules);
+
+
static inline xlat_exp_t *xlat_exp_head(xlat_exp_head_t const *head)
{
- return UNCONST(xlat_exp_t *, head);
+ if (!head || !head->next) return NULL;
+
+ return UNCONST(xlat_exp_t *, (head->next));
}
/** Iterate over the contents of a list, only one level
return UNCONST(xlat_exp_t *, item->next);
}
-static inline bool xlat_exp_is_head(xlat_exp_head_t const *head)
+static inline xlat_exp_head_t *xlat_exp_head_alloc(TALLOC_CTX *ctx)
{
- return (head && (head->type == XLAT_GROUP));
-
-// return (head && head->next && (head->next->type == XLAT_GROUP));
+ return talloc_zero(ctx, xlat_exp_head_t);
}
#ifdef __cplusplus
#include <freeradius-devel/server/regex.h>
#include <freeradius-devel/unlang/xlat_priv.h>
-
#undef XLAT_DEBUG
#undef XLAT_HEXDUMP
#ifdef DEBUG_XLAT
* @param[in] args Arguments to the function. Will be copied,
* and freed when the new xlat node is freed.
*/
-xlat_exp_t *xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t *func, xlat_exp_t const *args)
+xlat_exp_t *xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t *func, xlat_exp_head_t const *args)
{
xlat_exp_t *node;
*head = NULL;
}
-static int xlat_tokenize_string(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *flags,
+static int xlat_tokenize_string(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_flags_t *flags,
fr_sbuff_t *in, bool brace,
fr_sbuff_parse_rules_t const *p_rules, tmpl_attr_rules_t const *t_rules);
-static inline int xlat_tokenize_alternation(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+static inline int xlat_tokenize_alternation(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_flags_t *flags, fr_sbuff_t *in,
tmpl_attr_rules_t const *t_rules, bool func_args)
{
xlat_exp_t *node;
node = xlat_exp_alloc_null(ctx);
xlat_exp_set_type(node, XLAT_ALTERNATE);
+ MEM(node->alternate[0] = xlat_exp_head_alloc(node));
+ MEM(node->alternate[1] = xlat_exp_head_alloc(node));
if (func_args) {
- if (xlat_tokenize_function_args(node, &node->alternate[0], &node->flags, in, t_rules) < 0) {
+ if (xlat_tokenize_function_args(node, &node->alternate[0]->next, &node->flags, in, t_rules) < 0) {
error:
- *head = NULL;
talloc_free(node);
return -1;
}
} else {
- if (xlat_tokenize_expansion(node, &node->alternate[0], &node->flags, in, t_rules) < 0) goto error;
+ if (xlat_tokenize_expansion(node, &node->alternate[0]->next, &node->flags, in, t_rules) < 0) goto error;
}
if (!fr_sbuff_adv_past_str_literal(in, ":-")) {
* Allow the RHS to be empty as a special case.
*/
if (fr_sbuff_next_if_char(in, '}')) {
- node->alternate[1] = xlat_exp_alloc(node, XLAT_BOX, "", 0);
xlat_flags_merge(&node->flags, &node->alternate[1]->flags);
- *head = node;
+ *out = node;
return 0;
}
/*
* Parse the alternate expansion.
*/
- if (xlat_tokenize_string(node, &node->alternate[1], &node->flags, in,
+ if (xlat_tokenize_string(node, &node->alternate[1]->next, &node->flags, in,
true, &xlat_expansion_rules, t_rules) < 0) goto error;
- if (!node->alternate[1]) {
+ if (!node->alternate[1]->next) {
talloc_free(node);
fr_strerror_const("Empty expansion is invalid");
goto error;
}
xlat_flags_merge(flags, &node->flags);
- *head = node;
+ *out = node;
return 0;
}
* @verbatim %{<num>} @endverbatim
*
*/
-static inline int xlat_tokenize_regex(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *flags, fr_sbuff_t *in)
+static inline int xlat_tokenize_regex(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_flags_t *flags, fr_sbuff_t *in)
{
uint8_t num;
xlat_exp_t *node;
fr_sbuff_next(in); /* Skip '}' */
xlat_flags_merge(flags, &node->flags);
- *head = node;
+ *out = node;
return 0;
}
* - 0 if the string was parsed into a function.
* - <0 on parse error.
*/
-static inline int xlat_tokenize_function_mono(TALLOC_CTX *ctx, xlat_exp_t **head,
+static inline int xlat_tokenize_function_mono(TALLOC_CTX *ctx, xlat_exp_t **out,
xlat_flags_t *flags, fr_sbuff_t *in,
tmpl_attr_rules_t const *rules)
{
['.'] = true, ['-'] = true, ['_'] = true,
};
- XLAT_DEBUG("FUNC <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in)));
+ XLAT_DEBUG("FUNC-MONO <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in)));
/*
* %{module:args}
if (!fr_sbuff_is_char(in, ':')) {
fr_strerror_const("Can't find function/argument separator");
bad_function:
- *head = NULL;
+ *out = NULL;
fr_sbuff_set(in, &m_s); /* backtrack */
fr_sbuff_marker_release(&m_s);
return -1;
/*
* Allocate a node to hold the function
*/
- node = xlat_exp_alloc(ctx, XLAT_FUNC, fr_sbuff_current(&m_s), fr_sbuff_behind(&m_s));
+ MEM(node = xlat_exp_alloc(ctx, XLAT_FUNC, fr_sbuff_current(&m_s), fr_sbuff_behind(&m_s)));
+ MEM(node->call.args = xlat_exp_head_alloc(node));
if (!func) {
if (!rules || !rules->allow_unresolved) {
fr_strerror_const("Unresolved expansion functions are not allowed here");
fr_strerror_const("Function takes defined arguments and should "
"be called using %(func:args) syntax");
error:
- head = NULL;
talloc_free(node);
return -1;
}
* Now parse the child nodes that form the
* function's arguments.
*/
- if (xlat_tokenize_string(node, &node->call.args, &node->flags, in, true, &xlat_expansion_rules, rules) < 0) {
+ if (xlat_tokenize_string(node, &node->call.args->next, &node->flags, in, true, &xlat_expansion_rules, rules) < 0) {
goto error;
}
}
xlat_flags_merge(flags, &node->flags);
- *head = node;
+ *out = node;
return 0;
}
* - 0 if the string was parsed into a function.
* - <0 on parse error.
*/
-int xlat_tokenize_function_args(TALLOC_CTX *ctx, xlat_exp_t **head,
+int xlat_tokenize_function_args(TALLOC_CTX *ctx, xlat_exp_t **out,
xlat_flags_t *flags, fr_sbuff_t *in,
tmpl_attr_rules_t const *rules)
{
['.'] = true, ['-'] = true, ['_'] = true,
};
- XLAT_DEBUG("FUNC <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in)));
+ XLAT_DEBUG("FUNC-ARGS <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in)));
/*
* %(module:args)
if (!fr_sbuff_is_char(in, ':')) {
fr_strerror_const("Can't find function/argument separator");
bad_function:
- *head = NULL;
+ *out = NULL;
fr_sbuff_set(in, &m_s); /* backtrack */
fr_sbuff_marker_release(&m_s);
return -1;
}
xlat_flags_merge(flags, &node->flags);
- *head = node;
+ *out = node;
return 0;
}
/** Parse an attribute ref or a virtual attribute
*
*/
-static inline int xlat_tokenize_attribute(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+static inline int xlat_tokenize_attribute(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_flags_t *flags, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_attr_rules_t const *t_rules)
{
ssize_t slen;
*/
if (err == TMPL_ATTR_ERROR_MISSING_TERMINATOR) fr_sbuff_set(in, &m_s);
error:
- *head = NULL;
+ *out = NULL;
fr_sbuff_marker_release(&m_s);
talloc_free(node);
return -1;
}
xlat_flags_merge(flags, &node->flags);
- *head = node;
+ *out = node;
fr_sbuff_marker_release(&m_s);
return 0;
}
-int xlat_tokenize_expansion(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+int xlat_tokenize_expansion(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_flags_t *flags, fr_sbuff_t *in,
tmpl_attr_rules_t const *t_rules)
{
size_t len;
* %{...}:-bar}
*/
if (fr_sbuff_adv_past_str_literal(in, "%{")) {
- return xlat_tokenize_alternation(ctx, head, flags, in, t_rules, false);
+ return xlat_tokenize_alternation(ctx, out, flags, in, t_rules, false);
}
/*
* %(...):-bar}
*/
if (fr_sbuff_adv_past_str_literal(in, "%(")) {
- return xlat_tokenize_alternation(ctx, head, flags, in, t_rules, true);
+ return xlat_tokenize_alternation(ctx, out, flags, in, t_rules, true);
}
/*
* Handle regex's %{<num>} specially.
*/
if (fr_sbuff_is_digit(in)) {
- ret = xlat_tokenize_regex(ctx, head, flags, in);
+ ret = xlat_tokenize_regex(ctx, out, flags, in);
if (ret <= 0) return ret;
}
#endif /* HAVE_REGEX */
fr_sbuff_set(in, &s_m); /* backtrack */
fr_sbuff_marker_release(&s_m);
- ret = xlat_tokenize_function_mono(ctx, head, flags, in, t_rules);
+ ret = xlat_tokenize_function_mono(ctx, out, flags, in, t_rules);
if (ret <= 0) return ret;
}
break;
fr_sbuff_set(in, &s_m); /* backtrack */
fr_sbuff_marker_release(&s_m);
- if (xlat_tokenize_attribute(ctx, head, flags, in, &attr_p_rules, t_rules) < 0) return -1;
+ if (xlat_tokenize_attribute(ctx, out, flags, in, &attr_p_rules, t_rules) < 0) return -1;
break;
/*
* allocated in the same ctx. This is to allow
* manipulation by xlat instantiation functions
* later.
- * @param[out] head Where to write the first child node.
+ * @param[out] out Where to write the first child node.
* @param[out] flags where we store flags information for the parent.
* @param[in] in sbuff to parse.
* @param[in] brace true if we're inside a braced expansion, else false.
* - 0 on success.
* - -1 on failure.
*/
-static int xlat_tokenize_string(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *flags,
+static int xlat_tokenize_string(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_flags_t *flags,
fr_sbuff_t *in, bool brace,
fr_sbuff_parse_rules_t const *p_rules, tmpl_attr_rules_t const *t_rules)
{
);
fr_sbuff_term_t *tokens;
fr_sbuff_unescape_rules_t const *escapes;
- xlat_exp_t **tail;
+ xlat_exp_t *head, **tail;
- *head = NULL;
- tail = head;
+ head = NULL;
+ tail = &head;
+
+ XLAT_DEBUG("STRING <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in)));
escapes = p_rules ? p_rules->escapes : NULL;
tokens = p_rules && p_rules->terminals ?
} else if (slen < 0) {
error:
talloc_free(node);
- xlat_exp_list_free(head);
+ xlat_exp_list_free(&head);
/*
* Free our temporary array of terminals
*/
if (tokens != &expansions) talloc_free(tokens);
+ *out = head;
return 0;
}
* @param[in] head First node to print.
* @param[in] e_rules Specifying how to escape literal values.
*/
-ssize_t xlat_print(fr_sbuff_t *out, xlat_exp_t const *head, fr_sbuff_escape_rules_t const *e_rules)
+ssize_t xlat_print(fr_sbuff_t *out, xlat_exp_head_t const *head, fr_sbuff_escape_rules_t const *e_rules)
{
ssize_t slen;
size_t at_in = fr_sbuff_used_total(out);
* like LDAP or SQL.
*
* @param[in] ctx to allocate dynamic buffers in.
- * @param[out] head the head of the xlat list / tree structure.
+ * @param[out] out the head of the xlat list / tree structure.
* @param[in] el for registering any I/O handlers.
* @param[out] flags indicating the state of the ephemeral tree.
* @param[in] in the format string to expand.
* - 0 and *head != NULL - Zero length expansion
* - <0 the negative offset of the parse failure.
*/
-ssize_t xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_head_t **head,
+ssize_t xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_head_t **out,
fr_event_list_t *el,
xlat_flags_t *flags, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
fr_sbuff_t our_in = FR_SBUFF(in);
tmpl_rules_t our_t_rules = {};
xlat_flags_t tmp_flags = {};
+ xlat_exp_head_t *head;
if (!flags) flags = &tmp_flags;
- *head = NULL;
+ MEM(head = xlat_exp_head_alloc(ctx));
if (t_rules) our_t_rules = *t_rules;
our_t_rules.xlat.runtime_el = el;
fr_strerror_clear(); /* Clear error buffer */
- if (xlat_tokenize_string(ctx, head, flags, &our_in,
+ if (xlat_tokenize_string(head, &head->next, flags, &our_in,
false, p_rules, &our_t_rules.attr) < 0) return -fr_sbuff_used(&our_in);
/*
* Zero length expansion, return a zero length node.
*/
- if (!*head) {
- *head = xlat_exp_alloc(ctx, XLAT_BOX, "", 0);
+ if (!head->next) {
+ *out = head;
return 0;
}
/*
* Create ephemeral instance data for the xlat
*/
- if (xlat_instantiate_ephemeral(*head, el) < 0) {
+ if (xlat_instantiate_ephemeral(head, el) < 0) {
fr_strerror_const("Failed performing ephemeral instantiation for xlat");
- TALLOC_FREE(*head);
+ talloc_free(head);
return 0;
}
+ *out = head;
return fr_sbuff_set(in, &our_in);
}
* allocated in the same ctx. This is to allow
* manipulation by xlat instantiation functions
* later.
- * @param[out] head the head of the xlat list / tree structure.
+ * @param[out] out the head of the xlat list / tree structure.
* @param[out] flags Populated with parameters that control xlat
* evaluation and multi-pass parsing.
* @param[in] in the format string to expand.
* - <=0 on error.
* - >0 on success which is the number of characters parsed.
*/
-ssize_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+ssize_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_flags_t *flags, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_attr_rules_t const *t_rules)
{
fr_sbuff_t our_in = FR_SBUFF(in);
fr_sbuff_parse_rules_t tmp_p_rules;
xlat_flags_t tmp_flags = {};
xlat_exp_t **tail;
+ xlat_exp_head_t *head;
if (!flags) flags = &tmp_flags;
- *head = NULL;
- tail = head;
+ MEM(head = xlat_exp_head_alloc(ctx));
+ tail = &head->next;
if (p_rules && p_rules->terminals) {
tmp_p_rules = (fr_sbuff_parse_rules_t){ /* Stack allocated due to CL scope */
* Alloc a new node to hold the child nodes
* that make up the argument.
*/
- node = xlat_exp_alloc_null(ctx);
+ MEM(node = xlat_exp_alloc_null(head));
xlat_exp_set_type(node, XLAT_GROUP);
+ MEM(node->group = xlat_exp_head_alloc(node));
node->quote = quote;
switch (quote) {
* Barewords --may-contain=%{expansions}
*/
case T_BARE_WORD:
- if (xlat_tokenize_string(node, &node->group, &node->flags, &our_in,
+ if (xlat_tokenize_string(node, &node->group->next, &node->flags, &our_in,
false, our_p_rules, t_rules) < 0) {
error:
if (our_p_rules != &value_parse_rules_bareword_quoted) {
talloc_const_free(our_p_rules->terminals);
}
- talloc_free(node);
- xlat_exp_list_free(head);
+ talloc_free(head);
return -fr_sbuff_used(&our_in); /* error */
}
* "Double quoted strings may contain %{expansions}"
*/
case T_DOUBLE_QUOTED_STRING:
- if (xlat_tokenize_string(node, &node->group, &node->flags, &our_in,
+ if (xlat_tokenize_string(node, &node->group->next, &node->flags, &our_in,
false, &value_parse_rules_double_quoted, t_rules) < 0) goto error;
xlat_flags_merge(flags, &node->flags);
break;
case T_SINGLE_QUOTED_STRING:
{
char *str;
+ xlat_exp_t *child;
- node->group = xlat_exp_alloc_null(node);
- xlat_exp_set_type(node->group, XLAT_BOX);
+ node->group->next = child = xlat_exp_alloc_null(node);
+ xlat_exp_set_type(child, XLAT_BOX);
- slen = fr_sbuff_out_aunescape_until(node->group, &str, &our_in, SIZE_MAX,
+ slen = fr_sbuff_out_aunescape_until(child, &str, &our_in, SIZE_MAX,
value_parse_rules_single_quoted.terminals,
value_parse_rules_single_quoted.escapes);
if (slen < 0) goto error;
- xlat_exp_set_name_buffer_shallow(node->group, str);
- fr_value_box_strdup_shallow(&node->group->data, NULL, str, false);
+ xlat_exp_set_name_buffer_shallow(child, str);
+ fr_value_box_strdup_shallow(&child->data, NULL, str, false);
xlat_flags_merge(flags, &node->flags);
}
break;
if (our_p_rules != &value_parse_rules_bareword_quoted) talloc_const_free(our_p_rules->terminals);
+ *out = head;
return fr_sbuff_set(in, &our_in);
}
/** Tokenize an xlat expansion
*
* @param[in] ctx to allocate dynamic buffers in.
- * @param[out] head the head of the xlat list / tree structure.
+ * @param[out] out the head of the xlat list / tree structure.
* @param[in,out] flags that control evaluation and parsing.
* @param[in] in the format string to expand.
* @param[in] p_rules controlling how the string containing the xlat
* - 0 and *head != NULL - Zero length expansion
* - < 0 the negative offset of the parse failure.
*/
-ssize_t xlat_tokenize(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
+ssize_t xlat_tokenize(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_flags_t *flags, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_attr_rules_t const *t_rules)
{
fr_sbuff_t our_in = FR_SBUFF(in);
xlat_flags_t tmp_flags = {};
+ xlat_exp_head_t *head;
if (!flags) flags = &tmp_flags;
- *head = NULL;
+
+ MEM(head = xlat_exp_head_alloc(ctx));
fr_strerror_clear(); /* Clear error buffer */
- if (xlat_tokenize_string(ctx, head, flags, &our_in,
+ if (xlat_tokenize_string(head, &head->next, flags, &our_in,
false, p_rules, t_rules) < 0) return -fr_sbuff_used(&our_in);
/*
* Zero length expansion, return a zero length node.
*/
- if (!*head) {
- *head = xlat_exp_alloc(ctx, XLAT_BOX, "", 0);
+ if (!head->next) {
+ *out = head;
return fr_sbuff_set(in, &our_in);
}
* Add nodes that need to be bootstrapped to
* the registry.
*/
- if (xlat_bootstrap(*head) < 0) {
- TALLOC_FREE(*head);
+ if (xlat_bootstrap(head) < 0) {
+ talloc_free(head);
return 0;
}
+ *out = head;
return fr_sbuff_set(in, &our_in);
}
* - 0 on success.
* - -1 on failure.
*/
-int xlat_resolve(xlat_exp_head_t **head, xlat_flags_t *flags, xlat_res_rules_t const *xr_rules)
+int xlat_resolve(xlat_exp_head_t *head, xlat_flags_t *flags, xlat_res_rules_t const *xr_rules)
{
static xlat_res_rules_t xr_default;
xlat_flags_t our_flags;
our_flags = *flags;
our_flags.needs_resolving = false; /* We flip this if not all resolutions are successful */
- xlat_exp_foreach(*head, node) {
+ xlat_exp_foreach(head, node) {
if (!node->flags.needs_resolving) continue; /* This node and non of its children need resolving */
switch (node->type) {
case XLAT_GROUP:
- if (xlat_resolve(&node->group, &node->flags, xr_rules) < 0) return -1;
+ if (xlat_resolve(node->group, &node->flags, xr_rules) < 0) return -1;
break;
/*
{
xlat_flags_t child_flags = node->flags, alt_flags = node->flags;
- if ((xlat_resolve(&node->alternate[0], &child_flags, xr_rules) < 0) ||
- (xlat_resolve(&node->alternate[1], &alt_flags, xr_rules) < 0)) return -1;
+ if ((xlat_resolve(node->alternate[0], &child_flags, xr_rules) < 0) ||
+ (xlat_resolve(node->alternate[1], &alt_flags, xr_rules) < 0)) return -1;
xlat_flags_merge(&child_flags, &alt_flags);
node->flags = child_flags;
* A resolved function with unresolved args
*/
case XLAT_FUNC:
- if (xlat_resolve(&node->call.args, &node->flags, xr_rules) < 0) return -1;
+ if (xlat_resolve(node->call.args, &node->flags, xr_rules) < 0) return -1;
break;
/*
* We can't tell if it's just the function
* that needs resolving or its children too.
*/
- if (xlat_resolve(&node->call.args, &child_flags, xr_rules) < 0) return -1;
+ if (xlat_resolve(node->call.args, &child_flags, xr_rules) < 0) return -1;
/*
* Try and find the function
/** Try to convert an xlat to a tmpl for efficiency
*
* @param ctx to allocate new tmpl_t in.
- * @param node to convert.
+ * @param head to convert.
* @return
* - NULL if unable to convert (not necessarily error).
* - A new #tmpl_t.
*/
-tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *node)
+tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t *head)
{
tmpl_t *vpt;
+ xlat_exp_t *node = xlat_exp_head(head);
- if (node->next || (node->type != XLAT_TMPL) || !tmpl_is_attr(node->vpt)) return NULL;
+ if (node || (node->type != XLAT_TMPL) || !tmpl_is_attr(node->vpt)) return NULL;
/*
* Concat means something completely different as an attribute reference
/** Convert attr tmpl to an xlat for &attr[*]
*
* @param[in] ctx to allocate new expansion in.
- * @param[out] head Where to write new xlat node.
+ * @param[out] out Where to write new xlat node.
* @param[out] flags Where to write xlat resolution flags.
* @param[in,out] vpt_p to convert to xlat expansion.
* Will be set to NULL on completion
* - 0 on success.
* - -1 on failure.
*/
-int xlat_from_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *flags, tmpl_t **vpt_p)
+int xlat_from_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_flags_t *flags, tmpl_t **vpt_p)
{
xlat_exp_t *node;
xlat_t *func;
tmpl_t *vpt = *vpt_p;
+ xlat_exp_head_t *head;
if (!tmpl_is_attr(vpt) && !tmpl_is_attr_unresolved(vpt)) return 0;
+ MEM(head = xlat_exp_head_alloc(ctx));
+
/*
* If it's a single attribute reference
* see if it's actually a virtual attribute.
func = xlat_func_find(tmpl_da(vpt)->name, -1);
if (!func) {
unresolved:
- node = xlat_exp_alloc(ctx, XLAT_VIRTUAL_UNRESOLVED, vpt->name, vpt->len);
+ node = xlat_exp_alloc(head, XLAT_VIRTUAL_UNRESOLVED, vpt->name, vpt->len);
/*
* FIXME - Need a tmpl_copy function to
*/
node->vpt = talloc_move(node, vpt_p);
node->flags = (xlat_flags_t) { .needs_resolving = true };
- *head = node;
- xlat_flags_merge(flags, &node->flags);
- return 0;
+ goto done;
}
virtual:
- node = xlat_exp_alloc(ctx, XLAT_VIRTUAL, vpt->name, vpt->len);
+ node = xlat_exp_alloc(head, XLAT_VIRTUAL, vpt->name, vpt->len);
node->vpt = talloc_move(node, vpt_p);
node->call.func = func;
node->flags = func->flags;
+ goto done;
- *head = node;
} else if (tmpl_is_attr_unresolved(vpt)) {
func = xlat_func_find(tmpl_attr_unresolved(vpt), -1);
if (!func) goto unresolved;
}
}
- node = xlat_exp_alloc(ctx, XLAT_TMPL, vpt->name, vpt->len);
+ node = xlat_exp_alloc(head, XLAT_TMPL, vpt->name, vpt->len);
node->vpt = talloc_move(node, vpt_p);
+done:
+ head->next = node;
+ xlat_flags_merge(flags, &node->flags);
+
+ *out = head;
return 0;
}
* - 0 on success.
* - -1 on failure.
*/
-int xlat_copy(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_exp_t const *in)
+int xlat_copy(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_exp_head_t const *in)
{
xlat_exp_t **tail;
+ xlat_exp_head_t *head;
if (!in) {
*out = NULL;
return 0;
}
- *out = NULL;
- tail = out;
+ head = xlat_exp_head_alloc(ctx);
+ tail = &head->next;
/*
* Copy everything in the list of nodes
case XLAT_INVALID:
fr_strerror_printf("Cannot copy xlat node of type \"invalid\"");
error:
- xlat_exp_list_free(out);
+ talloc_free(head);
return -1;
case XLAT_BOX:
xlat_exp_append(tail, node);
}
+ *out = head;
return 0;
}