Skip to content

Commit 39d30ad

Browse files
michalvaskobradh352
andcommitted
tree schema UPDATE function for getting leafref backlinks
Meaning all leafrefs that target a specific node. Co-authored-by: Brad House <[email protected]>
1 parent b6ea2d3 commit 39d30ad

File tree

2 files changed

+119
-1
lines changed

2 files changed

+119
-1
lines changed

src/tree_schema.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @author Michal Vasko <[email protected]>
55
* @brief libyang representation of YANG schema trees.
66
*
7-
* Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
7+
* Copyright (c) 2015 - 2025 CESNET, z.s.p.o.
88
*
99
* This source code is licensed under BSD 3-Clause License (the "License").
1010
* You may not use this file except in compliance with the License.
@@ -1927,6 +1927,20 @@ LIBYANG_API_DECL const struct lysc_node *lysc_node_lref_target(const struct lysc
19271927
*/
19281928
LIBYANG_API_DECL LY_ERR lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set);
19291929

1930+
/**
1931+
* @brief Get all the leafref (or union with leafrefs) nodes that target a specific node.
1932+
*
1933+
* @param[in] ctx Context to use, may not be set if @p node is.
1934+
* @param[in] node Leafref target node to use for matching. If not set, all the leafref nodes are just collected.
1935+
* @param[in] match_ancestors If set, @p node is considered a match not only when a leafref targets it directly but
1936+
* even when an ancestor (parent) node of @p node is a target of the leafref.
1937+
* @param[out] set Set of matching leafref nodes.
1938+
* @return LY_SUCCESS on success.
1939+
* @return LY_ERR value on error.
1940+
*/
1941+
LIBYANG_API_DECL LY_ERR lysc_node_lref_backlinks(const struct ly_ctx *ctx, const struct lysc_node *node,
1942+
ly_bool match_ancestors, struct ly_set **set);
1943+
19301944
/**
19311945
* @brief Callback to be called for every schema node in a DFS traversal.
19321946
*

src/tree_schema_common.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1892,6 +1892,110 @@ lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set)
18921892
return rc;
18931893
}
18941894

1895+
struct lysc_node_lref_backlings_arg {
1896+
const struct lysc_node *node;
1897+
ly_bool match_ancestors;
1898+
struct ly_set *set;
1899+
};
1900+
1901+
static LY_ERR
1902+
lysc_node_lref_backlinks_clb(struct lysc_node *node, void *data, ly_bool *dfs_continue)
1903+
{
1904+
LY_ERR rc = LY_SUCCESS;
1905+
struct lysc_node_lref_backlings_arg *arg = data;
1906+
struct ly_set *set = NULL;
1907+
const struct lysc_node *par;
1908+
uint32_t i;
1909+
1910+
(void)dfs_continue;
1911+
1912+
if (!(node->nodetype & LYD_NODE_TERM)) {
1913+
/* skip */
1914+
goto cleanup;
1915+
}
1916+
1917+
/* get all the leafref targets */
1918+
LY_CHECK_GOTO(rc = lysc_node_lref_targets(node, &set), cleanup);
1919+
1920+
/* ignore node if has no leafref targets */
1921+
if (!set->count) {
1922+
goto cleanup;
1923+
}
1924+
1925+
/* if just collecting leafrefs, we are done */
1926+
if (!arg->node) {
1927+
rc = ly_set_add(arg->set, node, 1, NULL);
1928+
goto cleanup;
1929+
}
1930+
1931+
/* check that the node (or the ancestor of) is the target of this leafref */
1932+
for (i = 0; i < set->count; ++i) {
1933+
for (par = set->snodes[i]; par; par = par->parent) {
1934+
if (par == arg->node) {
1935+
/* match */
1936+
break;
1937+
}
1938+
1939+
if (!arg->match_ancestors) {
1940+
/* not a match */
1941+
par = NULL;
1942+
break;
1943+
}
1944+
}
1945+
1946+
1947+
if (par) {
1948+
/* add into the set, matches */
1949+
LY_CHECK_GOTO(rc = ly_set_add(arg->set, node, 1, NULL), cleanup);
1950+
break;
1951+
}
1952+
}
1953+
1954+
cleanup:
1955+
ly_set_free(set, NULL);
1956+
return rc;
1957+
}
1958+
1959+
LIBYANG_API_DEF LY_ERR
1960+
lysc_node_lref_backlinks(const struct ly_ctx *ctx, const struct lysc_node *node, ly_bool match_ancestors,
1961+
struct ly_set **set)
1962+
{
1963+
LY_ERR rc = LY_SUCCESS;
1964+
struct lysc_node_lref_backlings_arg arg = {0};
1965+
uint32_t idx = 0;
1966+
const struct lys_module *mod;
1967+
1968+
LY_CHECK_ARG_RET(NULL, ctx || node, set, LY_EINVAL);
1969+
1970+
if (!ctx) {
1971+
ctx = node->module->ctx;
1972+
}
1973+
1974+
/* allocate return set */
1975+
LY_CHECK_RET(ly_set_new(set));
1976+
1977+
/* prepare the arg */
1978+
arg.node = node;
1979+
arg.match_ancestors = match_ancestors;
1980+
arg.set = *set;
1981+
1982+
/* iterate across all loaded modules */
1983+
while ((mod = ly_ctx_get_module_iter(ctx, &idx))) {
1984+
if (!mod->compiled) {
1985+
continue;
1986+
}
1987+
1988+
LY_CHECK_GOTO(rc = lysc_module_dfs_full(mod, lysc_node_lref_backlinks_clb, &arg), cleanup);
1989+
}
1990+
1991+
cleanup:
1992+
if (rc) {
1993+
ly_set_free(*set, NULL);
1994+
*set = NULL;
1995+
}
1996+
return rc;
1997+
}
1998+
18951999
enum ly_stmt
18962000
lysp_match_kw(struct ly_in *in, uint64_t *indent)
18972001
{

0 commit comments

Comments
 (0)