schema mount NEW initial schema mount code
diff --git a/src/plugins_exts/schema_mount.c b/src/plugins_exts/schema_mount.c
new file mode 100644
index 0000000..4b1c1cf
--- /dev/null
+++ b/src/plugins_exts/schema_mount.c
@@ -0,0 +1,208 @@
+/**
+ * @file schema_mount.c
+ * @author Tadeas Vintrlik <xvintr04@stud.fit.vutbr.cz>
+ * @brief libyang extension plugin - Schema Mount (RFC 8528)
+ *
+ * Copyright (c) 2021 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dict.h"
+#include "libyang.h"
+#include "log.h"
+#include "plugins_exts.h"
+#include "tree_data.h"
+#include "tree_schema.h"
+
+/**
+ * @brief Check if given mount point is unique among its' siblings
+ *
+ * @param cctx Compilation context.
+ * @param c_ext Compiled extension instance for checking uniqueness.
+ * @param p_ext Extension instance of the mount-point for comparison.
+ *
+ * @return LY_SUCCESS if is unique. LY_EINVAL otherwise.
+ */
+static LY_ERR
+schema_mount_unique_mount_point(struct lysc_ctx *cctx, const struct lysc_ext_instance *c_ext,
+        const struct lysp_ext_instance *p_ext)
+{
+    struct lysp_module *pmod;
+    struct lysp_ext_instance *exts;
+    LY_ARRAY_COUNT_TYPE u, v;
+    struct lysp_node *parent;
+    struct lysp_import *module;
+    char *ext_prefix, *ext_name;
+
+    /* Check if it is the only instance of the mount-point among its' siblings */
+    parent = (struct lysp_node *) c_ext->parent;
+    exts = parent->exts;
+    pmod = lysc_ctx_get_pmod(cctx);
+    LY_ARRAY_FOR(exts, u) {
+        /* Extract prefix and name of the extension */
+        ext_prefix = strdup(exts[u].name);
+        ext_name = strstr(exts[u].name, ":");
+        ext_name++;
+        ext_prefix[strstr(ext_prefix, ":") - ext_prefix] = '\0';
+
+        module = NULL;
+        LY_ARRAY_FOR(pmod->imports, v) {
+            if (!strcmp(pmod->imports[v].prefix, ext_prefix)) {
+                /* Found the matching module */
+                module = &pmod->imports[v];
+                break;
+            }
+        }
+        free(ext_prefix);
+        if ((&exts[u] != p_ext) && module && (!strcmp(module->name, "ietf-yang-schema-mount")) &&
+                (!strcmp(exts[u].name, "mount-point"))) {
+            /* Found another instance of mount-point only one allowed per node */
+            return LY_EINVAL;
+        }
+    }
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Schema mount compile.
+ *
+ * Checks if it can be a valid extension instance for yang schema mount.
+ *
+ * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
+ */
+static LY_ERR
+schema_mount_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext,
+        struct lysc_ext_instance *c_ext)
+{
+    const struct lys_module *cur_mod;
+
+    /* Check if processing right callback */
+    assert(!strcmp(p_ext->name, "yangmnt:mount-point"));
+
+    /* Check if mount point was found in YANG version 1.1 module */
+    cur_mod = lysc_ctx_get_cur_mod(cctx);
+    if (cur_mod->parsed->version != LYS_VERSION_1_1) {
+        return LY_EINVAL;
+    }
+
+    /* Check if its' parent is a container or a list */
+    if ((p_ext->parent_stmt != LY_STMT_CONTAINER) && (p_ext->parent_stmt != LY_STMT_LIST)) {
+        return LY_EINVAL;
+    }
+
+    /* Check if the only mount-point among siblings */
+    if (schema_mount_unique_mount_point(cctx, c_ext, p_ext)) {
+        return LY_EINVAL;
+    }
+
+    (void)c_ext;
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse callback for schema mount.
+ *
+ * Check if data is valid for schema mount and inserts it to the parent.
+ */
+static LY_ERR
+schema_mount_parse(struct ly_in *in, LYD_FORMAT format, struct lysc_ext_instance *ext,
+        struct lyd_node *parent, uint32_t parse_opts, uint32_t val_opts)
+{
+    LY_ERR ret = LY_SUCCESS;
+    const struct ly_ctx *ctx;
+    struct lyd_node *subtree, *yanglib, *mount_point, *final = NULL;
+    struct ly_err_item *err;
+    ly_bool found_yanglib = 0, found_mount_point = 0;
+    uint32_t old_log_opts;
+
+    ctx = LYD_CTX(parent);
+
+    old_log_opts = ly_log_options(LY_LOSTORE_LAST);
+    /* Check if intended for schema-mount - had both required data nodes */
+    while (1) {
+        /* Parse by sub-trees */
+        if (lyd_parse_data(ctx, NULL, in, 0, parse_opts, val_opts, &subtree)) {
+            /* Either end or error - must check */
+            err = ly_err_first(ctx);
+            if (err->vecode == LYVE_SYNTAX_XML) {
+                /* Could just be EOF - check */
+                /* TODO: Search in error message  if EOF then break */
+                lyd_insert_sibling(final, subtree, NULL);
+                break;
+            } else {
+                /* Other parsing error encountered */
+                ret = LY_EINVAL;
+                goto cleanup;
+            }
+        }
+
+        if (!final) {
+            /* If there was nothing inserted yet this subtree becomes the one to insert into */
+            final = subtree;
+        }
+
+        lyd_find_path(subtree, "/ietf-yang-library:yang-library", 0, &yanglib);
+        if (yanglib && !(yanglib->flags & LYD_DEFAULT)) {
+            /* Found and not created by flags */
+            found_yanglib = 1;
+            lyd_insert_sibling(final, yanglib, NULL);
+            continue;
+        }
+        lyd_find_path(subtree, "/ietf-yang-schema-mount:mount-points", 0, &mount_point);
+        if (mount_point && !(mount_point->flags & LYD_DEFAULT)) {
+            /* Was found and not created by flags */
+            found_mount_point = 1;
+            lyd_insert_sibling(final, mount_point, NULL);
+            continue;
+        }
+    }
+
+    if (found_mount_point && found_yanglib) {
+        /* It is valid data and can be inserted into the parent */
+        lyd_insert_child(parent, final);
+    } else {
+        /* It was not data for schema mount */
+        lyd_free_tree(final);
+        ret = LY_ENOT;
+    }
+
+cleanup:
+    ly_log_options(old_log_opts);
+    return ret;
+}
+
+/**
+ * @brief Plugin descriptions for the Yang Schema Mount extension.
+ *
+ * Note that external plugins are supposed to use:
+ *
+ *   LYPLG_EXTENSIONS = {
+ */
+const struct lyplg_ext_record plugins_schema_mount[] = {
+    {
+        .module = "ietf-yang-schema-mount",
+        .revision = "2019-01-14",
+        .name = "mount-point",
+
+        .plugin.id = "libyang 2 - Schema Mount, version 1",
+        .plugin.compile = &schema_mount_compile,
+        .plugin.parse = &schema_mount_parse,
+        .plugin.validate = NULL,
+        .plugin.sprinter = NULL,
+        .plugin.free = NULL
+    },
+    {0} /* terminating zeroed item */
+};