From: Nick Porter Date: Thu, 11 Aug 2022 11:11:15 +0000 (+0100) Subject: Add fr_pair_find_by_da_nested() to find pairs by their da structure X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e45713609eb248389ddb2e4b516e2d9897372b3d;p=thirdparty%2Ffreeradius-server.git Add fr_pair_find_by_da_nested() to find pairs by their da structure --- diff --git a/src/lib/util/pair.c b/src/lib/util/pair.c index 09c45e8553f..51d69d764ca 100644 --- a/src/lib/util/pair.c +++ b/src/lib/util/pair.c @@ -696,6 +696,104 @@ fr_pair_t *fr_pair_find_by_da_idx(fr_pair_list_t const *list, fr_dict_attr_t con return NULL; } +/** Find a pair with a matching da walking the nested da tree + * + * The list should be the one containing the top level attributes. + * + * @param[in] list to search in. + * @param[in] prev pair to start searching from. + * @param[in] da the next da to find. + * @return + * - first matching fr_pair_t. + * - NULL if no fr_pair_ts match. + */ +fr_pair_t *fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da) +{ + fr_pair_t *vp; + fr_dict_attr_t const **find; /* DA currently being looked for */ + fr_pair_list_t const *cur_list; /* Current list being searched */ + fr_da_stack_t da_stack; + + if (fr_pair_list_empty(list)) return NULL; + + /* + * In the common case, we're looking for attributes in + * the root (at level 1), so we just skip to a special + * function for that + */ + if (da->depth <= 1) return fr_pair_find_by_da(list, prev, da); + + fr_proto_da_stack_build(&da_stack, da); + + /* + * Find the relevant starting point for `prev` + */ + if (prev) { + cur_list = fr_pair_parent_list(prev); + find = &da_stack.da[prev->da->depth - 1]; + vp = UNCONST(fr_pair_t *, prev); + } else { + cur_list = list; + find = &da_stack.da[0]; + vp = NULL; + } + + /* + * Loop over the list at each level until we find a matching da. + */ + while (true) { + fr_pair_t *next; + + fr_assert((*find)->depth <= da->depth); + + /* + * Find a vp which matches a given da. If found, + * recurse into the child list to find the child + * attribute. + * + */ + next = fr_pair_find_by_da(cur_list, vp, *find); + if (next) { + /* + * We've found a match for the requested + * da - return it. + */ + if ((*find) == da) return next; + + /* + * Prepare to search the next level. + */ + cur_list = &next->vp_group; + find++; + vp = NULL; + continue; + } + + /* + * We hit the end of the top-level list. Therefore we found nothing. + */ + if (cur_list == list) break; + + /* + * We hit the end of *A* list. Go to the parent + * VP, and then find its list. + * + * We still then have to go to the next attribute + * in the parent list, as we've checked all of the + * children of this VP. + */ + find--; + vp = fr_pair_list_parent(cur_list); + cur_list = fr_pair_parent_list(vp); + } + + /* + * Compatiblitity with flat atttrbutes + */ + if (fr_pair_parent_list(prev) != list) prev = NULL; + return fr_pair_find_by_da(list, prev, da); +} + /** Find a pair which has the specified ancestor * * @param[in] list to search in. diff --git a/src/lib/util/pair.h b/src/lib/util/pair.h index ae295d4bd04..112099b4b52 100644 --- a/src/lib/util/pair.h +++ b/src/lib/util/pair.h @@ -408,6 +408,9 @@ fr_pair_t *fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t *fr_pair_find_by_da_idx(fr_pair_list_t const *list, fr_dict_attr_t const *da, unsigned int idx) CC_HINT(nonnull); +fr_pair_t *fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, + fr_dict_attr_t const *da) CC_HINT(nonnull(1,3)); + fr_pair_t *fr_pair_find_by_ancestor(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *ancestor) CC_HINT(nonnull(1,3));