From: Alan T. DeKok Date: Sun, 12 Dec 2021 15:08:13 +0000 (-0500) Subject: allow &list := {} to clear the list X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=17545aef7ed1083d52c8e98b982fbfa123d1c419;p=thirdparty%2Ffreeradius-server.git allow &list := {} to clear the list which makes a bit more sense than the previous !*ANY --- diff --git a/src/lib/unlang/edit.c b/src/lib/unlang/edit.c index e2eabebf45..46fd16a793 100644 --- a/src/lib/unlang/edit.c +++ b/src/lib/unlang/edit.c @@ -238,12 +238,17 @@ static int apply_edits(request_t *request, unlang_frame_state_edit_t *state, map fr_pair_list_t *children; fr_value_box_t const *rhs_box = NULL; - fr_assert(state->rhs.vpt != NULL); fr_assert(state->lhs.vp != NULL); #ifdef __clang_analyzer__ if (!state->lhs.vp) return -1; #endif + + if (!state->rhs.vpt) { + children = &state->rhs.pair_list; + goto apply_list; + } + /* * Get the resulting value box. */ @@ -356,12 +361,22 @@ static int apply_edits(request_t *request, unlang_frame_state_edit_t *state, map * Apply structural thingies! */ apply_list: - RDEBUG2("%s %s %s", state->lhs.vpt->name, fr_tokens[map->op], state->rhs.vpt->name); + if (state->rhs.vpt) { + RDEBUG2("%s %s %s", state->lhs.vpt->name, fr_tokens[map->op], state->rhs.vpt->name); + } else { + fr_assert(children != NULL); - if (fr_debug_lvl >= L_DBG_LVL_3) { - RINDENT(); - fr_pair_list_debug(children); - REXDENT(); + /* + * @todo - we need a debug function which takes a request list... + */ + RDEBUG2("%s %s {", state->lhs.vpt->name, fr_tokens[map->op]); + if (fr_debug_lvl >= L_DBG_LVL_3) { + RINDENT(); + fr_pair_list_debug(children); + REXDENT(); + } + + RDEBUG2("}", state->lhs.vpt->name, fr_tokens[map->op]); } if (fr_edit_list_apply_list_assignment(state->el, @@ -407,6 +422,22 @@ leaf: return 0; } +static int expand_rhs_list(unlang_frame_state_edit_t *state, request_t *request, map_t const *map) +{ + if (map->op != T_OP_SET) { + REDEBUG("Operator not implemented"); + return -1; + } + + if (!fr_map_list_empty(&map->child)) { + REDEBUG("In-place lists not yet implemented"); + return -1; + } + + fr_assert(fr_pair_list_empty(&state->rhs.pair_list)); + + return 0; +} /** Create a list of modifications to apply to one or more fr_pair_t lists * @@ -488,6 +519,22 @@ static unlang_action_t process_edit(rlm_rcode_t *p_result, request_t *request, u goto error; } + /* + * Leaf attributes MUST have a RHS. + * Structural attributes MAY have a RHS. + */ + if (!map->rhs) { + if (fr_type_is_leaf(state->lhs.vp->vp_type)) { + REDEBUG("Cannot assign list as a value"); + goto error; + } + + rcode = expand_rhs_list(state, request, map); + if (rcode < 0) goto error; + + goto check_rhs; + } + rcode = template_realize(state, &state->rhs.result, request, map->rhs); if (rcode < 0) goto error; diff --git a/src/tests/keywords/edit-list-reset b/src/tests/keywords/edit-list-reset new file mode 100644 index 0000000000..ab78d70e05 --- /dev/null +++ b/src/tests/keywords/edit-list-reset @@ -0,0 +1,25 @@ +# +# PRE: edit-list +# + +update control { + &Tmp-String-0 := "foo" +} + +# must exist +if (!&control.Tmp-String-0) { + test_fail +} + +# +# Reset the list to empty contents +# +&control := {} + +# must not exist +if (&control.Tmp-String-0) { + test_fail +} + + +success