plugins ext FEATURE initial schema-mount support

Only for XML data for now. Includes lots of other
changes needed to support this extension.
diff --git a/src/validation.c b/src/validation.c
index b2b05bb..5699c8d 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -258,64 +258,31 @@
     return ret;
 }
 
-struct node_ext {
-    struct lyd_node *node;
-    struct lysc_ext_instance *ext;
-};
-
-static LY_ERR
-node_ext_tovalidate_add(struct ly_set *node_exts, struct lysc_ext_instance *exts, struct lyd_node *node)
-{
-    LY_ERR ret = LY_SUCCESS;
-    struct lysc_ext_instance *ext;
-    struct node_ext *rec;
-
-    LY_ARRAY_FOR(exts, struct lysc_ext_instance, ext) {
-        if (ext->def->plugin && ext->def->plugin->validate) {
-            rec = malloc(sizeof *rec);
-            LY_CHECK_ERR_RET(!rec, LOGMEM(LYD_CTX(node)), LY_EMEM);
-            rec->ext = ext;
-            rec->node = node;
-
-            ret = ly_set_add(node_exts, rec, 1, NULL);
-            if (ret) {
-                free(rec);
-                break;
-            }
-        }
-    }
-
-    return ret;
-}
-
-LY_ERR
-lysc_node_ext_tovalidate(struct ly_set *node_exts, struct lyd_node *node)
-{
-    const struct lysc_node *schema = node->schema;
-
-    if (!schema) {
-        /* nothing to do */
-        return LY_SUCCESS;
-    }
-
-    /* node's extensions */
-    LY_CHECK_RET(node_ext_tovalidate_add(node_exts, schema->exts, node));
-
-    if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
-        /* type's extensions */
-        LY_CHECK_RET(node_ext_tovalidate_add(node_exts, ((struct lysc_node_leaf *)schema)->type->exts, node));
-    }
-
-    return LY_SUCCESS;
-}
-
 LY_ERR
 lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when, uint32_t when_xp_opts,
-        struct ly_set *node_exts, struct ly_set *node_types, struct ly_set *meta_types, struct lyd_node **diff)
+        struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_val, uint32_t val_opts,
+        struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
     uint32_t i;
 
+    if (ext_val && ext_val->count) {
+        /* first validate parsed extension data */
+        i = ext_val->count;
+        do {
+            --i;
+
+            struct lyd_ctx_ext_val *ext_v = ext_val->objs[i];
+
+            /* validate extension data */
+            ret = ext_v->ext->def->plugin->validate(ext_v->ext, ext_v->sibling, val_opts);
+            LY_CHECK_RET(ret);
+
+            /* remove this item from the set */
+            ly_set_rm_index(node_types, i, free);
+        } while (i);
+    }
+
     if (node_when) {
         /* evaluate all when conditions */
         uint32_t prev_count;
@@ -329,23 +296,6 @@
         assert(!node_when->count);
     }
 
-    if (node_exts && node_exts->count) {
-        i = node_exts->count;
-        do {
-            --i;
-
-            struct node_ext *item = node_exts->objs[i];
-
-            LOG_LOCSET(item->node->schema, item->node, NULL, NULL);
-            ret = item->ext->def->plugin->validate(item->ext, item->node);
-            LOG_LOCBACK(item->node->schema ? 1 : 0, 1, 0, 0);
-            LY_CHECK_RET(ret);
-
-            /* remove this node from the set */
-            ly_set_rm_index(node_exts, i, free);
-        } while (i);
-    }
-
     if (node_types && node_types->count) {
         /* finish incompletely validated terminal values (traverse from the end for efficient set removal) */
         i = node_types->count;
@@ -1459,26 +1409,83 @@
 }
 
 /**
+ * @brief Validate extension instance data by storing it in its unres set.
+ *
+ * @param[in] sibling First sibling with ::LYD_EXT flag, all the following ones are expected to have it, too.
+ * @param[in,out] ext_val Set with parsed extension instance data to validate.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_validate_nested_ext(struct lyd_node *sibling, struct ly_set *ext_val)
+{
+    struct lyd_node *node;
+    struct lyd_ctx_ext_val *ext_v;
+    struct lysc_ext_instance *nested_exts, *ext = NULL;
+    LY_ARRAY_COUNT_TYPE u;
+
+    /* check of basic assumptions */
+    if (!sibling->parent || !sibling->parent->schema) {
+        LOGINT_RET(LYD_CTX(sibling));
+    }
+    LY_LIST_FOR(sibling, node) {
+        if (!(node->flags & LYD_EXT)) {
+            LOGINT_RET(LYD_CTX(sibling));
+        }
+    }
+
+    /* try to find the extension instance */
+    nested_exts = sibling->parent->schema->exts;
+    LY_ARRAY_FOR(nested_exts, u) {
+        if (nested_exts[u].def->plugin->validate) {
+            if (ext) {
+                /* more extension instances with validate callback */
+                LOGINT_RET(LYD_CTX(sibling));
+            }
+            ext = &nested_exts[u];
+        }
+    }
+    if (!ext) {
+        /* no extension instance with validate callback */
+        LOGINT_RET(LYD_CTX(sibling));
+    }
+
+    /* store for validation */
+    ext_v = malloc(sizeof *ext_v);
+    LY_CHECK_ERR_RET(!ext_v, LOGMEM(LYD_CTX(sibling)), LY_EMEM);
+    ext_v->ext = ext;
+    ext_v->sibling = sibling;
+    LY_CHECK_RET(ly_set_add(ext_val, ext_v, 1, NULL));
+
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Validate the whole data subtree.
  *
  * @param[in] root Subtree root.
  * @param[in,out] node_when Set for nodes with when conditions.
- * @param[in,out] node_exts Set for nodes and extension instances with validation plugin callback.
  * @param[in,out] node_types Set for unres node types.
  * @param[in,out] meta_types Set for unres metadata types.
+ * @param[in,out] ext_val Set for parsed extension data to validate.
  * @param[in] impl_opts Implicit options, see @ref implicitoptions.
  * @param[in,out] diff Validation diff.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyd_validate_subtree(struct lyd_node *root, struct ly_set *node_when, struct ly_set *node_exts, struct ly_set *node_types,
-        struct ly_set *meta_types, uint32_t impl_opts, struct lyd_node **diff)
+lyd_validate_subtree(struct lyd_node *root, struct ly_set *node_when, struct ly_set *node_types,
+        struct ly_set *meta_types, struct ly_set *ext_val, uint32_t impl_opts, struct lyd_node **diff)
 {
     const struct lyd_meta *meta;
     struct lyd_node *node;
 
     LYD_TREE_DFS_BEGIN(root, node) {
+        if (node->flags & LYD_EXT) {
+            /* validate using the extension instance callback */
+            return lyd_validate_nested_ext(node, ext_val);
+        }
+
         if (!node->schema) {
+            /* do not validate opaque nodes */
             goto next_node;
         }
 
@@ -1497,14 +1504,13 @@
             LY_CHECK_RET(lyd_validate_new(lyd_node_child_p(node), node->schema, NULL, diff));
 
             /* add nested defaults */
-            LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, NULL, NULL, NULL, impl_opts, diff));
+            LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, NULL, NULL, impl_opts, diff));
         }
 
         if (lysc_has_when(node->schema)) {
             /* when evaluation */
             LY_CHECK_RET(ly_set_add(node_when, (void *)node, 1, NULL));
         }
-        LY_CHECK_RET(lysc_node_ext_tovalidate(node_exts, node));
 
 next_node:
         LYD_TREE_DFS_END(root, node);
@@ -1515,24 +1521,24 @@
 
 LY_ERR
 lyd_validate(struct lyd_node **tree, const struct lys_module *module, const struct ly_ctx *ctx, uint32_t val_opts,
-        ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_exts_p,
-        struct ly_set *node_types_p, struct ly_set *meta_types_p, struct lyd_node **diff)
+        ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p, struct ly_set *meta_types_p,
+        struct ly_set *ext_val_p, struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *first, *next, **first2, *iter;
     const struct lys_module *mod;
-    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, node_exts = {0};
+    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_val = {0};
     uint32_t i = 0;
 
     assert(tree && ctx);
-    assert((node_when_p && node_exts_p && node_types_p && meta_types_p) ||
-            (!node_when_p && !node_exts_p && !node_types_p && !meta_types_p));
+    assert((node_when_p && node_types_p && meta_types_p && ext_val_p) ||
+            (!node_when_p && !node_types_p && !meta_types_p && !ext_val_p));
 
     if (!node_when_p) {
         node_when_p = &node_when;
-        node_exts_p = &node_exts;
         node_types_p = &node_types;
         meta_types_p = &meta_types;
+        ext_val_p = &ext_val;
     }
 
     next = *tree;
@@ -1558,7 +1564,7 @@
 
         /* add all top-level defaults for this module, if going to validate subtree, do not add into unres sets
          * (lyd_validate_subtree() adds all the nodes in that case) */
-        ret = lyd_new_implicit_r(NULL, first2, NULL, mod, validate_subtree ? NULL : node_when_p, validate_subtree ? NULL : node_exts_p,
+        ret = lyd_new_implicit_r(NULL, first2, NULL, mod, validate_subtree ? NULL : node_when_p,
                 validate_subtree ? NULL : node_types_p, (val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, diff);
         LY_CHECK_GOTO(ret, cleanup);
 
@@ -1578,14 +1584,14 @@
                     break;
                 }
 
-                ret = lyd_validate_subtree(iter, node_when_p, node_exts_p, node_types_p, meta_types_p,
+                ret = lyd_validate_subtree(iter, node_when_p, node_types_p, meta_types_p, ext_val_p,
                         (val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, diff);
                 LY_CHECK_GOTO(ret, cleanup);
             }
         }
 
         /* finish incompletely validated terminal values/attributes and when conditions */
-        ret = lyd_validate_unres(first2, mod, node_when_p, 0, node_exts_p, node_types_p, meta_types_p, diff);
+        ret = lyd_validate_unres(first2, mod, node_when_p, 0, node_types_p, meta_types_p, ext_val_p, val_opts, diff);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* perform final validation that assumes the data tree is final */
@@ -1595,9 +1601,9 @@
 
 cleanup:
     ly_set_erase(&node_when, NULL);
-    ly_set_erase(&node_exts, NULL);
     ly_set_erase(&node_types, NULL);
     ly_set_erase(&meta_types, NULL);
+    ly_set_erase(&ext_val, free);
     return ret;
 }
 
@@ -1700,31 +1706,31 @@
  * @param[in] int_opts Internal parser options.
  * @param[in] validate_subtree Whether subtree was already validated (as part of data parsing) or not (separate validation).
  * @param[in] node_when_p Set of nodes with when conditions, if NULL a local set is used.
- * @param[in] node_exts Set of nodes with extension instances with validation plugin callback, if NULL a local set is used.
  * @param[in] node_types_p Set of unres node types, if NULL a local set is used.
  * @param[in] meta_types_p Set of unres metadata types, if NULL a local set is used.
+ * @param[in] ext_val_p Set of parsed extension data to validate, if NULL a local set is used.
  * @param[out] diff Optional diff with any changes made by the validation.
  * @return LY_SUCCESS on success.
  * @return LY_ERR error on error.
  */
 static LY_ERR
 _lyd_validate_op(struct lyd_node *op_tree, struct lyd_node *op_node, const struct lyd_node *dep_tree,
-        uint32_t int_opts, ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_exts_p,
-        struct ly_set *node_types_p, struct ly_set *meta_types_p, struct lyd_node **diff)
+        uint32_t int_opts, ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p,
+        struct ly_set *meta_types_p, struct ly_set *ext_val_p, struct lyd_node **diff)
 {
     LY_ERR rc = LY_SUCCESS;
     struct lyd_node *tree_sibling, *tree_parent, *op_subtree, *op_parent, *child;
-    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, node_exts = {0};
+    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_val = {0};
 
     assert(op_tree && op_node);
-    assert((node_when_p && node_exts_p && node_types_p && meta_types_p) ||
-            (!node_when_p && !node_exts_p && !node_types_p && !meta_types_p));
+    assert((node_when_p && node_types_p && meta_types_p && ext_val_p) ||
+            (!node_when_p && !node_types_p && !meta_types_p && !ext_val_p));
 
     if (!node_when_p) {
         node_when_p = &node_when;
-        node_exts_p = &node_exts;
         node_types_p = &node_types;
         meta_types_p = &meta_types;
+        ext_val_p = &ext_val;
     }
 
     /* merge op_tree into dep_tree */
@@ -1740,28 +1746,28 @@
 
     if (int_opts & LYD_INTOPT_REPLY) {
         /* add output children defaults */
-        rc = lyd_new_implicit_r(op_node, lyd_node_child_p(op_node), NULL, NULL, node_when_p, node_exts_p, node_types_p,
+        rc = lyd_new_implicit_r(op_node, lyd_node_child_p(op_node), NULL, NULL, node_when_p, node_types_p,
                 LYD_IMPLICIT_OUTPUT, diff);
         LY_CHECK_GOTO(rc, cleanup);
 
         if (validate_subtree) {
             /* skip validating the operation itself, go to children directly */
             LY_LIST_FOR(lyd_child(op_node), child) {
-                rc = lyd_validate_subtree(child, node_when_p, node_exts_p, node_types_p, meta_types_p, 0, diff);
+                rc = lyd_validate_subtree(child, node_when_p, node_types_p, meta_types_p, ext_val_p, 0, diff);
                 LY_CHECK_GOTO(rc, cleanup);
             }
         }
     } else {
         if (validate_subtree) {
             /* prevalidate whole operation subtree */
-            rc = lyd_validate_subtree(op_node, node_when_p, node_exts_p, node_types_p, meta_types_p, 0, diff);
+            rc = lyd_validate_subtree(op_node, node_when_p, node_types_p, meta_types_p, ext_val_p, 0, diff);
             LY_CHECK_GOTO(rc, cleanup);
         }
     }
 
     /* finish incompletely validated terminal values/attributes and when conditions on the full tree */
-    LY_CHECK_GOTO(rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL,
-            node_when_p, 0, node_exts_p, node_types_p, meta_types_p, diff), cleanup);
+    LY_CHECK_GOTO(rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL, node_when_p, 0, node_types_p,
+            meta_types_p, ext_val_p, 0, diff), cleanup);
 
     /* perform final validation of the operation/notification */
     lyd_validate_obsolete(op_node);
@@ -1779,9 +1785,9 @@
     }
 
     ly_set_erase(&node_when, NULL);
-    ly_set_erase(&node_exts, NULL);
     ly_set_erase(&node_types, NULL);
     ly_set_erase(&meta_types, NULL);
+    ly_set_erase(&ext_val, free);
     return rc;
 }