libyang CHANGE bind errors and store them in a context
diff --git a/src/validation.c b/src/validation.c
index a8cfce9..620cc07 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -35,17 +35,17 @@
     for (i = 0, child = list->child; i < schema->keys_size; i++, child = child->next) {
         if (!child || child->schema != (struct lys_node *)schema->keys[i]) {
             /* key not found on the correct place */
-            LOGVAL(LYE_MISSELEM, LY_VLOG_LYD, list, schema->keys[i]->name, schema->name);
+            LOGVAL(schema->module->ctx, LYE_MISSELEM, LY_VLOG_LYD, list, schema->keys[i]->name, schema->name);
             for ( ; child; child = child->next) {
                 if (child->schema == (struct lys_node *)schema->keys[i]) {
-                    LOGVAL(LYE_SPEC, LY_VLOG_LYD, child, "Invalid position of the key element.");
+                    LOGVAL(schema->module->ctx, LYE_SPEC, LY_VLOG_LYD, child, "Invalid position of the key element.");
                     break;
                 }
             }
-            return EXIT_FAILURE;
+            return 1;
         }
     }
-    return EXIT_SUCCESS;
+    return 0;
 }
 
 int
@@ -53,14 +53,15 @@
 {
     const struct lys_node *siter = NULL;
     struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
+    struct ly_ctx *ctx = node->schema->module->ctx;
 
     assert(node);
     assert(unres);
 
     /* check if the node instance is enabled by if-feature */
     if (lys_is_disabled(node->schema, 2)) {
-        LOGVAL(LYE_INELEM, LY_VLOG_LYD, node, node->schema->name);
-        return EXIT_FAILURE;
+        LOGVAL(ctx, LYE_INELEM, LY_VLOG_LYD, node, node->schema->name);
+        return 1;
     }
 
     if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
@@ -68,15 +69,15 @@
         if ((((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_UNION)
                 && ((struct lys_node_leaf *)leaf->schema)->type.info.uni.has_ptr_type) {
             if (unres_data_add(unres, (struct lyd_node *)node, UNRES_UNION)) {
-                return EXIT_FAILURE;
+                return 1;
             }
         } else if ((((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_LEAFREF) && (leaf->validity & LYD_VAL_LEAFREF)) {
             if (unres_data_add(unres, (struct lyd_node *)node, UNRES_LEAFREF)) {
-                return EXIT_FAILURE;
+                return 1;
             }
         } else if (((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_INST) {
             if (unres_data_add(unres, (struct lyd_node *)node, UNRES_INSTID)) {
-                return EXIT_FAILURE;
+                return 1;
             }
         }
     }
@@ -85,14 +86,14 @@
     if (!(options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG))
             && (node->when_status & LYD_WHEN)) {
         if (unres_data_add(unres, (struct lyd_node *)node, UNRES_WHEN)) {
-            return EXIT_FAILURE;
+            return 1;
         }
     }
 
     /* check for (non-)presence of status data in edit-config data */
     if ((options & (LYD_OPT_EDIT | LYD_OPT_GETCONFIG | LYD_OPT_CONFIG)) && (node->schema->flags & LYS_CONFIG_R)) {
-        LOGVAL(LYE_INELEM, LY_VLOG_LYD, node, node->schema->name);
-        return EXIT_FAILURE;
+        LOGVAL(ctx, LYE_INELEM, LY_VLOG_LYD, node, node->schema->name);
+        return 1;
     }
 
     /* check elements order in case of RPC's input and output */
@@ -104,15 +105,15 @@
                 if (siter == node->prev->schema) {
                     /* data predecessor has the schema node after
                      * the schema node of the data node being checked */
-                    LOGVAL(LYE_INORDER, LY_VLOG_LYD, node, node->schema->name, siter->name);
-                    return EXIT_FAILURE;
+                    LOGVAL(ctx, LYE_INORDER, LY_VLOG_LYD, node, node->schema->name, siter->name);
+                    return 1;
                 }
             }
 
         }
     }
 
-    return EXIT_SUCCESS;
+    return 0;
 }
 
 struct eq_item {
@@ -142,9 +143,9 @@
             }
 
             /* compare nodes */
-            if (lyd_list_equal(node, table[i].node, action, 0, 1)) {
+            if (lyd_list_equal(node, table[i].node, action, 0)) {
                 /* instance duplication */
-                return EXIT_FAILURE;
+                return 1;
             }
         } while (c--);
 
@@ -160,7 +161,7 @@
         table[hash].hash = hash;
     }
 
-    return EXIT_SUCCESS;
+    return 0;
 }
 
 int
@@ -169,10 +170,11 @@
     struct lyd_node *diter, *key;
     struct lys_node_list *slist;
     struct ly_set *set;
-    int i, j, n = 0, ret = EXIT_SUCCESS;
+    int i, j, n = 0, ret = 0;
     uint32_t hash, u, usize = 0, hashmask;
     struct eq_item *keystable = NULL, **uniquetables = NULL;
     const char *id;
+    struct ly_ctx *ctx = node->schema->module->ctx;
 
     /* get the first list/leaflist instance sibling */
     if (!start) {
@@ -196,10 +198,10 @@
 
     if (set->number == 2) {
         /* simple comparison */
-        if (lyd_list_equal(set->set.d[0], set->set.d[1], -1, 0, 1)) {
+        if (lyd_list_equal(set->set.d[0], set->set.d[1], -1, 0)) {
             /* instance duplication */
             ly_set_free(set);
-            return EXIT_FAILURE;
+            return 1;
         }
     } else if (set->number > 2) {
         /* use hashes for comparison */
@@ -220,8 +222,8 @@
         }
         keystable = calloc(usize, sizeof *keystable);
         if (!keystable) {
-            LOGMEM;
-            ret = EXIT_FAILURE;
+            LOGMEM(ctx);
+            ret = 1;
             goto unique_cleanup;
         }
         n = 0;
@@ -229,16 +231,16 @@
             n = ((struct lys_node_list *)node->schema)->unique_size;
             uniquetables = malloc(n * sizeof *uniquetables);
             if (!uniquetables) {
-                LOGMEM;
-                ret = EXIT_FAILURE;
+                LOGMEM(ctx);
+                ret = 1;
                 n = 0;
                 goto unique_cleanup;
             }
             for (j = 0; j < n; j++) {
                 uniquetables[j] = calloc(usize, sizeof **uniquetables);
                 if (!uniquetables[j]) {
-                    LOGMEM;
-                    ret = EXIT_FAILURE;
+                    LOGMEM(ctx);
+                    ret = 1;
                     goto unique_cleanup;
                 }
             }
@@ -262,7 +264,7 @@
 
             /* insert into the hashtable */
             if (eq_table_insert(keystable, set->set.d[u], hash, usize, 0)) {
-                ret = EXIT_FAILURE;
+                ret = 1;
                 goto unique_cleanup;
             }
 
@@ -276,9 +278,8 @@
                         id = ((struct lyd_node_leaf_list *)diter)->value_str;
                     } else {
                         /* use default value */
-                        id = lyd_get_unique_default(slist->unique[j].expr[i], set->set.d[u]);
-                        if (ly_errno) {
-                            ret = EXIT_FAILURE;
+                        if (lyd_get_unique_default(slist->unique[j].expr[i], set->set.d[u], &id)) {
+                            ret = 1;
                             goto unique_cleanup;
                         }
                     }
@@ -298,7 +299,7 @@
 
                 /* insert into the hashtable */
                 if (eq_table_insert(uniquetables[j], set->set.d[u], hash, usize, j + 1)) {
-                    ret = EXIT_FAILURE;
+                    ret = 1;
                     goto unique_cleanup;
                 }
             }
@@ -363,19 +364,21 @@
     uint8_t iff_size;
     struct lys_iffeature *iff;
     const char *id, *idname;
+    struct ly_ctx *ctx;
 
     assert(node);
     assert(node->schema);
     assert(unres);
 
     schema = node->schema; /* shortcut */
+    ctx = schema->module->ctx;
 
     if (node->validity & LYD_VAL_MAND) {
         if (!(options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER))) {
             /* check presence and correct order of all keys in case of list */
             if (schema->nodetype == LYS_LIST && !(options & (LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
                 if (lyv_keys(node)) {
-                    return EXIT_FAILURE;
+                    return 1;
                 }
             }
 
@@ -386,9 +389,9 @@
                 start = lyd_first_sibling(node);
                 for (diter = start; diter; diter = diter->next) {
                     if (diter->schema == schema && diter != node) {
-                        LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, node, schema->name,
+                        LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, node, schema->name,
                             lys_parent(schema) ? lys_parent(schema)->name : "data tree");
-                        return EXIT_FAILURE;
+                        return 1;
                     }
                 }
             }
@@ -399,8 +402,8 @@
                 siter = node->schema;
                 do {
                     if (((siter->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) && (options & LYD_OPT_OBSOLETE)) {
-                        LOGVAL(LYE_OBSDATA, LY_VLOG_LYD, node, schema->name);
-                        return EXIT_FAILURE;
+                        LOGVAL(ctx, LYE_OBSDATA, LY_VLOG_LYD, node, schema->name);
+                        return 1;
                     }
                     siter = lys_parent(siter);
                 } while (siter && !(siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA)));
@@ -412,8 +415,8 @@
                         tpdf = ((struct lys_node_leaf *)node->schema)->type.der;
                         while (tpdf) {
                             if ((tpdf->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) {
-                                LOGVAL(LYE_OBSTYPE, LY_VLOG_LYD, node, schema->name, tpdf->name);
-                                return EXIT_FAILURE;
+                                LOGVAL(ctx, LYE_OBSTYPE, LY_VLOG_LYD, node, schema->name, tpdf->name);
+                                return 1;
                             }
                             tpdf = tpdf->type.der;
                         }
@@ -422,8 +425,8 @@
                         ident = ((struct lyd_node_leaf_list *)node)->value.ident;
                         if (lyp_check_status(schema->flags, schema->module, schema->name,
                                         ident->flags, ident->module, ident->name, NULL)) {
-                            LOGPATH(LY_VLOG_LYD, node);
-                            return EXIT_FAILURE;
+                            LOGPATH(ctx, LY_VLOG_LYD, node);
+                            return 1;
                         }
                     }
                 }
@@ -442,7 +445,7 @@
                     LY_TREE_FOR(node->child, diter) {
                         if (diter->schema == siter && (diter->validity & LYD_VAL_UNIQUE)) {
                             if (lyv_data_unique(diter, node->child)) {
-                                return EXIT_FAILURE;
+                                return 1;
                             }
                             /* all schema instances checked, continue with another schema node */
                             break;
@@ -494,10 +497,10 @@
         if (iff_size) {
             for (i = 0; i < iff_size; i++) {
                 if (!resolve_iffeature(&iff[i])) {
-                    LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, leaf->value_str, schema->name);
-                    LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "%s \"%s\" is disabled by its if-feature condition.",
+                    LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, node, leaf->value_str, schema->name);
+                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "%s \"%s\" is disabled by its if-feature condition.",
                            id, idname);
-                    return EXIT_FAILURE;
+                    return 1;
                 }
             }
             if (leaf->value_type == LY_TYPE_BITS) {
@@ -509,13 +512,80 @@
     /* check must conditions */
     if (!(options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG))) {
         i = resolve_applies_must(node);
-        if ((i & 0x1) && (unres_data_add(unres, node, UNRES_MUST) == -1)) {
-            return EXIT_FAILURE;
+        if ((i & 0x1) && unres_data_add(unres, node, UNRES_MUST)) {
+            return 1;
         }
-        if ((i & 0x2) && (unres_data_add(unres, node, UNRES_MUST_INOUT) == -1)) {
-            return EXIT_FAILURE;
+        if ((i & 0x2) && unres_data_add(unres, node, UNRES_MUST_INOUT)) {
+            return 1;
         }
     }
 
-    return EXIT_SUCCESS;
+    return 0;
+}
+
+int
+lyv_multicases(struct lyd_node *node, struct lys_node *schemanode, struct lyd_node **first_sibling,
+               int autodelete, struct lyd_node *nodel)
+{
+    struct lys_node *sparent, *schoice, *scase, *saux;
+    struct lyd_node *next, *iter;
+    assert(node || schemanode);
+
+    if (!schemanode) {
+        schemanode = node->schema;
+    }
+
+    sparent = lys_parent(schemanode);
+    if (!sparent || !(sparent->nodetype & (LYS_CHOICE | LYS_CASE))) {
+        /* node is not under any choice */
+        return 0;
+    } else if (!first_sibling || !(*first_sibling)) {
+        /* nothing to check */
+        return 0;
+    }
+
+    /* remember which case to skip in which choice */
+    if (sparent->nodetype == LYS_CHOICE) {
+        schoice = sparent;
+        scase = schemanode;
+    } else {
+        schoice = lys_parent(sparent);
+        scase = sparent;
+    }
+
+autodelete:
+    /* remove all nodes from other cases than 'sparent' */
+    LY_TREE_FOR_SAFE(*first_sibling, next, iter) {
+        if (schemanode == iter->schema) {
+            continue;
+        }
+
+        sparent = lys_parent(iter->schema);
+        if (sparent && ((sparent->nodetype == LYS_CHOICE && sparent == schoice) /* another implicit case */
+                || (sparent->nodetype == LYS_CASE && sparent != scase && lys_parent(sparent) == schoice)) /* another case */
+                ) {
+            if (autodelete) {
+                if (iter == nodel) {
+                    LOGVAL(schemanode->module->ctx, LYE_MCASEDATA, LY_VLOG_LYD, iter, schoice->name);
+                    return 2;
+                }
+                if (iter == *first_sibling) {
+                    *first_sibling = next;
+                }
+                lyd_free(iter);
+            } else {
+                LOGVAL(schemanode->module->ctx, LYE_MCASEDATA, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, schoice->name);
+                return 1;
+            }
+        }
+    }
+
+    if (*first_sibling && (saux = lys_parent(schoice)) && (saux->nodetype & LYS_CASE)) {
+        /* go recursively in case of nested choices */
+        schoice = lys_parent(saux);
+        scase = saux;
+        goto autodelete;
+    }
+
+    return 0;
 }