From: Alan T. DeKok Date: Thu, 19 May 2022 18:28:50 +0000 (-0400) Subject: add xlat_purify() function X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=613f3a9aab1f39dbeaa8b18d08aa0e18c9dfb005;p=thirdparty%2Ffreeradius-server.git add xlat_purify() function for now, it calls unlang_interpret_synchronous(). We'll fix that later. --- diff --git a/src/lib/unlang/all.mk b/src/lib/unlang/all.mk index 11ff07fce29..4b60200183f 100644 --- a/src/lib/unlang/all.mk +++ b/src/lib/unlang/all.mk @@ -28,7 +28,8 @@ SOURCES := base.c \ xlat_expr.c \ xlat_inst.c \ xlat_tokenize.c \ - xlat_pair.c + xlat_pair.c \ + xlat_purify.c HEADERS := $(subst src/lib/,,$(wildcard src/lib/unlang/*.h)) diff --git a/src/lib/unlang/xlat_priv.h b/src/lib/unlang/xlat_priv.h index 4ce34148576..9c70701e447 100644 --- a/src/lib/unlang/xlat_priv.h +++ b/src/lib/unlang/xlat_priv.h @@ -31,6 +31,7 @@ extern "C" { #endif #include +#include #ifdef DEBUG_XLAT # define XLAT_DEBUG RDEBUG3 @@ -333,6 +334,10 @@ int xlat_tokenize_function_args(xlat_exp_head_t *head, fr_sbuff_t *in, 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); +/* + * xlat_purify.c + */ +int xlat_purify(xlat_exp_head_t *head, unlang_interpret_t *intp); static inline xlat_exp_t *xlat_exp_head(xlat_exp_head_t const *head) diff --git a/src/lib/unlang/xlat_purify.c b/src/lib/unlang/xlat_purify.c new file mode 100644 index 00000000000..5e2c7c65761 --- /dev/null +++ b/src/lib/unlang/xlat_purify.c @@ -0,0 +1,154 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @file xlat_purify.c + * @brief Purification functions for xlats + * + * @copyright 2022 The FreeRADIUS server project + * @copyright 2022 Network RADIUS SAS (legal@networkradius.com) + */ + +RCSID("$Id$") + +#include +#include + +static void xlat_value_list_to_xlat(xlat_exp_head_t *head, fr_value_box_list_t *list) +{ + fr_value_box_t *box; + xlat_exp_t *node; + + while ((box = fr_dlist_pop_head(list)) != NULL) { + MEM(node = xlat_exp_alloc_null(head)); + node->type = XLAT_BOX; + node->fmt = ""; /* @todo - fixme? */ + fr_value_box_copy(node, &node->data, box); + talloc_free(box); + + xlat_exp_insert_tail(head, node); + } +} + + +static int xlat_purify_list(xlat_exp_head_t *head, request_t *request) +{ + int rcode; + bool success; + xlat_exp_head_t *group; + fr_value_box_list_t list; + + if (!head->flags.can_purify) return 0; + + /* + * We can't purify things which need resolving, + */ + if (head->flags.needs_resolving) return -1; + + xlat_exp_foreach(head, node) { + if (!node->flags.can_purify) continue; + + switch (node->type) { + default: + fr_strerror_printf("Internal error - cannot purify xlat"); + return -1; + + case XLAT_GROUP: + rcode = xlat_purify_list(node->group, request); + if (rcode < 0) return rcode; + + xlat_flags_merge(&node->flags, &node->group->flags); + break; + + + case XLAT_ALTERNATE: + if (node->alternate[0]->flags.can_purify) { + rcode = xlat_purify_list(node->alternate[0], request); + if (rcode < 0) return rcode; + } + + /* + * @todo - If the RHS of the alternation + * is now pure, then we can statically + * evaluate it, and replace this node + * with the children. But only if the + * child list is not empty. + */ + + if (node->alternate[1]->flags.can_purify) { + rcode = xlat_purify_list(node->alternate[1], request); + if (rcode < 0) return rcode; + } + break; + + case XLAT_FUNC: + if (unlang_xlat_push_node(node->call.args, &success, &list, request, node) < 0) { + return -1; + } + + /* + * Hope to god it doesn't yield. :) + */ + success = false; + (void) unlang_interpret_synchronous(NULL, request); + if (!success) return -1; + + /* + * The function call becomes a GROUP of + * boxes. We just re-use the argument head, which is already of the type we need. + */ + group = node->call.args; + fr_dlist_talloc_free(&group->dlist); + node->type = XLAT_GROUP; + node->group = group; + + xlat_value_list_to_xlat(group, &list); + break; + } + + node->flags.can_purify = false; + xlat_flags_merge(&head->flags, &node->flags); + } + + head->flags.can_purify = false; + return 0; +} + +/** Purify an xlat + * + * @param head the xlat to be purified + * @param intp the interpreter to use. + * + */ +int xlat_purify(xlat_exp_head_t *head, unlang_interpret_t *intp) +{ + int rcode; + request_t *request; + + if (!head->flags.can_purify) return 0; + + request = request_alloc_internal(NULL, (&(request_init_args_t){ .namespace = head->dict })); + if (!request) return -1; + + if (intp) unlang_interpret_set(request, intp); + + rcode = xlat_purify_list(head, request); + talloc_free(request); + + return rcode; +}