libyang REFACTOR return values and options changes

Unified, all functions that return a variety
of errors return LY_ERR. Any options such as
NOSIBLINGS, WITHSIBLINGS and so on were replaced
by function variants with suffixes _single, _all,
_tree, and _siblings.
diff --git a/src/tree_data.c b/src/tree_data.c
index 3b7e1a3..7780c97 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -657,30 +657,36 @@
     return LY_SUCCESS;
 }
 
-API struct lyd_node *
-lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name)
+API LY_ERR
+lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
 
-    LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || module, name, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
     }
 
-    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_CONTAINER | LYS_NOTIF | LYS_RPC | LYS_ACTION, 0);
-    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Inner node (and not a list) \"%s\" not found.", name), NULL);
+    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0,
+                            LYS_CONTAINER | LYS_NOTIF | LYS_RPC | LYS_ACTION, 0);
+    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Inner node (and not a list) \"%s\" not found.", name), LY_ENOTFOUND);
 
-    if (!lyd_create_inner(schema, &ret) && parent) {
+    LY_CHECK_RET(lyd_create_inner(schema, &ret));
+    if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
-    return ret;
+
+    if (node) {
+        *node = ret;
+    }
+    return LY_SUCCESS;
 }
 
-API struct lyd_node *
-lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, ...)
+API LY_ERR
+lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, struct lyd_node **node, ...)
 {
     struct lyd_node *ret = NULL, *key;
     const struct lysc_node *schema, *key_s;
@@ -689,19 +695,19 @@
     const char *key_val;
     LY_ERR rc = LY_SUCCESS;
 
-    LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || module, name, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
     }
 
     schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
-    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
+    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), LY_ENOTFOUND);
 
     /* create list inner node */
-    LY_CHECK_RET(lyd_create_inner(schema, &ret), NULL);
+    LY_CHECK_RET(lyd_create_inner(schema, &ret));
 
-    va_start(ap, name);
+    va_start(ap, node);
 
     /* create and insert all the keys */
     for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
@@ -713,30 +719,30 @@
         lyd_insert_node(ret, NULL, key);
     }
 
-    /* hash having all the keys */
-    lyd_hash(ret);
-
     if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
 
 cleanup:
+    va_end(ap);
     if (rc) {
         lyd_free_tree(ret);
         ret = NULL;
+    } else if (node) {
+        *node = ret;
     }
-    va_end(ap);
-    return ret;
+    return rc;
 }
 
-API struct lyd_node *
-lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys)
+API LY_ERR
+lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys,
+              struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
 
-    LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || module, name, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
@@ -747,69 +753,81 @@
 
     /* find schema node */
     schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
-    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
+    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), LY_ENOTFOUND);
 
     if ((schema->flags & LYS_KEYLESS) && !keys[0]) {
         /* key-less list */
-        LY_CHECK_RET(lyd_create_inner(schema, &ret), NULL);
+        LY_CHECK_RET(lyd_create_inner(schema, &ret));
     } else {
         /* create the list node */
-        LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret), NULL);
+        LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret));
     }
-
     if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
-    return ret;
+
+    if (node) {
+        *node = ret;
+    }
+    return LY_SUCCESS;
 }
 
-API struct lyd_node *
-lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
+API LY_ERR
+lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
+             struct lyd_node **node)
 {
     LY_ERR rc;
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
 
-    LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || module, name, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
     }
 
     schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, 0);
-    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), NULL);
+    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), LY_ENOTFOUND);
 
     rc = lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &ret);
-    LY_CHECK_RET(rc && (rc != LY_EINCOMPLETE), NULL);
-
+    LY_CHECK_RET(rc && (rc != LY_EINCOMPLETE), rc);
     if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
-    return ret;
+
+    if (node) {
+        *node = ret;
+    }
+    return LY_SUCCESS;
 }
 
-API struct lyd_node *
+API LY_ERR
 lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
-            LYD_ANYDATA_VALUETYPE value_type)
+            LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
 
-    LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || module, name, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
     }
 
     schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, 0);
-    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Any node \"%s\" not found.", name), NULL);
+    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Any node \"%s\" not found.", name), LY_ENOTFOUND);
 
-    if (!lyd_create_any(schema, value, value_type, &ret) && parent) {
+    LY_CHECK_RET(lyd_create_any(schema, value, value_type, &ret));
+    if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
-    return ret;
+
+    if (node) {
+        *node = ret;
+    }
+    return LY_SUCCESS;
 }
 
 /**
@@ -885,8 +903,9 @@
     return ret;
 }
 
-API struct lyd_meta *
-lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
+API LY_ERR
+lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
+             struct lyd_meta **meta)
 {
     struct lyd_meta *ret = NULL;
     const struct ly_ctx *ctx;
@@ -894,7 +913,7 @@
     char *str;
     size_t pref_len, name_len;
 
-    LY_CHECK_ARG_RET(NULL, parent, name, module || strchr(name, ':'), NULL);
+    LY_CHECK_ARG_RET(NULL, parent, name, module || strchr(name, ':'), LY_EINVAL);
 
     ctx = LYD_NODE_CTX(parent);
 
@@ -902,7 +921,7 @@
     tmp = name;
     if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
         LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
-        return NULL;
+        return LY_EVALID;
     }
 
     /* find the module */
@@ -910,7 +929,7 @@
         str = strndup(prefix, pref_len);
         module = ly_ctx_get_module_implemented(ctx, str);
         free(str);
-        LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%.*s\" not found.", pref_len, prefix), NULL);
+        LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%.*s\" not found.", pref_len, prefix), LY_ENOTFOUND);
     }
 
     /* set value if none */
@@ -918,18 +937,22 @@
         val_str = "";
     }
 
-    lyd_create_meta(parent, &ret, module, name, name_len, val_str, strlen(val_str), NULL, lydjson_resolve_prefix, NULL,
-                    LYD_JSON, parent->schema);
-    return ret;
+    LY_CHECK_RET(lyd_create_meta(parent, &ret, module, name, name_len, val_str, strlen(val_str), NULL,
+                                 lydjson_resolve_prefix, NULL, LYD_JSON, parent->schema));
+
+    if (meta) {
+        *meta = ret;
+    }
+    return LY_SUCCESS;
 }
 
-API struct lyd_node *
+API LY_ERR
 lyd_new_opaq(struct lyd_node *parent, const struct ly_ctx *ctx, const char *name, const char *value,
-             const char *module_name)
+             const char *module_name, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
 
-    LY_CHECK_ARG_RET(ctx, parent || ctx, name, module_name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || ctx, name, module_name, LY_EINVAL);
 
     if (!ctx) {
         ctx = LYD_NODE_CTX(parent);
@@ -938,22 +961,28 @@
         value = "";
     }
 
-    if (!lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), NULL, LYD_JSON, NULL, NULL, 0, module_name, &ret)
-            && parent) {
+    LY_CHECK_RET(lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), NULL, LYD_JSON, NULL, NULL, 0,
+                                 module_name, &ret));
+    if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
-    return ret;
+
+    if (node) {
+        *node = ret;
+    }
+    return LY_SUCCESS;
 }
 
-API struct ly_attr *
-lyd_new_attr(struct lyd_node *parent, const char *module_name, const char *name, const char *val_str)
+API LY_ERR
+lyd_new_attr(struct lyd_node *parent, const char *module_name, const char *name, const char *val_str,
+             struct ly_attr **attr)
 {
     struct ly_attr *ret = NULL;
     const struct ly_ctx *ctx;
     const char *prefix, *tmp;
     size_t pref_len, name_len;
 
-    LY_CHECK_ARG_RET(NULL, parent, !parent->schema, name, NULL);
+    LY_CHECK_ARG_RET(NULL, parent, !parent->schema, name, LY_EINVAL);
 
     ctx = LYD_NODE_CTX(parent);
 
@@ -961,7 +990,7 @@
     tmp = name;
     if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
         LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
-        return NULL;
+        return LY_EVALID;
     }
 
     /* set value if none */
@@ -969,9 +998,13 @@
         val_str = "";
     }
 
-    ly_create_attr(parent, &ret, ctx, name, name_len, val_str, strlen(val_str), NULL, LYD_JSON, NULL, prefix,
-                   pref_len, module_name);
-    return ret;
+    LY_CHECK_RET(ly_create_attr(parent, &ret, ctx, name, name_len, val_str, strlen(val_str), NULL, LYD_JSON, NULL,
+                                prefix, pref_len, module_name));
+
+    if (attr) {
+        *attr = ret;
+    }
+    return LY_SUCCESS;
 }
 
 API LY_ERR
@@ -1092,23 +1125,11 @@
     return ret;
 }
 
-API struct lyd_node *
-lyd_new_path(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const char *value, int options)
+API LY_ERR
+lyd_new_path(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const char *value, int options,
+             struct lyd_node **node)
 {
-    struct lyd_node *new_parent = NULL;
-
-    lyd_new_path2(parent, ctx, path, value, 0, options, &new_parent, NULL);
-    return new_parent;
-}
-
-API struct lyd_node *
-lyd_new_path_any(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const void *value,
-                 LYD_ANYDATA_VALUETYPE value_type, int options)
-{
-    struct lyd_node *new_parent = NULL;
-
-    lyd_new_path2(parent, ctx, path, value, value_type, options, &new_parent, NULL);
-    return new_parent;
+    return lyd_new_path2(parent, ctx, path, value, 0, options, node, NULL);
 }
 
 API LY_ERR
@@ -2106,8 +2127,8 @@
  * @return LY_ERR value
  */
 static LY_ERR
-lyd_dup_recursive(const struct lyd_node *node, struct lyd_node *parent, struct lyd_node **first, int options,
-                  struct lyd_node **dup_p)
+lyd_dup_r(const struct lyd_node *node, struct lyd_node *parent, struct lyd_node **first, int options,
+          struct lyd_node **dup_p)
 {
     LY_ERR ret;
     struct lyd_node *dup = NULL;
@@ -2155,10 +2176,7 @@
     /* duplicate metadata */
     if (!(options & LYD_DUP_NO_META)) {
         LY_LIST_FOR(node->meta, meta) {
-            if (!lyd_dup_meta(meta, dup)) {
-                ret = LY_EINT;
-                goto error;
-            }
+            LY_CHECK_GOTO(ret = lyd_dup_meta_single(meta, dup, NULL), error);
         }
     }
 
@@ -2171,7 +2189,7 @@
         if (options & LYD_DUP_RECURSIVE) {
             /* duplicate all the children */
             LY_LIST_FOR(orig->child, child) {
-                LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
+                LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, NULL, options, NULL), error);
             }
         }
         opaq->name = lydict_insert(LYD_NODE_CTX(node), orig->name, 0);
@@ -2207,7 +2225,7 @@
         if (options & LYD_DUP_RECURSIVE) {
             /* duplicate all the children */
             LY_LIST_FOR(orig->child, child) {
-                LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
+                LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, NULL, options, NULL), error);
             }
         } else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
             /* always duplicate keys of a list */
@@ -2223,7 +2241,7 @@
                      * but there can be also some non-key nodes */
                     continue;
                 }
-                LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
+                LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, NULL, options, NULL), error);
                 child = child->next;
             }
         }
@@ -2247,86 +2265,92 @@
     return ret;
 }
 
-API struct lyd_node *
-lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
+static LY_ERR
+lyd_dup_get_local_parent(const struct lyd_node *node, const struct lyd_node_inner *parent, struct lyd_node **dup_parent,
+                         struct lyd_node_inner **local_parent)
 {
+    const struct lyd_node_inner *orig_parent, *iter;
+    int repeat = 1;
+
+    *dup_parent = NULL;
+    *local_parent = NULL;
+
+    for (orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
+        if (parent && (parent->schema == orig_parent->schema)) {
+            /* stop creating parents, connect what we have into the provided parent */
+            iter = parent;
+            repeat = 0;
+        } else {
+            iter = NULL;
+            LY_CHECK_RET(lyd_dup_r((struct lyd_node *)orig_parent, NULL, (struct lyd_node **)&iter, 0,
+                                   (struct lyd_node **)&iter));
+        }
+        if (!*local_parent) {
+            *local_parent = (struct lyd_node_inner *)iter;
+        }
+        if (iter->child) {
+            /* 1) list - add after keys
+             * 2) provided parent with some children */
+            iter->child->prev->next = *dup_parent;
+            if (*dup_parent) {
+                (*dup_parent)->prev = iter->child->prev;
+                iter->child->prev = *dup_parent;
+            }
+        } else {
+            ((struct lyd_node_inner *)iter)->child = *dup_parent;
+        }
+        if (*dup_parent) {
+            (*dup_parent)->parent = (struct lyd_node_inner *)iter;
+        }
+        *dup_parent = (struct lyd_node *)iter;
+    }
+
+    if (repeat && parent) {
+        /* given parent and created parents chain actually do not interconnect */
+        LOGERR(LYD_NODE_CTX(node), LY_EINVAL,
+               "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
+        return LY_EINVAL;
+    }
+
+    return LY_SUCCESS;
+}
+
+static LY_ERR
+lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options, int nosiblings, struct lyd_node **dup)
+{
+    LY_ERR rc;
     const struct lyd_node *orig;          /* original node to be duplicated */
     struct lyd_node *first = NULL;        /* the first duplicated node, this is returned */
     struct lyd_node *top = NULL;          /* the most higher created node */
     struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
-    int keyless_parent_list = 0;
 
-    LY_CHECK_ARG_RET(NULL, node, NULL);
+    LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
 
     if (options & LYD_DUP_WITH_PARENTS) {
-        struct lyd_node_inner *orig_parent, *iter;
-        int repeat = 1;
-        for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
-            if (parent && parent->schema == orig_parent->schema) {
-                /* stop creating parents, connect what we have into the provided parent */
-                iter = parent;
-                repeat = 0;
-                /* get know if there is a keyless list which we will have to rehash */
-                for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
-                    if (piter->schema->nodetype == LYS_LIST && (piter->schema->flags & LYS_KEYLESS)) {
-                        keyless_parent_list = 1;
-                        break;
-                    }
-                }
-            } else {
-                iter = NULL;
-                LY_CHECK_GOTO(lyd_dup_recursive((struct lyd_node *)orig_parent, NULL, (struct lyd_node **)&iter, 0,
-                                                (struct lyd_node **)&iter), error);
-            }
-            if (!local_parent) {
-                local_parent = iter;
-            }
-            if (iter->child) {
-                /* 1) list - add after keys
-                 * 2) provided parent with some children */
-                iter->child->prev->next = top;
-                if (top) {
-                    top->prev = iter->child->prev;
-                    iter->child->prev = top;
-                }
-            } else {
-                iter->child = top;
-                if (iter->schema->nodetype == LYS_LIST) {
-                    /* keyless list - we will need to rehash it since we are going to add nodes into it */
-                    keyless_parent_list = 1;
-                }
-            }
-            if (top) {
-                top->parent = iter;
-            }
-            top = (struct lyd_node*)iter;
-        }
-        if (repeat && parent) {
-            /* given parent and created parents chain actually do not interconnect */
-            LOGERR(LYD_NODE_CTX(node), LY_EINVAL,
-                   "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
-            goto error;
-        }
+        LY_CHECK_GOTO(rc = lyd_dup_get_local_parent(node, parent, &top, &local_parent), error);
     } else {
         local_parent = parent;
     }
 
     LY_LIST_FOR(node, orig) {
         /* if there is no local parent, it will be inserted into first */
-        LY_CHECK_GOTO(lyd_dup_recursive(orig, (struct lyd_node *)local_parent, &first, options, first ? NULL : &first), error);
-        if (!(options & LYD_DUP_WITH_SIBLINGS)) {
+        LY_CHECK_GOTO(rc = lyd_dup_r(orig, (struct lyd_node *)local_parent, &first, options, first ? NULL : &first), error);
+        if (nosiblings) {
             break;
         }
     }
-    if (keyless_parent_list) {
-        /* rehash */
-        for (; local_parent; local_parent = local_parent->parent) {
-            if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
-                lyd_hash((struct lyd_node*)local_parent);
-            }
+
+    /* rehash if needed */
+    for (; local_parent; local_parent = local_parent->parent) {
+        if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
+            lyd_hash((struct lyd_node *)local_parent);
         }
     }
-    return first;
+
+    if (dup) {
+        *dup = first;
+    }
+    return LY_SUCCESS;
 
 error:
     if (top) {
@@ -2334,25 +2358,37 @@
     } else {
         lyd_free_siblings(first);
     }
-    return NULL;
+    return rc;
 }
 
-API struct lyd_meta *
-lyd_dup_meta(const struct lyd_meta *meta, struct lyd_node *node)
+API LY_ERR
+lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, int options, struct lyd_node **dup)
+{
+    return lyd_dup(node, parent, options, 1, dup);
+}
+
+API LY_ERR
+lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, int options, struct lyd_node **dup)
+{
+    return lyd_dup(node, parent, options, 0, dup);
+}
+
+API LY_ERR
+lyd_dup_meta_single(const struct lyd_meta *meta, struct lyd_node *node, struct lyd_meta **dup)
 {
     LY_ERR ret;
     struct lyd_meta *mt, *last;
 
-    LY_CHECK_ARG_RET(NULL, meta, node, NULL);
+    LY_CHECK_ARG_RET(NULL, meta, node, LY_EINVAL);
 
     /* create a copy */
     mt = calloc(1, sizeof *mt);
-    LY_CHECK_ERR_RET(!mt, LOGMEM(LYD_NODE_CTX(node)), NULL);
+    LY_CHECK_ERR_RET(!mt, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
     mt->parent = node;
     mt->annotation = meta->annotation;
     mt->value.realtype = meta->value.realtype;
     ret = mt->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &meta->value, &mt->value);
-    LY_CHECK_ERR_RET(ret, LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."), NULL);
+    LY_CHECK_ERR_RET(ret, LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."), ret);
     mt->name = lydict_insert(LYD_NODE_CTX(node), meta->name, 0);
 
     /* insert as the last attribute */
@@ -2363,7 +2399,10 @@
         node->meta = mt;
     }
 
-    return mt;
+    if (dup) {
+        *dup = mt;
+    }
+    return LY_SUCCESS;
 }
 
 /**
@@ -2401,8 +2440,8 @@
             /* since they are different, they cannot both be default */
             assert(!(sibling_src->flags & LYD_DEFAULT) || !(match_trg->flags & LYD_DEFAULT));
 
-            /* update value (or only LYD_DEFAULT flag) only if no flag set or the source node is not default */
-            if (!(options & LYD_MERGE_EXPLICIT) || !(sibling_src->flags & LYD_DEFAULT)) {
+            /* update value (or only LYD_DEFAULT flag) only if flag set or the source node is not default */
+            if ((options & LYD_MERGE_DEFAULTS) || !(sibling_src->flags & LYD_DEFAULT)) {
                 type = ((struct lysc_node_leaf *)match_trg->schema)->type;
                 type->plugin->free(LYD_NODE_CTX(match_trg), &((struct lyd_node_term *)match_trg)->value);
                 LY_CHECK_RET(type->plugin->duplicate(LYD_NODE_CTX(match_trg), &((struct lyd_node_term *)sibling_src)->value,
@@ -2418,8 +2457,7 @@
                 /* spend it */
                 *sibling_src_p = NULL;
             } else {
-                dup_src = lyd_dup(sibling_src, NULL, 0);
-                LY_CHECK_RET(!dup_src, LY_EMEM);
+                LY_CHECK_RET(lyd_dup_single(sibling_src, NULL, 0, &dup_src));
             }
             /* just switch values */
             tmp_val_type = ((struct lyd_node_any *)match_trg)->value_type;
@@ -2448,8 +2486,7 @@
             /* spend it */
             *sibling_src_p = NULL;
         } else {
-            dup_src = lyd_dup(sibling_src, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_FLAGS);
-            LY_CHECK_RET(!dup_src, LY_EMEM);
+            LY_CHECK_RET(lyd_dup_single(sibling_src, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_FLAGS, &dup_src));
         }
 
         /* set LYD_NEW for all the new nodes, required for validation */
@@ -2464,8 +2501,8 @@
     return LY_SUCCESS;
 }
 
-API LY_ERR
-lyd_merge(struct lyd_node **target, const struct lyd_node *source, int options)
+static LY_ERR
+lyd_merge(struct lyd_node **target, const struct lyd_node *source, int options, int nosiblings)
 {
     const struct lyd_node *sibling_src, *tmp;
     int first;
@@ -2490,7 +2527,7 @@
             source = tmp;
         }
 
-        if (options & LYD_MERGE_NOSIBLINGS) {
+        if (nosiblings) {
             break;
         }
     }
@@ -2503,6 +2540,18 @@
     return LY_SUCCESS;
 }
 
+API LY_ERR
+lyd_merge_tree(struct lyd_node **target, const struct lyd_node *source, int options)
+{
+    return lyd_merge(target, source, options, 1);
+}
+
+API LY_ERR
+lyd_merge_siblings(struct lyd_node **target, const struct lyd_node *source, int options)
+{
+    return lyd_merge(target, source, options, 0);
+}
+
 static LY_ERR
 lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
 {