From: Alan T. DeKok Date: Mon, 18 Jul 2022 16:30:57 +0000 (-0400) Subject: start of parent / child relationships for nested edit sections X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fcf9f2b3a0b8fcb574a255e751c631b925842baa;p=thirdparty%2Ffreeradius-server.git start of parent / child relationships for nested edit sections --- diff --git a/src/lib/unlang/edit.c b/src/lib/unlang/edit.c index 7027a16e556..5175f5c0324 100644 --- a/src/lib/unlang/edit.c +++ b/src/lib/unlang/edit.c @@ -49,14 +49,21 @@ typedef struct { fr_pair_list_t pair_list; //!< for structural attributes } edit_result_t; -typedef struct { +typedef struct edit_map_s edit_map_t; + +struct edit_map_s { + edit_map_t *parent; + edit_map_t *child; + + fr_pair_t *vp_parent; + unlang_edit_state_t state; //!< What we're currently doing. map_list_t const *map_head; map_t const *map; //!< the map to evaluate edit_result_t lhs; //!< LHS child entries edit_result_t rhs; //!< RHS child entries -} edit_map_t; +}; /** State of an edit block * @@ -64,7 +71,8 @@ typedef struct { typedef struct { fr_edit_list_t *el; //!< edit list - edit_map_t current; //!< what we're currently doing. + edit_map_t *current; //!< what we're currently doing. + edit_map_t first; } unlang_frame_state_edit_t; static int templatize_lhs(TALLOC_CTX *ctx, edit_result_t *out, request_t *request) CC_HINT(nonnull); @@ -510,22 +518,6 @@ leaf: return 0; } -static int expand_rhs_list( request_t *request, NDEBUG_UNUSED edit_map_t *current, map_t const *map) -{ - if (map->op != T_OP_SET) { - REDEBUG("Operator not implemented"); - return -1; - } - - if (!map_list_empty(&map->child)) { - REDEBUG("In-place lists not yet implemented"); - return -1; - } - - fr_assert(fr_pair_list_empty(¤t->rhs.pair_list)); - - return 0; -} /** Create a list of modifications to apply to one or more fr_pair_t lists * @@ -540,10 +532,11 @@ static int expand_rhs_list( request_t *request, NDEBUG_UNUSED edit_map_t *curren static unlang_action_t process_edit(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame) { unlang_frame_state_edit_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_edit_t); - edit_map_t *current = &state->current; + edit_map_t *current = state->current; map_t const *map; int rcode; +redo: /* * Iterate over the maps, expanding the LHS and RHS. */ @@ -590,9 +583,6 @@ static unlang_action_t process_edit(rlm_rcode_t *p_result, request_t *request, u case UNLANG_EDIT_CHECK_LHS: check_lhs: - /* - * Find the LHS VP to edit. - */ if (tmpl_find_vp(¤t->lhs.vp, request, current->lhs.vpt) < 0) { fr_pair_t *parent; @@ -606,9 +596,6 @@ static unlang_action_t process_edit(rlm_rcode_t *p_result, request_t *request, u fr_assert(!tmpl_is_list(current->lhs.vpt)); - /* - * The VP doesn't exist, get the list it's in. - */ parent = tmpl_get_list(request, current->lhs.vpt); if (!parent) { REDEBUG("Failed to find list for %s", current->lhs.vpt->name); @@ -635,15 +622,55 @@ static unlang_action_t process_edit(rlm_rcode_t *p_result, request_t *request, u * Structural attributes MAY have a RHS. */ if (!map->rhs) { + edit_map_t *child = current->child; + if (fr_type_is_leaf(current->lhs.vp->vp_type)) { REDEBUG("Cannot assign list as a value"); goto error; } - rcode = expand_rhs_list(request, current, map); - if (rcode < 0) goto error; + /* + * Fast path: child is empty, we don't need to do anything. + */ + if (fr_dlist_empty(&map->child.head)) { + fr_pair_list_empty(¤t->rhs.pair_list); + goto check_rhs; + } + + fr_assert(0); /* not done! */ + + /* + * Allocate a new child structure if necessary. + */ + if (!child) { + MEM(child = talloc_zero(state, edit_map_t)); + current->child = child; + child->parent = current; + } + + /* + * Initialize the child structure. + */ + child->state = UNLANG_EDIT_INIT; + child->vp_parent = current->lhs.vp; + child->map_head = &map->child; + child->map = map_list_head(child->map_head); + child->vp_parent = current->lhs.vp; - goto check_rhs; + memset(&child->lhs, 0, sizeof(child->lhs)); + memset(&child->rhs, 0, sizeof(child->rhs)); + + fr_pair_list_init(&child->rhs.pair_list); + fr_value_box_list_init(&child->lhs.result); + fr_value_box_list_init(&child->rhs.result); + + /* + * Continue back with the expanded RHS when we're done expanding the + * child. The go process the child. + */ + current->state = UNLANG_EDIT_EXPANDED_RHS; + state->current = child; + goto redo; } rcode = template_realize(state, ¤t->rhs.result, request, map->rhs); @@ -683,6 +710,14 @@ static unlang_action_t process_edit(rlm_rcode_t *p_result, request_t *request, u } /* loop over the map */ + /* + * There's a parent map, go update that. + */ + if (current->parent) { + state->current = current->parent; + goto redo; + } + /* * Freeing the edit list will automatically commit the edits. */ @@ -707,8 +742,9 @@ static unlang_action_t unlang_edit_state_init(rlm_rcode_t *p_result, request_t * { unlang_edit_t *edit = unlang_generic_to_edit(frame->instruction); unlang_frame_state_edit_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_edit_t); - edit_map_t *current = &state->current; + edit_map_t *current = &state->first; + state->current = current; fr_value_box_list_init(¤t->lhs.result); fr_value_box_list_init(¤t->rhs.result);