data tree FEATURE data merge with callback
Also, dup-inst list handling added with tests.
diff --git a/src/tree_data.c b/src/tree_data.c
index 83abaf2..d89e920 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -3513,28 +3513,49 @@
* @param[in,out] first_trg First target sibling, is updated if top-level.
* @param[in] parent_trg Target parent.
* @param[in,out] sibling_src Source sibling to merge, set to NULL if spent.
+ * @param[in] merge_cb Optional merge callback.
+ * @param[in] cb_data Arbitrary callback data.
* @param[in] options Merge options.
+ * @param[in,out] dup_inst Duplicate instance cache for all @p first_trg siblings.
* @return LY_ERR value.
*/
static LY_ERR
lyd_merge_sibling_r(struct lyd_node **first_trg, struct lyd_node *parent_trg, const struct lyd_node **sibling_src_p,
- uint16_t options)
+ lyd_merge_cb merge_cb, void *cb_data, uint16_t options, struct lyd_dup_inst **dup_inst)
{
- LY_ERR ret;
const struct lyd_node *child_src, *tmp, *sibling_src;
struct lyd_node *match_trg, *dup_src, *elem;
struct lysc_type *type;
+ struct lyd_dup_inst *child_dup_inst = NULL;
+ LY_ERR ret;
+ ly_bool first_inst = 0;
sibling_src = *sibling_src_p;
- if (sibling_src->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
+ if (!sibling_src->schema) {
+ /* try to find the same opaque node */
+ lyd_find_sibling_opaq_next(*first_trg, LYD_NAME(sibling_src), &match_trg);
+ } else if (sibling_src->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
/* try to find the exact instance */
- ret = lyd_find_sibling_first(*first_trg, sibling_src, &match_trg);
+ lyd_find_sibling_first(*first_trg, sibling_src, &match_trg);
} else {
/* try to simply find the node, there cannot be more instances */
- ret = lyd_find_sibling_val(*first_trg, sibling_src->schema, NULL, 0, &match_trg);
+ lyd_find_sibling_val(*first_trg, sibling_src->schema, NULL, 0, &match_trg);
}
- if (!ret) {
+ if (match_trg) {
+ /* update match as needed */
+ LY_CHECK_RET(lyd_dup_inst_next(&match_trg, *first_trg, dup_inst));
+ } else {
+ /* first instance of this node */
+ first_inst = 1;
+ }
+
+ if (match_trg) {
+ /* call callback */
+ if (merge_cb) {
+ LY_CHECK_RET(merge_cb(match_trg, sibling_src, cb_data));
+ }
+
/* node found, make sure even value matches for all node types */
if ((match_trg->schema->nodetype == LYS_LEAF) && lyd_compare_single(sibling_src, match_trg, LYD_COMPARE_DEFAULTS)) {
/* since they are different, they cannot both be default */
@@ -3557,12 +3578,19 @@
/* copy flags and add LYD_NEW */
match_trg->flags = sibling_src->flags | LYD_NEW;
- } else {
- /* check descendants, recursively */
- LY_LIST_FOR_SAFE(lyd_child_no_keys(sibling_src), tmp, child_src) {
- LY_CHECK_RET(lyd_merge_sibling_r(lyd_node_child_p(match_trg), match_trg, &child_src, options));
+ }
+
+ /* check descendants, recursively */
+ ret = LY_SUCCESS;
+ LY_LIST_FOR_SAFE(lyd_child_no_keys(sibling_src), tmp, child_src) {
+ ret = lyd_merge_sibling_r(lyd_node_child_p(match_trg), match_trg, &child_src, merge_cb, cb_data, options,
+ &child_dup_inst);
+ if (ret) {
+ break;
}
}
+ lyd_dup_inst_free(child_dup_inst);
+ LY_CHECK_RET(ret);
} else {
/* node not found, merge it */
if (options & LYD_MERGE_DESTRUCT) {
@@ -3580,17 +3608,31 @@
LYD_TREE_DFS_END(dup_src, elem);
}
+ /* insert */
lyd_insert_node(parent_trg, first_trg, dup_src);
+
+ if (first_inst) {
+ /* remember not to find this instance next time */
+ LY_CHECK_RET(lyd_dup_inst_next(&dup_src, *first_trg, dup_inst));
+ }
+
+ /* call callback, no source node */
+ if (merge_cb) {
+ LY_CHECK_RET(merge_cb(dup_src, NULL, cb_data));
+ }
}
return LY_SUCCESS;
}
static LY_ERR
-lyd_merge(struct lyd_node **target, const struct lyd_node *source, uint16_t options, ly_bool nosiblings)
+lyd_merge(struct lyd_node **target, const struct lyd_node *source, const struct lys_module *mod,
+ lyd_merge_cb merge_cb, void *cb_data, uint16_t options, ly_bool nosiblings)
{
const struct lyd_node *sibling_src, *tmp;
+ struct lyd_dup_inst *dup_inst = NULL;
ly_bool first;
+ LY_ERR ret = LY_SUCCESS;
LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
@@ -3605,8 +3647,16 @@
}
LY_LIST_FOR_SAFE(source, tmp, sibling_src) {
+ if (mod && (lyd_owner_module(sibling_src) != mod)) {
+ /* skip data nodes from different modules */
+ continue;
+ }
+
first = (sibling_src == source) ? 1 : 0;
- LY_CHECK_RET(lyd_merge_sibling_r(target, NULL, &sibling_src, options));
+ ret = lyd_merge_sibling_r(target, NULL, &sibling_src, merge_cb, cb_data, options, &dup_inst);
+ if (ret) {
+ break;
+ }
if (first && !sibling_src) {
/* source was spent (unlinked), move to the next node */
source = tmp;
@@ -3622,19 +3672,27 @@
lyd_free_siblings((struct lyd_node *)source);
}
- return LY_SUCCESS;
+ lyd_dup_inst_free(dup_inst);
+ return ret;
}
API LY_ERR
lyd_merge_tree(struct lyd_node **target, const struct lyd_node *source, uint16_t options)
{
- return lyd_merge(target, source, options, 1);
+ return lyd_merge(target, source, NULL, NULL, NULL, options, 1);
}
API LY_ERR
lyd_merge_siblings(struct lyd_node **target, const struct lyd_node *source, uint16_t options)
{
- return lyd_merge(target, source, options, 0);
+ return lyd_merge(target, source, NULL, NULL, NULL, options, 0);
+}
+
+API LY_ERR
+lyd_merge_module(struct lyd_node **target, const struct lyd_node *source, const struct lys_module *mod,
+ lyd_merge_cb merge_cb, void *cb_data, uint16_t options)
+{
+ return lyd_merge(target, source, mod, merge_cb, cb_data, options, 0);
}
static LY_ERR