libyang CHANGE allow using different versions of ietf-yang-library

By default, use the new ietf-yang-library revision (2017-08-17) as an
internal module, but allow caller to avoid its loading and instead the
caller can load its own version. In such a case, libyang will provide
context info (ly_ctx_info()) only in case the ietf-yang-library is
loaded in revision 2016-06-21 or 2017-08-17. Other revision can be loaded,
but libyang will not provide the context info in this form.
diff --git a/src/common.c b/src/common.c
index f330edc..2818035 100644
--- a/src/common.c
+++ b/src/common.c
@@ -260,7 +260,7 @@
                 if (end) {
                     name_len = end - cur_expr;
                     name = strndup(cur_expr, name_len);
-                    mod = ly_ctx_get_module(module->ctx, name, NULL);
+                    mod = ly_ctx_get_module(module->ctx, name, NULL, 1);
                     free(name);
                     if (!mod) {
                         LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len, cur_expr);
@@ -340,7 +340,7 @@
             if (!schema) {
                 prefix = NULL;
                 name = strndup(ptr, name_len);
-                mod = ly_ctx_get_module(module->ctx, name, NULL);
+                mod = ly_ctx_get_module(module->ctx, name, NULL, 1);
                 free(name);
                 if (mod) {
                     prefix = mod->prefix;
@@ -479,7 +479,7 @@
                 }
                 goto error;
             }
-            mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL);
+            mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL, 1);
             if (use_ctx_data_clb && ctx->data_clb) {
                 if (!mod) {
                     mod = ctx->data_clb(ctx, NULL, ns->value, 0, ctx->data_clb_data);
@@ -553,7 +553,7 @@
                 }
                 goto error;
             }
-            mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL);
+            mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL, 1);
             if (mod) {
                 /* adjust out size (it can even decrease in some strange cases) */
                 out_size += strlen(mod->name) - pref_len;
@@ -800,7 +800,7 @@
                 /* there is a prefix, get the module */
                 name_len = end - cur_expr;
                 name = strndup(cur_expr, name_len);
-                prev_mod = ly_ctx_get_module(cur_module->ctx, name, NULL);
+                prev_mod = ly_ctx_get_module(cur_module->ctx, name, NULL, 1);
                 free(name);
                 if (!prev_mod) {
                     LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len ? name_len : exp->tok_len[*i], cur_expr);
@@ -842,7 +842,7 @@
             /* get the module, but it may actually not be a module name */
             name_len = end - ptr;
             name = strndup(ptr, name_len);
-            mod = ly_ctx_get_module(cur_module->ctx, name, NULL);
+            mod = ly_ctx_get_module(cur_module->ctx, name, NULL, 1);
             free(name);
 
             if (mod && (mod != cur_module)) {
diff --git a/src/context.c b/src/context.c
index bb06f70..770805d 100644
--- a/src/context.c
+++ b/src/context.c
@@ -40,15 +40,18 @@
 #define YANG_PATH "../models/yang@2017-02-20.h"
 #define IETF_INET_TYPES_PATH "../models/ietf-inet-types@2013-07-15.h"
 #define IETF_YANG_TYPES_PATH "../models/ietf-yang-types@2013-07-15.h"
-#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2016-06-21.h"
-#define IETF_YANG_LIB_REV "2016-06-21"
+#define IETF_DATASTORES "../models/ietf-datastores@2017-08-17.h"
+#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2017-08-17.h"
+#define IETF_YANG_LIB_REV "2017-08-17"
 
 #include IETF_YANG_METADATA_PATH
 #include YANG_PATH
 #include IETF_INET_TYPES_PATH
 #include IETF_YANG_TYPES_PATH
+#include IETF_DATASTORES
 #include IETF_YANG_LIB_PATH
 
+#define LY_INTERNAL_MODULE_COUNT 6
 static struct internal_modules_s {
     const char *name;
     const char *revision;
@@ -60,10 +63,20 @@
     {"yang", "2017-02-20", (const char*)yang_2017_02_20_yin, 1, LYS_IN_YIN},
     {"ietf-inet-types", "2013-07-15", (const char*)ietf_inet_types_2013_07_15_yin, 0, LYS_IN_YIN},
     {"ietf-yang-types", "2013-07-15", (const char*)ietf_yang_types_2013_07_15_yin, 0, LYS_IN_YIN},
-    /* ietf-yang-library is expected at (LY_INTERNAL_MODULE_COUNT - 1) position! */
-    {"ietf-yang-library", "2016-06-21", (const char*)ietf_yang_library_2016_06_21_yin, 1, LYS_IN_YIN}
+    /* ietf-datastores and ietf-yang-library must be right here at the end of the list! */
+    {"ietf-datastores", "2017-08-17", (const char*)ietf_datastores_2017_08_17_yin, 0, LYS_IN_YIN},
+    {"ietf-yang-library", IETF_YANG_LIB_REV, (const char*)ietf_yang_library_2017_08_17_yin, 1, LYS_IN_YIN}
 };
 
+API unsigned int
+ly_ctx_internal_modules_count(struct ly_ctx *ctx)
+{
+    if (!ctx) {
+        return 0;
+    }
+    return ctx->internal_module_count;
+}
+
 API struct ly_ctx *
 ly_ctx_new(const char *search_dir, int options)
 {
@@ -110,7 +123,12 @@
     ctx->models.module_set_id = 1;
 
     /* load internal modules */
-    for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
+    if (options & LY_CTX_NOYANGLIBRARY) {
+        ctx->internal_module_count = LY_INTERNAL_MODULE_COUNT - 2;
+    } else {
+        ctx->internal_module_count = LY_INTERNAL_MODULE_COUNT;
+    }
+    for (i = 0; i < ctx->internal_module_count; i++) {
         module = (struct lys_module *)lys_parse_mem(ctx, internal_modules[i].data, internal_modules[i].format);
         if (!module) {
             goto error;
@@ -472,7 +490,7 @@
 }
 
 static const struct lys_module *
-ly_ctx_get_module_by(const struct ly_ctx *ctx, const char *key, int offset, const char *revision, int with_disabled)
+ly_ctx_get_module_by(const struct ly_ctx *ctx, const char *key, int offset, const char *revision, int with_disabled, int implemented)
 {
     int i;
     struct lys_module *result = NULL;
@@ -507,6 +525,17 @@
                     continue;
                 }
             }
+            if (implemented) {
+                if (ctx->models.list[i]->implemented) {
+                    /* we have the implemented revision */
+                    result = ctx->models.list[i];
+                    break;
+                } else {
+                    /* do not remember the result, we are supposed to return the implemented revision
+                     * not the newest one */
+                    continue;
+                }
+            }
 
             /* remember the current match and search for newer version */
             result = ctx->models.list[i];
@@ -524,15 +553,15 @@
 }
 
 API const struct lys_module *
-ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision)
+ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision, int implemented)
 {
-    return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision, 0);
+    return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision, 0, implemented);
 }
 
 API const struct lys_module *
-ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision)
+ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision, int implemented)
 {
-    return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 0);
+    return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 0, implemented);
 }
 
 API const struct lys_module *
@@ -641,11 +670,11 @@
 
     if (!module) {
         /* exception for internal modules */
-        for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
+        for (i = 0; i < ctx->internal_module_count; i++) {
             if (ly_strequal(name, internal_modules[i].name, 0)) {
                 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
                     /* return internal module */
-                    return (struct lys_module *)ly_ctx_get_module(ctx, name, revision);
+                    return (struct lys_module *)ly_ctx_get_module(ctx, name, revision, 0);
                 }
             }
         }
@@ -653,7 +682,7 @@
             /* try to get the schema with the specific revision from the context,
              * include the disabled modules in the search to avoid their duplication,
              * they are enabled by the subsequent call to lys_set_implemented() */
-            for (i = LY_INTERNAL_MODULE_COUNT, mod = NULL; i < ctx->models.used; i++) {
+            for (i = ctx->internal_module_count, mod = NULL; i < ctx->models.used; i++) {
                 mod = ctx->models.list[i]; /* shortcut */
                 if (ly_strequal(name, mod->name, 0) && mod->rev_size && !strcmp(revision, mod->rev[0].date)) {
                     break;
@@ -686,7 +715,7 @@
                 return NULL;
             } else {
                 /* get the newest revision from the context */
-                mod = ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 1);
+                mod = ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 1, 0);
                 if (mod && mod->disabled) {
                     /* enable the required module */
                     lys_set_enabled(mod);
@@ -736,7 +765,7 @@
     struct lys_node_leaf *leaf;
 
     /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
-    for (o = LY_INTERNAL_MODULE_COUNT - 1; o < ctx->models.used; o++) {
+    for (o = ctx->internal_module_count - 1; o < ctx->models.used; o++) {
         mod = ctx->models.list[o]; /* shortcut */
 
         /* 1) features */
@@ -930,7 +959,7 @@
     ctx = mod->ctx;
 
     /* avoid disabling internal modules */
-    for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
+    for (i = 0; i < ctx->internal_module_count; i++) {
         if (mod == ctx->models.list[i]) {
             LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be disabled.", mod->name);
             return EXIT_FAILURE;
@@ -946,7 +975,7 @@
     mods = ly_set_new();
     ly_set_add(mods, mod, 0);
 checkdependency:
-    for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
+    for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
         mod = ctx->models.list[i]; /* shortcut */
         if (mod->disabled) {
             /* skip the already disabled modules */
@@ -969,7 +998,7 @@
         /* check if the imported module is used in any module supposed to be kept */
         if (!mod->implemented) {
             imported = 0;
-            for (o = LY_INTERNAL_MODULE_COUNT; o < ctx->models.used; o++) {
+            for (o = ctx->internal_module_count; o < ctx->models.used; o++) {
                 if (ctx->models.list[o]->disabled) {
                     /* skip modules already disabled */
                     continue;
@@ -1073,7 +1102,7 @@
     ctx = mod->ctx;
 
     /* avoid disabling internal modules */
-    for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
+    for (i = 0; i < ctx->internal_module_count; i++) {
         if (mod == ctx->models.list[i]) {
             LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
             return EXIT_FAILURE;
@@ -1091,7 +1120,7 @@
      * it is going to be also enabled. This way we try to revert everething that was possibly done by
      * lys_set_disabled(). */
 checkdependency:
-    for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
+    for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
         mod = ctx->models.list[i]; /* shortcut */
         if (!mod->disabled || ly_set_contains(disabled, mod) != -1) {
             /* skip the enabled modules */
@@ -1175,14 +1204,14 @@
     ctx = mod->ctx;
 
     /* avoid removing internal modules ... */
-    for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
+    for (i = 0; i < ctx->internal_module_count; i++) {
         if (mod == ctx->models.list[i]) {
             LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
             return EXIT_FAILURE;
         }
     }
     /* ... and hide the module from the further processing of the context modules list */
-    for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
+    for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
         if (mod == ctx->models.list[i]) {
             ctx->models.list[i] = NULL;
             break;
@@ -1195,7 +1224,7 @@
     mods = ly_set_new();
     ly_set_add(mods, mod, 0);
 checkdependency:
-    for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
+    for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
         mod = ctx->models.list[i]; /* shortcut */
         if (!mod) {
             /* skip modules already selected for removing */
@@ -1218,7 +1247,7 @@
         /* check if the imported module is used in any module supposed to be kept */
         if (!mod->implemented) {
             imported = 0;
-            for (o = LY_INTERNAL_MODULE_COUNT; o < ctx->models.used; o++) {
+            for (o = ctx->internal_module_count; o < ctx->models.used; o++) {
                 if (!ctx->models.list[o]) {
                     /* skip modules already selected for removing */
                     continue;
@@ -1250,7 +1279,7 @@
 
 
     /* consolidate the modules list */
-    for (i = o = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
+    for (i = o = ctx->internal_module_count; i < ctx->models.used; i++) {
         if (ctx->models.list[o]) {
             /* used cell */
             o++;
@@ -1290,7 +1319,7 @@
     }
 
     /* models list */
-    for (; ctx->models.used > LY_INTERNAL_MODULE_COUNT; ctx->models.used--) {
+    for (; ctx->models.used > ctx->internal_module_count; ctx->models.used--) {
         /* remove the applied deviations and augments */
         lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
         /* remove the module */
@@ -1446,20 +1475,28 @@
 API struct lyd_node *
 ly_ctx_info(struct ly_ctx *ctx)
 {
-    int i;
+    int i, bis = 0;
     char id[8];
     char *str;
     const struct lys_module *mod;
-    struct lyd_node *root, *cont;
+    struct lyd_node *root, *root_bis = NULL, *cont, *cont_bis;
 
     if (!ctx) {
         ly_errno = LY_EINVAL;
         return NULL;
     }
 
-    mod = ly_ctx_get_module(ctx, "ietf-yang-library", IETF_YANG_LIB_REV);
+    mod = ly_ctx_get_module(ctx, "ietf-yang-library", NULL, 1);
     if (!mod || !mod->data) {
-        LOGINT;
+        LOGERR(LY_EINVAL, "ietf-yang-library is not implemented.");
+        return NULL;
+    }
+    if (mod->rev && !strcmp(mod->rev[0].date, "2016-06-21")) {
+        bis = 0;
+    } else if (mod->rev && !strcmp(mod->rev[0].date, IETF_YANG_LIB_REV)) {
+        bis = 1;
+    } else {
+        LOGERR(LY_EINVAL, "Incompatible ietf-yang-library version in context.");
         return NULL;
     }
 
@@ -1468,79 +1505,149 @@
         return NULL;
     }
 
+    if (bis) {
+        root_bis = lyd_new(NULL, mod, "yang-library");
+        if (!root_bis || !lyd_new(root_bis, mod, "modules") || !lyd_new(root_bis, mod, "module-sets")) {
+            goto error;
+        }
+    }
+
     for (i = 0; i < ctx->models.used; ++i) {
         if (ctx->models.list[i]->disabled) {
             /* skip the disabled modules */
             continue;
         }
 
-        cont = lyd_new(root, NULL, "module");
+        cont = lyd_new(root, mod, "module");
         if (!cont) {
-            lyd_free(root);
-            return NULL;
+            goto error;
+        }
+        if (bis) {
+            if (!(cont_bis = lyd_new(root_bis->child, mod, "module"))) {
+                goto error;
+            }
+
+            /* id is present only in yang-library container */
+            sprintf(id, "%d", i);
+            if (!lyd_new_leaf(cont_bis, mod, "id", id)) {
+                goto error;
+            }
         }
 
-        if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
-            lyd_free(root);
-            return NULL;
+        /* name */
+        if (!lyd_new_leaf(cont, mod, "name", ctx->models.list[i]->name)) {
+            goto error;
         }
-        if (!lyd_new_leaf(cont, NULL, "revision", (ctx->models.list[i]->rev_size ?
+        if (bis && !lyd_new_leaf(cont_bis, mod, "name", ctx->models.list[i]->name)) {
+            goto error;
+        }
+        /* revision */
+        if (!lyd_new_leaf(cont, mod, "revision", (ctx->models.list[i]->rev_size ?
                               ctx->models.list[i]->rev[0].date : ""))) {
-            lyd_free(root);
-            return NULL;
+            goto error;
         }
+        if (bis && !lyd_new_leaf(cont_bis, mod, "revision", (ctx->models.list[i]->rev_size ?
+                                 ctx->models.list[i]->rev[0].date : ""))) {
+            goto error;
+        }
+        /* schema */
         if (ctx->models.list[i]->filepath) {
             if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
                 LOGMEM;
-                lyd_free(root);
-                return NULL;
-            } else if (!lyd_new_leaf(cont, NULL, "schema", str)) {
+                goto error;
+            }
+            if (!lyd_new_leaf(cont, mod, "schema", str)) {
                 free(str);
-                lyd_free(root);
-                return NULL;
+                goto error;
+            }
+            if (bis && !lyd_new_leaf(cont_bis, mod, "schema", str)) {
+                free(str);
+                goto error;
             }
             free(str);
         }
-        if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
-            lyd_free(root);
-            return NULL;
+        /* namespace */
+        if (!lyd_new_leaf(cont, mod, "namespace", ctx->models.list[i]->ns)) {
+            goto error;
         }
+        if (bis && !lyd_new_leaf(cont_bis, mod, "namespace", ctx->models.list[i]->ns)) {
+            goto error;
+        }
+        /* feature leaf-list */
         if (ylib_feature(cont, ctx->models.list[i])) {
-            lyd_free(root);
-            return NULL;
+            goto error;
         }
+        if (bis && ylib_feature(cont_bis, ctx->models.list[i])) {
+            goto error;
+        }
+        /* deviation list */
         if (ylib_deviation(cont, ctx->models.list[i])) {
-            lyd_free(root);
-            return NULL;
+            goto error;
         }
-        if (ctx->models.list[i]->implemented
-                && !lyd_new_leaf(cont, NULL, "conformance-type", "implement")) {
-            lyd_free(root);
-            return NULL;
+        if (bis && ylib_deviation(cont_bis, ctx->models.list[i])) {
+            goto error;
         }
-        if (!ctx->models.list[i]->implemented
-                && !lyd_new_leaf(cont, NULL, "conformance-type", "import")) {
-            lyd_free(root);
-            return NULL;
+        /* conformance-type */
+        if (!lyd_new_leaf(cont, mod, "conformance-type",
+                          ctx->models.list[i]->implemented ? "implement" : "import")) {
+            goto error;
         }
+        if (bis && !lyd_new_leaf(cont_bis, mod, "conformance-type",
+                                 ctx->models.list[i]->implemented ? "implement" : "import")) {
+            goto error;
+        }
+        /* submodule list */
         if (ylib_submodules(cont, ctx->models.list[i])) {
-            lyd_free(root);
-            return NULL;
+            goto error;
+        }
+        if (bis && ylib_submodules(cont_bis, ctx->models.list[i])) {
+            goto error;
+        }
+    }
+
+    if (bis) {
+        /* module-sets - libyang currently has just one module set with all modules */
+        if (!(cont_bis = lyd_new(root_bis->child->next, mod, "module-set"))) {
+            goto error;
+        }
+        if (!lyd_new_leaf(cont_bis, mod, "id", "complete")) {
+            goto error;
+        }
+        /* refer all modules */
+        for (i = 0; i < ctx->models.used; ++i) {
+            sprintf(id, "%d", i);
+            if (!lyd_new_leaf(cont_bis, mod, "module", id)) {
+                goto error;
+            }
         }
     }
 
     sprintf(id, "%u", ctx->models.module_set_id);
     if (!lyd_new_leaf(root, mod, "module-set-id", id)) {
-        lyd_free(root);
-        return NULL;
+        goto error;
+    }
+    if (bis && !lyd_new_leaf(root_bis, mod, "checksum", id)) {
+        goto error;
+    }
+
+    if (root_bis) {
+        if (lyd_insert_sibling(&root_bis, root)) {
+            goto error;
+        }
+        root = root_bis;
+        root_bis = 0;
     }
 
     if (lyd_validate(&root, LYD_OPT_NOSIBLINGS, NULL)) {
-        lyd_free(root);
-        return NULL;
+        goto error;
     }
 
     return root;
+
+error:
+    lyd_free_withsiblings(root);
+    lyd_free_withsiblings(root_bis);
+    return NULL;
 }
 
 API const struct lys_node *
diff --git a/src/context.h b/src/context.h
index 4b002d5..88fb834 100644
--- a/src/context.h
+++ b/src/context.h
@@ -53,6 +53,7 @@
     ly_module_data_clb data_clb;
     void *data_clb_data;
     pthread_key_t errlist_key;
+    uint8_t internal_module_count;
 };
 
 #endif /* LY_CONTEXT_H_ */
diff --git a/src/libyang.h.in b/src/libyang.h.in
index 13614fa..ca4cf50 100644
--- a/src/libyang.h.in
+++ b/src/libyang.h.in
@@ -1022,11 +1022,6 @@
  */
 
 /**
- * @brief Number of internal modules, which are always in every context and cannot be removed nor disabled.
- */
-#define LY_INTERNAL_MODULE_COUNT 5
-
-/**
  * @defgroup context Context
  * @{
  *
@@ -1051,7 +1046,12 @@
 #define LY_CTX_TRUSTED        0x02 /**< Handle the schema being parsed as trusted and skip its validation
                                         tests. Note that while this option improves performance, it can
                                         lead to an undefined behavior if the schema is not correct. */
-
+#define LY_CTX_NOYANGLIBRARY  0x04 /**< Do not internally implement ietf-yang-library module. The option
+                                        causes that function ly_ctx_info() does not work (returns NULL) until
+                                        the ietf-yang-library module is loaded manually. While any revision
+                                        of this schema can be loaded with this option, note that the only
+                                        revisions implemented by ly_ctx_info() are 2016-06-21 and 2017-08-17.
+                                        This option cannot be used with ly_ctx_new_yl*() functions. */
 
 /**@} contextoptions */
 
@@ -1127,6 +1127,13 @@
 struct ly_ctx *ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options);
 
 /**
+ * @brief Number of internal modules, which are in the context and cannot be removed nor disabled.
+ * @param[in] ctx Context to investigate.
+ * @return Number of internal modules, 0 in case of invalid parameter.
+ */
+unsigned int ly_ctx_internal_modules_count(struct ly_ctx *ctx);
+
+/**
  * @brief Add the search path into libyang context
  *
  * To reset search paths set in the context, use ly_ctx_unset_searchdirs() and then
@@ -1230,11 +1237,13 @@
  * @param[in] ctx Context to work in.
  * @param[in] name Name of the YANG module to get.
  * @param[in] revision Optional revision date of the YANG module to get. If not specified,
- * the schema in the newest revision is returned if any.
+ * the schema in the newest/implemented revision (see \p implemented parameter) is returned if any.
+ * @param[in] implemented In case the revision is not specified, require the implemented module
+ * instead of the newest revision of the module.
  * @return Pointer to the data model structure, NULL if no schema following the name and
  * revision requirements is present in the context.
  */
-const struct lys_module *ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision);
+const struct lys_module *ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision, int implemented);
 
 /**
  * @brief Get pointer to the older schema tree to the specified one in the provided context.
@@ -1349,11 +1358,13 @@
  * @param[in] ctx Context to work in.
  * @param[in] ns Namespace of the YANG module to get.
  * @param[in] revision Optional revision date of the YANG module to get. If not specified,
- * the schema in the newest revision is returned if any.
+ * the schema in the newest/implemented revision (see \p implemented parameter) is returned if any.
+ * @param[in] implemented In case the revision is not specified, require the implemented module
+ * instead of the newest revision of the module.
  * @return Pointer to the data model structure, NULL if no schema following the namespace and
  * revision requirements is present in the context.
  */
-const struct lys_module *ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision);
+const struct lys_module *ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision, int implemented);
 
 /**
  * @brief Get submodule of a main module.
diff --git a/src/parser.c b/src/parser.c
index 89907a7..476993e 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -621,7 +621,7 @@
     if (!match_name) {
         if (!module && !revision) {
             /* otherwise the module would be already taken from the context */
-            result = (struct lys_module *)ly_ctx_get_module(ctx, name, revision);
+            result = (struct lys_module *)ly_ctx_get_module(ctx, name, NULL, 0);
         }
         if (!result) {
             LOGERR(LY_ESYS, "Data model \"%s\" not found.", name);
@@ -1398,7 +1398,7 @@
     }
 
     /* find module */
-    mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL);
+    mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL, 1);
     if (!mod) {
         LOGINT;
         return NULL;
@@ -2111,9 +2111,9 @@
 
     /* first, get module where the annotation should be defined */
     if (module_ns) {
-        mod = (struct lys_module *)ly_ctx_get_module_by_ns(ctx, module_ns, NULL);
+        mod = (struct lys_module *)ly_ctx_get_module_by_ns(ctx, module_ns, NULL, 1);
     } else if (module_name) {
-        mod = (struct lys_module *)ly_ctx_get_module(ctx, module_name, NULL);
+        mod = (struct lys_module *)ly_ctx_get_module(ctx, module_name, NULL, 1);
     } else {
         LOGINT;
         return -1;
diff --git a/src/parser_json.c b/src/parser_json.c
index 3762ac7..6bc156f 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -608,7 +608,7 @@
         *name = '\0';
         name++;
         prefix = str;
-        module = (struct lys_module *)ly_ctx_get_module(parent_module->ctx, prefix, NULL);
+        module = (struct lys_module *)ly_ctx_get_module(parent_module->ctx, prefix, NULL, 1);
         if (!module) {
             LOGVAL(LYE_INELEM, LY_VLOG_NONE, NULL, name);
             goto error;
@@ -862,7 +862,7 @@
     if (!(*parent)) {
         /* starting in root */
         /* get the proper schema */
-        module = ly_ctx_get_module(ctx, prefix, NULL);
+        module = ly_ctx_get_module(ctx, prefix, NULL, 1);
         if (ctx->data_clb) {
             if (!module) {
                 module = ctx->data_clb(ctx, prefix, NULL, 0, ctx->data_clb_data);
@@ -881,7 +881,7 @@
     } else {
         if (prefix) {
             /* get the proper module to give the chance to load/implement it */
-            module = ly_ctx_get_module(ctx, prefix, NULL);
+            module = ly_ctx_get_module(ctx, prefix, NULL, 1);
             if (ctx->data_clb) {
                 if (!module) {
                     ctx->data_clb(ctx, prefix, NULL, 0, ctx->data_clb_data);
@@ -1368,7 +1368,7 @@
         if (!result) {
             for (iter = next; iter && iter->prev->next; iter = iter->prev);
             result = iter;
-            if (iter && (options & LYD_OPT_DATA_ADD_YANGLIB) && iter->schema->module == ctx->models.list[LY_INTERNAL_MODULE_COUNT - 1]) {
+            if (iter && (options & LYD_OPT_DATA_ADD_YANGLIB) && iter->schema->module == ctx->models.list[ctx->internal_module_count - 1]) {
                 /* ietf-yang-library data present, so ignore the option to add them */
                 options &= ~LYD_OPT_DATA_ADD_YANGLIB;
             }
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 27ca66f..1d6eb20 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -140,7 +140,7 @@
 
     /* find schema node */
     if (!parent) {
-        mod = ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL);
+        mod = ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL, 1);
         if (ctx->data_clb) {
             if (!mod) {
                 mod = ctx->data_clb(ctx, NULL, xml->ns->value, 0, ctx->data_clb_data);
@@ -673,7 +673,7 @@
         }
         if (iter) {
             last = iter;
-            if ((options & LYD_OPT_DATA_ADD_YANGLIB) && iter->schema->module == ctx->models.list[LY_INTERNAL_MODULE_COUNT - 1]) {
+            if ((options & LYD_OPT_DATA_ADD_YANGLIB) && iter->schema->module == ctx->models.list[ctx->internal_module_count - 1]) {
                 /* ietf-yang-library data present, so ignore the option to add them */
                 options &= ~LYD_OPT_DATA_ADD_YANGLIB;
             }
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 46f65fd..949bed2 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -2620,7 +2620,7 @@
         tmp_mod = module;
 
         /* get the model from the context */
-        module = (struct lys_module *)ly_ctx_get_module(ctx, module->name, revision);
+        module = (struct lys_module *)ly_ctx_get_module(ctx, module->name, revision, 0);
         assert(module);
 
         /* free what was parsed */
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 03f7505..d444d49 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -7087,7 +7087,7 @@
         lys_free(module, NULL, 0);
 
         /* get the model from the context */
-        module = (struct lys_module *)ly_ctx_get_module(ctx, value, revision);
+        module = (struct lys_module *)ly_ctx_get_module(ctx, value, revision, 0);
         assert(module);
     }
 
diff --git a/src/printer_json.c b/src/printer_json.c
index 43210e5..6d56faf 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -150,7 +150,7 @@
             (!node->dflt && (options & LYP_WD_ALL_TAG) && lyd_wd_default(leaf))) {
         /* we have implicit OR explicit default node */
         /* get with-defaults module */
-        wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL);
+        wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
     }
 
     if (!onlyvalue) {
diff --git a/src/printer_xml.c b/src/printer_xml.c
index 54fd301..b02c2ba 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -90,7 +90,7 @@
     if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
         if (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG)) {
             /* get with-defaults module and print its namespace */
-            wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL);
+            wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
             if (wdmod && modlist_add(&mlist, wdmod)) {
                 goto print;
             }
@@ -144,7 +144,7 @@
                 (!node->dflt && (options & LYP_WD_ALL_TAG) && lyd_wd_default((struct lyd_node_leaf_list *)node))) {
             /* we have implicit OR explicit default node */
             /* get with-defaults module */
-            wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL);
+            wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
             if (wdmod) {
                 /* print attribute only if context include with-defaults schema */
                 ly_print(out, " %s:default=\"true\"", wdmod->prefix);
diff --git a/src/resolve.c b/src/resolve.c
index fcfe246..2f3b3b3 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -2201,7 +2201,7 @@
 
         memmove(module_name, mod_name, mod_name_len);
         module_name[mod_name_len] = '\0';
-        module = ly_ctx_get_module(ctx, module_name, NULL);
+        module = ly_ctx_get_module(ctx, module_name, NULL, 1);
 
         if (buf_backup) {
             /* return previous internal buffer content */
@@ -2256,7 +2256,7 @@
                     memmove(module_name, mod_name, mod_name_len);
                     module_name[mod_name_len] = '\0';
                     /* will also find an augment module */
-                    prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
+                    prefix_mod = ly_ctx_get_module(ctx, module_name, NULL, 1);
 
                     if (buf_backup) {
                         /* return previous internal buffer content */
@@ -2532,7 +2532,7 @@
                     memmove(module_name, mod_name, mod_name_len);
                     module_name[mod_name_len] = '\0';
                     /* will also find an augment module */
-                    prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
+                    prefix_mod = ly_ctx_get_module(ctx, module_name, NULL, 1);
 
                     if (buf_backup) {
                         /* return previous internal buffer content */
@@ -7288,7 +7288,7 @@
                 LOGMEM;
                 goto error;
             }
-            mod = ly_ctx_get_module(ctx, str, NULL);
+            mod = ly_ctx_get_module(ctx, str, NULL, 1);
             if (ctx->data_clb) {
                 if (!mod) {
                     mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
diff --git a/src/tree_data.c b/src/tree_data.c
index e9f4cf6..2333714 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -351,7 +351,7 @@
                 return EXIT_FAILURE;
             }
         } else {
-            for (i = (options & LYD_OPT_DATA_NO_YANGLIB) ? LY_INTERNAL_MODULE_COUNT : LY_INTERNAL_MODULE_COUNT - 1;
+            for (i = (options & LYD_OPT_DATA_NO_YANGLIB) ? ctx->internal_module_count : ctx->internal_module_count - 1;
                  i < ctx->models.used;
                  i++) {
                 /* skip not implemented and disabled modules */
@@ -777,6 +777,7 @@
     struct lyd_node_leaf_list *leaf_list;
     struct ly_set *set, *data;
     uint32_t i, j;
+    int validity_changed = 0;
 
     assert((op == 0) || (op == 1) || (op == 2));
 
@@ -794,6 +795,7 @@
                                 || ((op != 1) && (leaf_list->value_type & LY_TYPE_LEAFREF_UNRES))) {
                             /* invalidate the leafref, a change concerning it happened */
                             leaf_list->validity |= LYD_VAL_LEAFREF;
+                            validity_changed = 1;
                             if (leaf_list->value_type == LY_TYPE_LEAFREF) {
                                 /* remove invalid link */
                                 leaf_list->value.leafref = NULL;
@@ -811,7 +813,7 @@
     }
 
     /* invalidate parent to make sure it will be checked in future validation */
-    if (node->parent) {
+    if (validity_changed && node->parent) {
         node->parent->validity = LYD_VAL_MAND;
     }
 }
@@ -1296,7 +1298,7 @@
 
         memmove(module_name, mod_name, mod_name_len);
         module_name[mod_name_len] = '\0';
-        module = ly_ctx_get_module(ctx, module_name, NULL);
+        module = ly_ctx_get_module(ctx, module_name, NULL, 1);
 
         if (buf_backup) {
             /* return previous internal buffer content */
@@ -4154,7 +4156,7 @@
 
     data_tree = *node;
 
-    if ((!options || (options & (LYD_OPT_DATA | LYD_OPT_CONFIG | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT))) && !(*node)) {
+    if ((!(options & LYD_OPT_TYPEMASK) || (options & (LYD_OPT_DATA | LYD_OPT_CONFIG | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT))) && !(*node)) {
         /* get context with schemas from the var_arg */
         ctx = (struct ly_ctx *)var_arg;
         if (!ctx) {
@@ -4321,7 +4323,7 @@
      * only the inner instances were tested in lyv_data_content() */
     set = ly_set_new();
     LY_TREE_FOR(*node, root) {
-        if ((options & LYD_OPT_DATA_ADD_YANGLIB) && root->schema->module == ctx->models.list[LY_INTERNAL_MODULE_COUNT - 1]) {
+        if ((options & LYD_OPT_DATA_ADD_YANGLIB) && root->schema->module == ctx->models.list[ctx->internal_module_count - 1]) {
             /* ietf-yang-library data present, so ignore the option to add them */
             options &= ~LYD_OPT_DATA_ADD_YANGLIB;
         }
@@ -4878,22 +4880,22 @@
             LOGMEM;
             return NULL;
         }
-        module = ly_ctx_get_module(ctx, aux, NULL);
+        module = ly_ctx_get_module(ctx, aux, NULL, 1);
         free(aux);
         name = p + 1;
 
         if (!module) {
             /* module not found */
-            LOGERR(LY_EINVAL, "Attribute prefix does not match any schema in the context.");
+            LOGERR(LY_EINVAL, "Attribute prefix does not match any implemented schema in the context.");
             return NULL;
         }
     } else if (mod) {
         module = mod;
     } else if (!mod && (!strcmp(name, "type") || !strcmp(name, "select")) && !strcmp(parent->schema->name, "filter")) {
         /* special case of inserting unqualified filter attributes "type" and "select" */
-        module = ly_ctx_get_module(ctx, "ietf-netconf", NULL);
+        module = ly_ctx_get_module(ctx, "ietf-netconf", NULL, 1);
         if (!module) {
-            LOGERR(LY_EINVAL, "Attribute prefix does not match any schema in the context.");
+            LOGERR(LY_EINVAL, "Attribute prefix does not match any implemented schema in the context.");
             return NULL;
         }
     } else {
@@ -6391,7 +6393,7 @@
     int ret = EXIT_FAILURE;
 
     assert(root && unres && !(options & LYD_OPT_ACT_NOTIF));
-    assert(!data_tree || !data_tree->prev->next);
+    //assert(!data_tree || !data_tree->prev->next);
 
     if ((options & LYD_OPT_NOSIBLINGS) && !(*root)) {
         LOGERR(LY_EINVAL, "Cannot add default values for one module (LYD_OPT_NOSIBLINGS) without any data.");
diff --git a/src/tree_schema.c b/src/tree_schema.c
index d8e4235..7fcade4 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -2599,7 +2599,7 @@
             LOGMEM;
             return NULL;
         }
-        main_module = ly_ctx_get_module(module->ctx, str, NULL);
+        main_module = ly_ctx_get_module(module->ctx, str, NULL, 1);
         free(str);
         return main_module;
     }