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/common.h b/src/common.h
index 7e80b1e..f8094d3 100644
--- a/src/common.h
+++ b/src/common.h
@@ -328,6 +328,8 @@
more times */
uint16_t flags; /**< context settings, see @ref contextoptions */
+ ly_ext_data_clb ext_clb; /**< optional callback for providing extension-specific run-time data for extensions */
+ void *ext_clb_data; /**< optional private data for ::ly_ctx.ext_clb */
pthread_key_t errlist_key; /**< key for the thread-specific list of errors related to the context */
pthread_mutex_t lyb_hash_lock; /**< lock for storing LYB schema hashes in schema nodes */
};
diff --git a/src/context.c b/src/context.c
index 3d79958..15043d3 100644
--- a/src/context.c
+++ b/src/context.c
@@ -319,7 +319,7 @@
}
static LY_ERR
-ly_ctx_new_yl_legacy(struct ly_ctx *ctx, struct lyd_node *yltree)
+ly_ctx_new_yl_legacy(struct ly_ctx *ctx, const struct lyd_node *yltree)
{
struct lyd_node *module, *node;
struct ly_set *set;
@@ -329,11 +329,12 @@
ly_bool imported = 0;
const struct lys_module *mod;
LY_ERR ret = LY_SUCCESS;
+ uint32_t i, j;
LY_CHECK_RET(ret = lyd_find_xpath(yltree, "/ietf-yang-library:yang-library/modules-state/module", &set));
/* process the data tree */
- for (uint32_t i = 0; i < set->count; ++i) {
+ for (i = 0; i < set->count; ++i) {
module = set->dnodes[i];
/* initiate */
@@ -365,8 +366,8 @@
LY_CHECK_ERR_GOTO(!feature_arr, ret = LY_EMEM, cleanup);
/* Parse features into an array of strings */
- for (uint32_t u = 0; u < features.count; u++) {
- feature_arr[u] = lyd_get_value(features.dnodes[u]);
+ for (j = 0; j < features.count; ++j) {
+ feature_arr[j] = lyd_get_value(features.dnodes[j]);
}
feature_arr[features.count] = NULL;
ly_set_clean(&features, free);
@@ -387,32 +388,72 @@
return ret;
}
-static LY_ERR
-ly_ctx_new_yl_common(const char *search_dir, const char *input, LYD_FORMAT format, int options,
- LY_ERR (*parser_func)(const struct ly_ctx *, const char *, LYD_FORMAT, uint32_t, uint32_t, struct lyd_node **),
- struct ly_ctx **ctx)
+LIBYANG_API_DEF LY_ERR
+ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options, struct ly_ctx **ctx)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct ly_ctx *ctx_yl = NULL;
+ struct lyd_node *data_yl = NULL;
+
+ LY_CHECK_ARG_RET(NULL, path, ctx, LY_EINVAL);
+
+ /* create a seperate context for the data */
+ LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, 0, &ctx_yl), cleanup);
+
+ /* parse yang library data tree */
+ LY_CHECK_GOTO(ret = lyd_parse_data_path(ctx_yl, path, format, 0, LYD_VALIDATE_PRESENT, &data_yl), cleanup);
+
+ /* create the new context */
+ ret = ly_ctx_new_yldata(search_dir, data_yl, options, ctx);
+
+cleanup:
+ lyd_free_all(data_yl);
+ ly_ctx_destroy(ctx_yl);
+ return ret;
+}
+
+LIBYANG_API_DEF LY_ERR
+ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options, struct ly_ctx **ctx)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct ly_ctx *ctx_yl = NULL;
+ struct lyd_node *data_yl = NULL;
+
+ LY_CHECK_ARG_RET(NULL, data, ctx, LY_EINVAL);
+
+ /* create a seperate context for the data */
+ LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, 0, &ctx_yl), cleanup);
+
+ /* parse yang library data tree */
+ LY_CHECK_GOTO(ret = lyd_parse_data_mem(ctx_yl, data, format, 0, LYD_VALIDATE_PRESENT, &data_yl), cleanup);
+
+ /* create the new context */
+ ret = ly_ctx_new_yldata(search_dir, data_yl, options, ctx);
+
+cleanup:
+ lyd_free_all(data_yl);
+ ly_ctx_destroy(ctx_yl);
+ return ret;
+}
+
+LIBYANG_API_DEF LY_ERR
+ly_ctx_new_yldata(const char *search_dir, const struct lyd_node *tree, int options, struct ly_ctx **ctx)
{
const char *name = NULL, *revision = NULL;
struct lyd_node *module, *node;
- struct lyd_node *yltree = NULL;
struct ly_set *set = NULL;
const char **feature_arr = NULL;
struct ly_set features = {0};
LY_ERR ret = LY_SUCCESS;
const struct lys_module *mod;
- struct ly_ctx *ctx_yl = NULL, *ctx_new = NULL;
+ struct ly_ctx *ctx_new = NULL;
ly_bool no_expl_compile = 0;
+ uint32_t i, j;
- /* create a seperate context in case it is LY_CTX_NO_YANGLIBRARY since it needs it for parsing */
- if (options & LY_CTX_NO_YANGLIBRARY) {
- LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, 0, &ctx_yl), cleanup);
- LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, options, &ctx_new), cleanup);
- } else {
- LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, options, &ctx_new), cleanup);
- }
+ LY_CHECK_ARG_RET(NULL, tree, ctx, LY_EINVAL);
- /* parse yang library data tree */
- LY_CHECK_GOTO(ret = parser_func(ctx_yl ? ctx_yl : ctx_new, input, format, 0, LYD_VALIDATE_PRESENT, &yltree), cleanup);
+ /* create a new context */
+ LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, options, &ctx_new), cleanup);
/* redundant to compile modules one-by-one */
if (!(options & LY_CTX_EXPLICIT_COMPILE)) {
@@ -420,20 +461,20 @@
no_expl_compile = 1;
}
- LY_CHECK_GOTO(ret = lyd_find_xpath(yltree, "/ietf-yang-library:yang-library/module-set[1]/module", &set), cleanup);
+ LY_CHECK_GOTO(ret = lyd_find_xpath(tree, "/ietf-yang-library:yang-library/module-set[1]/module", &set), cleanup);
if (set->count == 0) {
/* perhaps a legacy data tree? */
- LY_CHECK_GOTO(ret = ly_ctx_new_yl_legacy(ctx_new, yltree), cleanup);
+ LY_CHECK_GOTO(ret = ly_ctx_new_yl_legacy(ctx_new, tree), cleanup);
} else {
/* process the data tree */
- for (uint32_t i = 0; i < set->count; ++i) {
+ for (i = 0; i < set->count; ++i) {
module = set->dnodes[i];
/* initiate */
name = NULL;
revision = NULL;
- /* Iterate over data */
+ /* iterate over data */
LY_LIST_FOR(lyd_child(module), node) {
if (!strcmp(node->schema->name, "name")) {
name = lyd_get_value(node);
@@ -447,9 +488,9 @@
feature_arr = malloc((features.count + 1) * sizeof *feature_arr);
LY_CHECK_ERR_GOTO(!feature_arr, ret = LY_EMEM, cleanup);
- /* Parse features into an array of strings */
- for (uint32_t u = 0; u < features.count; u++) {
- feature_arr[u] = lyd_get_value(features.dnodes[u]);
+ /* parse features into an array of strings */
+ for (j = 0; j < features.count; ++j) {
+ feature_arr[j] = lyd_get_value(features.dnodes[j]);
}
feature_arr[features.count] = NULL;
ly_set_clean(&features, NULL);
@@ -466,10 +507,6 @@
}
}
- /* free data because their context may be recompiled */
- lyd_free_all(yltree);
- yltree = NULL;
-
/* compile */
LY_CHECK_GOTO(ret = ly_ctx_compile(ctx_new), cleanup);
@@ -479,34 +516,17 @@
}
cleanup:
- lyd_free_all(yltree);
ly_set_free(set, NULL);
ly_set_erase(&features, NULL);
- ly_ctx_destroy(ctx_yl);
*ctx = ctx_new;
if (ret) {
ly_ctx_destroy(*ctx);
*ctx = NULL;
}
-
return ret;
}
LIBYANG_API_DEF LY_ERR
-ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options, struct ly_ctx **ctx)
-{
- LY_CHECK_ARG_RET(NULL, path, ctx, LY_EINVAL);
- return ly_ctx_new_yl_common(search_dir, path, format, options, lyd_parse_data_path, ctx);
-}
-
-LIBYANG_API_DEF LY_ERR
-ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options, struct ly_ctx **ctx)
-{
- LY_CHECK_ARG_RET(NULL, data, ctx, LY_EINVAL);
- return ly_ctx_new_yl_common(search_dir, data, format, options, lyd_parse_data_mem, ctx);
-}
-
-LIBYANG_API_DEF LY_ERR
ly_ctx_compile(struct ly_ctx *ctx)
{
LY_ERR ret = LY_SUCCESS;
@@ -641,15 +661,6 @@
return ctx->change_count;
}
-LIBYANG_API_DEF void
-ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
-{
- LY_CHECK_ARG_RET(ctx, ctx, );
-
- ctx->imp_clb = clb;
- ctx->imp_clb_data = user_data;
-}
-
LIBYANG_API_DEF ly_module_imp_clb
ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
{
@@ -661,6 +672,29 @@
return ctx->imp_clb;
}
+LIBYANG_API_DEF void
+ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
+{
+ LY_CHECK_ARG_RET(ctx, ctx, );
+
+ ctx->imp_clb = clb;
+ ctx->imp_clb_data = user_data;
+}
+
+LIBYANG_API_DEF ly_ext_data_clb
+ly_ctx_set_ext_data_clb(struct ly_ctx *ctx, ly_ext_data_clb clb, void *user_data)
+{
+ ly_ext_data_clb prev;
+
+ LY_CHECK_ARG_RET(ctx, ctx, NULL);
+
+ prev = ctx->ext_clb;
+ ctx->ext_clb = clb;
+ ctx->ext_clb_data = user_data;
+
+ return prev;
+}
+
LIBYANG_API_DEF struct lys_module *
ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *index)
{
diff --git a/src/context.h b/src/context.h
index fdd87e2..8752e56 100644
--- a/src/context.h
+++ b/src/context.h
@@ -224,7 +224,7 @@
LIBYANG_API_DECL LY_ERR ly_ctx_new(const char *search_dir, uint16_t options, struct ly_ctx **new_ctx);
/**
- * @brief Create libyang context according to the content of the given yang-library data.
+ * @brief Create libyang context according to the provided yang-library data in a file.
*
* This function loads the yang-library data from the given path. If you need to pass the data as
* string, use ::::ly_ctx_new_ylmem(). Both functions extend functionality of ::ly_ctx_new() by loading
@@ -244,20 +244,13 @@
* @param[out] ctx Pointer to the created libyang context if LY_SUCCESS returned.
* @return LY_ERR return value
*/
-LIBYANG_API_DECL LY_ERR ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options, struct ly_ctx **ctx);
+LIBYANG_API_DECL LY_ERR ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options,
+ struct ly_ctx **ctx);
/**
- * @brief Create libyang context according to the content of the given yang-library data.
+ * @brief Create libyang context according to the provided yang-library data in a string.
*
- * This function loads the yang-library data from the given string. If you need to pass the data as
- * path to a file holding the data, use ::ly_ctx_new_ylpath(). Both functions extend functionality of
- * ::ly_ctx_new() by loading modules specified in the ietf-yang-library form into the context being created.
- * The preferred tree model revision is 2019-01-04. However, only the first module-set is processed and loaded
- * into the context. If there are no matching nodes from this tree, the legacy tree (originally from model revision 2016-04-09)
- * is processed. Note, that the modules are loaded the same way as in case of ::ly_ctx_load_module(), so the schema paths in the
- * yang-library data are ignored and the modules are loaded from the context's search locations. On the other hand, YANG features
- * of the modules are set as specified in the yang-library data.
- * To get yang library data from a libyang context, use ::ly_ctx_get_yanglib_data().
+ * Details in ::ly_ctx_new_ylpath().
*
* @param[in] search_dir Directory where libyang will search for the imported or included modules and submodules.
* If no such directory is available, NULL is accepted.
@@ -267,7 +260,23 @@
* @param[out] ctx Pointer to the created libyang context if LY_SUCCESS returned.
* @return LY_ERR return value
*/
-LIBYANG_API_DECL LY_ERR ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options, struct ly_ctx **ctx);
+LIBYANG_API_DECL LY_ERR ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options,
+ struct ly_ctx **ctx);
+
+/**
+ * @brief Create libyang context according to the provided yang-library data in a data tree.
+ *
+ * Details in ::ly_ctx_new_ylpath().
+ *
+ * @param[in] search_dir Directory where libyang will search for the imported or included modules and submodules.
+ * If no such directory is available, NULL is accepted.
+ * @param[in] tree Data tree containing yang-library data.
+ * @param[in] options Context options, see @ref contextoptions.
+ * @param[out] ctx Pointer to the created libyang context if LY_SUCCESS returned.
+ * @return LY_ERR return value
+ */
+LIBYANG_API_DECL LY_ERR ly_ctx_new_yldata(const char *search_dir, const struct lyd_node *tree, int options,
+ struct ly_ctx **ctx);
/**
* @brief Compile (recompile) the context applying all the performed changes after the last context compilation.
@@ -410,6 +419,11 @@
*/
LIBYANG_API_DECL void ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data);
+typedef LY_ERR (*ly_ext_data_clb)(const struct lysc_ext_instance *ext, void *user_data, void **ext_data,
+ ly_bool *ext_data_free);
+
+LIBYANG_API_DECL ly_ext_data_clb ly_ctx_set_ext_data_clb(struct ly_ctx *ctx, ly_ext_data_clb clb, void *user_data);
+
/**
* @brief Get YANG module of the given name and revision.
*
diff --git a/src/in.c b/src/in.c
index c16b1c3..b893dd2 100644
--- a/src/in.c
+++ b/src/in.c
@@ -58,6 +58,16 @@
}
LIBYANG_API_DEF LY_ERR
+ly_in_reset(struct ly_in *in)
+{
+ LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
+
+ in->current = in->func_start = in->start;
+ in->line = 1;
+ return LY_SUCCESS;
+}
+
+LIBYANG_API_DEF LY_ERR
ly_in_new_fd(int fd, struct ly_in **in)
{
size_t length;
@@ -186,16 +196,6 @@
}
LIBYANG_API_DEF LY_ERR
-ly_in_reset(struct ly_in *in)
-{
- LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
-
- in->current = in->func_start = in->start;
- in->line = 1;
- return LY_SUCCESS;
-}
-
-LIBYANG_API_DEF LY_ERR
ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
{
LY_ERR ret;
@@ -318,6 +318,12 @@
}
+LIBYANG_API_DEF size_t
+ly_in_parsed(const struct ly_in *in)
+{
+ return in->current - in->func_start;
+}
+
LIBYANG_API_DEF void
ly_in_free(struct ly_in *in, ly_bool destroy)
{
@@ -371,12 +377,6 @@
return LY_SUCCESS;
}
-LIBYANG_API_DEF size_t
-ly_in_parsed(const struct ly_in *in)
-{
- return in->current - in->func_start;
-}
-
LY_ERR
ly_in_skip(struct ly_in *in, size_t count)
{
@@ -395,7 +395,7 @@
ly_set_erase(&lydctx->node_types, NULL);
ly_set_erase(&lydctx->meta_types, NULL);
ly_set_erase(&lydctx->node_when, NULL);
- ly_set_erase(&lydctx->node_exts, NULL);
+ ly_set_erase(&lydctx->ext_val, free);
}
LY_ERR
@@ -525,7 +525,7 @@
LY_ERR
lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod,
const char *name, size_t name_len, const void *value, size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format,
- void *prefix_data, uint32_t hints)
+ void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node)
{
ly_bool incomplete;
struct lyd_meta *first = NULL;
@@ -536,7 +536,7 @@
}
LY_CHECK_RET(lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, dynamic, format, prefix_data,
- hints, 0, &incomplete));
+ hints, ctx_node, 0, &incomplete));
if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) {
LY_CHECK_RET(ly_set_add(&lydctx->meta_types, *meta, 1, NULL));
diff --git a/src/log.h b/src/log.h
index d67eb96..e9a7c5b 100644
--- a/src/log.h
+++ b/src/log.h
@@ -241,8 +241,7 @@
* @typedef LY_ERR
* @brief libyang's error codes returned by the libyang functions.
*/
-typedef enum
-{
+typedef enum {
LY_SUCCESS = 0, /**< no error, not set by functions, included just to complete #LY_ERR enumeration */
LY_EMEM, /**< Memory allocation failure */
LY_ESYS, /**< System call failure */
diff --git a/src/parser_data.h b/src/parser_data.h
index 53f03dc..79898ab 100644
--- a/src/parser_data.h
+++ b/src/parser_data.h
@@ -157,6 +157,9 @@
modified manually. If this flag is used incorrectly (for unordered data),
the behavior is undefined and most functions executed with these
data will not work correctly. */
+#define LYD_PARSE_SUBTREE 0x400000 /**< Parse only the current data subtree with any descendants, no siblings.
+ Also, a new return value ::LY_ENOT is returned if there is a sibling
+ subtree following in the input data. */
#define LYD_PARSE_OPTS_MASK 0xFFFF0000 /**< Mask for all the LYD_PARSE_ options. */
@@ -258,8 +261,8 @@
* @return LY_SUCCESS in case of successful parsing (and validation).
* @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
*/
-LIBYANG_API_DECL LY_ERR lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT format, uint32_t parse_options,
- uint32_t validate_options, struct lyd_node **tree);
+LIBYANG_API_DECL LY_ERR lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT format,
+ uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);
/**
* @brief Parse (and validate) data from the input handler as an extension data tree following the schema tree of the given
@@ -280,8 +283,8 @@
* @return LY_SUCCESS in case of successful parsing (and validation).
* @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
*/
-LIBYANG_API_DECL LY_ERR lyd_parse_ext_data(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
- uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);
+LIBYANG_API_DECL LY_ERR lyd_parse_ext_data(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in,
+ LYD_FORMAT format, uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);
/**
* @ingroup datatree
@@ -394,13 +397,13 @@
* @return LY_ERR value.
* @return LY_ENOT if @p data_type is a NETCONF message and the root XML element is not the expected one.
*/
-LIBYANG_API_DECL LY_ERR lyd_parse_ext_op(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
- enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op);
+LIBYANG_API_DECL LY_ERR lyd_parse_ext_op(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in,
+ LYD_FORMAT format, enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op);
/**
* @brief Fully validate a data tree.
*
- * The data tree is modified in-place. As a result of the validation, some data might be removed
+ * The data tree is modified in-place. As a result of the validation, some data might be removed
* from the tree. In that case, the removed items are freed, not just unlinked.
*
* @param[in,out] tree Data tree to recursively validate. May be changed by validation, might become NULL.
@@ -410,12 +413,13 @@
* @return LY_SUCCESS on success.
* @return LY_ERR error on error.
*/
-LIBYANG_API_DECL LY_ERR lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, uint32_t val_opts, struct lyd_node **diff);
+LIBYANG_API_DECL LY_ERR lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, uint32_t val_opts,
+ struct lyd_node **diff);
/**
* @brief Fully validate a data tree of a module.
*
- * The data tree is modified in-place. As a result of the validation, some data might be removed
+ * The data tree is modified in-place. As a result of the validation, some data might be removed
* from the tree. In that case, the removed items are freed, not just unlinked.
*
* @param[in,out] tree Data tree to recursively validate. May be changed by validation, might become NULL.
@@ -425,7 +429,8 @@
* @return LY_SUCCESS on success.
* @return LY_ERR error on error.
*/
-LIBYANG_API_DECL LY_ERR lyd_validate_module(struct lyd_node **tree, const struct lys_module *module, uint32_t val_opts, struct lyd_node **diff);
+LIBYANG_API_DECL LY_ERR lyd_validate_module(struct lyd_node **tree, const struct lys_module *module, uint32_t val_opts,
+ struct lyd_node **diff);
/**
* @brief Validate an RPC/action request, reply, or notification.
diff --git a/src/parser_internal.h b/src/parser_internal.h
index dba6078..67baeed 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -56,9 +56,9 @@
#define LYD_PARSER_BUFSIZE 4078
char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
struct ly_set node_when; /**< set of nodes with "when" conditions */
- struct ly_set node_exts; /**< set of nodes and extensions connected with a plugin providing own validation callback */
struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
+ struct ly_set ext_val; /**< set of first siblings parsed by extensions to validate */
struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
/* callbacks */
@@ -82,9 +82,9 @@
uint32_t path_len;
char path[LYD_PARSER_BUFSIZE];
struct ly_set node_when;
- struct ly_set node_exts;
struct ly_set node_types;
struct ly_set meta_types;
+ struct ly_set ext_val;
struct lyd_node *op_node;
/* callbacks */
@@ -104,9 +104,9 @@
uint32_t path_len;
char path[LYD_PARSER_BUFSIZE];
struct ly_set node_when;
- struct ly_set node_exts;
struct ly_set node_types;
struct ly_set meta_types;
+ struct ly_set ext_val;
struct lyd_node *op_node;
/* callbacks */
@@ -131,9 +131,9 @@
uint32_t path_len;
char path[LYD_PARSER_BUFSIZE];
struct ly_set node_when;
- struct ly_set node_exts;
struct ly_set node_types;
struct ly_set meta_types;
+ struct ly_set ext_val;
struct lyd_node *op_node;
/* callbacks */
@@ -143,9 +143,17 @@
};
/**
+ * @brief Parsed extension instance data to validate.
+ */
+struct lyd_ctx_ext_val {
+ struct lysc_ext_instance *ext;
+ struct lyd_node *sibling;
+};
+
+/**
* @brief Common part to supplement the specific ::lyd_ctx_free_clb callbacks.
*/
-void lyd_ctx_free(struct lyd_ctx *);
+void lyd_ctx_free(struct lyd_ctx *ctx);
/**
* @brief Parse submodule from YANG data.
@@ -207,12 +215,13 @@
* @param[out] envp Individual parsed envelopes tree, returned only by specific @p data_type and possibly even if
* an error occurs later.
* @param[out] parsed Set to add all the parsed siblings into.
+ * @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
* @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
LY_ERR lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
- struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+ struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
/**
* @brief Parse JSON string as a YANG data tree.
@@ -226,12 +235,13 @@
* @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
* @param[in] data_type Expected data type of the data.
* @param[out] parsed Set to add all the parsed siblings into.
+ * @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
* @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
LY_ERR lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
- struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+ struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
/**
* @brief Parse binary LYB data as a YANG data tree.
@@ -245,12 +255,13 @@
* @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
* @param[in] data_type Expected data type of the data.
* @param[out] parsed Set to add all the parsed siblings into.
+ * @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
* @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
LY_ERR lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
- struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+ struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
/**
* @brief Search all the parents for an operation node, check validity based on internal parser flags.
@@ -305,10 +316,11 @@
* @param[in] format Prefix format.
* @param[in] prefix_data Prefix format data (see ::ly_resolve_prefix()).
* @param[in] hints [Value hint](@ref lydvalhints) from the parser regarding the value type.
+ * @param[in] ctx_node Value context node.
* @return LY_ERR value.
*/
LY_ERR lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta,
- const struct lys_module *mod, const char *name, size_t name_len, const void *value,
- size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints);
+ const struct lys_module *mod, const char *name, size_t name_len, const void *value, size_t value_len,
+ ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node);
#endif /* LY_PARSER_INTERNAL_H_ */
diff --git a/src/parser_json.c b/src/parser_json.c
index eb62897..e1dd7fe 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -614,7 +614,7 @@
if (mod) {
ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod,
meta->name.name, strlen(meta->name.name), meta->value, ly_strlen(meta->value),
- NULL, LY_VALUE_JSON, NULL, meta->hints);
+ NULL, LY_VALUE_JSON, NULL, meta->hints, node->schema);
LY_CHECK_GOTO(ret, cleanup);
} else if (lydctx->parse_opts & LYD_PARSE_STRICT) {
if (meta->name.prefix) {
@@ -631,7 +631,7 @@
}
}
/* add/correct flags */
- lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &node->meta, lydctx->parse_opts);
+ lyd_parse_set_data_flags(node, &lydctx->node_when, &node->meta, lydctx->parse_opts);
/* done */
break;
@@ -812,12 +812,11 @@
/* create metadata */
meta = NULL;
ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, &meta, mod, name, name_len, lydctx->jsonctx->value,
- lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL,
- LYD_HINT_DATA);
+ lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema);
LY_CHECK_GOTO(ret, cleanup);
/* add/correct flags */
- lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
+ lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
} else {
/* create attribute */
const char *module_name;
@@ -1239,7 +1238,7 @@
LY_CHECK_ERR_RET(ret, LOG_LOCBACK(1, 1, 0, 0), ret);
/* add any missing default children */
- ret = lyd_new_implicit_r(*node, lyd_node_child_p(*node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
+ ret = lyd_new_implicit_r(*node, lyd_node_child_p(*node), NULL, NULL, &lydctx->node_when,
&lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
LY_CHECK_ERR_RET(ret, LOG_LOCBACK(1, 1, 0, 0), ret);
}
@@ -1280,7 +1279,7 @@
LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status));
/* add/correct flags */
- lyd_parse_set_data_flags(*node, &lydctx->node_when, &lydctx->node_exts, &(*node)->meta, lydctx->parse_opts);
+ lyd_parse_set_data_flags(*node, &lydctx->node_when, &(*node)->meta, lydctx->parse_opts);
} else if (ret == LY_ENOT) {
/* parse it again as an opaq node */
ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent,
@@ -1533,7 +1532,7 @@
LY_ERR
lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
- struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+ struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_json_ctx *lydctx = NULL;
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 3352ed9..2cd4158 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -414,11 +414,12 @@
* @brief Parse YANG node metadata.
*
* @param[in] lybctx LYB context.
+ * @param[in] sparent Schema parent node of the metadata.
* @param[out] meta Parsed metadata.
* @return LY_ERR value.
*/
static LY_ERR
-lyb_parse_metadata(struct lyd_lyb_ctx *lybctx, struct lyd_meta **meta)
+lyb_parse_metadata(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent, struct lyd_meta **meta)
{
LY_ERR ret = LY_SUCCESS;
ly_bool dynamic;
@@ -455,7 +456,7 @@
/* create metadata */
ret = lyd_parser_create_meta((struct lyd_ctx *)lybctx, NULL, meta, mod, meta_name, strlen(meta_name), meta_value,
- ly_strlen(meta_value), &dynamic, LY_VALUE_JSON, NULL, LYD_HINT_DATA);
+ ly_strlen(meta_value), &dynamic, LY_VALUE_JSON, NULL, LYD_HINT_DATA, sparent);
/* free strings */
free(meta_name);
@@ -927,17 +928,18 @@
* @brief Parse header for non-opaq node.
*
* @param[in] lybctx LYB context.
+ * @param[in] sparent Schema parent node of the metadata.
* @param[out] flags Parsed node flags.
* @param[out] meta Parsed metadata of the node.
* @return LY_ERR value.
*/
static LY_ERR
-lyb_parse_node_header(struct lyd_lyb_ctx *lybctx, uint32_t *flags, struct lyd_meta **meta)
+lyb_parse_node_header(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent, uint32_t *flags, struct lyd_meta **meta)
{
LY_ERR ret;
/* create and read metadata */
- ret = lyb_parse_metadata(lybctx, meta);
+ ret = lyb_parse_metadata(lybctx, sparent, meta);
LY_CHECK_RET(ret);
/* read flags */
@@ -1002,9 +1004,8 @@
/* add any missing default children */
impl_opts = (lybctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0;
- ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL,
- NULL, &lybctx->node_when, &lybctx->node_exts,
- &lybctx->node_types, impl_opts, NULL);
+ ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lybctx->node_when, &lybctx->node_types,
+ impl_opts, NULL);
LY_CHECK_RET(ret);
}
@@ -1124,7 +1125,7 @@
const struct ly_ctx *ctx = lybctx->lybctx->ctx;
/* read necessary basic data */
- ret = lyb_parse_node_header(lybctx, &flags, &meta);
+ ret = lyb_parse_node_header(lybctx, snode, &flags, &meta);
LY_CHECK_GOTO(ret, error);
/* parse value type */
@@ -1212,7 +1213,7 @@
uint32_t flags;
/* read necessary basic data */
- ret = lyb_parse_node_header(lybctx, &flags, &meta);
+ ret = lyb_parse_node_header(lybctx, snode, &flags, &meta);
LY_CHECK_GOTO(ret, error);
/* create node */
@@ -1263,7 +1264,7 @@
uint32_t flags;
/* read necessary basic data */
- ret = lyb_parse_node_header(lybctx, &flags, &meta);
+ ret = lyb_parse_node_header(lybctx, snode, &flags, &meta);
LY_CHECK_GOTO(ret, error);
/* read value of term node and create it */
@@ -1338,7 +1339,7 @@
while (LYB_LAST_SIBLING(lybctx->lybctx).written) {
/* read necessary basic data */
- ret = lyb_parse_node_header(lybctx, &flags, &meta);
+ ret = lyb_parse_node_header(lybctx, snode, &flags, &meta);
LY_CHECK_GOTO(ret, error);
/* create list node */
@@ -1619,13 +1620,15 @@
LY_ERR
lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
- struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+ struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
{
uint32_t int_opts;
assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
+ LY_CHECK_ARG_RET(ctx, !(parse_opts & LYD_PARSE_SUBTREE), LY_EINVAL);
+
switch (data_type) {
case LYD_TYPE_DATA_YANG:
int_opts = LYD_INTOPT_WITH_SIBLINGS;
@@ -1644,6 +1647,9 @@
return LY_EINT;
}
+ if (subtree_sibling) {
+ *subtree_sibling = 0;
+ }
return _lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, parsed, lydctx_p);
}
diff --git a/src/parser_xml.c b/src/parser_xml.c
index fcfc8f9..e874231 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -48,12 +48,12 @@
* @brief Parse and create XML metadata.
*
* @param[in] lydctx XML data parser context.
- * @param[in] parent_exts Extension instances of the parent node.
+ * @param[in] sparent Schema node of the parent.
* @param[out] meta List of created metadata instances.
* @return LY_ERR value.
*/
static LY_ERR
-lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lysc_ext_instance *parent_exts, struct lyd_meta **meta)
+lydxml_metadata(struct lyd_xml_ctx *lydctx, const struct lysc_node *sparent, struct lyd_meta **meta)
{
LY_ERR ret = LY_SUCCESS;
const struct lyxml_ns *ns;
@@ -67,9 +67,9 @@
*meta = NULL;
/* check for NETCONF filter unqualified attributes */
- LY_ARRAY_FOR(parent_exts, u) {
- if (!strcmp(parent_exts[u].def->name, "get-filter-element-attributes") &&
- !strcmp(parent_exts[u].def->module->name, "ietf-netconf")) {
+ LY_ARRAY_FOR(sparent->exts, u) {
+ if (!strcmp(sparent->exts[u].def->name, "get-filter-element-attributes") &&
+ !strcmp(sparent->exts[u].def->module->name, "ietf-netconf")) {
filter_attrs = 1;
break;
}
@@ -141,7 +141,7 @@
/* create metadata */
ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
- xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
+ xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, sparent);
LY_CHECK_GOTO(ret, cleanup);
/* next attribute */
@@ -407,6 +407,77 @@
}
/**
+ * @brief Try to parse data with a parent based on an extension instance.
+ *
+ * @param[in] lydctx XML data parser context.
+ * @param[in,out] parent Parent node where the children are inserted.
+ * @return LY_SUCCESS on success;
+ * @return LY_ENOT if no extension instance parsed the data;
+ * @return LY_ERR on error.
+ */
+static LY_ERR
+lydxml_nested_ext(struct lyd_xml_ctx *lydctx, struct lyd_node *parent)
+{
+ LY_ERR r;
+ struct ly_in in_bck, in_start, in_ext;
+ LY_ARRAY_COUNT_TYPE u;
+ struct lysc_ext_instance *nested_exts = NULL;
+ lyplg_ext_data_parse_clb ext_parse_cb;
+ struct lyd_ctx_ext_val *ext_val;
+
+ /* backup current input */
+ in_bck = *lydctx->xmlctx->in;
+
+ /* go back in the input for extension parsing */
+ in_start = *lydctx->xmlctx->in;
+ if (lydctx->xmlctx->status != LYXML_ELEM_CONTENT) {
+ assert((lydctx->xmlctx->status == LYXML_ELEMENT) || (lydctx->xmlctx->status == LYXML_ATTRIBUTE));
+ in_start.current = lydctx->xmlctx->prefix ? lydctx->xmlctx->prefix : lydctx->xmlctx->name;
+ }
+ do {
+ --in_start.current;
+ } while (in_start.current[0] != '<');
+
+ /* check if there are any nested extension instances */
+ if (parent && parent->schema) {
+ nested_exts = parent->schema->exts;
+ }
+ LY_ARRAY_FOR(nested_exts, u) {
+ /* prepare the input and try to parse this extension data */
+ in_ext = in_start;
+ ext_parse_cb = nested_exts[u].def->plugin->parse;
+ r = ext_parse_cb(&in_ext, LYD_XML, &nested_exts[u], parent, lydctx->parse_opts | LYD_PARSE_ONLY);
+ if (!r) {
+ /* data successfully parsed, remember for validation */
+ if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
+ ext_val = malloc(sizeof *ext_val);
+ LY_CHECK_ERR_RET(!ext_val, LOGMEM(lydctx->xmlctx->ctx), LY_EMEM);
+ ext_val->ext = &nested_exts[u];
+ ext_val->sibling = lyd_child(parent);
+ LY_CHECK_RET(ly_set_add(&lydctx->ext_val, ext_val, 1, NULL));
+ }
+
+ /* adjust the xmlctx accordingly */
+ *lydctx->xmlctx->in = in_ext;
+ lydctx->xmlctx->status = LYXML_ELEM_CONTENT;
+ lydctx->xmlctx->dynamic = 0;
+ ly_set_rm_index(&lydctx->xmlctx->elements, lydctx->xmlctx->elements.count - 1, free);
+ lyxml_ns_rm(lydctx->xmlctx);
+ LY_CHECK_RET(lyxml_ctx_next(lydctx->xmlctx));
+ return LY_SUCCESS;
+ } else if (r != LY_ENOT) {
+ /* fatal error */
+ return r;
+ }
+ /* data was not from this module, continue */
+ }
+
+ /* no extensions or none matched, restore input */
+ *lydctx->xmlctx->in = in_bck;
+ return LY_ENOT;
+}
+
+/**
* @brief Parse XML subtree.
*
* @param[in] lydctx XML YANG data parser context.
@@ -420,9 +491,6 @@
lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
{
LY_ERR ret = LY_SUCCESS, r;
- LY_ARRAY_COUNT_TYPE u;
-
- lyplg_ext_data_parse_clb ext_parse;
const char *prefix, *name, *val;
size_t prefix_len, name_len;
struct lyxml_ctx *xmlctx;
@@ -435,9 +503,9 @@
uint32_t prev_parse_opts, prev_int_opts;
struct lyd_node *node = NULL, *anchor;
void *val_prefix_data = NULL;
- struct lysc_ext_instance *exts = NULL;
LY_VALUE_FORMAT format;
uint32_t getnext_opts;
+ ly_bool parse_subtree;
assert(parent || first_p);
@@ -445,6 +513,10 @@
ctx = xmlctx->ctx;
getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
+ parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
+ /* all descendants should be parsed */
+ lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
+
assert(xmlctx->status == LYXML_ELEMENT);
/* remember element prefix and name */
@@ -462,6 +534,18 @@
}
mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
if (!mod) {
+ /* check for extension data */
+ r = lydxml_nested_ext(lydctx, parent);
+ if (!r) {
+ /* successfully parsed */
+ return r;
+ } else if (r != LY_ENOT) {
+ /* error */
+ ret = r;
+ goto error;
+ }
+
+ /* unknown module */
if (lydctx->parse_opts & LYD_PARSE_STRICT) {
LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
ret = LY_EVALID;
@@ -486,22 +570,18 @@
snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
}
if (!snode) {
- /* Check if data of an extension */
- if (parent && parent->schema) {
- exts = parent->schema->exts;
+ /* check for extension data */
+ r = lydxml_nested_ext(lydctx, parent);
+ if (!r) {
+ /* successfully parsed */
+ return r;
+ } else if (r != LY_ENOT) {
+ /* error */
+ ret = r;
+ goto error;
}
- LY_ARRAY_FOR(exts, u) {
- ext_parse = exts[u].def->plugin->parse;
- r = ext_parse(xmlctx->in, LYD_XML, &exts[u], parent, lydctx->parse_opts,
- lydctx->val_opts);
- if (r == LY_SUCCESS) {
- /* Data was from this module*/
- return LY_SUCCESS;
- } else if (r != LY_ENOT) {
- /* Error while parsing */
- }
- /* Data was not from this module */
- }
+
+ /* unknown data node */
if (lydctx->parse_opts & LYD_PARSE_STRICT) {
if (parent) {
LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
@@ -537,7 +617,7 @@
/* create metadata/attributes */
if (xmlctx->status == LYXML_ATTRIBUTE) {
if (snode) {
- ret = lydxml_metadata(lydctx, snode->exts, &meta);
+ ret = lydxml_metadata(lydctx, snode, &meta);
LY_CHECK_GOTO(ret, error);
} else {
assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
@@ -648,8 +728,8 @@
LY_CHECK_GOTO(ret, error);
/* add any missing default children */
- ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
- &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
+ ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
+ (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
LY_CHECK_GOTO(ret, error);
}
@@ -711,12 +791,14 @@
/* add/correct flags */
if (snode) {
- lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
+ lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
}
/* parser next */
assert(xmlctx->status == LYXML_ELEM_CLOSE);
- LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
+ if (!parse_subtree) {
+ LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
+ }
/* add metadata/attributes */
if (snode) {
@@ -1398,12 +1480,13 @@
LY_ERR
lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
- struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+ struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_xml_ctx *lydctx;
uint32_t i, int_opts = 0, close_elem = 0;
ly_bool parsed_data_nodes = 0;
+ enum LYXML_PARSER_STATUS status;
assert(ctx && in && lydctx_p);
assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
@@ -1420,7 +1503,9 @@
switch (data_type) {
case LYD_TYPE_DATA_YANG:
- int_opts = LYD_INTOPT_WITH_SIBLINGS;
+ if (!(parse_opts & LYD_PARSE_SUBTREE)) {
+ int_opts = LYD_INTOPT_WITH_SIBLINGS;
+ }
break;
case LYD_TYPE_RPC_YANG:
int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
@@ -1489,10 +1574,20 @@
lydctx->op_node = NULL;
}
+ if (parse_opts & LYD_PARSE_SUBTREE) {
+ /* check for a sibling element */
+ assert(subtree_sibling);
+ if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
+ *subtree_sibling = 1;
+ } else {
+ *subtree_sibling = 0;
+ }
+ }
+
cleanup:
/* there should be no unres stored if validation should be skipped */
assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
- !lydctx->node_when.count && !lydctx->node_exts.count));
+ !lydctx->node_when.count));
if (rc) {
lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
diff --git a/src/path.c b/src/path.c
index e631e3a..932a039 100644
--- a/src/path.c
+++ b/src/path.c
@@ -446,6 +446,7 @@
break;
case LY_VALUE_CANON:
case LY_VALUE_XML:
+ case LY_VALUE_STR_NS:
/* not really defined or accepted */
LOGINT_RET(ctx);
}
diff --git a/src/plugins_exts.c b/src/plugins_exts.c
index df797f9..eb688d5 100644
--- a/src/plugins_exts.c
+++ b/src/plugins_exts.c
@@ -1,9 +1,10 @@
/**
* @file plugins_exts.c
* @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief Internally implemented YANG extensions.
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief helper functions for extension plugins
*
- * Copyright (c) 2019 CESNET, z.s.p.o.
+ * Copyright (c) 2019 - 2022 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.
@@ -69,3 +70,14 @@
{
return ctx->pmod;
}
+
+LIBYANG_API_DEF LY_ERR
+lyplg_ext_get_data(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, void **ext_data, ly_bool *ext_data_free)
+{
+ if (!ctx->ext_clb) {
+ lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "Failed to get extension data, no callback set.");
+ return LY_EINVAL;
+ }
+
+ return ctx->ext_clb(ext, ctx->ext_clb_data, ext_data, ext_data_free);
+}
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index d856420..2dba714 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -100,7 +100,7 @@
/**
* @brief Extensions API version
*/
-#define LYPLG_EXT_API_VERSION 1
+#define LYPLG_EXT_API_VERSION 2
/**
* @brief Macro to define plugin information in external plugins
@@ -130,16 +130,28 @@
*
* @param[in] cctx Current compile context.
* @param[in] p_ext Parsed extension instance data.
- * @param[in,out] c_ext Prepared compiled extension instance structure where an addition, extension-specific, data are supposed to be placed
- * for later use (data validation or use of external tool).
+ * @param[in,out] c_ext Prepared compiled extension instance structure where an addition, extension-specific, data are
+ * supposed to be placed for later use (data validation or use of external tool).
* @return LY_SUCCESS in case of success.
* @return LY_EVALID in case of non-conforming parsed data.
* @return LY_ENOT in case the extension instance is not supported and should be removed.
*/
-typedef LY_ERR (*lyplg_ext_compile_clb)(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext);
+typedef LY_ERR (*lyplg_ext_compile_clb)(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext,
+ struct lysc_ext_instance *c_ext);
/**
- * @brief Callback to free the extension specific data created by the ::lyplg_ext_compile_clb callback of the same extension plugin.
+ * @brief Callback to print the compiled extension instance's private data in the INFO format.
+ *
+ * @param[in] ctx YANG printer context to provide output handler and other information for printing.
+ * @param[in] ext The compiled extension instance, mainly to access the extensions.
+ * @param[in,out] flag Flag to be shared with the caller regarding the opening brackets - 0 if the '{' not yet printed,
+ * 1 otherwise.
+ * @return LY_SUCCESS when everything was fine, other LY_ERR values in case of failure
+ */
+typedef LY_ERR (*lyplg_ext_schema_printer_clb)(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag);
+
+/**
+ * @brief Callback to free the extension-specific data created by its compilation.
*
* @param[in] ctx libyang context.
* @param[in,out] ext Compiled extension structure where the data to free are placed.
@@ -147,57 +159,50 @@
typedef void (*lyplg_ext_free_clb)(struct ly_ctx *ctx, struct lysc_ext_instance *ext);
/**
- * @brief Callback to decide if data instance is valid according to the schema.
+ * @brief Callback for parsing YANG instance data described by an extension instance.
*
- * The callback is used only for the extension instances placed in the data nodes or type (the
- * ::lysc_ext_instance.parent_stmt value must be ::LY_STMT_IS_DATA_NODE() values or ::LY_STMT_TYPE):
+ * This callback is used only for nested data definition (with a standard YANG schema parent).
+ * Note that the siblings parsed by this function and directly connected to @p parent must have the flag ::LYD_EXT set.
*
- * @param[in] ext Extension instance to be checked.
- * @param[in] node Data node connected with the extension instance.
- *
- * @return LY_SUCCESS on data validation success.
- * @return LY_EVALID in case the validation fails.
+ * @param[in] in Input handler with the data to parse.
+ * @param[in] format Format if the data in @p in.
+ * @param[in] ext Compiled extension instance.
+ * @param[in,out] parent Data parent to append to.
+ * @param[in] parse_opts Parse options, see @ref dataparseroptions. They will always include ::LYD_PARSE_ONLY.
+ * @return LY_SUCCESS on success.
+ * @return LY_ENOT if the data are not described by @p ext.
+ * @return LY_ERR on error.
*/
-typedef LY_ERR (*lyplg_ext_data_validation_clb)(struct lysc_ext_instance *ext, struct lyd_node *node);
+typedef LY_ERR (*lyplg_ext_data_parse_clb)(struct ly_in *in, LYD_FORMAT format, struct lysc_ext_instance *ext,
+ struct lyd_node *parent, uint32_t parse_opts);
/**
- * @brief Callback to print the compiled extension instance's private data in the INFO format.
+ * @brief Callback for validating parsed YANG instance data described by an extension instance.
*
- * @param[in] ctx YANG printer context to provide output handler and other information for printing.
- * @param[in] ext The compiled extension instance, mainly to access the extensions.
- * @param[in, out] flag Flag to be shared with the caller regarding the opening brackets - 0 if the '{' not yet printed,
- * 1 otherwise.
+ * This callback is used only for nested data definition (with a standard YANG schema parent).
*
- * @return LY_SUCCESS when everything was fine, other LY_ERR values in case of failure
+ * @param[in] ext Compiled extension instance.
+ * @param[in] sibling First sibling parsed by ::lyplg_ext_data_parse_clb.
+ * @param[in] val_opts Validation options, see @ref datavalidationoptions.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR on error.
*/
-typedef LY_ERR (*lyplg_ext_schema_printer_clb)(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag);
-
-/**
- * @brief Callback to data according to extension specification.
- *
- * @param[in] in
- * @param[in] format
- * @param[in] ext
- * @param[in] parent
- * @param[in] parse_opts
- * @param[in] val_opts
- * @param[out] ly_err
- */
-typedef LY_ERR (*lyplg_ext_data_parse_clb)(struct ly_in *in, LYD_FORMAT format,
- struct lysc_ext_instance *ext, struct lyd_node *parent,
- uint32_t parse_opts, uint32_t val_opts);
+typedef LY_ERR (*lyplg_ext_data_validate_clb)(struct lysc_ext_instance *ext, struct lyd_node *sibling, uint32_t val_opts);
/**
* @brief Extension plugin implementing various aspects of a YANG extension
*/
struct lyplg_ext {
- const char *id; /**< Plugin identification (mainly for distinguish incompatible versions of the plugins for external tools) */
- lyplg_ext_compile_clb compile; /**< Callback to compile extension instance from the parsed data */
- lyplg_ext_schema_printer_clb sprinter; /**< Callback to print the compiled content (info format) of the extension instance */
- lyplg_ext_free_clb free; /**< Free the extension instance specific data created by ::lyplg_ext.compile callback */
+ const char *id; /**< plugin identification (mainly for distinguish incompatible versions
+ of the plugins for external tools) */
+ lyplg_ext_compile_clb compile; /**< callback to compile extension instance from the parsed data */
+ lyplg_ext_schema_printer_clb sprinter; /**< callback to print the compiled content (info format) of the extension
+ instance */
+ lyplg_ext_free_clb free; /**< free the extension-specific data created by its compilation */
- lyplg_ext_data_parse_clb parse; /**< Callback to parse data instance according to the extension definition. */
- lyplg_ext_data_validation_clb validate; /**< Callback to decide if data instance is valid according to the schema. */
+ lyplg_ext_data_parse_clb parse; /**< callback to parse data instance according to the extension definition */
+ lyplg_ext_data_validate_clb validate; /**< callback to validate parsed data instances according to the extension
+ definition */
};
struct lyplg_ext_record {
@@ -214,6 +219,19 @@
struct lyplg_ext plugin; /**< data to utilize plugin implementation */
};
+LIBYANG_API_DECL LY_ERR lyplg_ext_get_data(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, void **ext_data,
+ ly_bool *ext_data_free);
+
+/**
+ * @brief Insert extension instance data into a parent.
+ *
+ * @param[in] parent Parent node to insert into.
+ * @param[in] first First top-level sibling node to insert.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR error on error.
+ */
+LIBYANG_API_DECL LY_ERR lyd_insert_ext(struct lyd_node *parent, struct lyd_node *first);
+
/**
* @brief Provide a log message from an extension plugin.
*
diff --git a/src/plugins_exts/metadata.c b/src/plugins_exts/metadata.c
index 2313090..bc70694 100644
--- a/src/plugins_exts/metadata.c
+++ b/src/plugins_exts/metadata.c
@@ -161,10 +161,10 @@
.plugin.id = "libyang 2 - metadata, version 1",
.plugin.compile = &annotation_compile,
- .plugin.parse = NULL,
- .plugin.validate = NULL,
.plugin.sprinter = &annotation_schema_printer,
- .plugin.free = annotation_free
+ .plugin.free = annotation_free,
+ .plugin.parse = NULL,
+ .plugin.validate = NULL
},
{0} /* terminating zeroed record */
};
diff --git a/src/plugins_exts/nacm.c b/src/plugins_exts/nacm.c
index a222dfe..d8e1ca8 100644
--- a/src/plugins_exts/nacm.c
+++ b/src/plugins_exts/nacm.c
@@ -158,10 +158,10 @@
.plugin.id = "libyang 2 - NACM, version 1",
.plugin.compile = &nacm_compile,
- .plugin.parse = NULL,
- .plugin.validate = NULL,
.plugin.sprinter = NULL,
- .plugin.free = NULL
+ .plugin.free = NULL,
+ .plugin.parse = NULL,
+ .plugin.validate = NULL
}, {
.module = "ietf-netconf-acm",
.revision = "2018-02-14",
@@ -169,10 +169,10 @@
.plugin.id = "libyang 2 - NACM, version 1",
.plugin.compile = &nacm_compile,
- .plugin.parse = NULL,
- .plugin.validate = NULL,
.plugin.sprinter = NULL,
- .plugin.free = NULL
+ .plugin.free = NULL,
+ .plugin.parse = NULL,
+ .plugin.validate = NULL
}, {
.module = "ietf-netconf-acm",
.revision = "2012-02-22",
@@ -180,10 +180,10 @@
.plugin.id = "libyang 2 - NACM, version 1",
.plugin.compile = &nacm_compile,
- .plugin.parse = NULL,
- .plugin.validate = NULL,
.plugin.sprinter = NULL,
- .plugin.free = NULL
+ .plugin.free = NULL,
+ .plugin.parse = NULL,
+ .plugin.validate = NULL
}, {
.module = "ietf-netconf-acm",
.revision = "2018-02-14",
@@ -191,10 +191,10 @@
.plugin.id = "libyang 2 - NACM, version 1",
.plugin.compile = &nacm_compile,
- .plugin.parse = NULL,
- .plugin.validate = NULL,
.plugin.sprinter = NULL,
- .plugin.free = NULL
+ .plugin.free = NULL,
+ .plugin.parse = NULL,
+ .plugin.validate = NULL
},
{0} /* terminating zeroed item */
};
diff --git a/src/plugins_exts/schema_mount.c b/src/plugins_exts/schema_mount.c
index 4b1c1cf..d367fe7 100644
--- a/src/plugins_exts/schema_mount.c
+++ b/src/plugins_exts/schema_mount.c
@@ -15,6 +15,7 @@
#define _GNU_SOURCE
#include <assert.h>
+#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -27,164 +28,772 @@
#include "tree_schema.h"
/**
+ * @brief Internal schema mount data structure for holding all the contexts of parsed data.
+ */
+struct lyplg_ext_sm {
+ struct lyplg_ext_sm_shared {
+ pthread_mutex_t lock; /**< lock for accessing this shared structure */
+
+ struct {
+ struct ly_ctx *ctx; /**< context shared between all data of this mount point */
+ const char *mount_point; /**< mount point name */
+ const char *content_id; /**< yang-library content-id (alternatively module-set-id),
+ stored in the dictionary of the ext instance context */
+ } *schemas; /**< array of shared schema schemas */
+ uint32_t schema_count; /**< length of schemas array */
+ uint32_t ref_count; /**< number of references to this structure (mount-points with the same name
+ in the module) */
+ } *shared; /**< shared schema mount points */
+
+ struct lyplg_ext_sm_inln {
+ struct {
+ struct ly_ctx *ctx; /**< context created for single inline schema data */
+ } *schemas; /**< array of inline schemas */
+ uint32_t schema_count; /**< length of schemas array */
+ } inln; /**< inline mount points */
+};
+
+#define EXT_LOGERR_MEM_RET(ext) \
+ lyplg_ext_log(ext, LY_LLERR, LY_EMEM, NULL, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \
+ return LY_EMEM
+
+#define EXT_LOGERR_MEM_GOTO(ext, rc, label) \
+ lyplg_ext_log(ext, LY_LLERR, LY_EMEM, NULL, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \
+ rc = LY_EMEM; \
+ goto label
+
+#define EXT_LOGERR_INT_RET(ext) \
+ lyplg_ext_log(ext, LY_LLERR, LY_EINT, NULL, "Internal error (%s:%d).", __FILE__, __LINE__); \
+ return LY_EINT
+
+/**
* @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.
+ * @return LY_SUCCESS if is unique;
+ * @return LY_EINVAL otherwise.
*/
static LY_ERR
-schema_mount_unique_mount_point(struct lysc_ctx *cctx, const struct lysc_ext_instance *c_ext,
+schema_mount_compile_unique_mp(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;
+ struct lysc_ext_instance *exts;
+ LY_ARRAY_COUNT_TYPE u;
+ struct lysc_node *parent;
- /* Check if it is the only instance of the mount-point among its' siblings */
- parent = (struct lysp_node *) c_ext->parent;
+ /* check if it is the only instance of the mount-point among its' siblings */
+ parent = (struct lysc_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;
- }
+ if (&exts[u] == c_ext) {
+ continue;
}
- 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 */
+
+ if (!strcmp(exts[u].def->module->name, "ietf-yang-schema-mount") && !strcmp(exts[u].def->name, "mount-point")) {
+ lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Multiple extension \"%s\" instances.",
+ p_ext->name);
return LY_EINVAL;
}
}
return LY_SUCCESS;
}
+struct lyplg_ext_sm_shared_cb_data {
+ const struct lysc_ext_instance *ext;
+ struct lyplg_ext_sm_shared *sm_shared;
+};
+
+static LY_ERR
+schema_mount_compile_mod_dfs_cb(struct lysc_node *node, void *data, ly_bool *dfs_continue)
+{
+ struct lyplg_ext_sm_shared_cb_data *cb_data = data;
+ struct lyplg_ext_sm *sm_data;
+ struct lysc_ext_instance *exts;
+ LY_ARRAY_COUNT_TYPE u;
+
+ (void)dfs_continue;
+
+ if (node == cb_data->ext->parent) {
+ /* parent of the current compiled extension, skip */
+ return LY_SUCCESS;
+ }
+
+ /* find the same mount point */
+ exts = node->exts;
+ LY_ARRAY_FOR(exts, u) {
+ if (!strcmp(exts[u].def->module->name, "ietf-yang-schema-mount") && !strcmp(exts[u].def->name, "mount-point") &&
+ (exts[u].argument == cb_data->ext->argument)) {
+ /* same mount point, break the DFS search */
+ sm_data = exts[u].data;
+ cb_data->sm_shared = sm_data->shared;
+ return LY_EEXIST;
+ }
+ }
+
+ /* not found, continue search */
+ return LY_SUCCESS;
+}
+
+static struct lyplg_ext_sm_shared *
+schema_mount_compile_find_shared(const struct lys_module *mod, const struct lysc_ext_instance *ext)
+{
+ struct lyplg_ext_sm_shared_cb_data cb_data;
+ LY_ERR r;
+
+ /* prepare cb_data */
+ cb_data.ext = ext;
+ cb_data.sm_shared = NULL;
+
+ /* try to find the same mount point */
+ r = lysc_module_dfs_full(mod, schema_mount_compile_mod_dfs_cb, &cb_data);
+ assert((!r && !cb_data.sm_shared) || ((r == LY_EEXIST) && cb_data.sm_shared));
+
+ return cb_data.sm_shared;
+}
+
/**
* @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)
+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;
+ struct lyplg_ext_sm *sm_data;
- /* 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 */
+ /* check YANG version 1.1 */
cur_mod = lysc_ctx_get_cur_mod(cctx);
if (cur_mod->parsed->version != LYS_VERSION_1_1) {
+ lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+ "Extension \"%s\" instance not allowed in YANG version 1 module.", p_ext->name);
return LY_EINVAL;
}
- /* Check if its' parent is a container or a list */
+ /* check parent nodetype */
if ((p_ext->parent_stmt != LY_STMT_CONTAINER) && (p_ext->parent_stmt != LY_STMT_LIST)) {
+ lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+ "Extension \"%s\" instance allowed only in container or list statement.", p_ext->name);
return LY_EINVAL;
}
- /* Check if the only mount-point among siblings */
- if (schema_mount_unique_mount_point(cctx, c_ext, p_ext)) {
+ /* check uniqueness */
+ if (schema_mount_compile_unique_mp(cctx, c_ext, p_ext)) {
return LY_EINVAL;
}
- (void)c_ext;
+ /* init internal data */
+ sm_data = calloc(1, sizeof *sm_data);
+ if (!sm_data) {
+ EXT_LOGERR_MEM_RET(c_ext);
+ }
+ c_ext->data = sm_data;
+
+ /* reuse/init shared schema */
+ sm_data->shared = schema_mount_compile_find_shared(c_ext->module, c_ext);
+ if (sm_data->shared) {
+ ++sm_data->shared->ref_count;
+ } else {
+ sm_data->shared = calloc(1, sizeof *sm_data->shared);
+ if (!sm_data->shared) {
+ free(sm_data);
+ EXT_LOGERR_MEM_RET(c_ext);
+ }
+ pthread_mutex_init(&sm_data->shared->lock, NULL);
+ sm_data->shared->ref_count = 1;
+ }
return LY_SUCCESS;
}
/**
- * @brief Parse callback for schema mount.
+ * @brief Learn details about the current mount point.
*
- * Check if data is valid for schema mount and inserts it to the parent.
+ * @param[in] ext Compiled extension instance.
+ * @param[in] ext_data Extension data retrieved by the callback.
+ * @param[out] config Whether the whole schema should keep its config or be set to false.
+ * @param[out] shared Whether the schema is shared or inline.
+ * @return LY_ERR value.
*/
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)
+schema_mount_get_smount(const struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool *config,
+ ly_bool *shared)
{
- 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;
+ struct lyd_node *mpoint, *node;
+ char *path = NULL;
+ LY_ERR r;
- ctx = LYD_CTX(parent);
+ /* find the mount point */
+ if (asprintf(&path, "/ietf-yang-schema-mount:schema-mounts/mount-point[module='%s'][label='%s']", ext->module->name,
+ ext->argument) == -1) {
+ EXT_LOGERR_MEM_RET(ext);
+ }
+ r = ext_data ? lyd_find_path(ext_data, path, 0, &mpoint) : LY_ENOTFOUND;
+ free(path);
+ if (r) {
+ /* missing mount-point, cannot be data for this extension (https://datatracker.ietf.org/doc/html/rfc8528#page-10) */
+ return LY_ENOT;
+ }
- 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;
+ /* check config */
+ if (!lyd_find_path(mpoint, "config", 0, &node) && !strcmp(lyd_get_value(node), "false")) {
+ *config = 0;
+ } else {
+ *config = 1;
+ }
+
+ /* check schema-ref */
+ if (lyd_find_path(mpoint, "shared-schema", 0, NULL)) {
+ if (lyd_find_path(mpoint, "inline", 0, NULL)) {
+ EXT_LOGERR_INT_RET(ext);
+ }
+ *shared = 0;
+ } else {
+ *shared = 1;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Create schema (context) based on retrieved extension data.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[in] ext_data Extension data retrieved by the callback.
+ * @param[in] config Whether the whole schema should keep its config or be set to false.
+ * @param[out] ext_ctx Schema to use for parsing the data.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+schema_mount_create_ctx(const struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
+ struct ly_ctx **ext_ctx)
+{
+ LY_ERR r;
+ const char * const *searchdirs;
+ const struct lys_module *mod;
+ struct lysc_node *root, *node;
+ uint32_t idx = 0;
+
+ /* get searchdirs from the current context */
+ searchdirs = ly_ctx_get_searchdirs(ext->module->ctx);
+
+ /* create the context based on the data */
+ if ((r = ly_ctx_new_yldata(searchdirs ? searchdirs[0] : NULL, ext_data, ly_ctx_get_options(ext->module->ctx), ext_ctx))) {
+ lyplg_ext_log(ext, LY_LLERR, r, NULL, "Failed to create context for the schema-mount data.");
+ return r;
+ }
+
+ if (!config) {
+ /* manually change the config of all schema nodes in all the modules */
+ while ((mod = ly_ctx_get_module_iter(*ext_ctx, &idx))) {
+ if (!mod->implemented) {
+ continue;
}
- }
- if (!final) {
- /* If there was nothing inserted yet this subtree becomes the one to insert into */
- final = subtree;
- }
+ LY_LIST_FOR(mod->compiled->data, root) {
+ LYSC_TREE_DFS_BEGIN(root, node) {
+ node->flags &= ~LYS_CONFIG_W;
+ node->flags |= LYS_CONFIG_R;
- 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;
+ LYSC_TREE_DFS_END(root, node);
+ }
+ }
}
}
- if (found_mount_point && found_yanglib) {
- /* It is valid data and can be inserted into the parent */
- lyd_insert_child(parent, final);
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Get schema (context) for a shared-schema mount point.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[in] ext_data Extension data retrieved by the callback.
+ * @param[in] config Whether the whole schema should keep its config or be set to false.
+ * @param[out] ext_ctx Schema to use for parsing the data.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+schema_mount_get_ctx_shared(struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
+ const struct ly_ctx **ext_ctx)
+{
+ struct lyplg_ext_sm *sm_data = ext->data;
+ LY_ERR ret = LY_SUCCESS, r;
+ struct lyd_node *node = NULL;
+ struct ly_ctx *new_ctx;
+ uint32_t i;
+ const char *content_id = NULL;
+ void *mem;
+
+ assert(sm_data && sm_data->shared);
+
+ /* get yang-library content-id or module-set-id */
+ if (ext_data) {
+ lyd_find_path(ext_data, "/ietf-yang-library:yang-library/content-id", 0, &node);
+ if (!node) {
+ lyd_find_path(ext_data, "/ietf-yang-library:modules-state/module-set-id", 0, &node);
+ }
+ if (node) {
+ content_id = lyd_get_value(node);
+ }
+ }
+ if (!content_id) {
+ lyplg_ext_log(ext, LY_LLERR, LY_EVALID, NULL, "Missing \"content-id\" or \"module-set-id\" in ietf-yang-library data.");
+ return LY_EVALID;
+ }
+
+ /* LOCK */
+ if ((r = pthread_mutex_lock(&sm_data->shared->lock))) {
+ lyplg_ext_log(ext, LY_LLERR, LY_ESYS, NULL, "Mutex lock failed (%s).", strerror(r));
+ return LY_ESYS;
+ }
+
+ /* try to find this mount point */
+ for (i = 0; i < sm_data->shared->schema_count; ++i) {
+ if (ext->argument == sm_data->shared->schemas[i].mount_point) {
+ break;
+ }
+ }
+
+ if (i < sm_data->shared->schema_count) {
+ /* schema exists already */
+ if (strcmp(content_id, sm_data->shared->schemas[i].content_id)) {
+ lyplg_ext_log(ext, LY_LLERR, LY_EVALID, "/ietf-yang-library:yang-library/content-id",
+ "Shared-schema yang-library content-id \"%s\" differs from \"%s\" used previously.",
+ content_id, sm_data->shared->schemas[i].content_id);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
} else {
- /* It was not data for schema mount */
- lyd_free_tree(final);
- ret = LY_ENOT;
+ /* no schema found, create it */
+ if ((r = schema_mount_create_ctx(ext, ext_data, config, &new_ctx))) {
+ ret = r;
+ goto cleanup;
+ }
+
+ /* new entry */
+ mem = realloc(sm_data->shared->schemas, (i + 1) * sizeof *sm_data->shared->schemas);
+ if (!mem) {
+ ly_ctx_destroy(new_ctx);
+ EXT_LOGERR_MEM_GOTO(ext, ret, cleanup);
+ }
+ sm_data->shared->schemas = mem;
+ ++sm_data->shared->schema_count;
+
+ /* fill entry */
+ sm_data->shared->schemas[i].ctx = new_ctx;
+ sm_data->shared->schemas[i].mount_point = ext->argument;
+ lydict_insert(ext->module->ctx, content_id, 0, &sm_data->shared->schemas[i].content_id);
+ }
+
+ /* use the context */
+ *ext_ctx = sm_data->shared->schemas[i].ctx;
+
+cleanup:
+ /* UNLOCK */
+ pthread_mutex_unlock(&sm_data->shared->lock);
+
+ return ret;
+}
+
+/**
+ * @brief Get schema (context) for an inline mount point.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[in] ext_data Extension data retrieved by the callback.
+ * @param[in] config Whether the whole schema should keep its config or be set to false.
+ * @param[out] ext_ctx Schema to use for parsing the data.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+schema_mount_get_ctx_inline(struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
+ const struct ly_ctx **ext_ctx)
+{
+ struct lyplg_ext_sm *sm_data = ext->data;
+ LY_ERR r;
+ struct ly_ctx *new_ctx;
+ uint32_t i;
+ void *mem;
+
+ assert(sm_data && sm_data->shared);
+
+ i = sm_data->inln.schema_count;
+
+ /* always new schema required, create context */
+ if ((r = schema_mount_create_ctx(ext, ext_data, config, &new_ctx))) {
+ return r;
+ }
+
+ /* new entry */
+ mem = realloc(sm_data->inln.schemas, (i + 1) * sizeof *sm_data->inln.schemas);
+ if (!mem) {
+ ly_ctx_destroy(new_ctx);
+ EXT_LOGERR_MEM_RET(ext);
+ }
+ sm_data->inln.schemas = mem;
+ ++sm_data->inln.schema_count;
+
+ /* fill entry */
+ sm_data->inln.schemas[i].ctx = new_ctx;
+
+ /* use the context */
+ *ext_ctx = sm_data->inln.schemas[i].ctx;
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Get schema (context) for a mount point.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[out] ext_ctx Schema to use for parsing the data.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+schema_mount_get_ctx(struct lysc_ext_instance *ext, const struct ly_ctx **ext_ctx)
+{
+ LY_ERR ret = LY_SUCCESS, r;
+ struct lyd_node *iter, *ext_data = NULL;
+ ly_bool ext_data_free = 0, config, shared;
+
+ *ext_ctx = NULL;
+
+ /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
+ if ((r = lyplg_ext_get_data(ext->module->ctx, ext, (void **)&ext_data, &ext_data_free))) {
+ ret = r;
+ goto cleanup;
+ }
+
+ LY_LIST_FOR(ext_data, iter) {
+ if (iter->flags & LYD_NEW) {
+ /* must be validated for the parent-reference prefix data to be stored */
+ lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "Provided ext data have not been validated.");
+ ret = LY_EINVAL;
+ goto cleanup;
+ }
+ }
+
+ /* learn about this mount point */
+ if ((r = schema_mount_get_smount(ext, ext_data, &config, &shared))) {
+ ret = r;
+ goto cleanup;
+ }
+
+ /* create/get the context for parsing the data */
+ if (shared) {
+ r = schema_mount_get_ctx_shared(ext, ext_data, config, ext_ctx);
+ } else {
+ r = schema_mount_get_ctx_inline(ext, ext_data, config, ext_ctx);
+ }
+ if (r) {
+ ret = r;
+ goto cleanup;
+ }
+
+cleanup:
+ if (ext_data_free) {
+ lyd_free_all(ext_data);
+ }
+ return ret;
+}
+
+/**
+ * @brief Parse callback for schema mount.
+ * Check if data if 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)
+{
+ LY_ERR ret = LY_SUCCESS, r;
+ const struct ly_ctx *ext_ctx;
+ struct lyd_node *subtree, *first = NULL;
+ struct ly_err_item *err;
+ uint32_t old_log_opts;
+
+ /* get context based on ietf-yang-library data */
+ if ((r = schema_mount_get_ctx(ext, &ext_ctx))) {
+ return r;
+ }
+
+ /* prepare opts */
+ old_log_opts = ly_log_options(LY_LOSTORE_LAST);
+ assert(parse_opts & LYD_PARSE_ONLY);
+ parse_opts |= LYD_PARSE_SUBTREE;
+
+ do {
+ /* parse by nested subtrees */
+ r = lyd_parse_data(ext_ctx, NULL, in, format, parse_opts, 0, &subtree);
+ if (r && (r != LY_ENOT)) {
+ /* error, maybe valid, maybe not, print as verbose */
+ err = ly_err_first(ext_ctx);
+ if (!err) {
+ lyplg_ext_log(ext, LY_LLVRB, 0, NULL, "Unknown parsing error (err code %d).", r);
+ } else {
+ lyplg_ext_log(ext, LY_LLVRB, 0, NULL, "%s (err code %d).", err->msg, err->no);
+ }
+ ret = LY_ENOT;
+ goto cleanup;
+ }
+
+ /* set the special flag and insert into siblings */
+ subtree->flags |= LYD_EXT;
+ lyd_insert_sibling(first, subtree, &first);
+ } while (r == LY_ENOT);
+
+ /* append to parent */
+ if (first && (r = lyd_insert_ext(parent, first))) {
+ lyplg_ext_log(ext, LY_LLERR, r, NULL, "Failed to append parsed data.");
+ ret = r;
+ goto cleanup;
}
cleanup:
ly_log_options(old_log_opts);
+ if (ret) {
+ lyd_free_siblings(first);
+ }
return ret;
}
/**
+ * @brief Duplicate all accessible parent references for a shared-schema mount point.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[in] ctx_node Context node for evaluating the parent-reference XPath expressions.
+ * @param[in] ext_data Extension data retrieved by the callback.
+ * @param[in] trg_ctx Mounted data context to use for duplication.
+ * @param[out] ref_set Set of all top-level parent-ref subtrees connected to each other, may be empty.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+schema_mount_dup_parent_ref(const struct lysc_ext_instance *ext, const struct lyd_node *ctx_node,
+ const struct lyd_node *ext_data, const struct ly_ctx *trg_ctx, struct ly_set **ref_set)
+{
+ LY_ERR ret = LY_SUCCESS;
+ char *path = NULL;
+ struct ly_set *set = NULL, *par_set = NULL;
+ struct lyd_node_term *term;
+ struct lyd_node *dup = NULL, *top_node, *first;
+ struct lyd_value_xpath10 *xp_val;
+ uint32_t i, j;
+
+ *ref_set = NULL;
+
+ if (!ext_data) {
+ /* we expect the same ext data as before and there must be some for data to be parsed */
+ lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "No ext data provided.");
+ ret = LY_EINVAL;
+ goto cleanup;
+ }
+
+ /* get all parent references of this mount point */
+ if (asprintf(&path, "/ietf-yang-schema-mount:schema-mounts/mount-point[module='%s'][label='%s']"
+ "/shared-schema/parent-reference", ext->module->name, ext->argument) == -1) {
+ EXT_LOGERR_MEM_GOTO(ext, ret, cleanup);
+ }
+ if ((ret = lyd_find_xpath(ext_data, path, &set))) {
+ goto cleanup;
+ }
+
+ /* prepare result set */
+ if ((ret = ly_set_new(ref_set))) {
+ goto cleanup;
+ }
+
+ first = NULL;
+ for (i = 0; i < set->count; ++i) {
+ term = set->objs[i];
+
+ /* get the referenced nodes (subtrees) */
+ LYD_VALUE_GET(&term->value, xp_val);
+ if ((ret = lyd_find_xpath4(ctx_node, ctx_node, lyxp_get_expr(xp_val->exp), xp_val->format, xp_val->prefix_data,
+ NULL, &par_set))) {
+ goto cleanup;
+ }
+
+ for (j = 0; j < par_set->count; ++j) {
+ /* duplicate with parents in the context of the mounted data */
+ if ((ret = lyd_dup_single_to_ctx(par_set->dnodes[j], trg_ctx, NULL,
+ LYD_DUP_RECURSIVE | LYD_DUP_WITH_PARENTS | LYD_DUP_WITH_FLAGS, &dup))) {
+ goto cleanup;
+ }
+
+ /* go top-level */
+ while (dup->parent) {
+ dup = lyd_parent(dup);
+ }
+
+ /* check whether the top-level node exists */
+ if (first) {
+ if ((ret = lyd_find_sibling_first(first, dup, &top_node)) && (ret != LY_ENOTFOUND)) {
+ goto cleanup;
+ }
+ } else {
+ top_node = NULL;
+ }
+
+ if (top_node) {
+ /* merge */
+ ret = lyd_merge_tree(&first, dup, LYD_MERGE_DESTRUCT);
+ dup = NULL;
+ if (ret) {
+ goto cleanup;
+ }
+ } else {
+ /* insert */
+ if ((ret = lyd_insert_sibling(first, dup, &first))) {
+ goto cleanup;
+ }
+
+ /* add into the result set because a new top-level node was added */
+ if ((ret = ly_set_add(*ref_set, dup, 1, NULL))) {
+ goto cleanup;
+ }
+ dup = NULL;
+ }
+ }
+ }
+
+cleanup:
+ free(path);
+ ly_set_free(set, NULL);
+ ly_set_free(par_set, NULL);
+ lyd_free_tree(dup);
+ if (ret && *ref_set) {
+ if ((*ref_set)->count) {
+ lyd_free_siblings((*ref_set)->dnodes[0]);
+ }
+ ly_set_free(*ref_set, NULL);
+ *ref_set = NULL;
+ }
+ return ret;
+}
+
+/**
+ * @brief Validate callback for schema mount.
+ */
+static LY_ERR
+schema_mount_validate(struct lysc_ext_instance *ext, struct lyd_node *sibling, uint32_t val_opts)
+{
+ LY_ERR ret = LY_SUCCESS;
+ uint32_t old_log_opts, i;
+ struct ly_err_item *err;
+ struct lyd_node *iter, *ext_data = NULL, *ref_first = NULL, *orig_parent = lyd_parent(sibling);
+ ly_bool ext_data_free = 0;
+ struct ly_set *ref_set = NULL;
+
+ if (!sibling) {
+ /* some data had to be parsed for this callback to be called */
+ EXT_LOGERR_INT_RET(ext);
+ }
+
+ /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
+ if ((ret = lyplg_ext_get_data(ext->module->ctx, ext, (void **)&ext_data, &ext_data_free))) {
+ goto cleanup;
+ }
+
+ LY_LIST_FOR(ext_data, iter) {
+ if (iter->flags & LYD_NEW) {
+ /* must be validated for the parent-reference prefix data to be stored */
+ lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "Provided ext data have not been validated.");
+ ret = LY_EINVAL;
+ goto cleanup;
+ }
+ }
+
+ /* duplicate the referenced parent nodes into ext context */
+ if ((ret = schema_mount_dup_parent_ref(ext, orig_parent, ext_data, LYD_CTX(sibling), &ref_set))) {
+ goto cleanup;
+ }
+
+ /* create accessible tree, remove LYD_EXT to not call this callback recursively */
+ lyd_unlink_siblings(sibling);
+ LY_LIST_FOR(sibling, iter) {
+ iter->flags &= ~LYD_EXT;
+ }
+ if (ref_set->count) {
+ if ((ret = lyd_insert_sibling(sibling, ref_set->dnodes[0], &sibling))) {
+ goto cleanup;
+ }
+ }
+
+ /* only store messages in the context, log as an extension */
+ old_log_opts = ly_log_options(LY_LOSTORE_LAST);
+
+ /* validate all the data */
+ ret = lyd_validate_all(&sibling, NULL, val_opts, NULL);
+ ly_log_options(old_log_opts);
+
+ /* restore sibling tree */
+ for (i = 0; i < ref_set->count; ++i) {
+ if (ref_set->dnodes[i] == sibling) {
+ sibling = sibling->next;
+ }
+ lyd_free_tree(ref_set->dnodes[i]);
+ }
+ LY_LIST_FOR(sibling, iter) {
+ iter->flags |= LYD_EXT;
+ }
+ lyd_insert_ext(orig_parent, sibling);
+
+ if (ret) {
+ /* log the error in the original context */
+ err = ly_err_first(LYD_CTX(sibling));
+ if (!err) {
+ lyplg_ext_log(ext, LY_LLERR, ret, NULL, "Unknown validation error (err code %d).", ret);
+ } else {
+ lyplg_ext_log(ext, LY_LLERR, err->no, err->path, "%s", err->msg);
+ }
+ goto cleanup;
+ }
+
+cleanup:
+ ly_set_free(ref_set, NULL);
+ lyd_free_siblings(ref_first);
+ if (ext_data_free) {
+ lyd_free_all(ext_data);
+ }
+ return ret;
+}
+
+/**
+ * @brief Schema mount free.
+ *
+ * Implementation of ::lyplg_ext_free_clb callback set as ::lyext_plugin::free.
+ */
+static void
+schema_mount_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
+{
+ struct lyplg_ext_sm *sm_data = ext->data;
+ uint32_t i;
+
+ if (!sm_data) {
+ return;
+ }
+
+ if (!--sm_data->shared->ref_count) {
+ for (i = 0; i < sm_data->shared->schema_count; ++i) {
+ ly_ctx_destroy(sm_data->shared->schemas[i].ctx);
+ lydict_remove(ctx, sm_data->shared->schemas[i].content_id);
+ }
+ free(sm_data->shared->schemas);
+ pthread_mutex_destroy(&sm_data->shared->lock);
+ free(sm_data->shared);
+ }
+
+ for (i = 0; i < sm_data->inln.schema_count; ++i) {
+ ly_ctx_destroy(sm_data->inln.schemas[i].ctx);
+ }
+ free(sm_data->inln.schemas);
+ free(sm_data);
+}
+
+/**
* @brief Plugin descriptions for the Yang Schema Mount extension.
*
* Note that external plugins are supposed to use:
@@ -199,10 +808,10 @@
.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
+ .plugin.free = &schema_mount_free,
+ .plugin.parse = &schema_mount_parse,
+ .plugin.validate = &schema_mount_validate
},
{0} /* terminating zeroed item */
};
diff --git a/src/plugins_exts/yangdata.c b/src/plugins_exts/yangdata.c
index 0c96a14..55a03e3 100644
--- a/src/plugins_exts/yangdata.c
+++ b/src/plugins_exts/yangdata.c
@@ -172,10 +172,10 @@
.plugin.id = "libyang 2 - yang-data, version 1",
.plugin.compile = &yangdata_compile,
- .plugin.parse = NULL,
- .plugin.validate = NULL,
.plugin.sprinter = &yangdata_schema_printer,
- .plugin.free = yangdata_free
+ .plugin.free = yangdata_free,
+ .plugin.parse = NULL,
+ .plugin.validate = NULL
},
{0} /* terminating zeroed record */
};
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 372c783..5d0a82d 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -134,6 +134,7 @@
mod = ly_schema_resolved_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
break;
case LY_VALUE_XML:
+ case LY_VALUE_STR_NS:
mod = ly_xml_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
break;
case LY_VALUE_CANON:
@@ -147,8 +148,8 @@
}
LIBYANG_API_DEF const struct lys_module *
-lyplg_type_identity_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
- const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, const void *prefix_data)
+lyplg_type_identity_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *prefix,
+ size_t prefix_len, LY_VALUE_FORMAT format, const void *prefix_data)
{
if (prefix_len) {
return ly_resolve_prefix(ctx, prefix, prefix_len, format, prefix_data);
@@ -163,8 +164,9 @@
case LY_VALUE_CANON:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
+ case LY_VALUE_STR_NS:
/* use context node module (as specified) */
- return ctx_node->module;
+ return ctx_node ? ctx_node->module : NULL;
case LY_VALUE_XML:
/* use the default namespace */
return ly_xml_resolve_prefix(ctx, NULL, 0, prefix_data);
@@ -253,6 +255,7 @@
prefix = ly_schema_resolved_get_prefix(mod, prefix_data);
break;
case LY_VALUE_XML:
+ case LY_VALUE_STR_NS:
prefix = ly_xml_get_prefix(mod, prefix_data);
break;
case LY_VALUE_CANON:
@@ -784,6 +787,7 @@
case LY_VALUE_CANON:
case LY_VALUE_LYB:
case LY_VALUE_JSON:
+ case LY_VALUE_STR_NS:
prefix_opt = LY_PATH_PREFIX_STRICT_INHERIT;
break;
}
@@ -861,7 +865,7 @@
{
LY_ERR ret;
struct lyxp_set set = {0};
- const char *val_str;
+ const char *val_str, *xp_err_msg;
uint32_t i;
int rc;
@@ -871,9 +875,19 @@
ret = lyxp_eval(LYD_CTX(node), lref->path, node->schema->module, LY_VALUE_SCHEMA_RESOLVED, lref->prefixes,
node, tree, NULL, &set, LYXP_IGNORE_WHEN);
if (ret) {
- ret = LY_ENOTFOUND;
+ if (ly_errcode(LYD_CTX(node)) == ret) {
+ xp_err_msg = ly_errmsg(LYD_CTX(node));
+ } else {
+ xp_err_msg = NULL;
+ }
+
val_str = lref->plugin->print(LYD_CTX(node), value, LY_VALUE_CANON, NULL, NULL, NULL);
- if (asprintf(errmsg, "Invalid leafref value \"%s\" - XPath evaluation error.", val_str) == -1) {
+ if (xp_err_msg) {
+ rc = asprintf(errmsg, "Invalid leafref value \"%s\" - XPath evaluation error (%s).", val_str, xp_err_msg);
+ } else {
+ rc = asprintf(errmsg, "Invalid leafref value \"%s\" - XPath evaluation error.", val_str);
+ }
+ if (rc == -1) {
*errmsg = NULL;
ret = LY_EMEM;
}
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 13cee84..e9aa723 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -223,8 +223,8 @@
* @return LY_EMEM If there is not enough memory for allocating error record, the @p err is not touched in that case.
* @return LY_SUCCESS if @p ecode is LY_SUCCESS, the @p err is not touched in this case.
*/
-LIBYANG_API_DECL LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag, const char *err_format, ...)
-_FORMAT_PRINTF(6, 7);
+LIBYANG_API_DECL LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag,
+ const char *err_format, ...) _FORMAT_PRINTF(6, 7);
/**
* @brief Destructor for the error records created with ::ly_err_new().
@@ -251,8 +251,8 @@
* @param[out] err Pointer to store error information in case of failure.
* @return LY_ERR value
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_DATA_TYPE type, int *base,
- struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_DATA_TYPE type,
+ int *base, struct ly_err_item **err);
/**
* @brief Check that the value of a type is allowed based on its status.
@@ -297,8 +297,9 @@
* @return Resolved prefix module,
* @return NULL otherwise.
*/
-LIBYANG_API_DECL const struct lys_module *lyplg_type_identity_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
- const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, const void *prefix_data);
+LIBYANG_API_DECL const struct lys_module *lyplg_type_identity_module(const struct ly_ctx *ctx,
+ const struct lysc_node *ctx_node, const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format,
+ const void *prefix_data);
/**
* @brief Implement a module (just like ::lys_set_implemented()), but keep maintaining unresolved items.
@@ -311,7 +312,8 @@
* @return LY_ERECOMPILE if the context need to be recompiled, should be returned.
* @return LY_ERR value.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_make_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres);
+LIBYANG_API_DECL LY_ERR lyplg_type_make_implemented(struct lys_module *mod, const char **features,
+ struct lys_glob_unres *unres);
/**
* @brief Get the bitmap size of a bits value bitmap.
@@ -364,8 +366,8 @@
* @param[in,out] prefix_data_p Resulting prefix data for the value in format @p format_p.
* @return LY_ERR value.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_prefix_data_new(const struct ly_ctx *ctx, const void *value, size_t value_len, LY_VALUE_FORMAT format,
- const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p);
+LIBYANG_API_DECL LY_ERR lyplg_type_prefix_data_new(const struct ly_ctx *ctx, const void *value, size_t value_len,
+ LY_VALUE_FORMAT format, const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p);
/**
* @brief Duplicate prefix data.
*
@@ -377,7 +379,8 @@
* @param[out] dup Duplicated prefix data.
* @return LY_ERR value.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_prefix_data_dup(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *orig, void **dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_prefix_data_dup(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *orig,
+ void **dup);
/**
* @brief Free internal prefix data.
@@ -396,7 +399,7 @@
*
* @param[in] ctx libyang Context
* @param[in] value Lexical representation of the value to be stored.
- * @param[in] value_len Length (number of bytes) of the given \p value.
+ * @param[in] value_len Length (number of bytes) of the given @p value.
* @param[in] options [Type plugin store options](@ref plugintypestoreopts).
* @param[in] format Input format of the value.
* @param[in] prefix_data Format-specific data for resolving any prefixes (see ly_resolve_prefix()).
@@ -408,8 +411,8 @@
* @return LY_ERECOMPILE if the context need to be recompiled, should be returned.
* @return LY_ERR value on error.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_lypath_new(const struct ly_ctx *ctx, const char *value, size_t value_len, uint32_t options,
- LY_VALUE_FORMAT format, void *prefix_data, const struct lysc_node *ctx_node,
+LIBYANG_API_DECL LY_ERR lyplg_type_lypath_new(const struct ly_ctx *ctx, const char *value, size_t value_len,
+ uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, const struct lysc_node *ctx_node,
struct lys_glob_unres *unres, struct ly_path **path, struct ly_err_item **err);
/**
@@ -457,18 +460,18 @@
* @param[in] format Input format of the value, see the description for details.
* @param[in] prefix_data Format-specific data for resolving any prefixes (see ly_resolve_prefix()).
* @param[in] hints Bitmap of [value hints](@ref lydvalhints) of all the allowed value types.
- * @param[in] ctx_node Schema context node of @p value.
+ * @param[in] ctx_node Schema context node of @p value, may be NULL for metadata.
* @param[out] storage Storage for the value in the type's specific encoding. Except for _canonical, all the members
* should be filled by the plugin (if it fills them at all).
* @param[in,out] unres Global unres structure for newly implemented modules.
* @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic
- * error message is prepared instead. The error structure can be created by ::ly_err_new().
+ * error message is prepared instead. The error structure can be created by ::ly_err_new().
* @return LY_SUCCESS on success,
* @return LY_EINCOMPLETE in case the ::lyplg_type_validate_clb should be called to finish value validation in data,
* @return LY_ERR value on error.
*/
-LIBYANG_API_DECL typedef LY_ERR (*lyplg_type_store_clb)(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
- size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+LIBYANG_API_DECL typedef LY_ERR (*lyplg_type_store_clb)(const struct ly_ctx *ctx, const struct lysc_type *type,
+ const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
@@ -612,13 +615,14 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for a generic simple type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_simple(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_simple(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/**
* @brief Implementation of ::lyplg_type_dup_clb for a generic simple type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_simple(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_simple(const struct ly_ctx *ctx, const struct lyd_value *original,
+ struct lyd_value *dup);
/**
* @brief Implementation of ::lyplg_type_free_clb for a generic simple type.
@@ -638,9 +642,9 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in binary type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_compare_clb for the built-in binary type.
@@ -650,13 +654,14 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for the built-in binary type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_binary(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_binary(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/**
* @brief Implementation of ::lyplg_type_dup_clb for the built-in binary type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_binary(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_binary(const struct ly_ctx *ctx, const struct lyd_value *original,
+ struct lyd_value *dup);
/**
* @brief Implementation of ::lyplg_type_free_clb for the built-in binary type.
@@ -676,9 +681,9 @@
/**
* @brief Implementation of the ::lyplg_type_store_clb for the built-in bits type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_bits(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_bits(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of the ::lyplg_type_compare_clb for the built-in bits type.
@@ -688,13 +693,14 @@
/**
* @brief Implementation of the ::lyplg_type_print_clb for the built-in bits type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/**
* @brief Implementation of the ::lyplg_type_dup_clb for the built-in bits type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original,
+ struct lyd_value *dup);
/**
* @brief Implementation of the ::lyplg_type_free_clb for the built-in bits type.
@@ -714,9 +720,9 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in boolean type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_boolean(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_boolean(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_compare_clb for the built-in boolean type.
@@ -726,8 +732,8 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for the built-in boolean type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_boolean(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_boolean(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/** @} pluginsTypesBoolean */
@@ -742,9 +748,9 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in decimal64 type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *type,
+ const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_compare_clb for the built-in decimal64 type.
@@ -754,8 +760,8 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for the built-in decimal64 type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_decimal64(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_decimal64(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/** @} pluginsTypesDecimal64 */
@@ -770,9 +776,9 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in empty type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_empty(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_empty(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/** @} pluginsTypesEmpty */
@@ -787,15 +793,15 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in enumeration type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_enum(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_enum(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_print_clb for the built-in enumeration type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_enum(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_enum(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/** @} pluginsTypesEnumeration */
@@ -810,9 +816,9 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in identityref type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *type,
+ const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_compare_clb for the built-in identityref type.
@@ -822,8 +828,8 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for the built-in identityref type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_identityref(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_identityref(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/** @} pluginsTypesIdentityref */
@@ -838,15 +844,15 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in instance-identifier type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type,
+ const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_validate_clb for the built-in instance-identifier type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_validate_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
- const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_validate_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type,
+ const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_compare_clb for the built-in instance-identifier type.
@@ -856,13 +862,14 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for the built-in instance-identifier type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_instanceid(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_instanceid(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/**
* @brief Implementation of ::lyplg_type_dup_clb for the built-in instance-identifier type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original,
+ struct lyd_value *dup);
/**
* @brief Implementation of ::lyplg_type_free_clb for the built-in instance-identifier type.
@@ -882,9 +889,9 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in signed integer types.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_int(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_int(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_compare_clb for the built-in signed integer types.
@@ -894,15 +901,15 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for the built-in signed integer types.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_int(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_int(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in unsigned integer types.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_uint(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_uint(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_compare_clb for the built-in unsigned integer types.
@@ -912,8 +919,8 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for the built-in unsigned integer types.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_uint(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_uint(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/** @} pluginsTypesInteger */
@@ -928,9 +935,9 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in leafref type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_leafref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_leafref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_compare_clb for the built-in leafref type.
@@ -940,19 +947,20 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for the built-in leafref type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_leafref(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_leafref(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/**
* @brief Implementation of ::lyplg_type_dup_clb for the built-in leafref type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_leafref(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_leafref(const struct ly_ctx *ctx, const struct lyd_value *original,
+ struct lyd_value *dup);
/**
* @brief Implementation of ::lyplg_type_validate_clb for the built-in leafref type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_validate_leafref(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
- const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_validate_leafref(const struct ly_ctx *ctx, const struct lysc_type *type,
+ const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_free_clb for the built-in leafref type.
@@ -972,9 +980,9 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in string type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_string(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_string(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/** @} pluginsTypesString */
@@ -989,9 +997,9 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the built-in union type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_compare_clb for the built-in union type.
@@ -1001,19 +1009,20 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for the built-in union type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/**
* @brief Implementation of ::lyplg_type_dup_clb for the built-in union type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original,
+ struct lyd_value *dup);
/**
* @brief Implementation of ::lyplg_type_validate_clb for the built-in union type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
- const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type,
+ const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_free_clb for the built-in union type.
@@ -1033,9 +1042,9 @@
/**
* @brief Implementation of ::lyplg_type_store_clb for the ietf-yang-types xpath1.0 type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+ size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
/**
* @brief Implementation of ::lyplg_type_compare_clb for the ietf-yang-types xpath1.0 type.
@@ -1045,13 +1054,14 @@
/**
* @brief Implementation of ::lyplg_type_print_clb for the ietf-yang-types xpath1.0 type.
*/
-LIBYANG_API_DECL const void *lyplg_type_print_xpath10(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
- void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_xpath10(const struct ly_ctx *ctx, const struct lyd_value *value,
+ LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
/**
* @brief Implementation of ::lyplg_type_dup_clb for the ietf-yang-types xpath1.0 type.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_xpath10(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_xpath10(const struct ly_ctx *ctx, const struct lyd_value *original,
+ struct lyd_value *dup);
/**
* @brief Implementation of ::lyplg_type_free_clb for the ietf-yang-types xpath1.0 type.
@@ -1074,8 +1084,8 @@
* @param[out] err Error information in case of failure. The error structure can be freed by ::ly_err_free().
* @return LY_ERR value according to the result of the parsing and validation.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_parse_int(const char *datatype, int base, int64_t min, int64_t max, const char *value, size_t value_len,
- int64_t *ret, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_parse_int(const char *datatype, int base, int64_t min, int64_t max, const char *value,
+ size_t value_len, int64_t *ret, struct ly_err_item **err);
/**
* @brief Unsigned integer value parser and validator.
@@ -1090,8 +1100,8 @@
* @param[out] err Error information in case of failure. The error structure can be freed by ::ly_err_free().
* @return LY_ERR value according to the result of the parsing and validation.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_parse_uint(const char *datatype, int base, uint64_t max, const char *value, size_t value_len,
- uint64_t *ret, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_parse_uint(const char *datatype, int base, uint64_t max, const char *value,
+ size_t value_len, uint64_t *ret, struct ly_err_item **err);
/**
* @brief Convert a string with a decimal64 value into libyang representation:
@@ -1104,7 +1114,8 @@
* @param[out] err Error information in case of failure. The error structure can be freed by ::ly_err_free().
* @return LY_ERR value according to the result of the parsing and validation.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_parse_dec64(uint8_t fraction_digits, const char *value, size_t value_len, int64_t *ret, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_parse_dec64(uint8_t fraction_digits, const char *value, size_t value_len, int64_t *ret,
+ struct ly_err_item **err);
/**
* @brief Decide if the @p derived identity is derived from (based on) the @p base identity.
@@ -1127,8 +1138,8 @@
* @param[out] err Error information in case of failure. The error structure can be freed by ::ly_err_free().
* @return LY_ERR value according to the result of the validation.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, const char *strval,
- size_t strval_len, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value,
+ const char *strval, size_t strval_len, struct ly_err_item **err);
/**
* @brief Data type validator for pattern-restricted string values.
@@ -1142,7 +1153,8 @@
* @return LY_EVALID when @p does not match any of the patterns.
* @return LY_ESYS in case of PCRE2 error.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_validate_patterns(struct lysc_pattern **patterns, const char *str, size_t str_len, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_validate_patterns(struct lysc_pattern **patterns, const char *str, size_t str_len,
+ struct ly_err_item **err);
/**
* @brief Find leafref target in data.
@@ -1155,8 +1167,8 @@
* @param[out] errmsg Error message in case of error.
* @return LY_ERR value.
*/
-LIBYANG_API_DECL LY_ERR lyplg_type_resolve_leafref(const struct lysc_type_leafref *lref, const struct lyd_node *node, struct lyd_value *value,
- const struct lyd_node *tree, struct lyd_node **target, char **errmsg);
+LIBYANG_API_DECL LY_ERR lyplg_type_resolve_leafref(const struct lysc_type_leafref *lref, const struct lyd_node *node,
+ struct lyd_value *value, const struct lyd_node *tree, struct lyd_node **target, char **errmsg);
/** @} pluginsTypes */
diff --git a/src/plugins_types/identityref.c b/src/plugins_types/identityref.c
index 7eee215..8b7985d 100644
--- a/src/plugins_types/identityref.c
+++ b/src/plugins_types/identityref.c
@@ -249,9 +249,11 @@
ret = identityref_check_base(ident, type_ident, value, value_len, err);
LY_CHECK_GOTO(ret, cleanup);
- /* check status */
- ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
- LY_CHECK_GOTO(ret, cleanup);
+ if (ctx_node) {
+ /* check status */
+ ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
/* store value */
storage->ident = ident;
diff --git a/src/plugins_types/instanceid.c b/src/plugins_types/instanceid.c
index 4481067..d151d0a 100644
--- a/src/plugins_types/instanceid.c
+++ b/src/plugins_types/instanceid.c
@@ -64,6 +64,7 @@
case LY_VALUE_CANON:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
+ case LY_VALUE_STR_NS:
/* the same prefix is inherited and skipped */
inherit_prefix = 1;
break;
diff --git a/src/plugins_types/node_instanceid.c b/src/plugins_types/node_instanceid.c
index 31781d6..3e3eba7 100644
--- a/src/plugins_types/node_instanceid.c
+++ b/src/plugins_types/node_instanceid.c
@@ -64,6 +64,7 @@
case LY_VALUE_CANON:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
+ case LY_VALUE_STR_NS:
/* the same prefix is inherited and skipped */
inherit_prefix = 1;
break;
@@ -172,6 +173,7 @@
case LY_VALUE_CANON:
case LY_VALUE_LYB:
case LY_VALUE_JSON:
+ case LY_VALUE_STR_NS:
prefix_opt = LY_PATH_PREFIX_STRICT_INHERIT;
break;
}
@@ -191,7 +193,7 @@
/* resolve it on schema tree, use JSON format instead of LYB because for this type they are equal but for some
* nested types (such as numbers in predicates in the path) LYB would be invalid */
- ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, (ctx_node->flags & LYS_IS_OUTPUT) ?
+ ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, (ctx_node && (ctx_node->flags & LYS_IS_OUTPUT)) ?
LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY, 1, (format == LY_VALUE_LYB) ?
LY_VALUE_JSON : format, prefix_data, &path);
if (ret) {
diff --git a/src/plugins_types/xpath1.0.c b/src/plugins_types/xpath1.0.c
index 2d29e58..cdcc113 100644
--- a/src/plugins_types/xpath1.0.c
+++ b/src/plugins_types/xpath1.0.c
@@ -12,17 +12,22 @@
* https://opensource.org/licenses/BSD-3-Clause
*/
+#define _GNU_SOURCE
+
#include "plugins_types.h"
+#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include "libyang.h"
#include "common.h"
#include "compat.h"
-/* internal header */
+/* internal headers */
+#include "xml.h"
#include "xpath.h"
/**
@@ -35,16 +40,6 @@
*/
/**
- * @brief Stored value structure for xpath1.0
- */
-struct lyd_value_xpath10 {
- struct lyxp_expr *exp;
- const struct ly_ctx *ctx;
- void *prefix_data;
- LY_VALUE_FORMAT format;
-};
-
-/**
* @brief Print xpath1.0 token in the specific format.
*
* @param[in] token Token to transform.
@@ -268,9 +263,8 @@
LIBYANG_API_DEF LY_ERR
lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
- uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
- const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
- struct ly_err_item **err)
+ uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
+ struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres), struct ly_err_item **err)
{
LY_ERR ret = LY_SUCCESS;
struct lysc_type_str *type_str = (struct lysc_type_str *)type;
@@ -298,17 +292,28 @@
ret = lyplg_type_validate_patterns(type_str->patterns, value, value_len, err);
LY_CHECK_GOTO(ret, cleanup);
- /* store format-specific data and context for later prefix resolution */
- ret = lyplg_type_prefix_data_new(ctx, value, value_len, format, prefix_data, &val->format, &val->prefix_data);
- LY_CHECK_GOTO(ret, cleanup);
- val->ctx = ctx;
-
/* parse */
ret = lyxp_expr_parse(ctx, value_len ? value : "", value_len, 1, &val->exp);
LY_CHECK_GOTO(ret, cleanup);
+ val->ctx = ctx;
- /* store canonical value */
- if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
+ if (ctx_node && !strcmp(ctx_node->name, "parent-reference") && !strcmp(ctx_node->module->name, "ietf-yang-schema-mount")) {
+ /* special case, this type uses prefix-namespace mapping provided directly in data, keep empty for now */
+ val->format = format = LY_VALUE_STR_NS;
+ ret = ly_set_new((struct ly_set **)&val->prefix_data);
+ LY_CHECK_GOTO(ret, cleanup);
+ } else {
+ /* store format-specific data and context for later prefix resolution */
+ ret = lyplg_type_prefix_data_new(ctx, value, value_len, format, prefix_data, &val->format, &val->prefix_data);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ switch (format) {
+ case LY_VALUE_CANON:
+ case LY_VALUE_JSON:
+ case LY_VALUE_LYB:
+ case LY_VALUE_STR_NS:
+ /* store canonical value */
if (options & LYPLG_TYPE_STORE_DYNAMIC) {
ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
options &= ~LYPLG_TYPE_STORE_DYNAMIC;
@@ -317,13 +322,17 @@
ret = lydict_insert(ctx, value_len ? value : "", value_len, &storage->_canonical);
LY_CHECK_GOTO(ret, cleanup);
}
- } else {
+ break;
+ case LY_VALUE_SCHEMA:
+ case LY_VALUE_SCHEMA_RESOLVED:
+ case LY_VALUE_XML:
/* JSON format with prefix is the canonical one */
ret = xpath10_print_value(val, LY_VALUE_JSON, NULL, &canon, err);
LY_CHECK_GOTO(ret, cleanup);
ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
LY_CHECK_GOTO(ret, cleanup);
+ break;
}
cleanup:
@@ -333,6 +342,91 @@
if (ret) {
lyplg_type_free_xpath10(ctx, storage);
+ } else if (val->format == LY_VALUE_STR_NS) {
+ /* needs validation */
+ return LY_EINCOMPLETE;
+ }
+ return ret;
+}
+
+/**
+ * @brief Implementation of ::lyplg_type_validate_clb for the xpath1.0 ietf-yang-types type.
+ */
+static LY_ERR
+lyplg_type_validate_xpath10(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *UNUSED(type),
+ const struct lyd_node *ctx_node, const struct lyd_node *UNUSED(tree), struct lyd_value *storage,
+ struct ly_err_item **err)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_value_xpath10 *val;
+ struct ly_set *set = NULL;
+ uint32_t i;
+ const char *pref, *uri;
+ struct lyxml_ns *ns;
+
+ *err = NULL;
+ LYD_VALUE_GET(storage, val);
+
+ if (val->format != LY_VALUE_STR_NS) {
+ /* nothing to validate */
+ return LY_SUCCESS;
+ }
+
+ /* the XML namespace set must exist */
+ assert(val->prefix_data);
+
+ /* special handling of this particular node */
+ assert(!strcmp(LYD_NAME(ctx_node), "parent-reference") &&
+ !strcmp(ctx_node->schema->module->name, "ietf-yang-schema-mount"));
+
+ /* get all the prefix mappings */
+ if ((ret = lyd_find_xpath(ctx_node, "../../../namespace", &set))) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < set->count; ++i) {
+ assert(!strcmp(LYD_NAME(lyd_child(set->dnodes[i])), "prefix"));
+ pref = lyd_get_value(lyd_child(set->dnodes[i]));
+
+ if (!lyd_child(set->dnodes[i])->next) {
+ /* missing URI - invalid mapping, skip */
+ continue;
+ }
+ assert(!strcmp(LYD_NAME(lyd_child(set->dnodes[i])->next), "uri"));
+ uri = lyd_get_value(lyd_child(set->dnodes[i])->next);
+
+ /* create new ns */
+ ns = calloc(1, sizeof *ns);
+ if (!ns) {
+ ret = LY_EMEM;
+ goto cleanup;
+ }
+ ns->prefix = strdup(pref);
+ ns->uri = strdup(uri);
+ if (!ns->prefix || !ns->uri) {
+ free(ns->prefix);
+ free(ns->uri);
+ free(ns);
+ ret = LY_EMEM;
+ goto cleanup;
+ }
+ ns->depth = 1;
+
+ /* add into the XML namespace set */
+ if ((ret = ly_set_add(val->prefix_data, ns, 1, NULL))) {
+ free(ns->prefix);
+ free(ns->uri);
+ free(ns);
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ ly_set_free(set, NULL);
+ if (ret == LY_EMEM) {
+ ly_err_new(err, LY_EMEM, LYVE_DATA, NULL, NULL, LY_EMEM_MSG);
+ } else if (ret) {
+ ly_err_new(err, ret, LYVE_DATA, NULL, NULL, "%s", ly_errmsg(LYD_CTX(ctx_node)));
}
return ret;
}
@@ -347,7 +441,9 @@
LYD_VALUE_GET(value, val);
- if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
+ /* LY_VALUE_STR_NS should never be transformed */
+ if ((val->format == LY_VALUE_STR_NS) || (format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) ||
+ (format == LY_VALUE_LYB)) {
/* canonical */
if (dynamic) {
*dynamic = 0;
@@ -437,7 +533,7 @@
.plugin.id = "libyang 2 - xpath1.0, version 1",
.plugin.store = lyplg_type_store_xpath10,
- .plugin.validate = NULL,
+ .plugin.validate = lyplg_type_validate_xpath10,
.plugin.compare = lyplg_type_compare_simple,
.plugin.sort = NULL,
.plugin.print = lyplg_type_print_xpath10,
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index 4523e84..3f61230 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -1917,29 +1917,6 @@
return ret;
}
-/**
- * @brief Find the correct plugin implementing the described type
- *
- * @param[in] mod Module where the type is defined
- * @param[in] name Name of the type (typedef)
- * @param[in] basetype Type's basetype (when the built-in base plugin is supposed to be used)
- * @return Pointer to the plugin implementing the described data type.
- */
-static struct lyplg_type *
-lys_compile_type_get_plugin(struct lys_module *mod, const char *name, LY_DATA_TYPE basetype)
-{
- struct lyplg_type *p;
-
- /* try to find loaded user type plugins */
- p = lyplg_find(LYPLG_TYPE, mod->name, mod->revision, name);
- if (!p) {
- /* use the internal built-in type implementation */
- p = lyplg_find(LYPLG_TYPE, "", NULL, ly_data_type2str[basetype]);
- }
-
- return p;
-}
-
LY_ERR
lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags, const char *context_name,
struct lysp_type *type_p, struct lysc_type **type, const char **units, struct lysp_qname **dflt)
@@ -2121,8 +2098,13 @@
continue;
}
- /* get plugin for the specific typedef */
- plugin = lys_compile_type_get_plugin(tctx->tpdf->type.pmod->mod, tctx->tpdf->name, basetype);
+ /* try to find loaded user type plugins */
+ plugin = lyplg_find(LYPLG_TYPE, tctx->tpdf->type.pmod->mod->name, tctx->tpdf->type.pmod->mod->revision,
+ tctx->tpdf->name);
+ if (!plugin) {
+ /* use the internal built-in type implementation */
+ plugin = lyplg_find(LYPLG_TYPE, "", NULL, ly_data_type2str[basetype]);
+ }
assert(plugin);
if ((basetype != LY_TYPE_LEAFREF) && (u != tpdf_chain.count - 1) && !(tctx->tpdf->type.flags) &&
@@ -3048,6 +3030,7 @@
break;
case LY_VALUE_CANON:
case LY_VALUE_XML:
+ case LY_VALUE_STR_NS:
/* not really defined */
LOGINT_RET(ctx->ctx);
}
diff --git a/src/tree.h b/src/tree.h
index 1c283b7..72ce5e2 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -238,7 +238,8 @@
LY_VALUE_SCHEMA_RESOLVED, /**< resolved YANG schema value, prefixes map to module structures directly */
LY_VALUE_XML, /**< XML data value, prefixes map to XML namespace prefixes */
LY_VALUE_JSON, /**< JSON data value, prefixes map to module names */
- LY_VALUE_LYB /**< LYB data binary value, prefix mapping is type-specific (but usually like JSON) */
+ LY_VALUE_LYB, /**< LYB data binary value, prefix mapping is type-specific (but usually like JSON) */
+ LY_VALUE_STR_NS /**< any data format value, prefixes map to XML namespace prefixes */
} LY_VALUE_FORMAT;
/** @} trees */
diff --git a/src/tree_data.c b/src/tree_data.c
index ab4c495..893bdd0 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -346,6 +346,7 @@
struct ly_set parsed = {0};
struct lyd_node *first;
uint32_t i;
+ ly_bool subtree_sibling = 0;
assert(ctx && (parent || first_p));
@@ -360,13 +361,16 @@
/* parse the data */
switch (format) {
case LYD_XML:
- rc = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, NULL, &parsed, &lydctx);
+ rc = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, NULL, &parsed,
+ &subtree_sibling, &lydctx);
break;
case LYD_JSON:
- rc = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
+ rc = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed,
+ &subtree_sibling, &lydctx);
break;
case LYD_LYB:
- rc = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
+ rc = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed,
+ &subtree_sibling, &lydctx);
break;
case LYD_UNKNOWN:
LOGARG(ctx, format);
@@ -384,8 +388,8 @@
if (!(parse_opts & LYD_PARSE_ONLY)) {
/* validate data */
- rc = lyd_validate(first_p, NULL, ctx, val_opts, 0, &lydctx->node_when, &lydctx->node_exts, &lydctx->node_types,
- &lydctx->meta_types, NULL);
+ rc = lyd_validate(first_p, NULL, ctx, val_opts, 0, &lydctx->node_when, &lydctx->node_types, &lydctx->meta_types,
+ &lydctx->ext_val, NULL);
LY_CHECK_GOTO(rc, cleanup);
}
@@ -409,6 +413,8 @@
lyd_free_all(*first_p);
*first_p = NULL;
}
+ } else if (subtree_sibling) {
+ rc = LY_ENOT;
}
ly_set_erase(&parsed, NULL);
return rc;
@@ -558,7 +564,7 @@
/* parse the data */
switch (format) {
case LYD_XML:
- rc = lyd_parse_xml(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
+ rc = lyd_parse_xml(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, NULL, &lydctx);
if (rc && envp) {
/* special situation when the envelopes were parsed successfully */
if (tree) {
@@ -569,10 +575,10 @@
}
break;
case LYD_JSON:
- rc = lyd_parse_json(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
+ rc = lyd_parse_json(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, NULL, &lydctx);
break;
case LYD_LYB:
- rc = lyd_parse_lyb(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
+ rc = lyd_parse_lyb(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, NULL, &lydctx);
break;
case LYD_UNKNOWN:
LOGARG(ctx, format);
@@ -1310,7 +1316,7 @@
}
return lyd_create_meta(parent, meta, module, name, name_len, val_str, strlen(val_str), NULL, LY_VALUE_JSON,
- NULL, LYD_HINT_DATA, clear_dflt, NULL);
+ NULL, LYD_HINT_DATA, parent ? parent->schema : NULL, clear_dflt, NULL);
}
LIBYANG_API_DEF LY_ERR
@@ -1350,7 +1356,7 @@
}
return lyd_create_meta(parent, meta, mod, attr->name.name, strlen(attr->name.name), attr->value, strlen(attr->value),
- NULL, attr->format, attr->val_prefix_data, attr->hints, clear_dflt, NULL);
+ NULL, attr->format, attr->val_prefix_data, attr->hints, parent ? parent->schema : NULL, clear_dflt, NULL);
}
LIBYANG_API_DEF LY_ERR
@@ -1635,8 +1641,9 @@
}
/* parse the new value into a new meta structure */
- LY_CHECK_GOTO(ret = lyd_create_meta(NULL, &m2, meta->annotation->module, meta->name, strlen(meta->name), val_str,
- strlen(val_str), NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, 0, NULL), cleanup);
+ ret = lyd_create_meta(NULL, &m2, meta->annotation->module, meta->name, strlen(meta->name), val_str, strlen(val_str),
+ NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, meta->parent ? meta->parent->schema : NULL, 0, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
/* compare original and new value */
if (lyd_compare_meta(meta, m2)) {
@@ -2089,8 +2096,8 @@
LY_ERR
lyd_new_implicit_r(struct lyd_node *parent, struct lyd_node **first, const struct lysc_node *sparent,
- const struct lys_module *mod, struct ly_set *node_when, struct ly_set *node_exts, struct ly_set *node_types,
- uint32_t impl_opts, struct lyd_node **diff)
+ const struct lys_module *mod, struct ly_set *node_when, struct ly_set *node_types, uint32_t impl_opts,
+ struct lyd_node **diff)
{
LY_ERR ret;
const struct lysc_node *iter = NULL;
@@ -2123,11 +2130,11 @@
if (!node && ((struct lysc_node_choice *)iter)->dflt) {
/* create default case data */
LY_CHECK_RET(lyd_new_implicit_r(parent, first, &((struct lysc_node_choice *)iter)->dflt->node,
- NULL, node_when, node_exts, node_types, impl_opts, diff));
+ NULL, node_when, node_types, impl_opts, diff));
} else if (node) {
/* create any default data in the existing case */
assert(node->schema->parent->nodetype == LYS_CASE);
- LY_CHECK_RET(lyd_new_implicit_r(parent, first, node->schema->parent, NULL, node_when, node_exts, node_types,
+ LY_CHECK_RET(lyd_new_implicit_r(parent, first, node->schema->parent, NULL, node_when, node_types,
impl_opts, diff));
}
break;
@@ -2142,17 +2149,13 @@
/* remember to resolve when */
LY_CHECK_RET(ly_set_add(node_when, node, 1, NULL));
}
- if (node_exts) {
- /* remember to call all the extension's validation callbacks */
- LY_CHECK_RET(lysc_node_ext_tovalidate(node_exts, node));
- }
if (diff) {
/* add into diff */
LY_CHECK_RET(lyd_val_diff_add(node, LYD_DIFF_OP_CREATE, diff));
}
/* create any default children */
- LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, node_when, node_exts, node_types,
+ LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, node_when, node_types,
impl_opts, diff));
}
break;
@@ -2176,10 +2179,6 @@
/* remember to resolve when */
LY_CHECK_RET(ly_set_add(node_when, node, 1, NULL));
}
- if (node_exts) {
- /* remember to call all the extension's validation callbacks */
- LY_CHECK_RET(lysc_node_ext_tovalidate(node_exts, node));
- }
if (diff) {
/* add into diff */
LY_CHECK_RET(lyd_val_diff_add(node, LYD_DIFF_OP_CREATE, diff));
@@ -2208,10 +2207,6 @@
/* remember to resolve when */
LY_CHECK_RET(ly_set_add(node_when, node, 1, NULL));
}
- if (node_exts) {
- /* remember to call all the extension's validation callbacks */
- LY_CHECK_RET(lysc_node_ext_tovalidate(node_exts, node));
- }
if (diff) {
/* add into diff */
LY_CHECK_RET(lyd_val_diff_add(node, LYD_DIFF_OP_CREATE, diff));
@@ -2233,7 +2228,7 @@
{
LY_ERR ret = LY_SUCCESS;
struct lyd_node *node;
- struct ly_set node_when = {0}, node_exts = {0};
+ struct ly_set node_when = {0};
LY_CHECK_ARG_RET(NULL, tree, LY_EINVAL);
if (diff) {
@@ -2244,20 +2239,18 @@
/* skip added default nodes */
if (((node->flags & (LYD_DEFAULT | LYD_NEW)) != (LYD_DEFAULT | LYD_NEW)) &&
(node->schema->nodetype & LYD_NODE_INNER)) {
- LY_CHECK_GOTO(ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &node_when, &node_exts,
- NULL, implicit_options, diff), cleanup);
+ LY_CHECK_GOTO(ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &node_when, NULL,
+ implicit_options, diff), cleanup);
}
LYD_TREE_DFS_END(tree, node);
}
/* resolve when and remove any invalid defaults */
- LY_CHECK_GOTO(ret = lyd_validate_unres(&tree, NULL, &node_when, LYXP_IGNORE_WHEN, &node_exts, NULL, NULL, diff),
- cleanup);
+ LY_CHECK_GOTO(ret = lyd_validate_unres(&tree, NULL, &node_when, LYXP_IGNORE_WHEN, NULL, NULL, NULL, 0, diff), cleanup);
cleanup:
ly_set_erase(&node_when, NULL);
- ly_set_erase(&node_exts, NULL);
if (ret && diff) {
lyd_free_all(*diff);
*diff = NULL;
@@ -2311,7 +2304,7 @@
{
LY_ERR ret = LY_SUCCESS;
struct lyd_node *root, *d = NULL;
- struct ly_set node_when = {0}, node_exts = {0};
+ struct ly_set node_when = {0};
LY_CHECK_ARG_RET(NULL, tree, module, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, module ? module->ctx : NULL, LY_EINVAL);
@@ -2320,10 +2313,10 @@
}
/* add all top-level defaults for this module */
- LY_CHECK_GOTO(ret = lyd_new_implicit_r(NULL, tree, NULL, module, &node_when, &node_exts, NULL, implicit_options, diff), cleanup);
+ LY_CHECK_GOTO(ret = lyd_new_implicit_r(NULL, tree, NULL, module, &node_when, NULL, implicit_options, diff), cleanup);
/* resolve when and remove any invalid defaults */
- LY_CHECK_GOTO(ret = lyd_validate_unres(tree, module, &node_when, LYXP_IGNORE_WHEN, &node_exts, NULL, NULL, diff),
+ LY_CHECK_GOTO(ret = lyd_validate_unres(tree, module, &node_when, LYXP_IGNORE_WHEN, NULL, NULL, NULL, 0, diff),
cleanup);
/* process nested nodes */
@@ -2343,7 +2336,6 @@
cleanup:
ly_set_erase(&node_when, NULL);
- ly_set_erase(&node_exts, NULL);
if (ret && diff) {
lyd_free_all(*diff);
*diff = NULL;
@@ -2682,7 +2674,7 @@
LY_CHECK_RET(lyd_insert_check_schema(parent->schema, NULL, node->schema));
if (node->schema && (node->schema->flags & LYS_KEY)) {
- LOGERR(parent->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
+ LOGERR(LYD_CTX(parent), LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
return LY_EINVAL;
}
@@ -2700,6 +2692,28 @@
}
LIBYANG_API_DEF LY_ERR
+lyd_insert_ext(struct lyd_node *parent, struct lyd_node *first)
+{
+ struct lyd_node *iter;
+
+ LY_CHECK_ARG_RET(NULL, parent, first, !first->parent, !first->prev->next,
+ !parent->schema || (parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
+
+ if (first->schema && (first->schema->flags & LYS_KEY)) {
+ LOGERR(LYD_CTX(parent), LY_EINVAL, "Cannot insert key \"%s\".", first->schema->name);
+ return LY_EINVAL;
+ }
+
+ while (first) {
+ iter = first->next;
+ lyd_unlink_tree(first);
+ lyd_insert_node(parent, NULL, first, 0);
+ first = iter;
+ }
+ return LY_SUCCESS;
+}
+
+LIBYANG_API_DEF LY_ERR
lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, struct lyd_node **first)
{
struct lyd_node *iter;
@@ -2886,7 +2900,7 @@
LY_ERR
lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format,
- void *prefix_data, uint32_t hints, ly_bool clear_dflt, ly_bool *incomplete)
+ void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt, ly_bool *incomplete)
{
LY_ERR ret = LY_SUCCESS;
struct lysc_ext_instance *ant = NULL;
@@ -2896,7 +2910,7 @@
assert((parent || meta) && mod);
- LOG_LOCSET(parent ? parent->schema : NULL, parent, NULL, NULL);
+ LOG_LOCSET(ctx_node, parent, NULL, NULL);
LY_ARRAY_FOR(mod->compiled->exts, u) {
if ((mod->compiled->exts[u].def->plugin == lyplg_find(LYPLG_EXTENSION, LYEXT_PLUGIN_INTERNAL_ANNOTATION)) &&
@@ -2920,7 +2934,7 @@
mt->annotation = ant;
ant_type = ant->substmts[ANNOTATION_SUBSTMT_TYPE].storage;
ret = lyd_value_store(mod->ctx, &mt->value, *ant_type, value, value_len, dynamic, format, prefix_data, hints,
- parent ? parent->schema : NULL, incomplete);
+ ctx_node, incomplete);
LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
ret = lydict_insert(mod->ctx, name, name_len, &mt->name);
LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
@@ -2938,7 +2952,7 @@
}
cleanup:
- LOG_LOCBACK((parent && parent->schema) ? 1 : 0, parent ? 1 : 0, 0, 0);
+ LOG_LOCBACK(ctx_node ? 1 : 0, parent ? 1 : 0, 0, 0);
return ret;
}
@@ -3396,34 +3410,88 @@
}
/**
+ * @brief Find @p schema equivalent in @p trg_ctx.
+ *
+ * @param[in] schema Schema node to find.
+ * @param[in] trg_ctx Target context to search in.
+ * @param[in] parent Data parent of @p schema, if any.
+ * @param[out] trg_schema Found schema from @p trg_ctx to use.
+ * @return LY_RRR value.
+ */
+static LY_ERR
+lyd_dup_find_schema(const struct lysc_node *schema, const struct ly_ctx *trg_ctx, struct lyd_node *parent,
+ const struct lysc_node **trg_schema)
+{
+ const struct lysc_node *node = NULL, *sparent = NULL;
+ const struct lys_module *mod = NULL;
+ char *path;
+
+ if (!schema) {
+ /* opaque node */
+ *trg_schema = NULL;
+ return LY_SUCCESS;
+ }
+
+ if (parent && parent->schema) {
+ /* start from schema parent */
+ sparent = parent->schema;
+ } else {
+ /* start from module */
+ mod = ly_ctx_get_module_implemented(trg_ctx, schema->module->name);
+ if (!mod) {
+ LOGERR(trg_ctx, LY_ENOTFOUND, "Module \"%s\" not present/implemented in the target context.",
+ schema->module->name);
+ return LY_ENOTFOUND;
+ }
+ }
+
+ /* find the schema node */
+ while ((node = lys_getnext(node, sparent, mod ? mod->compiled : NULL, 0))) {
+ if (!strcmp(node->module->name, schema->module->name) && !strcmp(node->name, schema->name)) {
+ *trg_schema = node;
+ return LY_SUCCESS;
+ }
+ }
+
+ /* schema node not found */
+ path = lysc_path(schema, LYSC_PATH_LOG, NULL, 0);
+ LOGERR(trg_ctx, LY_ENOTFOUND, "Schema node \"%s\" not found in the target context.", path);
+ free(path);
+ return LY_ENOTFOUND;
+}
+
+/**
* @brief Duplicate a single node and connect it into @p parent (if present) or last of @p first siblings.
*
- * Ignores LYD_DUP_WITH_PARENTS and LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
+ * Ignores ::LYD_DUP_WITH_PARENTS and ::LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
*
- * @param[in] node Original node to duplicate
+ * @param[in] node Node to duplicate.
+ * @param[in] trg_ctx Target context for duplicated nodes.
* @param[in] parent Parent to insert into, NULL for top-level sibling.
* @param[in] insert_last Whether the duplicated node can be inserted as the last child of @p parent. Set for
* recursive duplication as an optimization.
* @param[in,out] first First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
* @param[in] options Bitmask of options flags, see @ref dupoptions.
- * @param[out] dup_p Pointer where the created duplicated node is placed (besides connecting it int @p parent / @p first sibling).
- * @return LY_ERR value
+ * @param[out] dup_p Pointer where the created duplicated node is placed (besides connecting it to @p parent / @p first).
+ * @return LY_ERR value.
*/
static LY_ERR
-lyd_dup_r(const struct lyd_node *node, struct lyd_node *parent, ly_bool insert_last, struct lyd_node **first,
- uint32_t options, struct lyd_node **dup_p)
+lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent, ly_bool insert_last,
+ struct lyd_node **first, uint32_t options, struct lyd_node **dup_p)
{
LY_ERR ret;
struct lyd_node *dup = NULL;
struct lyd_meta *meta;
struct lyd_attr *attr;
struct lyd_node_any *any;
+ const struct lysc_type *type;
+ const char *val_can;
LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
if (!node->schema) {
dup = calloc(1, sizeof(struct lyd_node_opaq));
- ((struct lyd_node_opaq *)dup)->ctx = LYD_CTX(node);
+ ((struct lyd_node_opaq *)dup)->ctx = trg_ctx;
} else {
switch (node->schema->nodetype) {
case LYS_RPC:
@@ -3442,19 +3510,23 @@
dup = calloc(1, sizeof(struct lyd_node_any));
break;
default:
- LOGINT(LYD_CTX(node));
+ LOGINT(trg_ctx);
ret = LY_EINT;
goto error;
}
}
- LY_CHECK_ERR_GOTO(!dup, LOGMEM(LYD_CTX(node)); ret = LY_EMEM, error);
+ LY_CHECK_ERR_GOTO(!dup, LOGMEM(trg_ctx); ret = LY_EMEM, error);
if (options & LYD_DUP_WITH_FLAGS) {
dup->flags = node->flags;
} else {
dup->flags = (node->flags & LYD_DEFAULT) | LYD_NEW;
}
- dup->schema = node->schema;
+ if (trg_ctx == LYD_CTX(node)) {
+ dup->schema = node->schema;
+ } else {
+ LY_CHECK_GOTO(ret = lyd_dup_find_schema(node->schema, trg_ctx, parent, &dup->schema), error);
+ }
dup->prev = dup;
/* duplicate metadata/attributes */
@@ -3479,17 +3551,17 @@
if (options & LYD_DUP_RECURSIVE) {
/* duplicate all the children */
LY_LIST_FOR(orig->child, child) {
- LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, 1, NULL, options, NULL), error);
+ LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, 1, NULL, options, NULL), error);
}
}
- LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->name.name, 0, &opaq->name.name), error);
- LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->name.prefix, 0, &opaq->name.prefix), error);
- LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->name.module_ns, 0, &opaq->name.module_ns), error);
- LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->value, 0, &opaq->value), error);
+ LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.name, 0, &opaq->name.name), error);
+ LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.prefix, 0, &opaq->name.prefix), error);
+ LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.module_ns, 0, &opaq->name.module_ns), error);
+ LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->value, 0, &opaq->value), error);
opaq->hints = orig->hints;
opaq->format = orig->format;
if (orig->val_prefix_data) {
- ret = ly_dup_prefix_data(LYD_CTX(node), opaq->format, orig->val_prefix_data, &opaq->val_prefix_data);
+ ret = ly_dup_prefix_data(trg_ctx, opaq->format, orig->val_prefix_data, &opaq->val_prefix_data);
LY_CHECK_GOTO(ret, error);
}
} else if (dup->schema->nodetype & LYD_NODE_TERM) {
@@ -3497,8 +3569,17 @@
struct lyd_node_term *orig = (struct lyd_node_term *)node;
term->hash = orig->hash;
- LY_CHECK_ERR_GOTO(orig->value.realtype->plugin->duplicate(LYD_CTX(node), &orig->value, &term->value),
- LOGERR(LYD_CTX(node), LY_EINT, "Value duplication failed."); ret = LY_EINT, error);
+ if (trg_ctx == LYD_CTX(node)) {
+ ret = orig->value.realtype->plugin->duplicate(trg_ctx, &orig->value, &term->value);
+ LY_CHECK_ERR_GOTO(ret, LOGERR(trg_ctx, ret, "Value duplication failed."), error);
+ } else {
+ /* store canonical value in the target context */
+ val_can = lyd_get_value(node);
+ type = ((struct lysc_node_leaf *)term->schema)->type;
+ ret = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), NULL, LY_VALUE_CANON, NULL,
+ LYD_HINT_DATA, term->schema, NULL);
+ LY_CHECK_GOTO(ret, error);
+ }
} else if (dup->schema->nodetype & LYD_NODE_INNER) {
struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
struct lyd_node *child;
@@ -3506,7 +3587,7 @@
if (options & LYD_DUP_RECURSIVE) {
/* duplicate all the children */
LY_LIST_FOR(orig->child, child) {
- LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, 1, NULL, options, NULL), error);
+ LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, 1, NULL, options, NULL), error);
}
} else if ((dup->schema->nodetype == LYS_LIST) && !(dup->schema->flags & LYS_KEYLESS)) {
/* always duplicate keys of a list */
@@ -3522,7 +3603,7 @@
* but there can be also some non-key nodes */
continue;
}
- LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, 1, NULL, options, NULL), error);
+ LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, 1, NULL, options, NULL), error);
child = child->next;
}
}
@@ -3550,6 +3631,7 @@
* @brief Get a parent node to connect duplicated subtree to.
*
* @param[in] node Node (subtree) to duplicate.
+ * @param[in] trg_ctx Target context for duplicated nodes.
* @param[in] parent Initial parent to connect to.
* @param[in] options Bitmask of options flags, see @ref dupoptions.
* @param[out] dup_parent First duplicated parent node, if any.
@@ -3557,8 +3639,8 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyd_dup_get_local_parent(const struct lyd_node *node, const struct lyd_node_inner *parent, uint32_t options,
- struct lyd_node **dup_parent, struct lyd_node_inner **local_parent)
+lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx *trg_ctx, const struct lyd_node_inner *parent,
+ uint32_t options, struct lyd_node **dup_parent, struct lyd_node_inner **local_parent)
{
const struct lyd_node_inner *orig_parent, *iter;
ly_bool repeat = 1;
@@ -3573,7 +3655,7 @@
repeat = 0;
} else {
iter = NULL;
- LY_CHECK_RET(lyd_dup_r((struct lyd_node *)orig_parent, NULL, 0, (struct lyd_node **)&iter, options,
+ LY_CHECK_RET(lyd_dup_r((struct lyd_node *)orig_parent, trg_ctx, NULL, 0, (struct lyd_node **)&iter, options,
(struct lyd_node **)&iter));
}
if (!*local_parent) {
@@ -3598,7 +3680,7 @@
if (repeat && parent) {
/* given parent and created parents chain actually do not interconnect */
- LOGERR(LYD_CTX(node), LY_EINVAL,
+ LOGERR(trg_ctx, LY_EINVAL,
"Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
return LY_EINVAL;
}
@@ -3607,8 +3689,8 @@
}
static LY_ERR
-lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, ly_bool nosiblings,
- struct lyd_node **dup)
+lyd_dup(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node_inner *parent, uint32_t options,
+ ly_bool nosiblings, struct lyd_node **dup)
{
LY_ERR rc;
const struct lyd_node *orig; /* original node to be duplicated */
@@ -3616,10 +3698,10 @@
struct lyd_node *top = NULL; /* the most higher created node */
struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
- LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
+ assert(node && trg_ctx && (!parent || (LYD_CTX(parent) == trg_ctx)));
if (options & LYD_DUP_WITH_PARENTS) {
- LY_CHECK_GOTO(rc = lyd_dup_get_local_parent(node, parent, options & (LYD_DUP_WITH_FLAGS | LYD_DUP_NO_META),
+ LY_CHECK_GOTO(rc = lyd_dup_get_local_parent(node, trg_ctx, parent, options & (LYD_DUP_WITH_FLAGS | LYD_DUP_NO_META),
&top, &local_parent), error);
} else {
local_parent = parent;
@@ -3630,16 +3712,17 @@
if (local_parent) {
/* the key must already exist in the parent */
rc = lyd_find_sibling_schema(local_parent->child, orig->schema, first ? NULL : &first);
- LY_CHECK_ERR_GOTO(rc, LOGINT(LYD_CTX(node)), error);
+ LY_CHECK_ERR_GOTO(rc, LOGINT(trg_ctx), error);
} else {
assert(!(options & LYD_DUP_WITH_PARENTS));
/* duplicating a single key, okay, I suppose... */
- rc = lyd_dup_r(orig, NULL, 0, &first, options, first ? NULL : &first);
+ rc = lyd_dup_r(orig, trg_ctx, NULL, 0, &first, options, first ? NULL : &first);
LY_CHECK_GOTO(rc, error);
}
} else {
/* if there is no local parent, it will be inserted into first */
- rc = lyd_dup_r(orig, local_parent ? &local_parent->node : NULL, 0, &first, options, first ? NULL : &first);
+ rc = lyd_dup_r(orig, trg_ctx, local_parent ? &local_parent->node : NULL, 0, &first, options,
+ first ? NULL : &first);
LY_CHECK_GOTO(rc, error);
}
if (nosiblings) {
@@ -3664,13 +3747,43 @@
LIBYANG_API_DEF LY_ERR
lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup)
{
- return lyd_dup(node, parent, options, 1, dup);
+ LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
+ if (node && parent && (LYD_CTX(node) != LYD_CTX(parent))) {
+ LOGERR(NULL, LY_EINVAL, "Different contexts used in node duplication.");
+ return LY_EINVAL;
+ }
+
+ return lyd_dup(node, LYD_CTX(node), parent, options, 1, dup);
+}
+
+LIBYANG_API_DEF LY_ERR
+lyd_dup_single_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node_inner *parent,
+ uint32_t options, struct lyd_node **dup)
+{
+ LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
+
+ return lyd_dup(node, trg_ctx, parent, options, 1, dup);
}
LIBYANG_API_DEF LY_ERR
lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup)
{
- return lyd_dup(node, parent, options, 0, dup);
+ LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
+ if (node && parent && (LYD_CTX(node) != LYD_CTX(parent))) {
+ LOGERR(NULL, LY_EINVAL, "Different contexts used in node duplication.");
+ return LY_EINVAL;
+ }
+
+ return lyd_dup(node, LYD_CTX(node), parent, options, 0, dup);
+}
+
+LIBYANG_API_DEF LY_ERR
+lyd_dup_siblings_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node_inner *parent,
+ uint32_t options, struct lyd_node **dup)
+{
+ LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
+
+ return lyd_dup(node, trg_ctx, parent, options, 0, dup);
}
LIBYANG_API_DEF LY_ERR
@@ -4461,24 +4574,24 @@
}
LIBYANG_API_DEF LY_ERR
-lyd_find_xpath3(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath,
- const struct lyxp_var *vars, struct ly_set **set)
+lyd_find_xpath4(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath, LY_VALUE_FORMAT format,
+ void *prefix_data, const struct lyxp_var *vars, struct ly_set **set)
{
LY_ERR ret = LY_SUCCESS;
struct lyxp_set xp_set = {0};
struct lyxp_expr *exp = NULL;
uint32_t i;
- LY_CHECK_ARG_RET(NULL, tree, xpath, set, LY_EINVAL);
+ LY_CHECK_ARG_RET(NULL, tree, xpath, format, set, LY_EINVAL);
*set = NULL;
- /* compile expression */
+ /* parse expression */
ret = lyxp_expr_parse((struct ly_ctx *)LYD_CTX(tree), xpath, 0, 1, &exp);
LY_CHECK_GOTO(ret, cleanup);
/* evaluate expression */
- ret = lyxp_eval(LYD_CTX(tree), exp, NULL, LY_VALUE_JSON, NULL, ctx_node, tree, vars, &xp_set, LYXP_IGNORE_WHEN);
+ ret = lyxp_eval(LYD_CTX(tree), exp, NULL, format, prefix_data, ctx_node, tree, vars, &xp_set, LYXP_IGNORE_WHEN);
LY_CHECK_GOTO(ret, cleanup);
/* allocate return set */
@@ -4511,11 +4624,20 @@
}
LIBYANG_API_DEF LY_ERR
+lyd_find_xpath3(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath,
+ const struct lyxp_var *vars, struct ly_set **set)
+{
+ LY_CHECK_ARG_RET(NULL, tree, xpath, set, LY_EINVAL);
+
+ return lyd_find_xpath4(ctx_node, tree, xpath, LY_VALUE_JSON, NULL, vars, set);
+}
+
+LIBYANG_API_DEF LY_ERR
lyd_find_xpath2(const struct lyd_node *ctx_node, const char *xpath, const struct lyxp_var *vars, struct ly_set **set)
{
LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
- return lyd_find_xpath3(ctx_node, ctx_node, xpath, vars, set);
+ return lyd_find_xpath4(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, vars, set);
}
LIBYANG_API_DEF LY_ERR
@@ -4523,7 +4645,7 @@
{
LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
- return lyd_find_xpath3(ctx_node, ctx_node, xpath, NULL, set);
+ return lyd_find_xpath4(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, NULL, set);
}
LIBYANG_API_DEF LY_ERR
diff --git a/src/tree_data.h b/src/tree_data.h
index 24b9458..65a9bda 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -680,6 +680,16 @@
};
/**
+ * @brief Special lyd_value structure for ietf-yang-types xpath1.0 values.
+ */
+struct lyd_value_xpath10 {
+ struct lyxp_expr *exp;
+ const struct ly_ctx *ctx;
+ void *prefix_data;
+ LY_VALUE_FORMAT format;
+};
+
+/**
* @brief Metadata structure.
*
* The structure provides information about metadata of a data element. Such attributes must map to
@@ -722,7 +732,7 @@
struct ly_opaq_name name; /**< attribute name with module information */
const char *value; /**< attribute value */
uint32_t hints; /**< additional information about from the data source, see the [hints list](@ref lydhints) */
- LY_VALUE_FORMAT format; /**< format of the attribute and any prefixes, ::LY_VALUE_XML or ::LY_VALUE_JSON */
+ LY_VALUE_FORMAT format; /**< format of the attribute and any prefixes, ::LY_VALUE_XML or ::LY_VALUE_JSON */
void *val_prefix_data; /**< format-specific prefix data */
};
@@ -753,9 +763,10 @@
*
*/
-#define LYD_DEFAULT 0x01 /**< default (implicit) node */
-#define LYD_WHEN_TRUE 0x02 /**< all when conditions of this node were evaluated to true */
-#define LYD_NEW 0x04 /**< node was created after the last validation, is needed for the next validation */
+#define LYD_DEFAULT 0x01 /**< default (implicit) node */
+#define LYD_WHEN_TRUE 0x02 /**< all when conditions of this node were evaluated to true */
+#define LYD_NEW 0x04 /**< node was created after the last validation, is needed for the next validation */
+#define LYD_EXT 0x08 /**< node is the first sibling parsed as extension instance data */
/** @} */
@@ -1908,32 +1919,63 @@
/** @} dupoptions */
/**
- * @brief Create a copy of the specified data tree \p node. Schema references are kept the same.
+ * @brief Create a copy of the specified data tree @p node. Schema references are kept the same.
*
* @param[in] node Data tree node to be duplicated.
- * @param[in] parent Optional parent node where to connect the duplicated node(s).
- * If set in combination with LYD_DUP_WITH_PARENTS, the parents chain is duplicated until it comes to and connects with
- * the @p parent.
+ * @param[in] parent Optional parent node where to connect the duplicated node(s). If set in combination with
+ * ::LYD_DUP_WITH_PARENTS, the missing parents' chain is duplicated and connected with @p parent.
* @param[in] options Bitmask of options flags, see @ref dupoptions.
* @param[out] dup Optional created copy of the node. Note that in case the parents chain is duplicated for the duplicated
- * node(s) (when LYD_DUP_WITH_PARENTS used), the first duplicated node is still returned.
+ * node(s) (when ::LYD_DUP_WITH_PARENTS used), the first duplicated node is still returned.
* @return LY_ERR value.
*/
-LIBYANG_API_DECL LY_ERR lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup);
+LIBYANG_API_DECL LY_ERR lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options,
+ struct lyd_node **dup);
/**
- * @brief Create a copy of the specified data tree \p node with any following siblings. Schema references are kept the same.
+ * @brief Create a copy of the specified data tree @p node. Schema references are assigned from @p trg_ctx.
*
* @param[in] node Data tree node to be duplicated.
- * @param[in] parent Optional parent node where to connect the duplicated node(s).
- * If set in combination with LYD_DUP_WITH_PARENTS, the parents chain is duplicated until it comes to and connects with
- * the @p parent.
+ * @param[in] trg_ctx Target context for duplicated nodes.
+ * @param[in] parent Optional parent node where to connect the duplicated node(s). If set in combination with
+ * ::LYD_DUP_WITH_PARENTS, the missing parents' chain is duplicated and connected with @p parent.
* @param[in] options Bitmask of options flags, see @ref dupoptions.
* @param[out] dup Optional created copy of the node. Note that in case the parents chain is duplicated for the duplicated
- * node(s) (when LYD_DUP_WITH_PARENTS used), the first duplicated node is still returned.
+ * node(s) (when ::LYD_DUP_WITH_PARENTS used), the first duplicated node is still returned.
* @return LY_ERR value.
*/
-LIBYANG_API_DECL LY_ERR lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup);
+LIBYANG_API_DECL LY_ERR lyd_dup_single_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx,
+ struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup);
+
+/**
+ * @brief Create a copy of the specified data tree @p node with any following siblings. Schema references are kept the same.
+ *
+ * @param[in] node Data tree node to be duplicated.
+ * @param[in] parent Optional parent node where to connect the duplicated node(s). If set in combination with
+ * ::LYD_DUP_WITH_PARENTS, the missing parents' chain is duplicated and connected with @p parent.
+ * @param[in] options Bitmask of options flags, see @ref dupoptions.
+ * @param[out] dup Optional created copy of the node. Note that in case the parents chain is duplicated for the duplicated
+ * node(s) (when ::LYD_DUP_WITH_PARENTS used), the first duplicated node is still returned.
+ * @return LY_ERR value.
+ */
+LIBYANG_API_DECL LY_ERR lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options,
+ struct lyd_node **dup);
+
+/**
+ * @brief Create a copy of the specified data tree @p node with any following siblings. Schema references are assigned
+ * from @p trg_ctx.
+ *
+ * @param[in] node Data tree node to be duplicated.
+ * @param[in] trg_ctx Target context for duplicated nodes.
+ * @param[in] parent Optional parent node where to connect the duplicated node(s). If set in combination with
+ * ::LYD_DUP_WITH_PARENTS, the missing parents' chain is duplicated and connected with @p parent.
+ * @param[in] options Bitmask of options flags, see @ref dupoptions.
+ * @param[out] dup Optional created copy of the node. Note that in case the parents chain is duplicated for the duplicated
+ * node(s) (when ::LYD_DUP_WITH_PARENTS used), the first duplicated node is still returned.
+ * @return LY_ERR value.
+ */
+LIBYANG_API_DECL LY_ERR lyd_dup_siblings_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx,
+ struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup);
/**
* @brief Create a copy of the metadata.
@@ -2265,7 +2307,8 @@
* @return Found metadata,
* @return NULL if not found.
*/
-LIBYANG_API_DECL struct lyd_meta *lyd_find_meta(const struct lyd_meta *first, const struct lys_module *module, const char *name);
+LIBYANG_API_DECL struct lyd_meta *lyd_find_meta(const struct lyd_meta *first, const struct lys_module *module,
+ const char *name);
/**
* @brief Search in the given siblings (NOT recursively) for the first target instance with the same value.
@@ -2278,7 +2321,8 @@
* @return LY_ENOTFOUND if not found, @p match set to NULL.
* @return LY_ERR value if another error occurred.
*/
-LIBYANG_API_DECL LY_ERR lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match);
+LIBYANG_API_DECL LY_ERR lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target,
+ struct lyd_node **match);
/**
* @brief Search in the given siblings for the first schema instance.
@@ -2304,8 +2348,8 @@
* @return LY_EINVAL if @p schema is a key-less list.
* @return LY_ERR value if another error occurred.
*/
-LIBYANG_API_DECL LY_ERR lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
- size_t val_len, struct lyd_node **match);
+LIBYANG_API_DECL LY_ERR lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema,
+ const char *key_or_value, size_t val_len, struct lyd_node **match);
/**
* @brief Search the given siblings for all the exact same instances of a specific node instance. Accepts only nodes
@@ -2318,7 +2362,8 @@
* @return LY_ENOTFOUND if not found, empty @p set returned.
* @return LY_ERR value if another error occurred.
*/
-LIBYANG_API_DECL LY_ERR lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set);
+LIBYANG_API_DECL LY_ERR lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_node *target,
+ struct ly_set **set);
/**
* @brief Search the given siblings for an opaque node with a specific name.
@@ -2361,7 +2406,7 @@
* (unless they are defined in top-level). Other predicates can still follow the aforementioned ones.
*
* @param[in] ctx_node XPath context node.
- * @param[in] xpath [XPath](@ref howtoXPath) to select.
+ * @param[in] xpath [XPath](@ref howtoXPath) to select in JSON format.
* @param[out] set Set of found data nodes. In case the result is a number, a string, or a boolean,
* the returned set is empty.
* @return LY_SUCCESS on success, @p set is returned.
@@ -2372,10 +2417,10 @@
/**
* @brief Search in the given data for instances of nodes matching the provided XPath.
*
- * It is just lyd_find_xpath() with @p vars added.
+ * It is just ::lyd_find_xpath() with @p vars added.
*
* @param[in] ctx_node XPath context node.
- * @param[in] xpath [XPath](@ref howtoXPath) to select.
+ * @param[in] xpath [XPath](@ref howtoXPath) to select in JSON format.
* @param[in] vars [Sized array](@ref sizedarrays) of XPath variables.
* @param[out] set Set of found data nodes. In case the result is a number, a string, or a boolean,
* the returned set is empty.
@@ -2388,11 +2433,11 @@
/**
* @brief Search in the given data for instances of nodes matching the provided XPath.
*
- * It is just lyd_find_xpath2() with @p tree added so that @p ctx_node may be the root.
+ * It is just ::lyd_find_xpath2() with @p tree added so that @p ctx_node may be the root.
*
* @param[in] ctx_node XPath context node, NULL for the root node.
* @param[in] tree Data tree to evaluate on.
- * @param[in] xpath [XPath](@ref howtoXPath) to select.
+ * @param[in] xpath [XPath](@ref howtoXPath) to select in JSON format.
* @param[in] vars [Sized array](@ref sizedarrays) of XPath variables.
* @param[out] set Set of found data nodes. In case the result is a number, a string, or a boolean,
* the returned set is empty.
@@ -2403,6 +2448,25 @@
const struct lyxp_var *vars, struct ly_set **set);
/**
+ * @brief Search in the given data for instances of nodes matching the provided XPath.
+ *
+ * It is just ::lyd_find_xpath3() with @p format and @p prefix_data added for special use-cases.
+ *
+ * @param[in] ctx_node XPath context node, NULL for the root node.
+ * @param[in] tree Data tree to evaluate on.
+ * @param[in] xpath [XPath](@ref howtoXPath) to select with prefix in @p format.
+ * @param[in] format Format of any prefixes in @p xpath.
+ * @param[in] prefix_data Format-specific prefix data.
+ * @param[in] vars [Sized array](@ref sizedarrays) of XPath variables.
+ * @param[out] set Set of found data nodes. In case the result is a number, a string, or a boolean,
+ * the returned set is empty.
+ * @return LY_SUCCESS on success, @p set is returned.
+ * @return LY_ERR value if an error occurred.
+ */
+LIBYANG_API_DECL LY_ERR lyd_find_xpath4(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath,
+ LY_VALUE_FORMAT format, void *prefix_data, const struct lyxp_var *vars, struct ly_set **set);
+
+/**
* @brief Evaluate an XPath on data and return the result converted to boolean.
*
* Optimizations similar as in ::lyd_find_xpath().
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index 84a6a7a..f1b453d 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -401,8 +401,7 @@
}
void
-lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct ly_set *node_exts, struct lyd_meta **meta,
- uint32_t parse_opts)
+lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct lyd_meta **meta, uint32_t parse_opts)
{
struct lyd_meta *meta2, *prev_meta = NULL;
@@ -412,7 +411,6 @@
LY_CHECK_RET(ly_set_add(node_when, node, 1, NULL), );
}
}
- LY_CHECK_RET(lysc_node_ext_tovalidate(node_exts, node), );
LY_LIST_FOR(*meta, meta2) {
if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
@@ -634,6 +632,7 @@
switch (format) {
case LY_VALUE_XML:
+ case LY_VALUE_STR_NS:
ns_list = prefix_data;
for (i = 0; i < ns_list->count; ++i) {
free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
@@ -689,6 +688,7 @@
}
break;
case LY_VALUE_XML:
+ case LY_VALUE_STR_NS:
/* copy all the namespaces */
LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
*prefix_data_p = ns_list;
@@ -775,15 +775,16 @@
}
break;
case LY_VALUE_XML:
+ case LY_VALUE_STR_NS:
/* copy all referenced namespaces as prefix - namespace pairs */
if (!*prefix_data_p) {
/* new prefix data */
LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
- *format_p = LY_VALUE_XML;
+ *format_p = format;
*prefix_data_p = ns_list;
} else {
/* reuse prefix data */
- assert(*format_p == LY_VALUE_XML);
+ assert(*format_p == format);
ns_list = *prefix_data_p;
}
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index f6d8694..90de1f8 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -129,12 +129,10 @@
*
* @param[in] node Node to use.
* @param[in,out] node_when Set of nodes with unresolved when.
- * @param[in,out] node_exts Set of nodes and their extension instances if they have own validation callback.
* @param[in,out] meta Node metadata, may be removed from.
* @param[in] parse_opts Parse options.
*/
-void lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct ly_set *node_exts,
- struct lyd_meta **meta, uint32_t parse_opts);
+void lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct lyd_meta **meta, uint32_t parse_opts);
/**
* @brief Get schema node of a data node. Useful especially for opaque nodes.
@@ -316,15 +314,14 @@
* @param[in] sparent Schema parent of the siblings, NULL if schema of @p parent can be used.
* @param[in] mod Module of the default values, NULL for nested siblings.
* @param[in] node_when Optional set to add nodes with "when" conditions into.
- * @param[in] node_exts Optional set to add nodes and extension instances having own validation plugin callback into it.
* @param[in] node_types Optional set to add nodes with unresolved types into.
* @param[in] impl_opts Implicit options (@ref implicitoptions).
* @param[in,out] diff Validation diff.
* @return LY_ERR value.
*/
LY_ERR lyd_new_implicit_r(struct lyd_node *parent, struct lyd_node **first, const struct lysc_node *sparent,
- const struct lys_module *mod, struct ly_set *node_when, struct ly_set *node_exts, struct ly_set *node_types,
- uint32_t impl_opts, struct lyd_node **diff);
+ const struct lys_module *mod, struct ly_set *node_when, struct ly_set *node_types, uint32_t impl_opts,
+ struct lyd_node **diff);
/**
* @brief Find the next node, before which to insert the new node.
@@ -369,6 +366,7 @@
* @param[in] format Input format of @p value.
* @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
* @param[in] hints [Value hints](@ref lydvalhints) from the parser regarding the value type.
+ * @param[in] ctx_node Value context node, may be NULL for metadata.
* @param[in] clear_dflt Whether to clear dflt flag starting from @p parent, recursively all NP containers.
* @param[out] incomplete Whether the value needs to be resolved.
* @return LY_SUCCESS on success.
@@ -377,7 +375,7 @@
*/
LY_ERR lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format,
- void *prefix_data, uint32_t hints, ly_bool clear_dflt, ly_bool *incomplete);
+ void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt, ly_bool *incomplete);
/**
* @brief Insert an attribute (last) into a parent
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 076fa37..0b92e67 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -471,6 +471,7 @@
}
}
}
+
return NULL;
}
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;
}
diff --git a/src/validation.h b/src/validation.h
index b8b1a98..abf7332 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -27,15 +27,6 @@
struct lysc_node;
/**
- * @brief Add information about the node's extensions having their own validation callback into an unres set.
- *
- * @param[in,out] node_exts Unres set for holding information for validating extension instances.
- * @param[in] node Data node to be examined.
- * @return LY_ERR values.
- */
-LY_ERR lysc_node_ext_tovalidate(struct ly_set *node_exts, struct lyd_node *node);
-
-/**
* @brief Add new changes into a diff. They are always merged.
*
* @param[in] node Node/subtree to add.
@@ -56,15 +47,16 @@
* the first top-level sibling.
* @param[in] node_when Set with nodes with "when" conditions, can be NULL.
* @param[in] when_xp_opts Additional XPath options to use for evaluating "when".
- * @param[in] node_exts Set with nodes with extension instances with validation plugin callback, can be NULL.
* @param[in] node_types Set with nodes with unresolved types, can be NULL
* @param[in] meta_types Set with metadata with unresolved types, can be NULL.
+ * @param[in] ext_val Set with extension data to validate, can be NULL.
+ * @param[in] val_opts Validation options, see @ref datavalidationoptions.
* @param[in,out] diff Validation diff.
* @return LY_ERR value.
*/
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);
+ uint32_t when_xp_opts, struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_val,
+ uint32_t val_opts, struct lyd_node **diff);
/**
* @brief Validate new siblings. Specifically, check duplicated instances, autodelete default values and cases.
@@ -89,14 +81,14 @@
* @param[in] val_opts Validation options, see @ref datavalidationoptions.
* @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_p Set with 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 unres extension data to validate, if NULL a local set is used.
* @param[out] diff Generated validation diff, not generated if NULL.
* @return LY_ERR value.
*/
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);
#endif /* LY_VALIDATION_H_ */
diff --git a/src/xml.c b/src/xml.c
index 49704d6..663d3e3 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -181,11 +181,6 @@
return LY_SUCCESS;
}
-/**
- * @brief Remove all the namespaces defined in the element recently closed (removed from the xmlctx->elements).
- *
- * @param[in] xmlctx XML context to work with.
- */
void
lyxml_ns_rm(struct lyxml_ctx *xmlctx)
{
diff --git a/src/xml.h b/src/xml.h
index edf9512..125271f 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -133,6 +133,13 @@
LY_ERR lyxml_ctx_peek(struct lyxml_ctx *xmlctx, enum LYXML_PARSER_STATUS *next);
/**
+ * @brief Remove all the namespaces defined in the element recently closed (removed from the xmlctx->elements).
+ *
+ * @param[in] xmlctx XML context to work with.
+ */
+void lyxml_ns_rm(struct lyxml_ctx *xmlctx);
+
+/**
* @brief Get a namespace record for the given prefix in the current context.
*
* @param[in] ns_set Set with namespaces from the XML context.
diff --git a/src/xpath.c b/src/xpath.c
index 8afebb3..64b9ef8 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -343,8 +343,8 @@
* @return LY_ERR
*/
static LY_ERR
-cast_string_recursive(const struct lyd_node *node, ly_bool fake_cont, enum lyxp_node_type root_type, uint16_t indent, char **str,
- uint16_t *used, uint16_t *size)
+cast_string_recursive(const struct lyd_node *node, ly_bool fake_cont, enum lyxp_node_type root_type, uint16_t indent,
+ char **str, uint16_t *used, uint16_t *size)
{
char *buf, *line, *ptr = NULL;
const char *value_str;
@@ -415,7 +415,8 @@
if (any->value_type == LYD_ANYDATA_LYB) {
/* try to parse it into a data tree */
- if (lyd_parse_data_mem((struct ly_ctx *)LYD_CTX(node), any->value.mem, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
+ if (lyd_parse_data_mem((struct ly_ctx *)LYD_CTX(node), any->value.mem, LYD_LYB,
+ LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
/* successfully parsed */
free(any->value.mem);
any->value.tree = tree;
@@ -1242,7 +1243,8 @@
}
LY_ERR
-lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, uint32_t *index_p)
+lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type,
+ uint32_t *index_p)
{
uint32_t index;
@@ -5368,6 +5370,7 @@
case LY_VALUE_CANON:
case LY_VALUE_JSON:
case LY_VALUE_LYB:
+ case LY_VALUE_STR_NS:
/* inherit parent (context node) module */
if (ctx_scnode) {
mod = ctx_scnode->module;
@@ -5481,6 +5484,7 @@
break;
case LY_VALUE_JSON:
case LY_VALUE_LYB:
+ case LY_VALUE_STR_NS:
/* inherit module of the context node, if any */
if (ctx_scnode) {
moveto_mod = ctx_scnode->module;
@@ -5591,7 +5595,7 @@
moveto_node_hash(struct lyxp_set *set, const struct lysc_node *scnode, const struct ly_path_predicate *predicates,
uint32_t options)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR ret = LY_SUCCESS, r;
uint32_t i;
const struct lyd_node *siblings;
struct lyxp_set result;
@@ -5644,10 +5648,11 @@
/* find the node using hashes */
if (inst) {
- lyd_find_sibling_first(siblings, inst, &sub);
+ r = lyd_find_sibling_first(siblings, inst, &sub);
} else {
- lyd_find_sibling_val(siblings, scnode, NULL, 0, &sub);
+ r = lyd_find_sibling_val(siblings, scnode, NULL, 0, &sub);
}
+ LY_CHECK_ERR_GOTO(r && (r != LY_ENOTFOUND), ret = r, cleanup);
/* when check */
if (!(options & LYXP_IGNORE_WHEN) && sub && lysc_has_when(sub->schema) && !(sub->flags & LYD_WHEN_TRUE)) {
@@ -8696,11 +8701,12 @@
const struct lyxp_var *vars, struct lyxp_set *set, uint32_t options)
{
uint16_t tok_idx = 0;
+ const struct lysc_node *snode;
LY_ERR rc;
LY_CHECK_ARG_RET(ctx, ctx, exp, set, LY_EINVAL);
if (!cur_mod && ((format == LY_VALUE_SCHEMA) || (format == LY_VALUE_SCHEMA_RESOLVED))) {
- LOGARG(NULL, "Current module must be set if schema format is used.");
+ LOGERR(ctx, LY_EINVAL, "Current module must be set if schema format is used.");
return LY_EINVAL;
}
@@ -8710,6 +8716,14 @@
tree = lyd_parent(tree);
}
tree = lyd_first_sibling(tree);
+
+ for (snode = tree->schema->parent; snode && (snode->nodetype & (LYS_CASE | LYS_CHOICE)); snode = snode->parent) {}
+ if (snode) {
+ /* unable to evaluate absolute paths */
+ LOGERR(ctx, LY_EINVAL, "Data node \"%s\" has no parent but is not instance of a top-level schema node.",
+ LYD_NAME(tree));
+ return LY_EINVAL;
+ }
}
/* prepare set for evaluation */
diff --git a/tests/modules/yang/sm.yang b/tests/modules/yang/sm.yang
new file mode 100644
index 0000000..00e9595
--- /dev/null
+++ b/tests/modules/yang/sm.yang
@@ -0,0 +1,41 @@
+module sm {
+ yang-version 1.1;
+ namespace "urn:sm";
+ prefix "sm";
+
+ import ietf-yang-schema-mount {
+ prefix yangmnt;
+ }
+ import ietf-interfaces {
+ prefix if;
+ }
+
+ container root {
+ yangmnt:mount-point "root";
+ }
+ container root2 {
+ yangmnt:mount-point "root";
+ }
+ container root3 {
+ list ls {
+ key name;
+ leaf name {
+ type string;
+ }
+ container mnt-root {
+ yangmnt:mount-point "mnt-root";
+ }
+ }
+ }
+ leaf target {
+ type string;
+ }
+
+ augment /if:interfaces/if:interface {
+ leaf sm-name {
+ type leafref {
+ path "/sm:target";
+ }
+ }
+ }
+}
diff --git a/tests/plugins/CMakeLists.txt b/tests/plugins/CMakeLists.txt
index 6435585..1e21824 100644
--- a/tests/plugins/CMakeLists.txt
+++ b/tests/plugins/CMakeLists.txt
@@ -17,4 +17,3 @@
ly_add_plugin(NAME invalid SOURCES invalid.c)
ly_add_plugin(NAME simple SOURCES simple.c)
-ly_add_plugin(NAME validate SOURCES validate.c)
diff --git a/tests/plugins/simple.c b/tests/plugins/simple.c
index 9129003..ead70b0 100644
--- a/tests/plugins/simple.c
+++ b/tests/plugins/simple.c
@@ -52,7 +52,6 @@
.plugin.id = "libyang 2 - simple test, version 1",
.plugin.compile = &hint_compile,
- .plugin.validate = NULL,
.plugin.sprinter = NULL,
.plugin.free = NULL
},
diff --git a/tests/plugins/validate.c b/tests/plugins/validate.c
deleted file mode 100644
index 0580d3c..0000000
--- a/tests/plugins/validate.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * @file validate.c
- * @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief Simple testing plugins implementation
- *
- * 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
- */
-
-#include <stdlib.h>
-
-#include "libyang.h"
-#include "plugins_exts.h"
-
-/**
- * @brief Compile NAMC's extension instances.
- *
- * Implementation of ::lyplg_ext_compile_clb callback set as ::lyext_plugin.compile.
- */
-static LY_ERR
-compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
-{
- /* check that the extension is instantiated at an allowed place - data node */
- if (!LY_STMT_IS_DATA_NODE(c_ext->parent_stmt) && (c_ext->parent_stmt != LY_STMT_TYPE)) {
- lyplg_ext_log(c_ext, LY_LLWRN, 0, lysc_ctx_get_path(cctx),
- "Extension %s is allowed only in a data nodes, but it is placed in \"%s\" statement.",
- p_ext->name, ly_stmt2str(c_ext->parent_stmt));
- return LY_ENOT;
- }
-
- return LY_SUCCESS;
-}
-
-/**
- * @brief Compile NAMC's extension instances.
- *
- * Implementation of ::lyplg_ext_data_validation_clb callback set as ::lyext_plugin.validate.
- */
-static LY_ERR
-validate(struct lysc_ext_instance *ext, struct lyd_node *node)
-{
- lyplg_ext_log(ext, LY_LLWRN, LY_SUCCESS, NULL, "extra validation callback invoked on %s", node->schema->name);
- return LY_SUCCESS;
-}
-
-/**
- * @brief Plugin descriptions for the test extensions
- */
-LYPLG_EXTENSIONS = {
- {
- .module = "libyang-plugins-validate",
- .revision = NULL,
- .name = "extra-validation",
-
- .plugin.id = "libyang 2 - validation test, version 1",
- .plugin.compile = &compile,
- .plugin.validate = &validate,
- .plugin.sprinter = NULL,
- .plugin.free = NULL
- },
- {0} /* terminating zeroed item */
-};
diff --git a/tests/utests/basic/test_context.c b/tests/utests/basic/test_context.c
index 7899079..8b79a1c 100644
--- a/tests/utests/basic/test_context.c
+++ b/tests/utests/basic/test_context.c
@@ -440,7 +440,10 @@
struct lys_glob_unres unres = {0};
unsigned int index = 0;
- const char *names[] = {"ietf-yang-metadata", "yang", "ietf-inet-types", "ietf-yang-types", "ietf-datastores", "ietf-yang-library", "a", "a", "a"};
+ const char *names[] = {
+ "ietf-yang-metadata", "yang", "ietf-inet-types", "ietf-yang-types", "ietf-yang-schema-mount",
+ "ietf-datastores", "ietf-yang-library", "a", "a", "a"
+ };
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str0, &in0));
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str1, &in1));
@@ -507,7 +510,7 @@
while ((mod = (struct lys_module *)ly_ctx_get_module_iter(UTEST_LYCTX, &index))) {
assert_string_equal(names[index - 1], mod->name);
}
- assert_int_equal(9, index);
+ assert_int_equal(10, index);
/* cleanup */
ly_in_free(in0, 0);
diff --git a/tests/utests/basic/test_plugins.c b/tests/utests/basic/test_plugins.c
index 95b190f..dd50347 100644
--- a/tests/utests/basic/test_plugins.c
+++ b/tests/utests/basic/test_plugins.c
@@ -68,61 +68,6 @@
}
static void
-test_validation(void **state)
-{
- struct lys_module *mod;
- struct lyd_node *tree;
- const char *data;
- const char *schema = "module libyang-plugins-validate {"
- " namespace urn:libyang:tests:plugins:validate;"
- " prefix v;"
- " extension extra-validation;"
- " typedef note { type string { v:extra-validation;}}"
- " leaf test1 {"
- " type v:note;"
- " }"
- " leaf test2 {"
- " type string;"
- " v:extra-validation;"
- " }"
- " leaf test3 {"
- " type string {v:extra-validation;}"
- " }"
- " leaf test4 {"
- " type string;"
- " }"
- "}";
-
- assert_int_equal(LY_SUCCESS, lyplg_add(TESTS_BIN "/plugins/plugin_validate" LYPLG_SUFFIX));
-
- UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
-
- /* test1 - extra-validation done based on typedef's extension */
- data = "<test1 xmlns=\"urn:libyang:tests:plugins:validate\">xxx</test1>";
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
- CHECK_LOG_CTX("Extension plugin \"libyang 2 - validation test, version 1\": extra validation callback invoked on test1", NULL);
- lyd_free_all(tree);
-
- /* test2 - extra-validation done based on node's extension */
- data = "<test2 xmlns=\"urn:libyang:tests:plugins:validate\">xxx</test2>";
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
- CHECK_LOG_CTX("Extension plugin \"libyang 2 - validation test, version 1\": extra validation callback invoked on test2", NULL);
- lyd_free_all(tree);
-
- /* test3 - extra-validation done based on node type's extension */
- data = "<test3 xmlns=\"urn:libyang:tests:plugins:validate\">xxx</test3>";
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
- CHECK_LOG_CTX("Extension plugin \"libyang 2 - validation test, version 1\": extra validation callback invoked on test3", NULL);
- lyd_free_all(tree);
-
- /* test4 - extra-validation not done */
- data = "<test4 xmlns=\"urn:libyang:tests:plugins:validate\">xxx</test4>";
- assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
- CHECK_LOG_CTX(NULL, NULL);
- lyd_free_all(tree);
-}
-
-static void
test_not_implemented(void **state)
{
struct lys_module *mod;
@@ -157,7 +102,6 @@
const struct CMUnitTest tests[] = {
UTEST(test_add_invalid),
UTEST(test_add_simple),
- UTEST(test_validation),
UTEST(test_not_implemented),
};
diff --git a/tests/utests/basic/test_xml.c b/tests/utests/basic/test_xml.c
index 1999f65..7e8132d 100644
--- a/tests/utests/basic/test_xml.c
+++ b/tests/utests/basic/test_xml.c
@@ -23,7 +23,6 @@
#include "xml.h"
LY_ERR lyxml_ns_add(struct lyxml_ctx *xmlctx, const char *prefix, size_t prefix_len, char *uri);
-LY_ERR lyxml_ns_rm(struct lyxml_ctx *xmlctx);
static void
test_element(void **state)
diff --git a/tests/utests/extensions/test_schema_mount.c b/tests/utests/extensions/test_schema_mount.c
index 5209dd1..4e3b650 100644
--- a/tests/utests/extensions/test_schema_mount.c
+++ b/tests/utests/extensions/test_schema_mount.c
@@ -1,9 +1,10 @@
-/*
+/**
* @file test_schema_mount.c
- * @author: Tadeas Vintrlik <xvintr04@stud.fit.vutbr.cz>
+ * @author Tadeas Vintrlik <xvintr04@stud.fit.vutbr.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
* @brief unit tests for Schema Mount extension support
*
- * Copyright (c) 2021 CESNET, z.s.p.o.
+ * Copyright (c) 2021 - 2022 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.
@@ -11,47 +12,1043 @@
*
* https://opensource.org/licenses/BSD-3-Clause
*/
+
#define _UTEST_MAIN_
#include "utests.h"
#include "libyang.h"
+void **glob_state;
+
static int
setup(void **state)
{
+ const char *schema =
+ "module sm {yang-version 1.1;namespace \"urn:sm\";prefix \"sm\";"
+ "import ietf-yang-schema-mount {prefix yangmnt;}"
+ "import ietf-interfaces {prefix if;}"
+ "container root {yangmnt:mount-point \"root\";}"
+ "container root2 {yangmnt:mount-point \"root\";}"
+ "container root3 {"
+ " list ls { key name; leaf name {type string;}"
+ " container mnt-root {yangmnt:mount-point \"mnt-root\";}"
+ " }"
+ "}"
+ "leaf target{type string;}"
+ "augment /if:interfaces/if:interface {"
+ " leaf sm-name {type leafref {path \"/sm:target\";}}"
+ "}"
+ "}";
+
UTEST_SETUP;
+ glob_state = state;
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
- assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-yang-schema-mount", "2019-01-14", NULL));
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "iana-if-type", NULL, NULL));
return 0;
}
static void
-test_compile(void **state)
+test_schema(void **state)
{
struct lys_module *mod;
- const char *data = "module test-parent {yang-version 1.1;namespace \"urn:test-parent\";"
- "prefix \"tp\"; import ietf-yang-schema-mount {prefix yangmnt;} container root {"
- "yangmnt:mount-point \"root\" {}}}";
+ const char *schema;
+ char *str;
- assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
+ /* invalid */
+ schema =
+ "module sm {\n"
+ " namespace \"urn:sm\";\n"
+ " prefix sm;\n"
+ "\n"
+ " import ietf-yang-schema-mount {\n"
+ " prefix yangmnt;\n"
+ " }\n"
+ "\n"
+ " container root {\n"
+ " yangmnt:mount-point \"root\";\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - Schema Mount, version 1\": "
+ "Extension \"yangmnt:mount-point\" instance not allowed in YANG version 1 module.",
+ "/sm:root/{extension='yangmnt:mount-point'}/root");
+
+ schema =
+ "module sm {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:sm\";\n"
+ " prefix sm;\n"
+ "\n"
+ " import ietf-yang-schema-mount {\n"
+ " prefix yangmnt;\n"
+ " }\n"
+ "\n"
+ " yangmnt:mount-point \"root\";\n"
+ "}\n";
+ assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - Schema Mount, version 1\": "
+ "Extension \"yangmnt:mount-point\" instance allowed only in container or list statement.",
+ "/sm:{extension='yangmnt:mount-point'}/root");
+
+ schema =
+ "module sm {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:sm\";\n"
+ " prefix sm;\n"
+ "\n"
+ " import ietf-yang-schema-mount {\n"
+ " prefix yangmnt;\n"
+ " }\n"
+ "\n"
+ " container root {\n"
+ " leaf l {\n"
+ " type empty;\n"
+ " yangmnt:mount-point \"root\";\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - Schema Mount, version 1\": "
+ "Extension \"yangmnt:mount-point\" instance allowed only in container or list statement.",
+ "/sm:root/l/{extension='yangmnt:mount-point'}/root");
+
+ schema =
+ "module sm {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:sm\";\n"
+ " prefix sm;\n"
+ "\n"
+ " import ietf-yang-schema-mount {\n"
+ " prefix yangmnt;\n"
+ " }\n"
+ "\n"
+ " list l {\n"
+ " key \"k\";\n"
+ " leaf k {\n"
+ " type string;\n"
+ " }\n"
+ " yangmnt:mount-point \"root\";\n"
+ " yangmnt:mount-point \"root2\";\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - Schema Mount, version 1\": "
+ "Multiple extension \"yangmnt:mount-point\" instances.",
+ "/sm:l/{extension='yangmnt:mount-point'}/root2");
+
+ /* valid */
+ schema =
+ "module sm {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:sm\";\n"
+ " prefix sm;\n"
+ "\n"
+ " import ietf-yang-schema-mount {\n"
+ " prefix yangmnt;\n"
+ " }\n"
+ "\n"
+ " container root {\n"
+ " yangmnt:mount-point \"root\";\n"
+ " }\n"
+ "}\n";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ lys_print_mem(&str, mod, LYS_YIN, 0);
+ assert_string_equal(str, schema);
+ free(str);
+}
+
+static LY_ERR
+test_ext_data_clb(const struct lysc_ext_instance *ext, void *user_data, void **ext_data, ly_bool *ext_data_free)
+{
+ void **state = glob_state;
+ struct lyd_node *data = NULL;
+
+ (void)ext;
+
+ if (user_data) {
+ CHECK_PARSE_LYD_PARAM(user_data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ }
+
+ *ext_data = data;
+ *ext_data_free = 1;
+ return LY_SUCCESS;
}
static void
-test_parse_no_yanglib(void **state)
+test_parse_xml_invalid(void **state)
{
- struct ly_ctx *new;
- const char *data = "<root/>";
+ const char *xml;
+ struct lyd_node *data;
- assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &new));
+ /* no callback set */
+ xml =
+ "<root xmlns=\"urn:sm\">"
+ " <unknown xmlns=\"unknown\">"
+ " <interface>"
+ " <name>bu</name>"
+ " <type xmlns:ii=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ii:ethernetCsmacd</type>"
+ " </interface>"
+ " </unknown>"
+ "</root>";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EINVAL, data);
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - Schema Mount, version 1\": Failed to get extension data, no callback set.",
+ NULL);
+
+ /* unknown data */
+ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb, NULL);
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ assert_string_equal(LYD_NAME(data), "root");
+ assert_null(lyd_child(data));
+ assert_non_null(data->next);
+ assert_true(data->next->flags & LYD_DEFAULT);
+ lyd_free_siblings(data);
+
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("No module with namespace \"unknown\" in the context.",
+ "Schema location /sm:root, data location /sm:root, line number 1.");
+
+ /* missing required callback data */
+ xml =
+ "<root xmlns=\"urn:sm\">"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">"
+ " <interface>"
+ " <name>bu</name>"
+ " </interface>"
+ " </interfaces>"
+ "</root>";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Node \"interfaces\" not found as a child of \"root\" node.",
+ "Schema location /sm:root, data location /sm:root, line number 1.");
+
+ 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-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </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>");
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Node \"interfaces\" not found as a child of \"root\" node.", NULL);
+
+ /* missing module in yang-library data */
+ 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-yang-library</name>"
+ " <revision>2019-01-04</revision>"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
+ " </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>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Node \"interfaces\" not found as a child of \"root\" node.", NULL);
+
+ /* callback data correct, invalid YANG data */
+ 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>"
+ " <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>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - Schema Mount, version 1\": "
+ "Mandatory node \"type\" instance does not exist.",
+ "Schema location /ietf-interfaces:interfaces/interface/type.");
+
+ /* validation fail */
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, LY_SUCCESS, data);
+ assert_int_equal(LY_EVALID, lyd_validate_all(&data, NULL, LYD_VALIDATE_PRESENT, NULL));
+ lyd_free_siblings(data);
+
+ /* success */
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ "</root>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+}
+
+static void
+test_parse_xml_inline(void **state)
+{
+ const char *xml;
+ struct lyd_node *data;
+
+ 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>"
+ " <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>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <oper-status>not-present</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2022-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+
+ /* different yang-lib data */
+ 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>ietf-ip</name>"
+ " <revision>2014-06-16</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>"
+ " <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>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+}
+
+static void
+test_parse_xml_shared(void **state)
+{
+ const char *xml;
+ struct lyd_node *data;
+
+ 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>"
+ " <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>");
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <oper-status>not-present</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2022-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+
+ /* different yang-lib data */
+ 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>ietf-ip</name>"
+ " <revision>2014-06-16</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>"
+ " <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>2</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>");
+ xml =
+ "<root2 xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <oper-status>not-present</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2022-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root2>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - Schema Mount, version 1\": "
+ "Shared-schema yang-library content-id \"2\" differs from \"1\" used previously.",
+ "/ietf-yang-library:yang-library/content-id");
+
+ /* data for 2 mount points */
+ 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>"
+ " <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>");
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <oper-status>not-present</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2022-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root>\n"
+ "<root2 xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>fu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:fddi</type>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>fu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:fddi</type>\n"
+ " <oper-status>down</oper-status>\n"
+ " <statistics>\n"
+ " <discontinuity-time>2020-01-01T10:00:00-00:00</discontinuity-time>\n"
+ " </statistics>\n"
+ " </interface>\n"
+ " </interfaces-state>\n"
+ "</root2>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+}
+
+static void
+test_parse_xml_shared_parent_ref(void **state)
+{
+ const char *xml;
+ struct lyd_node *data;
+
+ /* wrong leafref value */
+ 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>sm</name>"
+ " <namespace>urn:sm</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>"
+ " <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\">"
+ " <namespace>"
+ " <prefix>smp</prefix>"
+ " <uri>urn:sm</uri>"
+ " </namespace>"
+ " <mount-point>"
+ " <module>sm</module>"
+ " <label>mnt-root</label>"
+ " <shared-schema>"
+ " <parent-reference>/smp:target[. = current()/../smp:name]</parent-reference>"
+ " </shared-schema>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root3 xmlns=\"urn:sm\">\n"
+ " <ls>\n"
+ " <name>target-value</name>\n"
+ " <mnt-root>\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <sm-name xmlns=\"urn:sm\">target-value</sm-name>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " </mnt-root>\n"
+ " </ls>\n"
+ "</root3>\n"
+ "<target xmlns=\"urn:sm\">wrong-target-value</target>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - Schema Mount, version 1\": "
+ "Invalid leafref value \"target-value\" - no existing target instance \"/sm:target\".",
+ "Schema location /ietf-interfaces:interfaces/interface/sm:sm-name, "
+ "data location /ietf-interfaces:interfaces/interface[name='bu']/sm:sm-name.");
+
+ /* success */
+ xml =
+ "<root3 xmlns=\"urn:sm\">\n"
+ " <ls>\n"
+ " <name>target-value</name>\n"
+ " <mnt-root>\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <sm-name xmlns=\"urn:sm\">target-value</sm-name>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ " </mnt-root>\n"
+ " </ls>\n"
+ "</root3>\n"
+ "<target xmlns=\"urn:sm\">target-value</target>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ lyd_free_siblings(data);
+}
+
+static void
+test_parse_xml_config(void **state)
+{
+ const char *xml;
+ struct lyd_node *data;
+ const struct lyd_node *node;
+
+ 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>"
+ " <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>"
+ " <config>false</config>"
+ " <inline/>"
+ " </mount-point>"
+ "</schema-mounts>");
+ xml =
+ "<root xmlns=\"urn:sm\">\n"
+ " <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>bu</name>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <enabled>true</enabled>\n"
+ " </interface>\n"
+ " </interfaces>\n"
+ "</root>\n";
+ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, data);
+ CHECK_LYD_STRING_PARAM(data, xml, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+
+ node = lyd_child(data);
+ assert_string_equal(LYD_NAME(node), "interfaces");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child(node);
+ assert_string_equal(LYD_NAME(node), "interface");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = lyd_child(node);
+ assert_string_equal(LYD_NAME(node), "name");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+ node = node->next;
+ assert_string_equal(LYD_NAME(node), "type");
+ assert_true(node->schema->flags & LYS_CONFIG_R);
+
+ lyd_free_siblings(data);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
- UTEST(test_compile, setup),
+ UTEST(test_schema),
+ UTEST(test_parse_xml_invalid, setup),
+ UTEST(test_parse_xml_inline, setup),
+ UTEST(test_parse_xml_shared, setup),
+ UTEST(test_parse_xml_shared_parent_ref, setup),
+ UTEST(test_parse_xml_config, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/utests/utests.h b/tests/utests/utests.h
index 46b3d04..7e85a66 100644
--- a/tests/utests/utests.h
+++ b/tests/utests/utests.h
@@ -126,16 +126,25 @@
* @param[in] INPUT_FORMAT Format of the input data to be parsed. Can be 0 to try to detect format from the input handler.
* @param[in] PARSE_OPTIONS Options for parser, see @ref dataparseroptions.
* @param[in] VALIDATE_OPTIONS Options for the validation phase, see @ref datavalidationoptions.
- * @param[in] OUT_STATUS expected return status
- * @param[out] OUT_NODE Resulting data tree built from the input data. Note that NULL can be a valid result as a representation of an empty YANG data tree.
- * The returned data are expected to be freed using LYD_TREE_DESTROY().
+ * @param[in] RET expected return status
+ * @param[out] OUT_NODE Resulting data tree built from the input data. Note that NULL can be a valid result as a
+ * representation of an empty YANG data tree.
*/
-#define CHECK_PARSE_LYD_PARAM(INPUT, INPUT_FORMAT, PARSE_OPTIONS, VALIDATE_OPTIONS, OUT_STATUS, OUT_NODE) \
- assert_int_equal(OUT_STATUS, lyd_parse_data_mem(_UC->ctx, INPUT, INPUT_FORMAT, PARSE_OPTIONS, VALIDATE_OPTIONS, &OUT_NODE)); \
- if (OUT_STATUS == LY_SUCCESS) { \
- assert_non_null(OUT_NODE); \
- } else { \
- assert_null(OUT_NODE); \
+#define CHECK_PARSE_LYD_PARAM(INPUT, INPUT_FORMAT, PARSE_OPTIONS, VALIDATE_OPTIONS, RET, OUT_NODE) \
+ { \
+ LY_ERR _r = lyd_parse_data_mem(_UC->ctx, INPUT, INPUT_FORMAT, PARSE_OPTIONS, VALIDATE_OPTIONS, &OUT_NODE); \
+ if (_r != RET) { \
+ if (_r) { \
+ fail_msg("%s != 0x%d; MSG: %s", #RET, _r, ly_err_last(_UC->ctx)->msg); \
+ } else { \
+ fail_msg("%s != 0x%d", #RET, _r); \
+ } \
+ } \
+ if (RET == LY_SUCCESS) { \
+ assert_non_null(OUT_NODE); \
+ } else { \
+ assert_null(OUT_NODE); \
+ } \
}
/**
@@ -147,10 +156,13 @@
*/
#define CHECK_LYD_STRING_PARAM(NODE, TEXT, FORMAT, PARAM) \
{ \
- char *test; \
- lyd_print_mem(&test, NODE, FORMAT, PARAM); \
- assert_string_equal(test, TEXT); \
- free(test); \
+ char *str; \
+ LY_ERR _r = lyd_print_mem(&str, NODE, FORMAT, PARAM); \
+ if (_r) { \
+ fail_msg("Print err 0x%d; MSG: %s", _r, ly_err_last(_UC->ctx)->msg); \
+ } \
+ assert_string_equal(str, TEXT); \
+ free(str); \
}
/**
@@ -160,15 +172,15 @@
*/
#define CHECK_LYD(NODE_1, NODE_2) \
{ \
- char *test_1; \
- char *test_2; \
- assert_int_equal(LY_SUCCESS, lyd_print_mem(&test_1, NODE_1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK)); \
- assert_int_equal(LY_SUCCESS, lyd_print_mem(&test_2, NODE_2, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK)); \
- assert_non_null(test_1); \
- assert_non_null(test_2); \
- assert_string_equal(test_1, test_2); \
- free(test_1); \
- free(test_2); \
+ char *str1; \
+ char *str2; \
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&str1, NODE_1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK)); \
+ assert_int_equal(LY_SUCCESS, lyd_print_mem(&str2, NODE_2, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK)); \
+ assert_non_null(str1); \
+ assert_non_null(str2); \
+ assert_string_equal(str1, str2); \
+ free(str1); \
+ free(str2); \
}
/*
@@ -215,6 +227,7 @@
/**
* @brief check compileted type
+ *
* @param[in] NODE pointer to lysc_type value
* @param[in] TYPE expected type [LY_DATA_TYPE](@ref LY_DATA_TYPE)
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of extens list
@@ -225,7 +238,9 @@
CHECK_ARRAY((NODE)->exts, EXTS); \
assert_ptr_equal((NODE)->plugin, lyplg_find(LYPLG_TYPE, "", NULL, ly_data_type2str[TYPE]))
-/* @brief check compileted numeric type
+/**
+ * @brief check compileted numeric type
+ *
* @param[in] NODE pointer to lysc_type_num value
* @param[in] TYPE expected type [LY_DATA_TYPE](@ref LY_DATA_TYPE)
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of extens list
@@ -235,7 +250,9 @@
CHECK_LYSC_TYPE(NODE, TYPE, EXTS);\
CHECK_POINTER((NODE)->range, RANGE)
-/* @brief check compiled string type
+/**
+ * @brief check compiled string type
+ *
* @param[in] NODE pointer to lysc_type_num value
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of extens list
* @param[in] LENGTH 0 -> node dosnt have length limitation, 1 -> node have length limitation
@@ -247,7 +264,9 @@
CHECK_POINTER((NODE)->length, LENGTH); \
CHECK_ARRAY((NODE)->patterns, PATTERNS)
-/* @brief check compiled bits type
+/**
+ * @brief check compiled bits type
+ *
* @param[in] NODE pointer to lysc_type_num value
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of extens list
* @param[in] BITS expected number of bits
@@ -266,7 +285,9 @@
CHECK_STRING((NODE)->name, NAME); \
CHECK_STRING((NODE)->ref, REF) \
-/* @brief check range
+/**
+ * @brief check range
+ *
* @param[in] NODE pointer to lysc_range value
* @param[in] DSC expected descriptin (string)
* @param[in] EAPPTAG expected string reprezenting error-app-tag value
@@ -284,7 +305,9 @@
CHECK_ARRAY((NODE)->parts, PARTS); \
CHECK_STRING((NODE)->ref, REF)
-/* @brief check pattern
+/**
+ * @brief check pattern
+ *
* @param[in] NODE pointer to lysc_pattern value
* @param[in] DSC expected descriptin (string)
* @param[in] EAPPTAG expected string reprezenting error-app-tag value
@@ -307,6 +330,7 @@
/**
* @brief assert that lysp_action_inout structure members are correct
+ *
* @param[in] NODE pointer to lysp_action_inout variable
* @param[in] DATA 0 -> check if pointer to data is NULL, 1 -> check if pointer to data is not null
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of extens list
@@ -328,6 +352,7 @@
/**
* @brief assert that lysp_action structure members are correct
+ *
* @param[in] NODE pointer to lysp_action variable
* @param[in] DSC expected description
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of extension list
@@ -367,6 +392,7 @@
/**
* @brief assert that lysp_when structure members are correct
+ *
* @param[in] NODE pointer to lysp_when variable
* @param[in] COND expected string specifid condition
* @param[in] DSC expected string description statement
@@ -387,6 +413,7 @@
/**
* @brief assert that lysp_restr structure members are correct
+ *
* @param[in] NODE pointer to lysp_restr variable
* @param[in] ARG_STR expected string. The restriction expression/value
* @param[in] DSC expected descrition
@@ -408,6 +435,7 @@
/**
* @brief assert that lysp_import structure members are correct
+ *
* @param[in] NODE pointer to lysp_import variable
* @param[in] DSC expected description or NULL
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of list of extensions
@@ -428,6 +456,7 @@
/**
* @brief assert that lysp_ext structure members are correct
+ *
* @param[in] NODE pointer to lysp_ext_instance variable
* @param[in] ARGNAME expected argument name
* @param[in] COMPILED 0 -> compiled data dosnt exists, 1 -> compiled data exists
@@ -449,6 +478,7 @@
/**
* @brief assert that lysp_ext_instance structure members are correct
+ *
* @param[in] NODE pointer to lysp_ext_instance variable
* @param[in] ARGUMENT expected optional value of the extension's argument
* @param[in] CHILD 0 -> node doesnt have child, 1 -> node have children
@@ -468,6 +498,7 @@
/**
* @brief assert that lysp_stmt structure members are correct
+ *
* @param[in] NODE pointer to lysp_stmt variable
* @param[in] ARG expected statemet argumet
* @param[in] CHILD 0 -> node doesnt have child, 1 -> node have children
@@ -487,6 +518,7 @@
/**
* @brief assert that lysp_type_enum structure members are correct
+ *
* @param[in] NODE pointer to lysp_type_enum variable
* @param[in] DSC expected description
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of list of the extension instances
@@ -508,6 +540,7 @@
/**
* @brief assert that lysp_type_enum structure members are correct
+ *
* @param[in] NODE pointer to lysp_type variable
* @param[in] BASES expected [sized array](@ref sizedarrays) size of list of indentifiers
* @param[in] BITS expected [sized array](@ref sizedarrays) size of list of bits
@@ -546,6 +579,7 @@
/**
* @brief assert that lysp_node structure members are correct
+ *
* @param[in] NODE pointer to lysp_node variable
* @param[in] DSC expected description statement
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of list of the extension instances
@@ -575,6 +609,7 @@
/**
* @brief assert that lysp_node structure members are correct
+ *
* @param[in] NODE pointer to lysp_node variable
* @param[in] DSC expected description statement
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of list of the extension instances
@@ -598,6 +633,7 @@
/**
* @brief assert that lysc_notif structure members are correct
+ *
* @param[in] NODE pointer to lysp_notif variable
* @param[in] DATA 0 pointer is null, 1 pointer is not null
* @param[in] DSC expected description
@@ -628,6 +664,7 @@
/**
* @brief assert that lysc_action_inout structure members are correct
+ *
* @param[in] NODE pointer to lysp_notif variable
* @param[in] DATA 0 pointer is null, 1 pointer is not null
* @param[in] MUST expected [sized array](@ref sizedarrays) size of list of must restrictions
@@ -641,6 +678,7 @@
/**
* @brief assert that lysc_action structure members are correct
+ *
* @param[in] NODE pointer to lysp_action variable
* @param[in] DSC string description statement
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of list of the extension instances
@@ -679,6 +717,7 @@
/**
* @brief assert that lysc_node structure members are correct
+ *
* @param[in] NODE pointer to lysc_node variable
* @param[in] DSC expected description
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of list of the extension instances
@@ -712,6 +751,7 @@
/**
* @brief assert that lysc_node_leaf structure members are correct
+ *
* @param[in] NODE pointer to lysc_node variable
* @param[in] DSC expected description
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of list of the extension instances
@@ -745,6 +785,7 @@
/**
* @brief assert that lysc_node_leaf structure members are correct
+ *
* @param[in] NODE pointer to lysc_node variable
* @param[in] DSC expected description
* @param[in] EXTS expected [sized array](@ref sizedarrays) size of list of the extension instances
@@ -770,6 +811,7 @@
/**
* @brief assert that lyd_meta structure members are correct
+ *
* @param[in] NODE pointer to lyd_meta variable
* @param[in] ANNOTATION 0 pointer is null, 1 pointer is not null
* @param[in] NAME expected name
@@ -788,6 +830,7 @@
/**
* @brief assert that lyd_node_term structure members are correct
+ *
* @param[in] NODE pointer to lyd_node_term variable
* @param[in] FLAGS expected [data node flags](@ref dnodeflags)
* @param[in] META 0 -> meta is not prezent, 1 -> meta is prezent
@@ -808,6 +851,7 @@
/**
* @brief assert that lyd_node_any structure members are correct
+ *
* @param[in] NODE pointer to lyd_node_term variable
* @param[in] FLAGS expected [data node flags](@ref dnodeflags)
* @param[in] META 0 meta isnt present , 1 meta is present
@@ -825,6 +869,7 @@
/**
* @brief assert that lyd_node_opaq structure members are correct
+ *
* @param[in] NODE pointer to lyd_node_opaq variable
* @param[in] ATTR 0 if pointer is null ,1 if pointer is not null
* @param[in] CHILD 0 if pointer is null ,1 if pointer is not null
@@ -849,6 +894,7 @@
/**
* @brief assert that lyd_node_opaq structure members are correct
+ *
* @param[in] NODE pointer to lyd_node_opaq variable
* @param[in] CHILD 1 if node has children other 0
* @param[in] HILD_HT 1 if node has children hash table other 0
@@ -873,6 +919,7 @@
/**
* @brief assert that lyd_value structure members are correct
+ *
* @param[in] NODE lyd_value
* @param[in] TYPE_VAL value type. EMPTY, UNION, BITS, INST, ENUM, INT8, INT16, UINT8, STRING, LEAFREF, DEC64, BINARY, BOOL, IDENT
* part of text reprezenting LY_DATA_TYPE.
@@ -890,6 +937,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type EMPTY
* Example CHECK_LYD_VALUE(node->value, EMPTY, "");
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
*/
@@ -903,6 +951,7 @@
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type UNION
* Example CHECK_LYD_VALUE(node->value, UNION, "12", INT8, "12", 12);
* @warning type of subvalue cannot be UNION. Example of calling
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] TYPE_VAL value type. EMPTY, UNION, BITS, INST, ENUM, INT8, INT16, UINT8, STRING, LEAFREF, DEC64, BINARY, BOOL, IDENT
@@ -927,6 +976,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type BITS
* Example arr[] = {"a", "b"}; CHECK_LYD_VALUE(node->value, BITS, "a b", arr);
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected array of bits names
@@ -949,6 +999,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type INST
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected array of enum ly_path_pred_type
@@ -970,6 +1021,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type ENUM.
* Example CHECK_LYD_VALUE(node->value, ENUM, "item_name", "item_name");
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected enum item name
@@ -984,6 +1036,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type INT8
* Example CHECK_LYD_VALUE(node->value, INT8, "12", 12);
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected inteager value (-128 to 127).
@@ -998,6 +1051,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type INT16
* Example CHECK_LYD_VALUE(node->value, INT8, "12", 12);
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected inteager value.
@@ -1012,6 +1066,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type UINT8.
* Example CHECK_LYD_VALUE(node->value, UINT8, "12", 12);
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected inteager (0 to 255).
@@ -1026,6 +1081,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type UINT32.
* Example CHECK_LYD_VALUE(node->value, UINT32, "12", 12);
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected inteager (0 to MAX_UINT32).
@@ -1040,6 +1096,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type STRING.
* Example CHECK_LYD_VALUE(node->value, STRING, "text");
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
*/
@@ -1051,7 +1108,8 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type LEAFREF
- * @brief Example CHECK_LYD_VALUE(node->value, LEAFREF, "");
+ * Example CHECK_LYD_VALUE(node->value, LEAFREF, "");
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
*/
@@ -1065,6 +1123,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type DEC64
* Example CHECK_LYD_VALUE(node->value, DEC64, "125", 125);
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected value 64bit inteager
@@ -1079,6 +1138,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type BINARY.
* Example CHECK_LYD_VALUE(node->value, BINARY, "aGVs\nbG8=");
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected value data
@@ -1099,6 +1159,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type BOOL.
* Example CHECK_LYD_VALUE(node->value, BOOL, "true", 1);
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected boolean value 0,1
@@ -1113,6 +1174,7 @@
/**
* @brief Internal macro. Assert that lyd_value structure members are correct. Lyd value is type IDENT.
* Example CHECK_LYD_VALUE(node->value, IDENT, "types:gigabit-ethernet", "gigabit-ethernet");
+ *
* @param[in] NODE lyd_value variable
* @param[in] CANNONICAL_VAL expected cannonical value
* @param[in] VALUE expected ident name
@@ -1126,6 +1188,7 @@
/**
* @brief Macro testing parser when parsing incorrect module;
+ *
* @param[in] DATA String storing the schema module representation.
* @param[in] FORMAT Schema format of the @p DATA
* @param[in] FEATURES Array of module's features to enable
@@ -1143,6 +1206,7 @@
/**
* @brief Add module (from a string) into the used libyang context.
+ *
* @param[in] DATA String storing the schema module representation.
* @param[in] FORMAT Schema format of the @p DATA
* @param[in] FEATURES Array of module's features to enable
@@ -1157,6 +1221,7 @@
/**
* @brief Internal macro to compare error info record with the expected error message and path.
* If NULL is provided as MSG, no error info record (NULL) is expected.
+ *
* @param[in] ERR Error information record from libyang context.
* @param[in] MSG Expected error message.
* @param[in] PATH Expected error path.
diff --git a/tools/lint/tests/expect/list.exp b/tools/lint/tests/expect/list.exp
index 92fea12..663d4d0 100755
--- a/tools/lint/tests/expect/list.exp
+++ b/tools/lint/tests/expect/list.exp
@@ -12,6 +12,7 @@
I yang@2021-04-07\r
i ietf-inet-types@2013-07-15\r
i ietf-yang-types@2013-07-15\r
+ I ietf-yang-schema-mount@2019-01-14\r
I ietf-datastores@2018-02-14\r
I ietf-yang-library@2019-01-04\r
> " { }
diff --git a/tools/lint/tests/shunit2/list.sh b/tools/lint/tests/shunit2/list.sh
index fe6cf2a..6f04587 100755
--- a/tools/lint/tests/shunit2/list.sh
+++ b/tools/lint/tests/shunit2/list.sh
@@ -4,7 +4,8 @@
i ietf-yang-metadata@2016-08-05
I yang@2021-04-07
i ietf-inet-types@2013-07-15
- i ietf-yang-types@2013-07-15"
+ i ietf-yang-types@2013-07-15
+ I ietf-yang-schema-mount@2019-01-14"
testListEmptyContext() {
output=`${YANGLINT} -l`
@@ -16,7 +17,8 @@
I ietf-yang-metadata@2016-08-05
I yang@2021-04-07
I ietf-inet-types@2013-07-15
- I ietf-yang-types@2013-07-15"
+ I ietf-yang-types@2013-07-15
+ I ietf-yang-schema-mount@2019-01-14"
output=`${YANGLINT} -lii`
assertEquals "Unexpected list of modules in empty context with -ii." "${LIST_BASE_ALLIMPLEMENTED}" "${output}"
}