From: Alan T. DeKok Date: Wed, 27 Apr 2022 17:18:22 +0000 (-0400) Subject: move xlat_exp_head_t to it's own data structure X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cfab6e575136ab19bacad4b06ca743518aaa907f;p=thirdparty%2Ffreeradius-server.git move xlat_exp_head_t to it's own data structure fmt and flags are not yet filled out --- diff --git a/src/bin/unit_test_module.c b/src/bin/unit_test_module.c index 62cd7d144c3..8326882713c 100644 --- a/src/bin/unit_test_module.c +++ b/src/bin/unit_test_module.c @@ -446,7 +446,7 @@ static bool do_xlats(fr_event_list_t *el, char const *filename, FILE *fp) 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; diff --git a/src/lib/server/tmpl_tokenize.c b/src/lib/server/tmpl_tokenize.c index 3aac7abaae9..d1799033140 100644 --- a/src/lib/server/tmpl_tokenize.c +++ b/src/lib/server/tmpl_tokenize.c @@ -2895,7 +2895,7 @@ ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, * 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); @@ -3568,7 +3568,7 @@ static inline CC_HINT(always_inline) int tmpl_attr_resolve(tmpl_t *vpt, tmpl_res 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 @@ -3682,7 +3682,7 @@ void tmpl_unresolve(tmpl_t *vpt) 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: diff --git a/src/lib/unlang/module.c b/src/lib/unlang/module.c index 06a3d75a070..c88762d30c8 100644 --- a/src/lib/unlang/module.c +++ b/src/lib/unlang/module.c @@ -442,7 +442,7 @@ int unlang_module_set_resume(request_t *request, unlang_module_resume_t resume) * - 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) { diff --git a/src/lib/unlang/module.h b/src/lib/unlang/module.h index 156dc55f795..6f0d52498b9 100644 --- a/src/lib/unlang/module.h +++ b/src/lib/unlang/module.h @@ -122,7 +122,7 @@ unlang_action_t unlang_module_yield_to_section(rlm_rcode_t *p_result, 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); diff --git a/src/lib/unlang/xlat.c b/src/lib/unlang/xlat.c index 8b5b4db5e9f..7edace23758 100644 --- a/src/lib/unlang/xlat.c +++ b/src/lib/unlang/xlat.c @@ -226,7 +226,7 @@ int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out, * 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; diff --git a/src/lib/unlang/xlat.h b/src/lib/unlang/xlat.h index 43cb1528858..68da41a4c81 100644 --- a/src/lib/unlang/xlat.h +++ b/src/lib/unlang/xlat.h @@ -326,7 +326,7 @@ bool xlat_is_literal(xlat_exp_head_t const *head); 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); @@ -384,7 +384,7 @@ tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t *xlat); 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 @@ -401,7 +401,7 @@ void xlat_thread_detach(void); 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); diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index 0829e20575c..e08e1a382cc 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -548,7 +548,7 @@ typedef struct { 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. @@ -557,9 +557,9 @@ typedef struct { 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 @@ -682,12 +682,12 @@ static int xlat_redundant_instantiate(xlat_inst_ctx_t const *xctx) 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 @@ -702,7 +702,7 @@ static int xlat_redundant_instantiate(xlat_inst_ctx_t const *xctx) 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); @@ -712,7 +712,7 @@ static int xlat_redundant_instantiate(xlat_inst_ctx_t const *xctx) 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; @@ -726,15 +726,16 @@ static int xlat_redundant_instantiate(xlat_inst_ctx_t const *xctx) */ 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; @@ -746,7 +747,8 @@ static int xlat_redundant_instantiate(xlat_inst_ctx_t const *xctx) * 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: @@ -775,8 +777,8 @@ static int xlat_redundant_instantiate(xlat_inst_ctx_t const *xctx) * they'll get called at some point after * we return. */ - xlat_bootstrap(node); - xri->ex[num++] = node; + xlat_bootstrap(head); + xri->ex[num++] = head; } /* @@ -1523,7 +1525,7 @@ static xlat_action_t xlat_func_next_time(TALLOC_CTX *ctx, fr_dcursor_t *out, 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 @@ -1611,7 +1613,7 @@ static xlat_action_t xlat_func_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, * 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; diff --git a/src/lib/unlang/xlat_ctx.h b/src/lib/unlang/xlat_ctx.h index 59bbab437ba..8aae87a1f10 100644 --- a/src/lib/unlang/xlat_ctx.h +++ b/src/lib/unlang/xlat_ctx.h @@ -33,7 +33,7 @@ extern "C" { /* 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 * diff --git a/src/lib/unlang/xlat_eval.c b/src/lib/unlang/xlat_eval.c index 5caef96fe8d..c638baaae40 100644 --- a/src/lib/unlang/xlat_eval.c +++ b/src/lib/unlang/xlat_eval.c @@ -1619,8 +1619,6 @@ int xlat_aeval_compiled_argv(TALLOC_CTX *ctx, char ***argv, request_t *request, char **my_argv; size_t count; - if (!xlat_exp_is_head(head)) return -1; - count = 0; xlat_exp_foreach(head, node) { count++; @@ -1654,8 +1652,6 @@ int xlat_flatten_compiled_argv(TALLOC_CTX *ctx, xlat_exp_head_t const ***argv, x 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++; diff --git a/src/lib/unlang/xlat_expr.c b/src/lib/unlang/xlat_expr.c index eac448efe98..4925da3f9db 100644 --- a/src/lib/unlang/xlat_expr.c +++ b/src/lib/unlang/xlat_expr.c @@ -30,6 +30,13 @@ RCSID("$Id$") #include #include +#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. @@ -99,9 +106,10 @@ static fr_slen_t xlat_expr_print_unary(fr_sbuff_t *out, xlat_exp_t const *node, 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 @@ -109,7 +117,8 @@ static fr_slen_t xlat_expr_print_binary(fr_sbuff_t *out, xlat_exp_t const *node, */ 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, ')'); @@ -157,7 +166,7 @@ static int CC_HINT(nonnull) xlat_purify_expr(xlat_exp_t *node) 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; } @@ -175,9 +184,9 @@ static int CC_HINT(nonnull) xlat_purify_expr(xlat_exp_t *node) 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; @@ -236,7 +245,8 @@ static xlat_exp_t *xlat_groupify_node(TALLOC_CTX *ctx, xlat_exp_t *node) 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) { @@ -247,30 +257,6 @@ static xlat_exp_t *xlat_groupify_node(TALLOC_CTX *ctx, xlat_exp_t *node) 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 }, @@ -395,13 +381,14 @@ static void cast_to_bool(bool *out, fr_value_box_t const *in) } 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; @@ -409,24 +396,36 @@ static fr_slen_t xlat_expr_print_logical(fr_sbuff_t *out, xlat_exp_t const *node { 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, ')'); @@ -434,12 +433,37 @@ static fr_slen_t xlat_expr_print_logical(fr_sbuff_t *out, xlat_exp_t const *node 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; @@ -508,12 +532,12 @@ static xlat_action_t xlat_logical_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, } 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. @@ -521,7 +545,7 @@ static xlat_action_t xlat_logical_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, 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; } @@ -535,7 +559,7 @@ static xlat_action_t xlat_func_logical(TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out 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) { @@ -545,7 +569,7 @@ static xlat_action_t xlat_func_logical(TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out } 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; } @@ -770,7 +794,7 @@ static const int precedence[T_TOKEN_LAST] = { 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); @@ -784,7 +808,7 @@ static fr_table_num_sorted_t const expr_quote_table[] = { 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; @@ -850,7 +874,7 @@ static ssize_t tokenize_regex(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flag if (slen <= 0) goto error; } - *head = node; + *out = node; xlat_flags_merge(flags, &node->flags); return fr_sbuff_used(&our_in); @@ -871,7 +895,7 @@ static ssize_t tokenize_regex(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flag * 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) { @@ -887,6 +911,8 @@ static ssize_t tokenize_field(TALLOC_CTX *input_ctx, xlat_exp_head_t **head, xla 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 @@ -1076,12 +1102,17 @@ done: * @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); @@ -1127,7 +1158,7 @@ static size_t const expr_assignment_op_table_len = NUM_ELEMENTS(expr_assignment_ * !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) { @@ -1137,6 +1168,9 @@ static ssize_t tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat 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); @@ -1160,7 +1194,7 @@ redo: */ if (fr_sbuff_extend(&our_in) == 0) { done: - *head = lhs; + *out = lhs; return fr_sbuff_set(in, &our_in); } @@ -1189,6 +1223,7 @@ redo: /* * 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); @@ -1251,6 +1286,7 @@ redo: /* * 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); @@ -1278,7 +1314,9 @@ redo: 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. @@ -1307,11 +1345,12 @@ redo: 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); @@ -1326,11 +1365,6 @@ redo: } } - /* - * Ensure that the various nodes are grouped properly. - */ - xlat_groupify_expr(node); - lhs = node; goto redo; } @@ -1361,7 +1395,7 @@ static const fr_sbuff_term_t operator_terms = FR_SBUFF_TERMS( 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; @@ -1369,6 +1403,7 @@ ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_f 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 @@ -1399,9 +1434,9 @@ ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_f 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); @@ -1410,8 +1445,8 @@ ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_f /* * 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; } @@ -1419,11 +1454,12 @@ ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_f * 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; } @@ -1433,7 +1469,7 @@ ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_f * 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. @@ -1445,7 +1481,7 @@ ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_f * - 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) @@ -1455,6 +1491,7 @@ ssize_t xlat_tokenize_ephemeral_expression(TALLOC_CTX *ctx, xlat_exp_head_t **he 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 @@ -1488,9 +1525,9 @@ ssize_t xlat_tokenize_ephemeral_expression(TALLOC_CTX *ctx, xlat_exp_head_t **he } 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); @@ -1499,19 +1536,20 @@ ssize_t xlat_tokenize_ephemeral_expression(TALLOC_CTX *ctx, xlat_exp_head_t **he /* * 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; } diff --git a/src/lib/unlang/xlat_inst.c b/src/lib/unlang/xlat_inst.c index 529814005a1..47ecc6154d1 100644 --- a/src/lib/unlang/xlat_inst.c +++ b/src/lib/unlang/xlat_inst.c @@ -513,9 +513,9 @@ static int _xlat_bootstrap_walker(xlat_exp_t *node, UNUSED void *uctx) * 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 @@ -533,7 +533,7 @@ int xlat_bootstrap(xlat_exp_t *root) * 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 diff --git a/src/lib/unlang/xlat_priv.h b/src/lib/unlang/xlat_priv.h index d9942a5f9f9..64b5f61b78d 100644 --- a/src/lib/unlang/xlat_priv.h +++ b/src/lib/unlang/xlat_priv.h @@ -148,6 +148,13 @@ struct xlat_exp { }; }; +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. @@ -314,17 +321,21 @@ int xlat_register_expressions(void); /* * 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 @@ -343,11 +354,9 @@ static inline xlat_exp_t *xlat_exp_next(UNUSED xlat_exp_head_t const *head, xlat 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 diff --git a/src/lib/unlang/xlat_tokenize.c b/src/lib/unlang/xlat_tokenize.c index 398a8aa5d2a..a3d8b5e1505 100644 --- a/src/lib/unlang/xlat_tokenize.c +++ b/src/lib/unlang/xlat_tokenize.c @@ -33,7 +33,6 @@ RCSID("$Id$") #include #include - #undef XLAT_DEBUG #undef XLAT_HEXDUMP #ifdef DEBUG_XLAT @@ -116,7 +115,7 @@ static fr_sbuff_parse_rules_t const xlat_multi_arg_rules = { * @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; @@ -167,11 +166,11 @@ void xlat_exp_free(xlat_exp_head_t **head) *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; @@ -180,16 +179,17 @@ static inline int xlat_tokenize_alternation(TALLOC_CTX *ctx, xlat_exp_t **head, 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, ":-")) { @@ -201,19 +201,18 @@ static inline int xlat_tokenize_alternation(TALLOC_CTX *ctx, xlat_exp_t **head, * 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; @@ -225,7 +224,7 @@ static inline int xlat_tokenize_alternation(TALLOC_CTX *ctx, xlat_exp_t **head, } xlat_flags_merge(flags, &node->flags); - *head = node; + *out = node; return 0; } @@ -237,7 +236,7 @@ static inline int xlat_tokenize_alternation(TALLOC_CTX *ctx, xlat_exp_t **head, * @verbatim %{} @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; @@ -280,7 +279,7 @@ static inline int xlat_tokenize_regex(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_f fr_sbuff_next(in); /* Skip '}' */ xlat_flags_merge(flags, &node->flags); - *head = node; + *out = node; return 0; } @@ -307,7 +306,7 @@ int xlat_validate_function_mono(xlat_exp_t *node) * - 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) { @@ -324,7 +323,7 @@ static inline int xlat_tokenize_function_mono(TALLOC_CTX *ctx, xlat_exp_t **head ['.'] = 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} @@ -335,7 +334,7 @@ static inline int xlat_tokenize_function_mono(TALLOC_CTX *ctx, xlat_exp_t **head 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; @@ -346,7 +345,8 @@ static inline int xlat_tokenize_function_mono(TALLOC_CTX *ctx, xlat_exp_t **head /* * 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"); @@ -359,7 +359,6 @@ static inline int xlat_tokenize_function_mono(TALLOC_CTX *ctx, xlat_exp_t **head fr_strerror_const("Function takes defined arguments and should " "be called using %(func:args) syntax"); error: - head = NULL; talloc_free(node); return -1; } @@ -386,7 +385,7 @@ static inline int xlat_tokenize_function_mono(TALLOC_CTX *ctx, xlat_exp_t **head * 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; } @@ -401,7 +400,7 @@ static inline int xlat_tokenize_function_mono(TALLOC_CTX *ctx, xlat_exp_t **head } xlat_flags_merge(flags, &node->flags); - *head = node; + *out = node; return 0; } @@ -443,7 +442,7 @@ int xlat_validate_function_args(xlat_exp_t *node) * - 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) { @@ -460,7 +459,7 @@ int xlat_tokenize_function_args(TALLOC_CTX *ctx, xlat_exp_t **head, ['.'] = 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) @@ -471,7 +470,7 @@ int xlat_tokenize_function_args(TALLOC_CTX *ctx, xlat_exp_t **head, 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; @@ -535,7 +534,7 @@ int xlat_tokenize_function_args(TALLOC_CTX *ctx, xlat_exp_t **head, } xlat_flags_merge(flags, &node->flags); - *head = node; + *out = node; return 0; } @@ -565,7 +564,7 @@ static int xlat_resolve_virtual_attribute(xlat_exp_t *node, tmpl_t *vpt) /** 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; @@ -611,7 +610,7 @@ static inline int xlat_tokenize_attribute(TALLOC_CTX *ctx, xlat_exp_t **head, xl */ 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; @@ -686,12 +685,12 @@ done: } 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; @@ -716,14 +715,14 @@ int xlat_tokenize_expansion(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *fl * %{...}:-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); } /* @@ -739,7 +738,7 @@ int xlat_tokenize_expansion(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *fl * Handle regex's %{} 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 */ @@ -800,7 +799,7 @@ int xlat_tokenize_expansion(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *fl 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; @@ -816,7 +815,7 @@ int xlat_tokenize_expansion(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *fl 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; /* @@ -872,7 +871,7 @@ static void xlat_exp_list_free(xlat_exp_t **head) * 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. @@ -882,7 +881,7 @@ static void xlat_exp_list_free(xlat_exp_t **head) * - 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) { @@ -911,10 +910,12 @@ static int xlat_tokenize_string(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t ); 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 ? @@ -949,7 +950,7 @@ static int xlat_tokenize_string(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t } else if (slen < 0) { error: talloc_free(node); - xlat_exp_list_free(head); + xlat_exp_list_free(&head); /* * Free our temporary array of terminals @@ -1028,6 +1029,7 @@ static int xlat_tokenize_string(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t */ if (tokens != &expansions) talloc_free(tokens); + *out = head; return 0; } @@ -1286,7 +1288,7 @@ done: * @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); @@ -1306,7 +1308,7 @@ ssize_t xlat_print(fr_sbuff_t *out, xlat_exp_t const *head, fr_sbuff_escape_rule * 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. @@ -1318,7 +1320,7 @@ ssize_t xlat_print(fr_sbuff_t *out, xlat_exp_t const *head, fr_sbuff_escape_rule * - 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) @@ -1326,36 +1328,38 @@ ssize_t xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_head_t **head, 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); } @@ -1365,7 +1369,7 @@ ssize_t xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_head_t **head, * 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. @@ -1376,7 +1380,7 @@ ssize_t xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_head_t **head, * - <=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); @@ -1386,11 +1390,12 @@ ssize_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t 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 */ @@ -1425,8 +1430,9 @@ ssize_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t * 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) { @@ -1434,14 +1440,13 @@ ssize_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t * 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 */ } @@ -1452,7 +1457,7 @@ ssize_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t * "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; @@ -1463,17 +1468,18 @@ ssize_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t 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; @@ -1528,13 +1534,14 @@ ssize_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t 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 @@ -1546,25 +1553,27 @@ ssize_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t * - 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); } @@ -1572,11 +1581,12 @@ ssize_t xlat_tokenize(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *fla * 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); } @@ -1647,7 +1657,7 @@ bool xlat_to_string(TALLOC_CTX *ctx, char **str, xlat_exp_head_t **head) * - 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; @@ -1659,12 +1669,12 @@ int xlat_resolve(xlat_exp_head_t **head, xlat_flags_t *flags, xlat_res_rules_t c 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; /* @@ -1676,8 +1686,8 @@ int xlat_resolve(xlat_exp_head_t **head, xlat_flags_t *flags, xlat_res_rules_t c { 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; @@ -1688,7 +1698,7 @@ int xlat_resolve(xlat_exp_head_t **head, xlat_flags_t *flags, xlat_res_rules_t c * 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; /* @@ -1704,7 +1714,7 @@ int xlat_resolve(xlat_exp_head_t **head, xlat_flags_t *flags, xlat_res_rules_t c * 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 @@ -1831,16 +1841,17 @@ int xlat_resolve(xlat_exp_head_t **head, xlat_flags_t *flags, xlat_res_rules_t c /** 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 @@ -1861,7 +1872,7 @@ tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *node) /** 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 @@ -1869,14 +1880,17 @@ tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *node) * - 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. @@ -1886,7 +1900,7 @@ int xlat_from_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *f 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 @@ -1895,18 +1909,16 @@ int xlat_from_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *f */ 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; @@ -1914,9 +1926,14 @@ int xlat_from_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *f } } - 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; } @@ -1929,17 +1946,18 @@ int xlat_from_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t **head, xlat_flags_t *f * - 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 @@ -1955,7 +1973,7 @@ int xlat_copy(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_exp_t const *in) 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: @@ -2007,5 +2025,6 @@ int xlat_copy(TALLOC_CTX *ctx, xlat_exp_t **out, xlat_exp_t const *in) xlat_exp_append(tail, node); } + *out = head; return 0; }