tree schema UPDATE schema mount support for lys_getnext

... which also adds the support for lys_find_xpath_atoms().
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 5c897bf..3ec4574 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -37,6 +37,7 @@
 #include "parser_internal.h"
 #include "parser_schema.h"
 #include "path.h"
+#include "plugins_exts.h"
 #include "plugins_internal.h"
 #include "schema_compile.h"
 #include "schema_compile_amend.h"
@@ -164,7 +165,11 @@
         const struct lysc_ext_instance *ext, uint32_t options)
 {
     const struct lysc_node *next = NULL;
-    ly_bool action_flag = 0, notif_flag = 0;
+    ly_bool action_flag = 0, notif_flag = 0, sm_flag = options & LYS_GETNEXT_WITHSCHEMAMOUNT ? 0 : 1;
+    LY_ARRAY_COUNT_TYPE u;
+    struct ly_ctx *sm_ctx = NULL;
+    const struct lys_module *mod;
+    uint32_t idx;
 
     LY_CHECK_ARG_RET(NULL, parent || module || ext, NULL);
 
@@ -172,7 +177,7 @@
     if (!last) {
         /* first call */
 
-        /* get know where to start */
+        /* learn where to start */
         if (parent) {
             /* schema subtree */
             next = last = lysc_node_child(parent);
@@ -204,8 +209,29 @@
 
 repeat:
     if (!next) {
-        /* possibly go back to parent */
-        if (last && (last->parent != parent)) {
+        if (last && !sm_flag && parent && (last->module->ctx != parent->module->ctx)) {
+            sm_flag = 1;
+
+            /* find the module of last */
+            sm_ctx = last->module->ctx;
+            idx = 0;
+            while ((mod = ly_ctx_get_module_iter(sm_ctx, &idx))) {
+                if (mod == last->module) {
+                    break;
+                }
+            }
+            assert(mod);
+
+            /* get node from the next mounted module */
+            while (!next && (mod = ly_ctx_get_module_iter(sm_ctx, &idx))) {
+                if (!mod->implemented) {
+                    continue;
+                }
+
+                next = lys_getnext(NULL, NULL, mod->compiled, options & ~LYS_GETNEXT_WITHSCHEMAMOUNT);
+            }
+        } else if (last && (last->parent != parent)) {
+            /* go back to parent */
             last = last->parent;
             goto next;
         } else if (!action_flag) {
@@ -226,6 +252,35 @@
             } else {
                 next = (struct lysc_node *)module->notifs;
             }
+        } else if (!sm_flag) {
+            sm_flag = 1;
+            if (parent) {
+                LY_ARRAY_FOR(parent->exts, u) {
+                    if (!strcmp(parent->exts[u].def->name, "mount-point") &&
+                            !strcmp(parent->exts[u].def->module->name, "ietf-yang-schema-mount")) {
+                        lyplg_ext_schema_mount_create_context(&parent->exts[u], &sm_ctx);
+                        if (sm_ctx) {
+                            /* some usable context created */
+                            break;
+                        }
+                    }
+                }
+                if (sm_ctx) {
+                    /* get the first node from the first usable module */
+                    idx = 0;
+                    while (!next && (mod = ly_ctx_get_module_iter(sm_ctx, &idx))) {
+                        if (!mod->implemented) {
+                            continue;
+                        }
+
+                        next = lys_getnext(NULL, NULL, mod->compiled, options & ~LYS_GETNEXT_WITHSCHEMAMOUNT);
+                    }
+                    if (!next) {
+                        /* no nodes found */
+                        ly_ctx_destroy(sm_ctx);
+                    }
+                }
+            }
         } else {
             return NULL;
         }
diff --git a/src/tree_schema.h b/src/tree_schema.h
index c57a0fc..8155885 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1971,6 +1971,8 @@
 #define LYS_FIND_XP_OUTPUT  0x10    /**< Search RPC/action output nodes instead of input ones. */
 #define LYS_FIND_NO_MATCH_ERROR 0x40    /**< Return error if a path segment matches no nodes, otherwise only warning
                                              is printed. */
+#define LYS_FIND_SCHEMAMOUNT    0x0200  /**< Traverse also nodes from mounted modules. If any such nodes are returned,
+                                             the caller **must free** their context! */
 /** @} findxpathoptions */
 
 /**
@@ -2189,6 +2191,9 @@
 #define LYS_GETNEXT_INTONPCONT   0x08 /**< ::lys_getnext() option to look into non-presence container, instead of returning container itself */
 #define LYS_GETNEXT_OUTPUT       0x10 /**< ::lys_getnext() option to provide RPC's/action's output schema nodes instead of input schema nodes
                                             provided by default */
+#define LYS_GETNEXT_WITHSCHEMAMOUNT 0x20    /**< ::lys_getnext() option to also traverse top-level nodes of all the mounted modules
+                                                 on the parent mount point but note that if any such nodes are returned,
+                                                 the caller **must free** their context */
 /** @} sgetnextflags */
 
 /**
diff --git a/src/xpath.c b/src/xpath.c
index 578324a..b83e1cc 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -6673,6 +6673,9 @@
     if (options & LYXP_SCNODE_OUTPUT) {
         getnext_opts |= LYS_GETNEXT_OUTPUT;
     }
+    if (options & LYXP_SCNODE_SCHEMAMOUNT) {
+        getnext_opts |= LYS_GETNEXT_WITHSCHEMAMOUNT;
+    }
 
     orig_used = set->used;
     for (i = 0; i < orig_used; ++i) {
diff --git a/src/xpath.h b/src/xpath.h
index 3e61bb0..c34a0f3 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -381,6 +381,7 @@
                                                              warning is printed. */
 #define LYXP_ACCESS_TREE_ALL 0x80   /**< Explicit accessible tree of all the nodes. */
 #define LYXP_ACCESS_TREE_CONFIG 0x0100  /**< Explicit accessible tree of only configuration data. */
+#define LYXP_SCNODE_SCHEMAMOUNT LYS_FIND_SCHEMAMOUNT    /**< Nodes from mounted modules are also accessible. */
 
 /**
  * @brief Cast XPath set to another type.
diff --git a/tests/utests/extensions/test_schema_mount.c b/tests/utests/extensions/test_schema_mount.c
index be879ec..d11eeaf 100644
--- a/tests/utests/extensions/test_schema_mount.c
+++ b/tests/utests/extensions/test_schema_mount.c
@@ -1549,6 +1549,108 @@
     lyd_free_siblings(data);
 }
 
+static void
+test_lys_getnext(void **state)
+{
+    const struct lysc_node *parent, *node;
+    struct ly_ctx *sm_ctx;
+
+    ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb,
+            "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
+            "    xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
+            "  <module-set>"
+            "    <name>test-set</name>"
+            "    <module>"
+            "      <name>ietf-datastores</name>"
+            "      <revision>2018-02-14</revision>"
+            "      <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
+            "    </module>"
+            "    <module>"
+            "      <name>ietf-yang-library</name>"
+            "      <revision>2019-01-04</revision>"
+            "      <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+            "    </module>"
+            "    <module>"
+            "      <name>ietf-yang-schema-mount</name>"
+            "      <revision>2019-01-14</revision>"
+            "      <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
+            "    </module>"
+            "    <module>"
+            "      <name>ietf-interfaces</name>"
+            "      <revision>2014-05-08</revision>"
+            "      <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
+            "    </module>"
+            "    <module>"
+            "      <name>iana-if-type</name>"
+            "      <revision>2014-05-08</revision>"
+            "      <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
+            "    </module>"
+            "    <module>"
+            "      <name>ietf-ip</name>"
+            "      <revision>2014-06-16</revision>"
+            "      <namespace>urn:ietf:params:xml:ns:yang:ietf-ip</namespace>"
+            "    </module>"
+            "    <import-only-module>"
+            "      <name>ietf-yang-types</name>"
+            "      <revision>2013-07-15</revision>"
+            "      <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
+            "    </import-only-module>"
+            "  </module-set>"
+            "  <schema>"
+            "    <name>test-schema</name>"
+            "    <module-set>test-set</module-set>"
+            "  </schema>"
+            "  <datastore>"
+            "    <name>ds:running</name>"
+            "    <schema>test-schema</schema>"
+            "  </datastore>"
+            "  <datastore>"
+            "    <name>ds:operational</name>"
+            "    <schema>test-schema</schema>"
+            "  </datastore>"
+            "  <content-id>1</content-id>"
+            "</yang-library>"
+            "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
+            "  <module-set-id>1</module-set-id>"
+            "</modules-state>"
+            "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
+            "  <mount-point>"
+            "    <module>sm</module>"
+            "    <label>root</label>"
+            "    <shared-schema/>"
+            "  </mount-point>"
+            "</schema-mounts>");
+
+    parent = lys_find_path(UTEST_LYCTX, NULL, "/sm:root", 0);
+    assert_non_null(parent);
+
+    node = lys_getnext(NULL, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT);
+    assert_non_null(node);
+    assert_string_equal(node->name, "schema-mounts");
+    sm_ctx = node->module->ctx;
+
+    node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT);
+    assert_non_null(node);
+    assert_string_equal(node->name, "yang-library");
+
+    node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT);
+    assert_non_null(node);
+    assert_string_equal(node->name, "modules-state");
+
+    node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT);
+    assert_non_null(node);
+    assert_string_equal(node->name, "interfaces");
+
+    node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT);
+    assert_non_null(node);
+    assert_string_equal(node->name, "interfaces-state");
+
+    node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT);
+    assert_null(node);
+
+    ly_ctx_destroy(sm_ctx);
+}
+
 int
 main(void)
 {
@@ -1560,6 +1662,7 @@
         UTEST(test_parse_shared_parent_ref, setup),
         UTEST(test_parse_config, setup),
         UTEST(test_new, setup),
+        UTEST(test_lys_getnext, setup),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);