data tree NEW opaque data node
Used for unknown anyxml/anydata nodes.
Some refactoring including making context
const for cases when only the dictionary
is modified or replacing unsigned int with
uint32_t.
diff --git a/src/common.h b/src/common.h
index bcc2426..2b58fbf 100644
--- a/src/common.h
+++ b/src/common.h
@@ -15,7 +15,6 @@
#ifndef LY_COMMON_H_
#define LY_COMMON_H_
-#define _DEFAULT_SOURCE
#define _GNU_SOURCE
#include <pthread.h>
@@ -445,7 +444,7 @@
*
* Implemented in parser_json.c
*/
-const struct lys_module *lydjson_resolve_prefix(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser);
+const struct lys_module *lydjson_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser);
/**
* @brief mmap(2) wrapper to map input files into memory to unify parsing.
diff --git a/src/dict.h b/src/dict.h
index 35f9148..88e9647 100644
--- a/src/dict.h
+++ b/src/dict.h
@@ -47,7 +47,7 @@
* byte is added automatically. If \p len is 0, it is count automatically using strlen().
* @return pointer to the string stored in the dictionary, NULL if \p value was NULL.
*/
-const char *lydict_insert(struct ly_ctx *ctx, const char *value, size_t len);
+const char *lydict_insert(const struct ly_ctx *ctx, const char *value, size_t len);
/**
* @brief Insert string into dictionary - zerocopy version. If the string is
@@ -63,7 +63,7 @@
* value address anymore. If NULL, function does nothing.
* @return pointer to the string stored in the dictionary, NULL if \p value was NULL.
*/
-const char *lydict_insert_zc(struct ly_ctx *ctx, char *value);
+const char *lydict_insert_zc(const struct ly_ctx *ctx, char *value);
/**
* @brief Remove specified string from the dictionary. It decrement reference
@@ -74,9 +74,9 @@
* must match the stored value, but also the address is being compared and the
* counter is decremented only if it matches. If NULL, function does nothing.
*/
-void lydict_remove(struct ly_ctx *ctx, const char *value);
+void lydict_remove(const struct ly_ctx *ctx, const char *value);
-/**@} dict */
+/** @} dict */
#ifdef __cplusplus
}
diff --git a/src/hash_table.c b/src/hash_table.c
index 2d9af2a..c115e38 100644
--- a/src/hash_table.c
+++ b/src/hash_table.c
@@ -124,7 +124,7 @@
}
API void
-lydict_remove(struct ly_ctx *ctx, const char *value)
+lydict_remove(const struct ly_ctx *ctx, const char *value)
{
size_t len;
int ret;
@@ -143,7 +143,7 @@
rec.value = (char *)value;
rec.refcount = 0;
- pthread_mutex_lock(&ctx->dict.lock);
+ pthread_mutex_lock((pthread_mutex_t *)&ctx->dict.lock);
/* set len as data for compare callback */
lyht_set_cb_data(ctx->dict.hash_tab, (void *)&len);
/* check if value is already inserted */
@@ -168,11 +168,11 @@
}
finish:
- pthread_mutex_unlock(&ctx->dict.lock);
+ pthread_mutex_unlock((pthread_mutex_t *)&ctx->dict.lock);
}
static char *
-dict_insert(struct ly_ctx *ctx, char *value, size_t len, int zerocopy)
+dict_insert(const struct ly_ctx *ctx, char *value, size_t len, int zerocopy)
{
struct dict_rec *match = NULL, rec;
int ret = 0;
@@ -216,7 +216,7 @@
}
API const char *
-lydict_insert(struct ly_ctx *ctx, const char *value, size_t len)
+lydict_insert(const struct ly_ctx *ctx, const char *value, size_t len)
{
const char *result;
@@ -226,23 +226,23 @@
len = strlen(value);
}
- pthread_mutex_lock(&ctx->dict.lock);
+ pthread_mutex_lock((pthread_mutex_t *)&ctx->dict.lock);
result = dict_insert(ctx, (char *)value, len, 0);
- pthread_mutex_unlock(&ctx->dict.lock);
+ pthread_mutex_unlock((pthread_mutex_t *)&ctx->dict.lock);
return result;
}
API const char *
-lydict_insert_zc(struct ly_ctx *ctx, char *value)
+lydict_insert_zc(const struct ly_ctx *ctx, char *value)
{
const char *result;
LY_CHECK_ARG_RET(ctx, ctx, value, NULL);
- pthread_mutex_lock(&ctx->dict.lock);
+ pthread_mutex_lock((pthread_mutex_t *)&ctx->dict.lock);
result = dict_insert(ctx, value, strlen(value), 1);
- pthread_mutex_unlock(&ctx->dict.lock);
+ pthread_mutex_unlock((pthread_mutex_t *)&ctx->dict.lock);
return result;
}
diff --git a/src/parser_json.c b/src/parser_json.c
index 400b078..5b59fed 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -34,7 +34,7 @@
* in the values to the schema via context module names.
*/
const struct lys_module *
-lydjson_resolve_prefix(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *UNUSED(parser))
+lydjson_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *UNUSED(parser))
{
const struct lys_module *mod;
char *name;
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 28238bf..34e3161 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -42,12 +42,12 @@
struct ly_set elements; /**< list of not-yet-closed elements */
struct ly_set ns; /**< handled with LY_SET_OPT_USEASLIST */
- uint16_t options; /**< various @ref dataparseroptions. */
- uint16_t path_len; /**< used bytes in the path buffer */
+ uint32_t options; /**< various @ref dataparseroptions. */
+ uint32_t path_len; /**< used bytes in the path buffer */
#define LYD_PARSER_BUFSIZE 4078
char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
- struct ly_set incomplete_type_validation; /**< set of nodes validated with LY_EINCOMPLETE result */
- struct ly_set incomplete_type_validation_meta; /**< set of metdata validated with LY_EINCOMPLETE result */
+ struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
+ struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
struct ly_set when_check; /**< set of nodes with "when" conditions */
};
@@ -56,7 +56,7 @@
* via XML namespaces.
*/
static const struct lys_module *
-lydxml_resolve_prefix(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
+lydxml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
{
const struct lyxml_ns *ns;
struct lyxml_context *xmlctx = (struct lyxml_context*)parser;
@@ -82,14 +82,14 @@
/**
* @brief Parse XML attributes of the XML element of YANG data.
*
- * @param[in] ctx XML YANG data parser context.
+ * @param[in] xmlctx XML parser context.
* @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
* @param[out] attributes Resulting list of the parsed attributes. XML namespace definitions are not parsed
* as attributes, they are stored internally in the parser context.
* @reutn LY_ERR value.
*/
static LY_ERR
-lydxml_attributes_parse(struct lyd_xml_ctx *ctx, const char **data, struct ly_set *attrs_data)
+lydxml_attributes_parse(struct lyxml_context *xmlctx, const char **data, struct ly_set *attrs_data)
{
LY_ERR ret = LY_SUCCESS;
unsigned int u;
@@ -97,8 +97,8 @@
size_t prefix_len, name_len;
struct attr_data_s *attr_data;
- while(ctx->status == LYXML_ATTRIBUTE &&
- lyxml_get_attribute((struct lyxml_context*)ctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS) {
+ while (xmlctx->status == LYXML_ATTRIBUTE &&
+ lyxml_get_attribute(xmlctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS) {
char *buffer = NULL;
size_t buffer_size = 0;
@@ -115,7 +115,7 @@
attr_data->name = name;
attr_data->prefix_len = prefix_len;
attr_data->name_len = name_len;
- ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &attr_data->value, &attr_data->value_len, &attr_data->dynamic);
+ ret = lyxml_get_string(xmlctx, data, &buffer, &buffer_size, &attr_data->value, &attr_data->value_len, &attr_data->dynamic);
LY_CHECK_ERR_GOTO(ret, free(attr_data), error);
ly_set_add(attrs_data, attr_data, LY_SET_OPT_USEASLIST);
}
@@ -133,7 +133,8 @@
}
static LY_ERR
-lydxml_metadata(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, const struct lysc_node *sparent, struct lyd_meta **meta)
+lydxml_metadata(struct lyxml_context *xmlctx, struct ly_set *attrs_data, const struct lysc_node *sparent, int strict,
+ struct ly_set *type_meta_check, struct lyd_meta **meta)
{
LY_ERR ret = LY_EVALID, rc;
const struct lyxml_ns *ns;
@@ -145,8 +146,8 @@
if (!attr_data->prefix_len) {
/* in XML, all attributes must be prefixed
* TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
- if (ctx->options & LYD_OPT_STRICT) {
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
+ if (strict) {
+ LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
attr_data->name_len, attr_data->name);
}
skip_attr:
@@ -158,17 +159,18 @@
}
/* get namespace of the attribute to find its annotation definition */
- ns = lyxml_ns_get((struct lyxml_context *)ctx, attr_data->prefix, attr_data->prefix_len);
+ ns = lyxml_ns_get(xmlctx, attr_data->prefix, attr_data->prefix_len);
if (!ns) {
- /* unknown namespace, ignore the attribute */
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", attr_data->prefix_len, attr_data->prefix);
+ /* unknown namespace, XML error */
+ LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
+ attr_data->prefix_len, attr_data->prefix);
goto cleanup;
}
- mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
+ mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
if (!mod) {
/* module is not implemented or not present in the schema */
- if (ctx->options & LYD_OPT_STRICT) {
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
+ if (strict) {
+ LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
"Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
ns, attr_data->prefix_len, attr_data->prefix, attr_data->prefix_len ? ":" : "", attr_data->name_len,
attr_data->name);
@@ -176,19 +178,21 @@
goto skip_attr;
}
- rc = lyd_create_meta(NULL, meta, mod, attr_data->name, attr_data->name_len, attr_data->value,
- attr_data->value_len, &attr_data->dynamic, lydxml_resolve_prefix, ctx, LYD_XML, sparent);
+ rc = lyd_create_meta(NULL, meta, mod, attr_data->name, attr_data->name_len, attr_data->value, attr_data->value_len,
+ &attr_data->dynamic, lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
if (rc == LY_EINCOMPLETE) {
- ly_set_add(&ctx->incomplete_type_validation_meta, meta, LY_SET_OPT_USEASLIST);
+ if (type_meta_check) {
+ ly_set_add(type_meta_check, meta, LY_SET_OPT_USEASLIST);
+ }
} else if (rc) {
ret = rc;
goto cleanup;
}
}
+
ret = LY_SUCCESS;
cleanup:
-
for (unsigned int u = 0; u < attrs_data->count; ++u) {
if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
free(((struct attr_data_s*)attrs_data->objs[u])->value);
@@ -199,6 +203,62 @@
return ret;
}
+static LY_ERR
+lydxml_attrs(struct lyxml_context *xmlctx, struct ly_set *attrs_data, struct ly_attr **attr)
+{
+ LY_ERR ret = LY_SUCCESS;
+ const struct lyxml_ns *ns;
+ struct ly_prefix *val_prefs;
+ struct ly_attr *attr2;
+
+ assert(attr);
+
+ for (unsigned int u = 0; u < attrs_data->count; ++u) {
+ struct attr_data_s *attr_data = (struct attr_data_s *)attrs_data->objs[u];
+
+ ns = NULL;
+ if (attr_data->prefix_len) {
+ /* get namespace of the attribute */
+ ns = lyxml_ns_get(xmlctx, attr_data->prefix, attr_data->prefix_len);
+ if (!ns) {
+ LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
+ attr_data->prefix_len, attr_data->prefix);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ }
+
+ if (*attr) {
+ attr2 = *attr;
+ } else {
+ attr2 = NULL;
+ }
+
+ /* get value prefixes */
+ ret = lyxml_get_prefixes(xmlctx, attr_data->value, attr_data->value_len, &val_prefs);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* attr2 is always changed to the created attribute */
+ ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, attr_data->name, attr_data->name_len, attr_data->value,
+ attr_data->value_len, &attr_data->dynamic, LYD_XML, val_prefs, attr_data->prefix,
+ attr_data->prefix_len, ns ? ns->uri : NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ if (!*attr) {
+ *attr = attr2;
+ }
+ }
+
+cleanup:
+ for (unsigned int u = 0; u < attrs_data->count; ++u) {
+ if (((struct attr_data_s *)attrs_data->objs[u])->dynamic) {
+ free(((struct attr_data_s *)attrs_data->objs[u])->value);
+ }
+ }
+ ly_set_erase(attrs_data, free);
+ return ret;
+}
+
/**
* @brief Parse XML elements as YANG data node children the specified parent node.
*
@@ -216,11 +276,14 @@
size_t prefix_len, name_len;
struct ly_set attrs_data = {0};
const struct lyxml_ns *ns;
- struct lyd_meta *meta = NULL, *meta2;
+ struct lyd_meta *meta = NULL, *meta2, *prev_meta;
+ struct ly_attr *attr = NULL;
const struct lysc_node *snode;
struct lys_module *mod;
unsigned int parents_count = ctx->elements.count;
- struct lyd_node *cur = NULL, *key_anchor;
+ uint32_t prev_opts;
+ struct lyd_node *cur = NULL, *anchor;
+ struct ly_prefix *val_prefs;
int dynamic = 0;
char *buffer = NULL, *value;
size_t buffer_size = 0, value_len;
@@ -240,7 +303,7 @@
if (ctx->status == LYXML_ATTRIBUTE) {
/* first parse all attributes so we have all the namespaces available */
- if (lydxml_attributes_parse(ctx, data, &attrs_data) != LY_SUCCESS) {
+ if (lydxml_attributes_parse((struct lyxml_context *)ctx, data, &attrs_data) != LY_SUCCESS) {
ret = LY_EVALID;
goto cleanup;
}
@@ -253,37 +316,97 @@
goto cleanup;
}
mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
- if (!mod) {
+ if (!mod && (ctx->options & LYD_OPT_STRICT)) {
LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
ret = LY_EVALID;
goto cleanup;
}
- /* leave if-feature check for validation */
- snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
- if (!snode) {
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
- name_len, name, mod->name);
- ret = LY_EVALID;
- goto cleanup;
- }
- if ((ctx->options & LYD_OPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INSTATE, snode->name);
- return LY_EVALID;
+
+ snode = NULL;
+ if (mod && (!parent || parent->schema)) {
+ /* leave if-feature check for validation */
+ snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
+ if (!snode && (ctx->options & LYD_OPT_STRICT)) {
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
+ name_len, name, mod->name);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ if (snode) {
+ if ((ctx->options & LYD_OPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INSTATE, snode->name);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ if (snode->nodetype & (LYS_ACTION | LYS_NOTIF)) {
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected %s element \"%.*s\".",
+ snode->nodetype == LYS_ACTION ? "RPC/action" : "notification", name_len, name);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ }
}
/* create actual metadata so that prefixes are available in the context */
if (attrs_data.count) {
- LY_CHECK_GOTO(ret = lydxml_metadata(ctx, &attrs_data, snode, &meta), cleanup);
+ if (snode) {
+ ret = lydxml_metadata((struct lyxml_context *)ctx, &attrs_data, snode, ctx->options & LYD_OPT_STRICT,
+ &ctx->unres_meta_type, &meta);
+ LY_CHECK_GOTO(ret, cleanup);
+ } else if (ctx->options & LYD_OPT_OPAQ) {
+ ret = lydxml_attrs((struct lyxml_context *)ctx, &attrs_data, &attr);
+ LY_CHECK_GOTO(ret, cleanup);
+ } else {
+ /* free attr data */
+ for (uint32_t u = 0; u < attrs_data.count; ++u) {
+ if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
+ free(((struct attr_data_s*)attrs_data.objs[u])->value);
+ }
+ }
+ ly_set_erase(&attrs_data, free);
+ }
}
- if (snode->nodetype & (LYS_ACTION | LYS_NOTIF)) {
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected %s element \"%.*s\".",
- snode->nodetype == LYS_ACTION ? "RPC/action" : "notification", name_len, name);
- ret = LY_EVALID;
- goto cleanup;
- }
+ if (!snode) {
+ if (ctx->options & LYD_OPT_OPAQ) {
+ /* get the value */
+ LY_ERR r = LY_EINVAL;
+ if (ctx->status == LYXML_ELEM_CONTENT) {
+ r = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
+ if (r && (r != LY_EINVAL)) {
+ LOGINT(ctx->ctx);
+ ret = LY_EINT;
+ goto cleanup;
+ }
+ }
+ if (r == LY_EINVAL) {
+ /* empty value */
+ value = "";
+ value_len = 0;
+ dynamic = 0;
+ }
- if (snode->nodetype & LYD_NODE_TERM) {
+ /* get value prefixes */
+ ret = lyxml_get_prefixes((struct lyxml_context *)ctx, value, value_len, &val_prefs);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* create node */
+ ret = lyd_create_opaq(ctx->ctx, name, name_len, value, value_len, &dynamic, LYD_XML, val_prefs, prefix,
+ prefix_len, ns->uri, &cur);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* process children */
+ if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
+ ret = lydxml_data_r(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ } else {
+ /* skip element */
+ ret = lyxml_skip_element((struct lyxml_context *)ctx, data);
+ LY_CHECK_GOTO(ret, cleanup);
+ break;
+ }
+ } else if (snode->nodetype & LYD_NODE_TERM) {
if (ctx->status == LYXML_ELEM_CONTENT) {
/* get the value */
ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
@@ -308,7 +431,7 @@
buffer = NULL;
if (ret == LY_EINCOMPLETE) {
if (!(ctx->options & LYD_OPT_PARSE_ONLY)) {
- ly_set_add(&ctx->incomplete_type_validation, cur, LY_SET_OPT_USEASLIST);
+ ly_set_add(&ctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
}
} else if (ret) {
goto cleanup;
@@ -316,8 +439,8 @@
if (parent && (cur->schema->flags & LYS_KEY)) {
/* check the key order, the anchor must always be the last child */
- key_anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
- if ((!key_anchor && parent->child) || (key_anchor && key_anchor->next)) {
+ anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
+ if ((!anchor && parent->child) || (anchor && anchor->next)) {
if (ctx->options & LYD_OPT_STRICT) {
LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
cur->schema->name);
@@ -361,7 +484,7 @@
/* add any missing default children */
ret = lyd_validate_defaults_r((struct lyd_node_inner *)cur, lyd_node_children_p(cur), NULL, NULL,
- &ctx->incomplete_type_validation, &ctx->when_check, ctx->options);
+ &ctx->unres_node_type, &ctx->when_check, ctx->options);
LY_CHECK_GOTO(ret, cleanup);
}
@@ -370,80 +493,75 @@
lyd_hash(cur);
}
} else if (snode->nodetype & LYD_NODE_ANY) {
- unsigned int cur_element_index = ctx->elements.count;
- const char *start = *data, *stop;
- const char *p, *n;
- size_t p_len, n_len;
-
- /* skip children data and store them as a string */
- while (ctx->status != LYXML_END && cur_element_index <= ctx->elements.count) {
- switch (ctx->status) {
- case LYXML_ELEMENT:
- ret = lyxml_get_element((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
- LY_CHECK_GOTO(ret, cleanup);
- break;
- case LYXML_ATTRIBUTE:
- lyxml_get_attribute((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
- break;
- case LYXML_ELEM_CONTENT:
- case LYXML_ATTR_CONTENT:
- ret = lyxml_get_string((struct lyxml_context *)ctx, data, NULL, NULL, NULL, NULL, NULL);
- /* not an error, just incorrect XML parser status */
- if (ret && (ret != LY_EINVAL)) {
- goto cleanup;
- }
- break;
- case LYXML_END:
- /* end of data */
+ /* just incorrect status */
+ if (ctx->status == LYXML_ELEM_CONTENT) {
+ LY_ERR r = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
+ if (r != LY_EINVAL && (r != LY_SUCCESS || value_len != 0)) {
LOGINT(ctx->ctx);
ret = LY_EINT;
goto cleanup;
}
}
- /* get value */
- if (start != *data) {
- /* data now points after the anydata's closing element tag, we need just end of its content */
- for (stop = *data - 1; *stop != '<'; --stop);
- start = lydict_insert(ctx->ctx, start, stop - start);
- } else {
- start = NULL;
- }
+ /* parse any data tree with correct options */
+ prev_opts = ctx->options;
+ ctx->options &= ~LYD_OPT_STRICT;
+ ctx->options |= LYD_OPT_OPAQ;
+ anchor = NULL;
+ ret = lydxml_data_r(ctx, NULL, data, &anchor);
+ ctx->options = prev_opts;
+ LY_CHECK_GOTO(ret, cleanup);
/* create node */
- ret = lyd_create_any(snode, start, LYD_ANYDATA_XML, &cur);
- if (ret) {
- lydict_remove(ctx->ctx, start);
- goto cleanup;
- }
+ ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &cur);
+ LY_CHECK_GOTO(ret, cleanup);
}
/* correct flags */
- if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
- if (ctx->options & LYD_OPT_TRUSTED) {
- /* just set it to true */
- cur->flags |= LYD_WHEN_TRUE;
- } else {
- /* remember we need to evaluate this node's when */
- ly_set_add(&ctx->when_check, cur, LY_SET_OPT_USEASLIST);
+ if (snode) {
+ if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
+ if (ctx->options & LYD_OPT_TRUSTED) {
+ /* just set it to true */
+ cur->flags |= LYD_WHEN_TRUE;
+ } else {
+ /* remember we need to evaluate this node's when */
+ ly_set_add(&ctx->when_check, cur, LY_SET_OPT_USEASLIST);
+ }
}
- }
- if (ctx->options & LYD_OPT_TRUSTED) {
- /* node is valid */
- cur->flags &= ~LYD_NEW;
- }
- LY_LIST_FOR(meta, meta2) {
- if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
- && meta2->value.boolean) {
- /* node is default according to the metadata */
- cur->flags |= LYD_DEFAULT;
+ if (ctx->options & LYD_OPT_TRUSTED) {
+ /* node is valid */
+ cur->flags &= ~LYD_NEW;
+ }
+ prev_meta = NULL;
+ LY_LIST_FOR(meta, meta2) {
+ if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
+ && meta2->value.boolean) {
+ /* node is default according to the metadata */
+ cur->flags |= LYD_DEFAULT;
+
+ /* delete the metadata */
+ if (prev_meta) {
+ prev_meta->next = meta2->next;
+ } else {
+ meta = meta->next;
+ }
+ lyd_free_meta(ctx->ctx, meta2, 0);
+ break;
+ }
+
+ prev_meta = meta2;
}
}
- /* add metdata */
- assert(!cur->meta);
- cur->meta = meta;
- meta = NULL;
+ /* add metadata/attributes */
+ if (snode) {
+ cur->meta = meta;
+ meta = NULL;
+ } else {
+ assert(!cur->schema);
+ ((struct lyd_node_opaq *)cur)->attr = attr;
+ attr = NULL;
+ }
/* insert */
lyd_insert_node((struct lyd_node *)parent, first, cur);
@@ -457,8 +575,9 @@
cleanup:
free(buffer);
lyd_free_meta(ctx->ctx, meta, 1);
+ ly_free_attr(ctx->ctx, attr, 1);
lyd_free_tree(cur);
- for (unsigned int u = 0; u < attrs_data.count; ++u) {
+ for (uint32_t u = 0; u < attrs_data.count; ++u) {
if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
free(((struct attr_data_s*)attrs_data.objs[u])->value);
}
@@ -514,13 +633,13 @@
LY_CHECK_GOTO(ret, cleanup);
/* add all top-level defaults for this module */
- ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &xmlctx.incomplete_type_validation,
- &xmlctx.when_check, options & LYD_VALOPT_MASK);
+ ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &xmlctx.unres_node_type, &xmlctx.when_check,
+ options & LYD_VALOPT_MASK);
LY_CHECK_GOTO(ret, cleanup);
/* finish incompletely validated terminal values/attributes and when conditions */
- ret = lyd_validate_unres(tree, &xmlctx.when_check, &xmlctx.incomplete_type_validation,
- &xmlctx.incomplete_type_validation_meta, LYD_XML, lydxml_resolve_prefix, ctx);
+ ret = lyd_validate_unres(tree, &xmlctx.when_check, &xmlctx.unres_node_type, &xmlctx.unres_meta_type, LYD_XML,
+ lydxml_resolve_prefix, ctx);
LY_CHECK_GOTO(ret, cleanup);
/* perform final validation that assumes the data tree is final */
@@ -531,11 +650,11 @@
cleanup:
/* there should be no unresolved types stored */
- assert(!(options & LYD_OPT_PARSE_ONLY) || (!xmlctx.incomplete_type_validation.count
- && !xmlctx.incomplete_type_validation_meta.count && !xmlctx.when_check.count));
+ assert(!(options & LYD_OPT_PARSE_ONLY) || (!xmlctx.unres_node_type.count && !xmlctx.unres_meta_type.count
+ && !xmlctx.when_check.count));
- ly_set_erase(&xmlctx.incomplete_type_validation, NULL);
- ly_set_erase(&xmlctx.incomplete_type_validation_meta, NULL);
+ ly_set_erase(&xmlctx.unres_node_type, NULL);
+ ly_set_erase(&xmlctx.unres_meta_type, NULL);
ly_set_erase(&xmlctx.when_check, NULL);
lyxml_context_clear((struct lyxml_context *)&xmlctx);
if (ret) {
@@ -560,7 +679,7 @@
}
if (ctx->status == LYXML_ATTRIBUTE) {
- LY_CHECK_RET(lydxml_attributes_parse(ctx, data, &attrs_data));
+ LY_CHECK_RET(lydxml_attributes_parse((struct lyxml_context *)ctx, data, &attrs_data));
}
ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
diff --git a/src/plugins_types.c b/src/plugins_types.c
index f05b5c2..4c690b3 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -63,7 +63,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_original(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_original(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
dup->canonical_cache = original->canonical_cache;
dup->original = (void*)lydict_insert(ctx, original->original, strlen(original->original));
@@ -80,7 +80,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_canonical(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_canonical(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
ly_type_dup_original(ctx, original, dup);
dup->canonical_cache = (void*)lydict_insert(ctx, original->canonical_cache, strlen(original->canonical_cache));
@@ -97,7 +97,7 @@
* Implementation of the ly_type_free_clb.
*/
static void
-ly_type_free_original(struct ly_ctx *ctx, struct lyd_value *value)
+ly_type_free_original(const struct ly_ctx *ctx, struct lyd_value *value)
{
lydict_remove(ctx, value->original);
value->original = NULL;
@@ -109,7 +109,7 @@
* Implementation of the ly_type_free_clb.
*/
static void
-ly_type_free_canonical(struct ly_ctx *ctx, struct lyd_value *value)
+ly_type_free_canonical(const struct ly_ctx *ctx, struct lyd_value *value)
{
ly_type_free_original(ctx, value);
lydict_remove(ctx, value->canonical_cache);
@@ -117,7 +117,8 @@
}
API LY_ERR
-ly_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)
+ly_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)
{
char *errmsg = NULL;
@@ -148,7 +149,8 @@
}
API struct lyd_value_prefix *
-ly_type_get_prefixes(struct ly_ctx *ctx, const char *value, size_t value_len, ly_clb_resolve_prefix resolve_prefix, void *parser)
+ly_type_get_prefixes(const struct ly_ctx *ctx, const char *value, size_t value_len, ly_clb_resolve_prefix resolve_prefix,
+ void *parser)
{
LY_ERR ret;
unsigned int c;
@@ -203,7 +205,8 @@
}
API LY_ERR
-ly_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)
+ly_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)
{
char *errmsg = NULL;
@@ -380,7 +383,8 @@
}
API LY_ERR
-ly_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, const char *strval, struct ly_err_item **err)
+ly_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, const char *strval,
+ struct ly_err_item **err)
{
unsigned int u;
char *errmsg = NULL;
@@ -443,7 +447,7 @@
}
static void
-ly_type_store_strval(struct ly_ctx *ctx, int options, const char *orig, const char *value,
+ly_type_store_strval(const struct ly_ctx *ctx, int options, const char *orig, const char *value,
struct lyd_value *storage, const char **canonized)
{
if (options & LY_TYPE_OPTS_CANONIZE) {
@@ -461,7 +465,7 @@
}
#if 0
static void
-ly_type_store_canonized(struct ly_ctx *ctx, int options, const char *value, struct lyd_value *storage, const char **canonized)
+ly_type_store_canonized(const struct ly_ctx *ctx, int options, const char *value, struct lyd_value *storage, const char **canonized)
{
if (options & LY_TYPE_OPTS_CANONIZE) {
*canonized = value;
@@ -482,7 +486,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_int(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_int(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -546,7 +550,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_int(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_int(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
dup->int64 = original->int64;
return ly_type_dup_canonical(ctx, original, dup);
@@ -558,7 +562,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_uint(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_uint(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -621,7 +625,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_uint(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_uint(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
dup->uint64 = original->uint64;
return ly_type_dup_canonical(ctx, original, dup);
@@ -633,7 +637,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_decimal64(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_decimal64(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -705,7 +709,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_decimal64(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_decimal64(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
dup->dec64 = original->dec64;
return ly_type_dup_canonical(ctx, original, dup);
@@ -717,7 +721,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_binary(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_binary(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -822,7 +826,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_string(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_string(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -866,7 +870,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_bits(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_bits(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -1017,7 +1021,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_bits(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
unsigned int u;
@@ -1036,7 +1040,7 @@
* Implementation of the ly_type_free_clb.
*/
static void
-ly_type_free_bits(struct ly_ctx *ctx, struct lyd_value *value)
+ly_type_free_bits(const struct ly_ctx *ctx, struct lyd_value *value)
{
LY_ARRAY_FREE(value->bits_items);
value->bits_items = NULL;
@@ -1051,7 +1055,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_enum(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_enum(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -1115,7 +1119,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_enum(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_enum(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
dup->enum_item = original->enum_item;
return ly_type_dup_original(ctx, original, dup);
@@ -1127,7 +1131,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_boolean(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
+ly_type_store_boolean(const struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -1171,7 +1175,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_boolean(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_boolean(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
dup->int64 = original->int64;
return ly_type_dup_original(ctx, original, dup);
@@ -1183,7 +1187,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_empty(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
+ly_type_store_empty(const struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -1244,7 +1248,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_identityref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_identityref(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT UNUSED(format),
const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -1365,7 +1369,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_identityref(struct ly_ctx *UNUSED(ctx), const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *original, struct lyd_value *dup)
{
dup->ident = original->ident;
return LY_SUCCESS;
@@ -1483,7 +1487,7 @@
* Implementation of the ly_clb_resolve_prefix.
*/
static const struct lys_module *
-ly_type_stored_prefixes_clb(struct ly_ctx *UNUSED(ctx), const char *prefix, size_t prefix_len, void *private)
+ly_type_stored_prefixes_clb(const struct ly_ctx *UNUSED(ctx), const char *prefix, size_t prefix_len, void *private)
{
struct lyd_value_prefix *prefixes = (struct lyd_value_prefix*)private;
unsigned int u;
@@ -1510,8 +1514,8 @@
* @return LY_ERR value.
*/
static LY_ERR
-ly_type_store_instanceid_parse_predicate_value(struct ly_ctx *ctx, const struct lysc_node *key, const char *val, size_t val_len,
- struct lyd_value_prefix *prefixes, LYD_FORMAT format,
+ly_type_store_instanceid_parse_predicate_value(const struct ly_ctx *ctx, const struct lysc_node *key, const char *val,
+ size_t val_len, struct lyd_value_prefix *prefixes, LYD_FORMAT format,
struct lyd_value_path_predicate *pred, char **errmsg)
{
LY_ERR ret = LY_SUCCESS;
@@ -1581,7 +1585,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_instanceid(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_instanceid(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
const void *UNUSED(context_node), const struct lyd_node *tree,
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -2107,7 +2111,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_instanceid(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
unsigned int u, v;
@@ -2150,7 +2154,7 @@
* Implementation of the ly_type_free_clb.
*/
static void
-ly_type_free_instanceid(struct ly_ctx *ctx, struct lyd_value *value)
+ly_type_free_instanceid(const struct ly_ctx *ctx, struct lyd_value *value)
{
lyd_value_free_path(ctx, value->target);
value->target = NULL;
@@ -2161,7 +2165,7 @@
* @brief Find leafref target in instance data.
*/
const struct lyd_node *
-ly_type_find_leafref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len,
+ly_type_find_leafref(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len,
const struct lyd_node *context_node, const struct lyd_node *tree, struct lyd_value *storage, char **errmsg)
{
struct lysc_type_leafref *type_lr = (struct lysc_type_leafref*)type;
@@ -2351,7 +2355,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_leafref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_leafref(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
const void *context_node, const struct lyd_node *tree,
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -2434,7 +2438,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_leafref(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_leafref(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
return original->realtype->plugin->duplicate(ctx, original, dup);
}
@@ -2445,7 +2449,7 @@
* Implementation of the ly_type_free_clb.
*/
static void
-ly_type_free_leafref(struct ly_ctx *ctx, struct lyd_value *value)
+ly_type_free_leafref(const struct ly_ctx *ctx, struct lyd_value *value)
{
value->realtype->plugin->free(ctx, value);
}
@@ -2456,7 +2460,7 @@
* Implementation of the ly_type_store_clb.
*/
static LY_ERR
-ly_type_store_union(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ly_type_store_union(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
const void *context_node, const struct lyd_node *tree,
struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
@@ -2588,7 +2592,7 @@
* Implementation of the ly_type_dup_clb.
*/
static LY_ERR
-ly_type_dup_union(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+ly_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
{
unsigned int u;
@@ -2616,7 +2620,7 @@
* Implementation of the ly_type_free_clb.
*/
static void
-ly_type_free_union(struct ly_ctx *ctx, struct lyd_value *value)
+ly_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
{
unsigned int u;
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 2987382..44497cd 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -158,8 +158,8 @@
* @return LY_EINCOMPLETE in case the option included LY_TYPE_OPTS_INCOMPLETE_DATA flag and the data @p trees are needed to finish the validation.
* @return LY_ERR value if an error occurred and the value could not be canonized following the type's rules.
*/
-typedef LY_ERR (*ly_type_store_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
+typedef LY_ERR (*ly_type_store_clb)(const struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len,
+ int options, ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
const void *context_node, const struct lyd_node *tree,
struct lyd_value *storage, const char **canonized, struct ly_err_item **err);
@@ -207,7 +207,7 @@
* @return LY_SUCCESS after successful duplication.
* @return other LY_ERR values on error.
*/
-typedef LY_ERR (*ly_type_dup_clb)(struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+typedef LY_ERR (*ly_type_dup_clb)(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
/**
* @brief Callback for freeing the user type values stored by ly_type_store_clb().
@@ -217,7 +217,7 @@
* @param[in] ctx libyang ctx to enable correct manipulation with values that are in the dictionary.
* @param[in,out] value Value structure to free the data stored there by the plugin's ly_type_store_clb() callback
*/
-typedef void (*ly_type_free_clb)(struct ly_ctx *ctx, struct lyd_value *value);
+typedef void (*ly_type_free_clb)(const struct ly_ctx *ctx, struct lyd_value *value);
/**
* @brief Hold type-specific functions for various operations with the data values.
@@ -341,8 +341,8 @@
* @param[out] errmsg Error message in case of error.
* @return Leafref target node or NULL on error when @p errmsg is always set.
*/
-const struct lyd_node *ly_type_find_leafref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len,
- const struct lyd_node *context_node, const struct lyd_node *tree,
+const struct lyd_node *ly_type_find_leafref(const struct ly_ctx *ctx, struct lysc_type *type, const char *value,
+ size_t value_len, const struct lyd_node *context_node, const struct lyd_node *tree,
struct lyd_value *storage, char **errmsg);
/**
@@ -355,9 +355,9 @@
* @param[in] parser Parser's data for @p get_prefix.
* @return Created [sized array](@ref sizedarrays) of prefix mappings, NULL in case of error.
*/
-struct lyd_value_prefix *ly_type_get_prefixes(struct ly_ctx *ctx, const char *value, size_t value_len,
+struct lyd_value_prefix *ly_type_get_prefixes(const struct ly_ctx *ctx, const char *value, size_t value_len,
ly_clb_resolve_prefix get_prefix, void *parser);
-/**@} types */
+/** @} types */
#endif /* LY_PLUGINS_TYPES_H_ */
diff --git a/src/printer_data.h b/src/printer_data.h
index 245dbb4..5abb2ac 100644
--- a/src/printer_data.h
+++ b/src/printer_data.h
@@ -1,7 +1,7 @@
/**
- * @file printer_schema.h
+ * @file printer_data.h
* @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief Schema printers for libyang
+ * @brief Data printers for libyang
*
* Copyright (c) 2015-2019 CESNET, z.s.p.o.
*
diff --git a/src/printer_xml.c b/src/printer_xml.c
index 44e8ff4..c5785dc 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -17,6 +17,7 @@
#include <stdlib.h>
#include <string.h>
+#include <assert.h>
#include "log.h"
#include "plugins_types.h"
@@ -34,7 +35,9 @@
struct lyout *out; /**< output specification */
unsigned int level; /**< current indentation level: 0 - no formatting, >= 1 indentation levels */
int options; /**< [Data printer flags](@ref dataprinterflags) */
- int toplevel; /**< top-level flag */
+ const struct ly_ctx *ctx; /**< libyang context */
+ struct ly_set prefix; /**< printed namespace prefixes */
+ struct ly_set ns; /**< printed namespaces */
};
#define LEVEL ctx->level /**< current level */
@@ -42,113 +45,62 @@
#define LEVEL_INC if (LEVEL) {LEVEL++;} /**< increase indentation level */
#define LEVEL_DEC if (LEVEL) {LEVEL--;} /**< decrease indentation level */
-/**
- * TODO
- */
-struct mlist {
- struct mlist *next;
- struct lys_module *module;
-} *mlist = NULL, *mlist_new;
-
-static LY_ERR
-modlist_add(struct mlist **mlist, const struct lys_module *mod)
-{
- struct mlist *iter;
-
- for (iter = *mlist; iter; iter = iter->next) {
- if (mod == iter->module) {
- break;
- }
- }
-
- if (!iter) {
- iter = malloc(sizeof *iter);
- LY_CHECK_ERR_RET(!iter, LOGMEM(mod->ctx), LY_EMEM);
- iter->next = *mlist;
- iter->module = (struct lys_module *)mod;
- *mlist = iter;
- }
-
- return LY_SUCCESS;
-}
+#define LYXML_PREFIX_REQUIRED 0x01 /**< The prefix is not just a suggestion but a requirement. */
/**
- * TODO
+ * @brief Print a namespace if not already printed.
+ *
+ * @param[in] ctx XML printer context.
+ * @param[in] ns Namespace to print, expected to be in dictionary.
+ * @param[in] new_prefix Suggested new prefix, NULL for a default namespace without prefix. Stored in the dictionary.
+ * @param[in] prefix_opts Prefix options changing the meaning of parameters.
+ * @return Printed prefix of the namespace to use.
*/
-static void
-xml_print_ns(struct xmlpr_ctx *ctx, const struct lyd_node *node)
+static const char *
+xml_print_ns(struct xmlpr_ctx *ctx, const char *ns, const char *new_prefix, int prefix_opts)
{
- struct lyd_node *next, *cur, *child;
- struct lyd_meta *meta;
- struct mlist *mlist = NULL, *miter;
- const struct lys_module *wdmod = NULL;
+ int i;
- /* add node metadata modules */
- for (meta = node->meta; meta; meta = meta->next) {
- if (!strcmp(node->schema->name, "filter") &&
- (!strcmp(node->schema->module->name, "ietf-netconf") ||
- !strcmp(node->schema->module->name, "notifications"))) {
- /* exception for NETCONF's filter attributes */
- continue;
- } else if (modlist_add(&mlist, meta->annotation->module)) {
- goto print;
- }
- }
-
- /* add node children nodes and attribute modules */
- switch (node->schema->nodetype) {
- case LYS_LEAFLIST:
- case LYS_LEAF:
- /* ietf-netconf-with-defaults namespace */
- if (((node->flags & LYD_DEFAULT) && (ctx->options & (LYDP_WD_ALL_TAG | LYDP_WD_IMPL_TAG))) ||
- ((ctx->options & LYDP_WD_ALL_TAG) && ly_is_default(node))) {
- /* get with-defaults module and print its namespace */
- wdmod = ly_ctx_get_module_latest(node->schema->module->ctx, "ietf-netconf-with-defaults");
- if (wdmod && modlist_add(&mlist, wdmod)) {
- goto print;
- }
- }
- break;
- case LYS_CONTAINER:
- case LYS_LIST:
- case LYS_ACTION:
- case LYS_NOTIF:
- if (ctx->options & (LYDP_WD_ALL_TAG | LYDP_WD_IMPL_TAG)) {
- /* get with-defaults module and print its namespace */
- wdmod = ly_ctx_get_module_latest(node->schema->module->ctx, "ietf-netconf-with-defaults");
- if (wdmod && modlist_add(&mlist, wdmod)) {
- goto print;
- }
- }
-
- LY_LIST_FOR(((struct lyd_node_inner*)node)->child, child) {
- LYD_TREE_DFS_BEGIN(child, next, cur) {
- for (meta = cur->meta; meta; meta = meta->next) {
- if (!strcmp(cur->schema->name, "filter") &&
- (!strcmp(cur->schema->module->name, "ietf-netconf") ||
- !strcmp(cur->schema->module->name, "notifications"))) {
- /* exception for NETCONF's filter attributes */
- continue;
- } else {
- /* TODO annotations r = modlist_add(&mlist, lys_main_module(meta->annotation->module)); */
- }
+ for (i = ctx->ns.count - 1; i > -1; --i) {
+ if (!new_prefix) {
+ /* find default namespace */
+ if (!ctx->prefix.objs[i]) {
+ if (ctx->ns.objs[i] != ns) {
+ /* different default namespace */
+ i = -1;
}
- LYD_TREE_DFS_END(child, next, cur)}
+ break;
+ }
+ } else {
+ /* find prefixed namespace */
+ if (ctx->ns.objs[i] == ns) {
+ if (!ctx->prefix.objs[i]) {
+ /* default namespace is not interesting */
+ continue;
+ }
+
+ if (!strcmp(ctx->prefix.objs[i], new_prefix) || !(prefix_opts & LYXML_PREFIX_REQUIRED)) {
+ /* the same prefix or can be any */
+ break;
+ }
+ }
}
- break;
- default:
- break;
}
-print:
- /* print used namespaces */
- while (mlist) {
- miter = mlist;
- mlist = mlist->next;
+ if (i == -1) {
+ /* suitable namespace not found, must be printed */
+ ly_print(ctx->out, " xmlns%s%s=\"%s\"", new_prefix ? ":" : "", new_prefix ? new_prefix : "", ns);
- ly_print(ctx->out, " xmlns:%s=\"%s\"", miter->module->prefix, miter->module->ns);
- free(miter);
+ /* and added into namespaces */
+ if (new_prefix) {
+ new_prefix = lydict_insert(ctx->ctx, new_prefix, 0);
+ }
+ ly_set_add(&ctx->prefix, (void *)new_prefix, LY_SET_OPT_USEASLIST);
+ i = ly_set_add(&ctx->ns, (void *)ns, LY_SET_OPT_USEASLIST);
}
+
+ /* return it */
+ return ctx->prefix.objs[i];
}
/**
@@ -168,11 +120,12 @@
/**
* TODO
*/
-static LY_ERR
+static void
xml_print_meta(struct xmlpr_ctx *ctx, const struct lyd_node *node)
{
struct lyd_meta *meta;
- const struct lys_module *wdmod = NULL;
+ const struct lys_module *mod;
+ struct ly_set ns_list = {0};
#if 0
const char **prefs, **nss;
const char *xml_expr = NULL, *mod_name;
@@ -181,7 +134,6 @@
char *p;
size_t len;
#endif
- struct ly_set ns_list = {0};
int dynamic;
unsigned int u;
@@ -189,12 +141,10 @@
if (node->schema->nodetype & LYD_NODE_TERM) {
if (((node->flags & LYD_DEFAULT) && (ctx->options & (LYDP_WD_ALL_TAG | LYDP_WD_IMPL_TAG))) ||
((ctx->options & LYDP_WD_ALL_TAG) && ly_is_default(node))) {
- /* we have implicit OR explicit default node */
- /* get with-defaults module */
- wdmod = ly_ctx_get_module_latest(node->schema->module->ctx, "ietf-netconf-with-defaults");
- if (wdmod) {
- /* print attribute only if context include with-defaults schema */
- ly_print(ctx->out, " %s:default=\"true\"", wdmod->prefix);
+ /* we have implicit OR explicit default node, print attribute only if context include with-defaults schema */
+ mod = ly_ctx_get_module_latest(node->schema->module->ctx, "ietf-netconf-with-defaults");
+ if (mod) {
+ ly_print(ctx->out, " %s:default=\"true\"", xml_print_ns(ctx, mod->ns, mod->prefix, 0));
}
}
}
@@ -208,10 +158,10 @@
for (meta = node->meta; meta; meta = meta->next) {
const char *value = meta->value.realtype->plugin->print(&meta->value, LYD_XML, xml_print_get_prefix, &ns_list, &dynamic);
- /* print namespaces connected with the values's prefixes */
+ /* print namespaces connected with the value's prefixes */
for (u = 0; u < ns_list.count; ++u) {
- const struct lys_module *mod = (const struct lys_module*)ns_list.objs[u];
- ly_print(ctx->out, " xmlns:%s=\"%s\"", mod->prefix, mod->ns);
+ mod = (const struct lys_module *)ns_list.objs[u];
+ xml_print_ns(ctx, mod->ns, mod->prefix, 1);
}
ly_set_erase(&ns_list, NULL);
@@ -235,21 +185,22 @@
ly_print(out, " %s=\"", meta->name);
} else {
#endif
- ly_print(ctx->out, " %s:%s=\"", meta->annotation->module->prefix, meta->name);
+ /* print the metadata with its namespace */
+ mod = meta->annotation->module;
+ ly_print(ctx->out, " %s:%s=\"", xml_print_ns(ctx, mod->ns, mod->prefix, 1), meta->name);
#if 0
}
#endif
+ /* print metadata value */
if (value && value[0]) {
lyxml_dump_text(ctx->out, value, 1);
}
ly_print(ctx->out, "\"");
if (dynamic) {
- free((void*)value);
+ free((void *)value);
}
}
-
- return LY_SUCCESS;
}
/**
@@ -259,24 +210,75 @@
*
* @param[in] ctx XML printer context.
* @param[in] node Data node to be printed.
- * @return LY_ERR value.
*/
-static LY_ERR
+static void
xml_print_node_open(struct xmlpr_ctx *ctx, const struct lyd_node *node)
{
- if (ctx->toplevel || !node->parent || node->schema->module != node->parent->schema->module) {
- /* print "namespace" */
- ly_print(ctx->out, "%*s<%s xmlns=\"%s\"", INDENT, node->schema->name, node->schema->module->ns);
- } else {
- ly_print(ctx->out, "%*s<%s", INDENT, node->schema->name);
+ /* print node name */
+ ly_print(ctx->out, "%*s<%s", INDENT, node->schema->name);
+
+ /* print default namespace */
+ xml_print_ns(ctx, node->schema->module->ns, NULL, 0);
+
+ /* print metadata */
+ xml_print_meta(ctx, node);
+}
+
+static LY_ERR
+xml_print_attr(struct xmlpr_ctx *ctx, const struct lyd_node_opaq *node)
+{
+ const struct ly_attr *attr;
+ const char *pref;
+ uint32_t u;
+
+ LY_LIST_FOR(node->attr, attr) {
+ pref = NULL;
+ if (attr->prefix.pref) {
+ /* print attribute namespace */
+ switch (attr->format) {
+ case LYD_XML:
+ pref = xml_print_ns(ctx, attr->prefix.ns, attr->prefix.pref, 0);
+ break;
+ case LYD_SCHEMA:
+ /* cannot be created */
+ LOGINT(node->ctx);
+ return LY_EINT;
+ }
+ }
+
+ /* print namespaces connected with the value's prefixes */
+ if (attr->val_prefs) {
+ LY_ARRAY_FOR(attr->val_prefs, u) {
+ xml_print_ns(ctx, attr->val_prefs[u].ns, attr->val_prefs[u].pref, LYXML_PREFIX_REQUIRED);
+ }
+ }
+
+ /* print the attribute with its prefix and value */
+ ly_print(ctx->out, " %s%s%s=\"%s\"", pref ? pref : "", pref ? ":" : "", attr->name, attr->value);
}
- if (ctx->toplevel) {
- xml_print_ns(ctx, node);
- ctx->toplevel = 0;
+ return LY_SUCCESS;
+}
+
+static LY_ERR
+xml_print_opaq_open(struct xmlpr_ctx *ctx, const struct lyd_node_opaq *node)
+{
+ /* print node name */
+ ly_print(ctx->out, "%*s<%s", INDENT, node->name);
+
+ /* print default namespace */
+ switch (node->format) {
+ case LYD_XML:
+ xml_print_ns(ctx, node->prefix.ns, NULL, 0);
+ break;
+ case LYD_SCHEMA:
+ /* cannot be created */
+ LOGINT(node->ctx);
+ return LY_EINT;
}
- LY_CHECK_RET(xml_print_meta(ctx, node));
+ /* print attributes */
+ LY_CHECK_RET(xml_print_attr(ctx, node));
return LY_SUCCESS;
}
@@ -288,9 +290,8 @@
*
* @param[in] ctx XML printer context.
* @param[in] node Data node to be printed.
- * @return LY_ERR value.
*/
-static LY_ERR
+static void
xml_print_term(struct xmlpr_ctx *ctx, const struct lyd_node_term *node)
{
struct ly_set ns_list = {0};
@@ -298,7 +299,7 @@
int dynamic;
const char *value;
- LY_CHECK_RET(xml_print_node_open(ctx, (struct lyd_node *)node));
+ xml_print_node_open(ctx, (struct lyd_node *)node);
value = ((struct lysc_node_leaf *)node->schema)->type->plugin->print(&node->value, LYD_XML, xml_print_get_prefix, &ns_list, &dynamic);
/* print namespaces connected with the values's prefixes */
@@ -318,8 +319,6 @@
if (dynamic) {
free((void *)value);
}
-
- return LY_SUCCESS;
}
/**
@@ -335,7 +334,7 @@
LY_ERR ret;
struct lyd_node *child;
- LY_CHECK_RET(xml_print_node_open(ctx, (struct lyd_node *)node));
+ xml_print_node_open(ctx, (struct lyd_node *)node);
if (!node->child) {
ly_print(ctx->out, "/>%s", ctx->level ? "\n" : "");
@@ -362,9 +361,10 @@
{
struct lyd_node_any *any = (struct lyd_node_any *)node;
struct lyd_node *iter;
- int options_backup;
+ int prev_opts;
+ LY_ERR ret;
- LY_CHECK_RET(xml_print_node_open(ctx, (struct lyd_node *)node));
+ xml_print_node_open(ctx, (struct lyd_node *)node);
if (!any->value.tree) {
/* no content */
@@ -375,19 +375,18 @@
switch (any->value_type) {
case LYD_ANYDATA_DATATREE:
/* close opening tag and print data */
- options_backup = ctx->options;
+ prev_opts = ctx->options;
ctx->options &= ~(LYDP_WITHSIBLINGS | LYDP_NETCONF);
LEVEL_INC;
ly_print(ctx->out, ">%s", LEVEL ? "\n" : "");
LY_LIST_FOR(any->value.tree, iter) {
- if (xml_print_node(ctx, iter)) {
- return EXIT_FAILURE;
- }
+ ret = xml_print_node(ctx, iter);
+ LY_CHECK_ERR_RET(ret, LEVEL_DEC, ret);
}
LEVEL_DEC;
- ctx->options = options_backup;
+ ctx->options = prev_opts;
break;
case LYD_ANYDATA_STRING:
/* escape XML-sensitive characters */
@@ -425,6 +424,50 @@
return LY_SUCCESS;
}
+static LY_ERR
+xml_print_opaq(struct xmlpr_ctx *ctx, const struct lyd_node_opaq *node)
+{
+ LY_ERR ret;
+ struct lyd_node *child;
+ uint32_t u;
+
+ LY_CHECK_RET(xml_print_opaq_open(ctx, node));
+
+ if (node->value[0]) {
+ /* print namespaces connected with the value's prefixes */
+ if (node->val_prefs) {
+ LY_ARRAY_FOR(node->val_prefs, u) {
+ xml_print_ns(ctx, node->val_prefs[u].ns, node->val_prefs[u].pref, LYXML_PREFIX_REQUIRED);
+ }
+ }
+
+ ly_print(ctx->out, ">%s", node->value);
+ }
+
+ if (node->child) {
+ /* children */
+ if (!node->value[0]) {
+ ly_print(ctx->out, ">%s", ctx->level ? "\n" : "");
+ }
+
+ LEVEL_INC;
+ LY_LIST_FOR(node->child, child) {
+ ret = xml_print_node(ctx, child);
+ LY_CHECK_ERR_RET(ret, LEVEL_DEC, ret);
+ }
+ LEVEL_DEC;
+
+ ly_print(ctx->out, "%*s</%s>%s", INDENT, node->name, LEVEL ? "\n" : "");
+ } else if (node->value[0]) {
+ ly_print(ctx->out, "</%s>%s", node->name, LEVEL ? "\n" : "");
+ } else {
+ /* no value or children */
+ ly_print(ctx->out, "/>%s", ctx->level ? "\n" : "");
+ }
+
+ return LY_SUCCESS;
+}
+
/**
* @brief Print XML element representing lyd_node.
*
@@ -436,31 +479,46 @@
xml_print_node(struct xmlpr_ctx *ctx, const struct lyd_node *node)
{
LY_ERR ret = LY_SUCCESS;
+ uint32_t ns_count;
if (!ly_should_print(node, ctx->options)) {
/* do not print at all */
- return EXIT_SUCCESS;
+ return LY_SUCCESS;
}
- switch (node->schema->nodetype) {
- case LYS_CONTAINER:
- case LYS_LIST:
- case LYS_NOTIF:
- case LYS_ACTION:
- ret = xml_print_inner(ctx, (const struct lyd_node_inner*)node);
- break;
- case LYS_LEAF:
- case LYS_LEAFLIST:
- ret = xml_print_term(ctx, (const struct lyd_node_term*)node);
- break;
- case LYS_ANYXML:
- case LYS_ANYDATA:
- ret = xml_print_anydata(ctx, (const struct lyd_node_any*)node);
- break;
- default:
- LOGINT(node->schema->module->ctx);
- ret = LY_EINT;
- break;
+ /* remember namespace definition count on this level */
+ ns_count = ctx->ns.count;
+
+ if (!node->schema) {
+ ret = xml_print_opaq(ctx, (const struct lyd_node_opaq *)node);
+ } else {
+ switch (node->schema->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ case LYS_NOTIF:
+ case LYS_ACTION:
+ ret = xml_print_inner(ctx, (const struct lyd_node_inner *)node);
+ break;
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ xml_print_term(ctx, (const struct lyd_node_term *)node);
+ break;
+ case LYS_ANYXML:
+ case LYS_ANYDATA:
+ ret = xml_print_anydata(ctx, (const struct lyd_node_any *)node);
+ break;
+ default:
+ LOGINT(node->schema->module->ctx);
+ ret = LY_EINT;
+ break;
+ }
+ }
+
+ /* remove all added namespaces */
+ while (ns_count < ctx->ns.count) {
+ FREE_STRING(ctx->ctx, ctx->prefix.objs[ctx->prefix.count - 1]);
+ ly_set_rm_index(&ctx->prefix, ctx->prefix.count - 1, NULL);
+ ly_set_rm_index(&ctx->ns, ctx->ns.count - 1, NULL);
}
return ret;
@@ -470,7 +528,7 @@
xml_print_data(struct lyout *out, const struct lyd_node *root, int options)
{
const struct lyd_node *node;
- struct xmlpr_ctx ctx_ = {.out = out, .level = (options & LYDP_FORMAT ? 1 : 0), .options = options}, *ctx = &ctx_;
+ struct xmlpr_ctx ctx = {0};
if (!root) {
if (out->type == LYOUT_MEMORY || out->type == LYOUT_CALLBACK) {
@@ -479,18 +537,23 @@
goto finish;
}
+ ctx.out = out;
+ ctx.level = (options & LYDP_FORMAT ? 1 : 0);
+ ctx.options = options;
+ ctx.ctx = LYD_NODE_CTX(root);
+
/* content */
LY_LIST_FOR(root, node) {
- ctx_.toplevel = 1;
- if (xml_print_node(ctx, node)) {
- return EXIT_FAILURE;
- }
+ LY_CHECK_RET(xml_print_node(&ctx, node));
if (!(options & LYDP_WITHSIBLINGS)) {
break;
}
}
finish:
+ assert(!ctx.prefix.count && !ctx.ns.count);
+ ly_set_erase(&ctx.prefix, NULL);
+ ly_set_erase(&ctx.ns, NULL);
ly_print_flush(out);
return LY_SUCCESS;
}
diff --git a/src/set.c b/src/set.c
index 3b7f078..378a22e 100644
--- a/src/set.c
+++ b/src/set.c
@@ -16,6 +16,7 @@
#include <stdlib.h>
#include <string.h>
+#include <stdint.h>
#include "log.h"
#include "set.h"
@@ -33,7 +34,7 @@
API void
ly_set_clean(struct ly_set *set, void (*destructor)(void *obj))
{
- unsigned int u;
+ uint32_t u;
if (!set) {
return;
@@ -76,7 +77,7 @@
API int
ly_set_contains(const struct ly_set *set, void *object)
{
- unsigned int i;
+ uint32_t i;
LY_CHECK_ARG_RET(NULL, set, -1);
@@ -95,7 +96,7 @@
ly_set_dup(const struct ly_set *set, void *(*duplicator)(void *obj))
{
struct ly_set *new;
- unsigned int u;
+ uint32_t u;
LY_CHECK_ARG_RET(NULL, set, NULL);
@@ -119,10 +120,10 @@
API int
ly_set_add(struct ly_set *set, void *object, int options)
{
- unsigned int i;
+ uint32_t i;
void **new;
- LY_CHECK_ARG_RET(NULL, set, object, -1);
+ LY_CHECK_ARG_RET(NULL, set, -1);
if (!(options & LY_SET_OPT_USEASLIST)) {
/* search for duplication */
@@ -149,7 +150,7 @@
API int
ly_set_merge(struct ly_set *trg, struct ly_set *src, int options, void *(*duplicator)(void *obj))
{
- unsigned int u, c, ret = 0;
+ uint32_t u, c, ret = 0;
int i;
void *obj;
@@ -164,7 +165,7 @@
}
c = trg->count;
i = ly_set_add(trg, obj, options);
- if (i > 0 && (unsigned int)i == c) {
+ if (i > 0 && (unsigned)i == c) {
++ret;
}
}
@@ -173,7 +174,7 @@
}
API LY_ERR
-ly_set_rm_index(struct ly_set *set, unsigned int index, void (*destructor)(void *obj))
+ly_set_rm_index(struct ly_set *set, uint32_t index, void (*destructor)(void *obj))
{
LY_CHECK_ARG_RET(NULL, set, LY_EINVAL);
LY_CHECK_ERR_RET(index >= set->count, LOGARG(NULL, index), LY_EINVAL);
@@ -197,7 +198,7 @@
API LY_ERR
ly_set_rm(struct ly_set *set, void *object, void (*destructor)(void *obj))
{
- unsigned int i;
+ uint32_t i;
LY_CHECK_ARG_RET(NULL, set, object, LY_EINVAL);
diff --git a/src/set.h b/src/set.h
index 915e91e..2f09f2f 100644
--- a/src/set.h
+++ b/src/set.h
@@ -15,6 +15,8 @@
#ifndef LY_SET_H_
#define LY_SET_H_
+#include <stdint.h>
+
#include "log.h"
#ifdef __cplusplus
@@ -43,8 +45,8 @@
*/
struct ly_set
{
- unsigned int size; /**< allocated size of the set array */
- unsigned int count; /**< number of elements in (used size of) the set array */
+ uint32_t size; /**< allocated size of the set array */
+ uint32_t count; /**< number of elements in (used size of) the set array */
void **objs; /**< set array of generic object pointers */
};
@@ -104,7 +106,8 @@
int ly_set_merge(struct ly_set *trg, struct ly_set *src, int options, void *(*duplicator)(void *obj));
/**
- * @brief Get know if the set contains the specified object.
+ * @brief Learn whether the set contains the specified object.
+ *
* @param[in] set Set to explore.
* @param[in] object Object to be found in the set.
* @return Index of the object in the set or -1 if the object is not present in the set.
@@ -143,7 +146,7 @@
* @param[in] destructor Optional function to free the objects being removed.
* @return LY_ERR return value.
*/
-LY_ERR ly_set_rm_index(struct ly_set *set, unsigned int index, void (*destructor)(void *obj));
+LY_ERR ly_set_rm_index(struct ly_set *set, uint32_t index, void (*destructor)(void *obj));
/**
* @brief Free the ::ly_set data. If the destructor is not provided, it frees only the set structure
diff --git a/src/tree.h b/src/tree.h
index bf86260..32526f4 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -119,33 +119,6 @@
(ELEM) = (NEXT))
/**
- * @brief Generic tree node structure.
- */
-struct ly_node {
- LYD_FORMAT format;
- union {
- struct {
- const struct lysc_node *schema;
- struct lyd_meta *meta;
- } sch;
- struct {
- const char *name;
- struct ly_attr *attr;
- } xml;
- };
- const char *value;
-};
-
-/**
- * @brief Generic attribute structure.
- */
-struct ly_attr {
- struct ly_attr *next;
- const char *name;
- const char *value;
-};
-
-/**
* @brief YANG built-in types
*/
typedef enum
diff --git a/src/tree_data.c b/src/tree_data.c
index 634ede6..5026d4e 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -29,6 +29,7 @@
#include "tree_data_internal.h"
#include "hash_table.h"
#include "tree_schema.h"
+#include "xml.h"
#include "plugins_exts_metadata.h"
#include "plugins_exts_internal.h"
@@ -316,7 +317,7 @@
lyd_parse_lyb(ctx, data, options, trees, &result);
break;
#endif
- case LYD_UNKNOWN:
+ case LYD_SCHEMA:
LOGINT(ctx);
break;
}
@@ -659,6 +660,43 @@
return LY_SUCCESS;
}
+LY_ERR
+lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *value, size_t value_len,
+ int *dynamic, LYD_FORMAT format, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
+ const char *ns, struct lyd_node **node)
+{
+ struct lyd_node_opaq *opaq;
+
+ assert(ctx && name && name_len && ns);
+
+ if (!value_len) {
+ value = "";
+ }
+
+ opaq = calloc(1, sizeof *opaq);
+ LY_CHECK_ERR_RET(!opaq, LOGMEM(ctx), LY_EMEM);
+
+ opaq->prev = (struct lyd_node *)opaq;
+
+ opaq->name = lydict_insert(ctx, name, name_len);
+ opaq->format = format;
+ if (pref_len) {
+ opaq->prefix.pref = lydict_insert(ctx, prefix, pref_len);
+ }
+ opaq->prefix.ns = lydict_insert(ctx, ns, 0);
+ opaq->val_prefs = val_prefs;
+ if (dynamic && *dynamic) {
+ opaq->value = lydict_insert_zc(ctx, (char *)value);
+ *dynamic = 0;
+ } else {
+ opaq->value = lydict_insert(ctx, value, value_len);
+ }
+ opaq->ctx = ctx;
+
+ *node = (struct lyd_node *)opaq;
+ return LY_SUCCESS;
+}
+
API struct lyd_node *
lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name)
{
@@ -919,7 +957,7 @@
struct lyd_node_inner *par;
assert(parent && !node->next && (node->prev == node));
- assert(parent->schema->nodetype & LYD_NODE_INNER);
+ assert(!parent->schema || (parent->schema->nodetype & LYD_NODE_INNER));
par = (struct lyd_node_inner *)parent;
@@ -937,7 +975,7 @@
/* remove default flags from NP containers */
par->flags &= ~LYD_DEFAULT;
}
- if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
+ if (par->schema && (par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
/* rehash key-less list */
lyd_hash((struct lyd_node *)par);
}
@@ -954,14 +992,14 @@
const struct lysc_node *skey = NULL;
int has_keys;
- assert((parent || first_sibling) && node && node->hash);
+ assert((parent || first_sibling) && node && (node->hash || !node->schema));
if (!parent && first_sibling && (*first_sibling) && (*first_sibling)->parent) {
parent = (struct lyd_node *)(*first_sibling)->parent;
}
if (parent) {
- if (node->schema->flags & LYS_KEY) {
+ if (node->schema && (node->schema->flags & LYS_KEY)) {
/* it is key and we need to insert it at the correct place */
anchor = lyd_get_prev_key_anchor(lyd_node_children(parent), node->schema);
if (anchor) {
@@ -1275,7 +1313,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, int *dynamic, ly_clb_resolve_prefix get_prefix,
+ size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix resolve_prefix,
void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode)
{
LY_ERR ret;
@@ -1304,7 +1342,7 @@
LY_CHECK_ERR_RET(!mt, LOGMEM(mod->ctx), LY_EMEM);
mt->parent = parent;
mt->annotation = ant;
- ret = lyd_value_parse_meta(mod->ctx, mt, value, value_len, dynamic, 0, get_prefix, prefix_data, format, ctx_snode, NULL);
+ ret = lyd_value_parse_meta(mod->ctx, mt, value, value_len, dynamic, 0, resolve_prefix, prefix_data, format, ctx_snode, NULL);
if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
free(mt);
return ret;
@@ -1336,6 +1374,60 @@
return ret;
}
+LY_ERR
+ly_create_attr(struct lyd_node *parent, struct ly_attr **attr, const struct ly_ctx *ctx, const char *name,
+ size_t name_len, const char *value, size_t value_len, int *dynamic, LYD_FORMAT format,
+ struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *ns)
+{
+ struct ly_attr *at, *last;
+ struct lyd_node_opaq *opaq;
+
+ assert(ctx && (parent || attr) && (!parent || !parent->schema));
+ assert(name && name_len);
+ assert((prefix_len && ns) || (!prefix_len && !ns));
+
+ if (!value_len) {
+ value = "";
+ }
+
+ at = calloc(1, sizeof *at);
+ LY_CHECK_ERR_RET(!at, LOGMEM(ctx), LY_EMEM);
+ at->parent = (struct lyd_node_opaq *)parent;
+ at->name = lydict_insert(ctx, name, name_len);
+ if (dynamic && *dynamic) {
+ at->value = lydict_insert_zc(ctx, (char *)value);
+ *dynamic = 0;
+ } else {
+ at->value = lydict_insert(ctx, value, value_len);
+ }
+
+ at->format = format;
+ at->val_prefs = val_prefs;
+ if (ns) {
+ at->prefix.pref = lydict_insert(ctx, prefix, prefix_len);
+ at->prefix.ns = lydict_insert(ctx, ns, 0);
+ }
+
+ /* insert as the last attribute */
+ if (parent) {
+ opaq = (struct lyd_node_opaq *)parent;
+ if (opaq->attr) {
+ for (last = opaq->attr; last->next; last = last->next);
+ last->next = at;
+ } else {
+ opaq->attr = at;
+ }
+ } else if (*attr) {
+ for (last = *attr; last->next; last = last->next);
+ last->next = at;
+ }
+
+ if (attr) {
+ *attr = at;
+ }
+ return LY_SUCCESS;
+}
+
API const struct lyd_node_term *
lyd_target(struct lyd_value_path *path, const struct lyd_node *tree)
{
@@ -1415,6 +1507,7 @@
const struct lyd_node *iter1, *iter2;
struct lyd_node_term *term1, *term2;
struct lyd_node_any *any1, *any2;
+ struct lyd_node_opaq *opaq1, *opaq2;
struct lysc_type *type;
size_t len1, len2;
@@ -1426,212 +1519,251 @@
}
}
- if (node1->schema->module->ctx != node2->schema->module->ctx || node1->schema != node2->schema) {
+ if ((LYD_NODE_CTX(node1) != LYD_NODE_CTX(node2)) || (node1->schema != node2->schema)) {
return LY_ENOT;
}
if (node1->hash != node2->hash) {
return LY_ENOT;
}
+ /* equal hashes do not mean equal nodes, they can be just in collision (or both be 0) so the nodes must be checked explicitly */
- /* equal hashes do not mean equal nodes, they can be just in collision so the nodes must be checked explicitly */
-
- switch (node1->schema->nodetype) {
- case LYS_LEAF:
- case LYS_LEAFLIST:
- if (options & LYD_COMPARE_DEFAULTS) {
- if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
- return LY_ENOT;
- }
- }
-
- term1 = (struct lyd_node_term*)node1;
- term2 = (struct lyd_node_term*)node2;
- type = ((struct lysc_node_leaf*)node1->schema)->type;
-
- return type->plugin->compare(&term1->value, &term2->value);
- case LYS_CONTAINER:
- if (options & LYD_COMPARE_DEFAULTS) {
- if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
- return LY_ENOT;
- }
- }
- if (options & LYD_COMPARE_FULL_RECURSION) {
- iter1 = ((struct lyd_node_inner*)node1)->child;
- iter2 = ((struct lyd_node_inner*)node2)->child;
- goto all_children_compare;
- }
- return LY_SUCCESS;
- case LYS_ACTION:
- if (options & LYD_COMPARE_FULL_RECURSION) {
- /* TODO action/RPC
- goto all_children_compare;
- */
- }
- return LY_SUCCESS;
- case LYS_NOTIF:
- if (options & LYD_COMPARE_FULL_RECURSION) {
- /* TODO Notification
- goto all_children_compare;
- */
- }
- return LY_SUCCESS;
- case LYS_LIST:
- iter1 = ((struct lyd_node_inner*)node1)->child;
- iter2 = ((struct lyd_node_inner*)node2)->child;
-
- if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
- /* lists with keys, their equivalence is based on their keys */
- for (struct lysc_node *key = ((struct lysc_node_list*)node1->schema)->child;
- key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
- key = key->next) {
- if (lyd_compare(iter1, iter2, options)) {
- return LY_ENOT;
- }
- iter1 = iter1->next;
- iter2 = iter2->next;
- }
- } else {
- /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
-
-all_children_compare:
- if (!iter1 && !iter2) {
- /* no children, nothing to compare */
- return LY_SUCCESS;
- }
-
- for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
- if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
- return LY_ENOT;
- }
- }
- if (iter1 || iter2) {
- return LY_ENOT;
- }
- }
- return LY_SUCCESS;
- case LYS_ANYXML:
- case LYS_ANYDATA:
- any1 = (struct lyd_node_any*)node1;
- any2 = (struct lyd_node_any*)node2;
-
- if (any1->value_type != any2->value_type) {
+ if (!node1->schema) {
+ opaq1 = (struct lyd_node_opaq *)node1;
+ opaq2 = (struct lyd_node_opaq *)node2;
+ if ((opaq1->name != opaq2->name) || (opaq1->prefix.ns != opaq2->prefix.ns) || (opaq1->format != opaq2->format)) {
return LY_ENOT;
}
- switch (any1->value_type) {
- case LYD_ANYDATA_DATATREE:
- iter1 = any1->value.tree;
- iter2 = any2->value.tree;
+ switch (opaq1->format) {
+ case LYD_XML:
+ if (lyxml_value_compare(opaq1->value, opaq1->val_prefs, opaq2->value, opaq2->val_prefs)) {
+ return LY_ENOT;
+ }
+ break;
+ case LYD_SCHEMA:
+ /* not allowed */
+ LOGINT(LYD_NODE_CTX(node1));
+ return LY_EINT;
+ }
+ if (options & LYD_COMPARE_FULL_RECURSION) {
+ iter1 = opaq1->child;
+ iter2 = opaq2->child;
goto all_children_compare;
- case LYD_ANYDATA_STRING:
- case LYD_ANYDATA_XML:
- case LYD_ANYDATA_JSON:
- len1 = strlen(any1->value.str);
- len2 = strlen(any2->value.str);
- if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
- return LY_ENOT;
+ }
+ return LY_SUCCESS;
+ } else {
+ switch (node1->schema->nodetype) {
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ if (options & LYD_COMPARE_DEFAULTS) {
+ if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
+ return LY_ENOT;
+ }
+ }
+
+ term1 = (struct lyd_node_term*)node1;
+ term2 = (struct lyd_node_term*)node2;
+ type = ((struct lysc_node_leaf*)node1->schema)->type;
+
+ return type->plugin->compare(&term1->value, &term2->value);
+ case LYS_CONTAINER:
+ if (options & LYD_COMPARE_DEFAULTS) {
+ if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
+ return LY_ENOT;
+ }
+ }
+ if (options & LYD_COMPARE_FULL_RECURSION) {
+ iter1 = ((struct lyd_node_inner*)node1)->child;
+ iter2 = ((struct lyd_node_inner*)node2)->child;
+ goto all_children_compare;
}
return LY_SUCCESS;
-#if 0 /* TODO LYB format */
- case LYD_ANYDATA_LYB:
- int len1 = lyd_lyb_data_length(any1->value.mem);
- int len2 = lyd_lyb_data_length(any2->value.mem);
- if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
- return LY_ENOT;
+ case LYS_ACTION:
+ if (options & LYD_COMPARE_FULL_RECURSION) {
+ /* TODO action/RPC
+ goto all_children_compare;
+ */
}
return LY_SUCCESS;
-#endif
+ case LYS_NOTIF:
+ if (options & LYD_COMPARE_FULL_RECURSION) {
+ /* TODO Notification
+ goto all_children_compare;
+ */
+ }
+ return LY_SUCCESS;
+ case LYS_LIST:
+ iter1 = ((struct lyd_node_inner*)node1)->child;
+ iter2 = ((struct lyd_node_inner*)node2)->child;
+
+ if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
+ /* lists with keys, their equivalence is based on their keys */
+ for (struct lysc_node *key = ((struct lysc_node_list*)node1->schema)->child;
+ key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
+ key = key->next) {
+ if (lyd_compare(iter1, iter2, options)) {
+ return LY_ENOT;
+ }
+ iter1 = iter1->next;
+ iter2 = iter2->next;
+ }
+ } else {
+ /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
+
+ all_children_compare:
+ if (!iter1 && !iter2) {
+ /* no children, nothing to compare */
+ return LY_SUCCESS;
+ }
+
+ for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
+ if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
+ return LY_ENOT;
+ }
+ }
+ if (iter1 || iter2) {
+ return LY_ENOT;
+ }
+ }
+ return LY_SUCCESS;
+ case LYS_ANYXML:
+ case LYS_ANYDATA:
+ any1 = (struct lyd_node_any*)node1;
+ any2 = (struct lyd_node_any*)node2;
+
+ if (any1->value_type != any2->value_type) {
+ return LY_ENOT;
+ }
+ switch (any1->value_type) {
+ case LYD_ANYDATA_DATATREE:
+ iter1 = any1->value.tree;
+ iter2 = any2->value.tree;
+ goto all_children_compare;
+ case LYD_ANYDATA_STRING:
+ case LYD_ANYDATA_XML:
+ case LYD_ANYDATA_JSON:
+ len1 = strlen(any1->value.str);
+ len2 = strlen(any2->value.str);
+ if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
+ return LY_ENOT;
+ }
+ return LY_SUCCESS;
+ #if 0 /* TODO LYB format */
+ case LYD_ANYDATA_LYB:
+ int len1 = lyd_lyb_data_length(any1->value.mem);
+ int len2 = lyd_lyb_data_length(any2->value.mem);
+ if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
+ return LY_ENOT;
+ }
+ return LY_SUCCESS;
+ #endif
+ }
}
}
- LOGINT(node1->schema->module->ctx);
+ LOGINT(LYD_NODE_CTX(node1));
return LY_EINT;
}
/**
- * @brief Duplicates just a single node and interconnect it into a @p parent (if present) and after the @p prev
- * sibling (if present).
+ * @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().
*/
-static struct lyd_node *
-lyd_dup_recursive(const struct lyd_node *node, struct lyd_node_inner *parent, struct lyd_node *prev, int options)
+static LY_ERR
+lyd_dup_recursive(const struct lyd_node *node, struct lyd_node *parent, struct lyd_node **first, int options,
+ struct lyd_node **dup_p)
{
- struct ly_ctx *ctx;
+ LY_ERR ret;
struct lyd_node *dup = NULL;
+ uint32_t u;
- LY_CHECK_ARG_RET(NULL, node, NULL);
- ctx = node->schema->module->ctx;
+ LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
- switch (node->schema->nodetype) {
- case LYS_ACTION:
- case LYS_NOTIF:
- case LYS_CONTAINER:
- case LYS_LIST:
- dup = calloc(1, sizeof(struct lyd_node_inner));
- break;
- case LYS_LEAF:
- case LYS_LEAFLIST:
- dup = calloc(1, sizeof(struct lyd_node_term));
- break;
- case LYS_ANYDATA:
- case LYS_ANYXML:
- dup = calloc(1, sizeof(struct lyd_node_any));
- break;
- default:
- LOGINT(ctx);
- goto error;
+ if (!node->schema) {
+ dup = calloc(1, sizeof(struct lyd_node_opaq));
+ } else {
+ switch (node->schema->nodetype) {
+ case LYS_ACTION:
+ case LYS_NOTIF:
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ dup = calloc(1, sizeof(struct lyd_node_inner));
+ break;
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ dup = calloc(1, sizeof(struct lyd_node_term));
+ break;
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ dup = calloc(1, sizeof(struct lyd_node_any));
+ break;
+ default:
+ LOGINT(LYD_NODE_CTX(node));
+ ret = LY_EINT;
+ goto error;
+ }
}
+ LY_CHECK_ERR_GOTO(!dup, LOGMEM(LYD_NODE_CTX(node)); ret = LY_EMEM, error);
/* TODO implement LYD_DUP_WITH_WHEN */
dup->flags = node->flags;
dup->schema = node->schema;
-
- /* interconnect the node at the end */
- dup->parent = parent;
- if (prev) {
- dup->prev = prev;
- prev->next = dup;
- } else {
- dup->prev = dup;
- if (parent) {
- parent->child = dup;
- }
- }
- if (parent) {
- parent->child->prev = dup;
- } else if (prev) {
- struct lyd_node *first;
- for (first = prev; first->prev != prev; first = first->prev);
- first->prev = dup;
- }
+ dup->prev = dup;
/* TODO duplicate attributes, implement LYD_DUP_NO_ATTR */
/* nodetype-specific work */
- if (dup->schema->nodetype & LYD_NODE_TERM) {
- struct lyd_node_term *term = (struct lyd_node_term*)dup;
- struct lyd_node_term *orig = (struct lyd_node_term*)node;
-
- term->hash = orig->hash;
- term->value.realtype = orig->value.realtype;
- LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(ctx, &orig->value, &term->value),
- LOGERR(ctx, LY_EINT, "Value duplication failed."), error);
- } else if (dup->schema->nodetype & LYD_NODE_INNER) {
- struct lyd_node_inner *inner = (struct lyd_node_inner*)dup;
- struct lyd_node_inner *orig = (struct lyd_node_inner*)node;
- struct lyd_node *child, *last = NULL;
+ if (!dup->schema) {
+ struct lyd_node_opaq *opaq = (struct lyd_node_opaq *)dup;
+ struct lyd_node_opaq *orig = (struct lyd_node_opaq *)node;
+ struct lyd_node *child;
if (options & LYD_DUP_RECURSIVE) {
/* duplicate all the children */
LY_LIST_FOR(orig->child, child) {
- last = lyd_dup_recursive(child, inner, last, options);
- LY_CHECK_GOTO(!last, error);
+ LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
+ }
+ }
+ opaq->name = lydict_insert(LYD_NODE_CTX(node), orig->name, 0);
+ opaq->format = orig->format;
+ if (orig->prefix.pref) {
+ opaq->prefix.pref = lydict_insert(LYD_NODE_CTX(node), orig->prefix.pref, 0);
+ }
+ if (orig->prefix.ns) {
+ opaq->prefix.ns = lydict_insert(LYD_NODE_CTX(node), orig->prefix.ns, 0);
+ }
+ if (orig->val_prefs) {
+ LY_ARRAY_CREATE_GOTO(LYD_NODE_CTX(node), opaq->val_prefs, LY_ARRAY_SIZE(orig->val_prefs), ret, error);
+ LY_ARRAY_FOR(orig->val_prefs, u) {
+ opaq->val_prefs[u].pref = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].pref, 0);
+ opaq->val_prefs[u].ns = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].ns, 0);
+ LY_ARRAY_INCREMENT(opaq->val_prefs);
+ }
+ }
+ opaq->value = lydict_insert(LYD_NODE_CTX(node), orig->value, 0);
+ opaq->ctx = orig->ctx;
+ } else if (dup->schema->nodetype & LYD_NODE_TERM) {
+ struct lyd_node_term *term = (struct lyd_node_term *)dup;
+ struct lyd_node_term *orig = (struct lyd_node_term *)node;
+
+ term->hash = orig->hash;
+ term->value.realtype = orig->value.realtype;
+ LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &orig->value, &term->value),
+ LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."); ret = LY_EINT, error);
+ } else if (dup->schema->nodetype & LYD_NODE_INNER) {
+ struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
+ struct lyd_node *child;
+
+ if (options & LYD_DUP_RECURSIVE) {
+ /* duplicate all the children */
+ LY_LIST_FOR(orig->child, child) {
+ LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
}
} else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
/* always duplicate keys of a list */
child = orig->child;
- for (struct lysc_node *key = ((struct lysc_node_list*)dup->schema)->child;
+ for (struct lysc_node *key = ((struct lysc_node_list *)dup->schema)->child;
key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
key = key->next) {
if (!child) {
@@ -1642,14 +1774,14 @@
* but there can be also some non-key nodes */
continue;
}
- last = lyd_dup_recursive(child, inner, last, options);
+ LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
child = child->next;
}
}
lyd_hash(dup);
} else if (dup->schema->nodetype & LYD_NODE_ANY) {
- struct lyd_node_any *any = (struct lyd_node_any*)dup;
- struct lyd_node_any *orig = (struct lyd_node_any*)node;
+ struct lyd_node_any *any = (struct lyd_node_any *)dup;
+ struct lyd_node_any *orig = (struct lyd_node_any *)node;
any->hash = orig->hash;
any->value_type = orig->value_type;
@@ -1664,20 +1796,24 @@
case LYD_ANYDATA_XML:
case LYD_ANYDATA_JSON:
if (orig->value.str) {
- any->value.str = lydict_insert(ctx, orig->value.str, strlen(orig->value.str));
+ any->value.str = lydict_insert(LYD_NODE_CTX(node), orig->value.str, strlen(orig->value.str));
}
break;
}
}
+ /* insert */
+ lyd_insert_node(parent, first, dup);
lyd_insert_hash(dup);
- return dup;
+
+ if (dup_p) {
+ *dup_p = dup;
+ }
+ return LY_SUCCESS;
error:
- if (!parent && !prev) {
- lyd_free_tree(dup);
- }
- return NULL;
+ lyd_free_tree(dup);
+ return ret;
}
API struct lyd_node *
@@ -1686,7 +1822,6 @@
struct ly_ctx *ctx;
const struct lyd_node *orig; /* original node to be duplicated */
struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
- struct lyd_node *last = NULL; /* the last sibling of the duplicated nodes */
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) */
int keyless_parent_list = 0;
@@ -1710,8 +1845,9 @@
}
}
} else {
- iter = (struct lyd_node_inner*)lyd_dup_recursive((struct lyd_node*)orig_parent, NULL, NULL, 0);
- LY_CHECK_GOTO(!iter, error);
+ iter = NULL;
+ LY_CHECK_GOTO(lyd_dup_recursive((struct lyd_node *)orig_parent, NULL, (struct lyd_node **)&iter, 0,
+ (struct lyd_node **)&iter), error);
}
if (!local_parent) {
local_parent = iter;
@@ -1745,17 +1881,9 @@
local_parent = parent;
}
- if (local_parent && local_parent->child) {
- last = local_parent->child->prev;
- }
-
LY_LIST_FOR(node, orig) {
- last = lyd_dup_recursive(orig, local_parent, last, options);
- LY_CHECK_GOTO(!last, error);
- if (!first) {
- first = last;
- }
-
+ /* if there is no local parent, it will be inserted into first */
+ LY_CHECK_GOTO(lyd_dup_recursive(orig, (struct lyd_node *)local_parent, &first, options, first ? NULL : &first), error);
if (!(options & LYD_DUP_WITH_SIBLINGS)) {
break;
}
diff --git a/src/tree_data.h b/src/tree_data.h
index 34ddd46..80ecca5 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -108,16 +108,16 @@
/**
* @brief Macro to get context from a data tree node.
*/
-#define LYD_NODE_CTX(node) ((node)->schema->module->ctx)
+#define LYD_NODE_CTX(node) ((node)->schema ? (node)->schema->module->ctx : ((struct lyd_node_opaq *)(node))->ctx)
/**
* @brief Data input/output formats supported by libyang [parser](@ref howtodataparsers) and
- * [printer](@ref howtodataprinters) functions.
+ * [printer](@ref howtodataprinters) functions. Also used for value prefix format.
*/
typedef enum {
- LYD_UNKNOWN = 0, /**< unknown format, used as return value in case of error */
- LYD_XML, /**< XML format of the instance data */
- LYD_JSON, /**< JSON format of the instance data */
+ LYD_SCHEMA = 0, /**< invalid instance data format, value prefixes map to YANG import prefixes */
+ LYD_XML, /**< XML instance data format, value prefixes map to XML namespace prefixes */
+ LYD_JSON, /**< JSON instance data format, value prefixes map to module names */
#if 0
LYD_LYB, /**< LYB format of the instance data */
#endif
@@ -224,6 +224,28 @@
struct lyd_value value; /**< metadata value representation */
};
+/**
+ * @brief Generic prefix and namespace mapping, meaning depends on the format.
+ */
+struct ly_prefix {
+ const char *pref;
+ const char *ns;
+};
+
+/**
+ * @brief Generic attribute structure.
+ */
+struct ly_attr {
+ struct lyd_node_opaq *parent; /**< data node where the attribute is placed */
+ struct ly_attr *next;
+ struct ly_prefix *val_prefs; /**< list of prefixes in the value ([sized array](@ref sizedarrays)) */
+ const char *name;
+ const char *value;
+
+ LYD_FORMAT format;
+ struct ly_prefix prefix; /**< name prefix, it is stored because they are a real pain to generate properly */
+
+};
#define LYD_NODE_INNER (LYS_CONTAINER|LYS_LIST|LYS_ACTION|LYS_NOTIF) /**< Schema nodetype mask for lyd_node_inner */
#define LYD_NODE_TERM (LYS_LEAF|LYS_LEAFLIST) /**< Schema nodetype mask for lyd_node_term */
@@ -255,6 +277,7 @@
#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 */
+
/** @} */
/**
@@ -271,7 +294,8 @@
* @param[in] private Internal data needed by the callback.
* @return Pointer to the YANG schema identified by the provided prefix or NULL if no mapping found.
*/
-typedef const struct lys_module *(*ly_clb_resolve_prefix)(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *private);
+typedef const struct lys_module *(*ly_clb_resolve_prefix)(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len,
+ void *private);
/**
* @brief Callback provided by the data/schema printers to type plugins to resolve (format-specific) mapping between YANG module of a data object
@@ -396,6 +420,31 @@
};
/**
+ * @brief Data node structure for unparsed (opaque) nodes.
+ */
+struct lyd_node_opaq {
+ uint32_t hash; /**< always 0 */
+ uint32_t flags; /**< always 0 */
+ const struct lysc_node *schema; /**< always NULL */
+ struct lyd_node *parent; /**< pointer to the parent node (NULL in case of root node) */
+ struct lyd_node *next; /**< pointer to the next sibling node (NULL if there is no one) */
+ struct lyd_node *prev; /**< pointer to the previous sibling node (last sibling if there is none) */
+ struct ly_attr *attr;
+
+#ifdef LY_ENABLED_LYD_PRIV
+ void *priv; /**< private user data, not used by libyang */
+#endif
+
+ struct lyd_node *child; /**< pointer to the child node (NULL if there are none) */
+ const char *name;
+ LYD_FORMAT format;
+ struct ly_prefix prefix; /**< name prefix */
+ struct ly_prefix *val_prefs; /**< list of prefixes in the value ([sized array](@ref sizedarrays)) */
+ const char *value; /**< original value */
+ const struct ly_ctx *ctx; /**< libyang context */
+};
+
+/**
* @defgroup dataparseroptions Data parser options
* @ingroup datatree
*
@@ -422,24 +471,31 @@
*/
#define LYD_OPT_DATA 0x0 /**< Default type of data - complete datastore content with configuration as well as
- state data. */
-#define LYD_OPT_CONFIG LYD_OPT_NO_STATE /**< A configuration datastore - complete datastore without state data. */
-#define LYD_OPT_GET LYD_OPT_PARSE_ONLY /**< Data content from a NETCONF reply message to the NETCONF
- \<get\> operation. */
-#define LYD_OPT_GETCONFIG LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE /**< Data content from a NETCONF reply message to
- the NETCONF \<get-config\> operation. */
+ state data. */
+#define LYD_OPT_CONFIG LYD_OPT_NO_STATE
+ /**< A configuration datastore - complete datastore without state data. */
+#define LYD_OPT_GET LYD_OPT_PARSE_ONLY
+ /**< Data content from a NETCONF reply message to the NETCONF \<get\> operation. */
+#define LYD_OPT_GETCONFIG LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE
+ /**< Data content from a NETCONF reply message to the NETCONF \<get-config\> operation. */
+#define LYD_OPT_EDIT LYD_OPT_OPAQ
+ /**< Data content of a NETCONF RPC \<edit-config\> operation. */
-#define LYD_OPT_PARSE_ONLY 0x0001 /**< Data will be only parsed and no validation will be performed. When statements
- are kept unevaluated, union types may not be fully resolved, if-feature
- statements are not checked, and default values are not added (only the ones
- parsed are present). */
-#define LYD_OPT_TRUSTED 0x0002 /**< Data are considered trusted so they will be parsed as validated. If the parsed
- data are not valid, using this flag may lead to some unexpected behavior!
- This flag can be used only with #LYD_OPT_PARSE_ONLY. */
-#define LYD_OPT_STRICT 0x0004 /**< Instead of silently ignoring data without schema definition raise an error. */
-#define LYD_OPT_NO_STATE 0x0008 /**< Forbid state data in the parsed data. */
-#define LYD_OPT_MASK 0xFFFF /**< Mask for all the parser options. */
+#define LYD_OPT_PARSE_ONLY 0x0001 /**< Data will be only parsed and no validation will be performed. When statements
+ are kept unevaluated, union types may not be fully resolved, if-feature
+ statements are not checked, and default values are not added (only the ones
+ parsed are present). */
+#define LYD_OPT_TRUSTED 0x0002 /**< Data are considered trusted so they will be parsed as validated. If the parsed
+ data are not valid, using this flag may lead to some unexpected behavior!
+ This flag can be used only with #LYD_OPT_PARSE_ONLY. */
+#define LYD_OPT_STRICT 0x0004 /**< Instead of silently ignoring data without schema definition raise an error.
+ Do not combine with #LYD_OPT_OPAQ. */
+#define LYD_OPT_OPAQ 0x0008 /**< Instead of silently ignoring data without definition, parse them into
+ an opaq node. Do not combine with #LYD_OPT_STRICT. */
+#define LYD_OPT_NO_STATE 0x0010 /**< Forbid state data in the parsed data. */
+
+#define LYD_OPT_MASK 0xFFFF /**< Mask for all the parser options. */
/** @} dataparseroptions */
@@ -724,10 +780,20 @@
*
* @param[in] ctx Context where the metadata was created.
* @param[in] meta Metadata to destroy
- * @param[in] recursive Zero to destroy only the metadata (the metadata list is corrected),
+ * @param[in] recursive Zero to destroy only the single metadata (the metadata list is corrected),
* non-zero to destroy also all the subsequent metadata in the list.
*/
-void lyd_free_meta(struct ly_ctx *ctx, struct lyd_meta *meta, int recursive);
+void lyd_free_meta(const struct ly_ctx *ctx, struct lyd_meta *meta, int recursive);
+
+/**
+ * @brief Destroy attributes.
+ *
+ * @param[in] ctx Context where the attributes were created.
+ * @param[in] attr Attributes to destroy.
+ * @param[in] recursive Zero to destroy only the single attribute (the attribute list is corrected),
+ * non-zero to destroy also all the subsequent attributes in the list.
+ */
+void ly_free_attr(const struct ly_ctx *ctx, struct ly_attr *attr, int recursive);
/**
* @brief Check type restrictions applicable to the particular leaf/leaf-list with the given string @p value.
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index 7aa63ae..beb1f40 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -26,7 +26,7 @@
#include "plugins_types.h"
void
-lyd_value_free_path(struct ly_ctx *ctx, struct lyd_value_path *path)
+lyd_value_free_path(const struct ly_ctx *ctx, struct lyd_value_path *path)
{
unsigned int u, v;
@@ -43,7 +43,7 @@
}
API void
-lyd_free_meta(struct ly_ctx *ctx, struct lyd_meta *meta, int recursive)
+lyd_free_meta(const struct ly_ctx *ctx, struct lyd_meta *meta, int recursive)
{
struct lyd_meta *iter;
@@ -75,7 +75,7 @@
meta->next = NULL;
}
- for(iter = meta; iter; ) {
+ for (iter = meta; iter; ) {
meta = iter;
iter = iter->next;
@@ -85,52 +85,128 @@
}
}
+API void
+ly_free_attr(const struct ly_ctx *ctx, struct ly_attr *attr, int recursive)
+{
+ struct ly_attr *iter;
+ uint32_t u;
+
+ LY_CHECK_ARG_RET(NULL, ctx, );
+ if (!attr) {
+ return;
+ }
+
+ if (attr->parent) {
+ if (attr->parent->attr == attr) {
+ if (recursive) {
+ attr->parent->attr = NULL;
+ } else {
+ attr->parent->attr = attr->next;
+ }
+ } else {
+ for (iter = attr->parent->attr; iter->next != attr; iter = iter->next);
+ if (iter->next) {
+ if (recursive) {
+ iter->next = NULL;
+ } else {
+ iter->next = attr->next;
+ }
+ }
+ }
+ }
+
+ if (!recursive) {
+ attr->next = NULL;
+ }
+
+ for (iter = attr; iter; ) {
+ attr = iter;
+ iter = iter->next;
+
+ LY_ARRAY_FOR(attr->val_prefs, u) {
+ FREE_STRING(ctx, attr->val_prefs[u].pref);
+ FREE_STRING(ctx, attr->val_prefs[u].ns);
+ }
+ LY_ARRAY_FREE(attr->val_prefs);
+ FREE_STRING(ctx, attr->name);
+ FREE_STRING(ctx, attr->value);
+ FREE_STRING(ctx, attr->prefix.pref);
+ FREE_STRING(ctx, attr->prefix.ns);
+ free(attr);
+ }
+}
+
/**
* @brief Free Data (sub)tree.
- * @param[in] ctx libyang context.
* @param[in] node Data node to be freed.
* @param[in] top Recursion flag to unlink the root of the subtree being freed.
*/
static void
-lyd_free_subtree(struct ly_ctx *ctx, struct lyd_node *node, int top)
+lyd_free_subtree(struct lyd_node *node, int top)
{
struct lyd_node *iter, *next;
struct lyd_node *children;
+ struct lyd_node_opaq *opaq;
+ uint32_t u;
assert(node);
- /* remove children hash table in case of inner data node */
- if (node->schema->nodetype & LYD_NODE_INNER) {
- lyht_free(((struct lyd_node_inner*)node)->children_ht);
- ((struct lyd_node_inner*)node)->children_ht = NULL;
+ if (!node->schema) {
+ opaq = (struct lyd_node_opaq *)node;
/* free the children */
- children = (struct lyd_node*)lyd_node_children(node);
+ children = (struct lyd_node *)lyd_node_children(node);
LY_LIST_FOR_SAFE(children, next, iter) {
- lyd_free_subtree(ctx, iter, 0);
+ lyd_free_subtree(iter, 0);
+ }
+
+ FREE_STRING(LYD_NODE_CTX(opaq), opaq->name);
+ FREE_STRING(LYD_NODE_CTX(opaq), opaq->prefix.pref);
+ FREE_STRING(LYD_NODE_CTX(opaq), opaq->prefix.ns);
+ if (opaq->val_prefs) {
+ LY_ARRAY_FOR(opaq->val_prefs, u) {
+ FREE_STRING(LYD_NODE_CTX(opaq), opaq->val_prefs[u].pref);
+ FREE_STRING(LYD_NODE_CTX(opaq), opaq->val_prefs[u].ns);
+ }
+ LY_ARRAY_FREE(opaq->val_prefs);
+ }
+ FREE_STRING(LYD_NODE_CTX(opaq), opaq->value);
+ } else if (node->schema->nodetype & LYD_NODE_INNER) {
+ /* remove children hash table in case of inner data node */
+ lyht_free(((struct lyd_node_inner *)node)->children_ht);
+ ((struct lyd_node_inner *)node)->children_ht = NULL;
+
+ /* free the children */
+ children = (struct lyd_node *)lyd_node_children(node);
+ LY_LIST_FOR_SAFE(children, next, iter) {
+ lyd_free_subtree(iter, 0);
}
} else if (node->schema->nodetype & LYD_NODE_ANY) {
- switch (((struct lyd_node_any*)node)->value_type) {
+ switch (((struct lyd_node_any *)node)->value_type) {
case LYD_ANYDATA_DATATREE:
- lyd_free_all(((struct lyd_node_any*)node)->value.tree);
+ lyd_free_all(((struct lyd_node_any *)node)->value.tree);
break;
case LYD_ANYDATA_STRING:
case LYD_ANYDATA_XML:
case LYD_ANYDATA_JSON:
- FREE_STRING(node->schema->module->ctx, ((struct lyd_node_any*)node)->value.str);
+ FREE_STRING(LYD_NODE_CTX(node), ((struct lyd_node_any *)node)->value.str);
break;
#if 0 /* TODO LYB format */
case LYD_ANYDATA_LYB:
- free(((struct lyd_node_any*)node)->value.mem);
+ free(((struct lyd_node_any *)node)->value.mem);
break;
#endif
}
} else if (node->schema->nodetype & LYD_NODE_TERM) {
- ((struct lysc_node_leaf*)node->schema)->type->plugin->free(ctx, &((struct lyd_node_term*)node)->value);
+ ((struct lysc_node_leaf *)node->schema)->type->plugin->free(LYD_NODE_CTX(node), &((struct lyd_node_term *)node)->value);
}
- /* free the node's metadata */
- lyd_free_meta(ctx, node->meta, 1);
+ if (!node->schema) {
+ ly_free_attr(LYD_NODE_CTX(node), opaq->attr, 1);
+ } else {
+ /* free the node's metadata */
+ lyd_free_meta(LYD_NODE_CTX(node), node->meta, 1);
+ }
/* unlink only the nodes from the first level, nodes in subtree are freed all, so no unlink is needed */
if (top) {
@@ -147,7 +223,7 @@
return;
}
- lyd_free_subtree(node->schema->module->ctx, node, 1);
+ lyd_free_subtree(node, 1);
}
static void
@@ -161,7 +237,7 @@
/* get the first (top-level) sibling */
if (top) {
- for (; node->parent; node = (struct lyd_node*)node->parent);
+ for (; node->parent; node = (struct lyd_node *)node->parent);
}
while (node->prev->next) {
node = node->prev;
@@ -169,7 +245,7 @@
LY_LIST_FOR_SAFE(node, next, iter) {
/* in case of the top-level nodes (node->parent is NULL), no unlinking needed */
- lyd_free_subtree(iter->schema->module->ctx, iter, iter->parent ? 1 : 0);
+ lyd_free_subtree(iter, iter->parent ? 1 : 0);
}
}
diff --git a/src/tree_data_hash.c b/src/tree_data_hash.c
index 33104cc..ff64300 100644
--- a/src/tree_data_hash.c
+++ b/src/tree_data_hash.c
@@ -46,6 +46,10 @@
{
struct lyd_node *iter;
+ if (!node->schema) {
+ return LY_SUCCESS;
+ }
+
node->hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
node->hash = dict_hash_multi(node->hash, node->schema->name, strlen(node->schema->name));
@@ -117,7 +121,7 @@
{
struct lyd_node *iter;
- if (!node->parent) {
+ if (!node->parent || !node->schema || !node->parent->schema) {
/* nothing to do */
return LY_SUCCESS;
}
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index 90f5736..8328ad7 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -26,14 +26,19 @@
lyd_node_children_p(struct lyd_node *node)
{
assert(node);
- switch (node->schema->nodetype) {
- case LYS_CONTAINER:
- case LYS_LIST:
- case LYS_ACTION:
- case LYS_NOTIF:
- return &((struct lyd_node_inner*)node)->child;
- default:
- return NULL;
+
+ if (!node->schema) {
+ return &((struct lyd_node_opaq *)node)->child;
+ } else {
+ switch (node->schema->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ case LYS_ACTION:
+ case LYS_NOTIF:
+ return &((struct lyd_node_inner *)node)->child;
+ default:
+ return NULL;
+ }
}
}
@@ -59,7 +64,7 @@
{
const struct lysc_node *schema;
- if (!node) {
+ if (!node || !node->schema) {
return NULL;
}
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 2d92f2e..a942f77 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -18,6 +18,11 @@
#include "tree_data.h"
#include "plugins_types.h"
+#include <assert.h>
+#include <stddef.h>
+
+static_assert(offsetof(struct lyd_node, flags) == offsetof(struct lyd_node_opaq, flags), "");
+
/**
* @brief Check whether a node to be deleted is the first top-level sibling.
*
@@ -113,6 +118,28 @@
struct lyd_node **node);
/**
+ * @brief Create an opaque node.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] name Element name.
+ * @param[in] name_len Length of @p name, must be set correctly.
+ * @param[in] value String value to be parsed.
+ * @param[in] value_len Length of @p value, must be set correctly.
+ * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
+ * @param[in] format Input format of @p value and @p ns.
+ * @param[in] val_prefs Possible value prefixes, array is spent.
+ * @param[in] prefix Element prefix.
+ * @param[in] pref_len Length of @p prefix, must be set correctly.
+ * @param[in] ns Node namespace, meaning depends on @p format.
+ * @param[out] node Created node.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR value if an error occurred.
+ */
+LY_ERR lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *value, size_t value_len,
+ int *dynamic, LYD_FORMAT format, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
+ const char *ns, struct lyd_node **node);
+
+/**
* @brief Find the key after which to insert the new key.
*
* @param[in] first_sibling List first sibling.
@@ -135,9 +162,9 @@
void lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node);
/**
- * @brief Create and insert an attribute (last) into a parent.
+ * @brief Create and insert a metadata (last) into a parent.
*
- * @param[in] parent Parent of the attribute, can be NULL.
+ * @param[in] parent Parent of the metadata, can be NULL.
* @param[in,out] meta Metadata list to add at its end if @p parent is NULL, returned created attribute.
* @param[in] mod Metadata module (with the annotation definition).
* @param[in] name Attribute name.
@@ -145,7 +172,7 @@
* @param[in] value String value to be parsed.
* @param[in] value_len Length of @p value, must be set correctly.
* @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
- * @param[in] get_prefix Parser-specific getter to resolve prefixes used in the @p value string.
+ * @param[in] resolve_prefix Parser-specific getter to resolve prefixes used in the @p value string.
* @param[in] prefix_data User data for @p get_prefix.
* @param[in] format Input format of @p value.
* @param[in] ctx_snode Context node for value resolution in schema.
@@ -154,10 +181,33 @@
* @return LY_ERR value if an error occurred.
*/
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, int *dynamic, ly_clb_resolve_prefix get_prefix,
+ size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix resolve_prefix,
void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode);
/**
+ * @brief Create and insert a generic attribute (last) into a parent.
+ *
+ * @param[in] parent Parent of the attribute, can be NULL.
+ * @param[in,out] attr Attribute list to add at its end if @p parent is NULL, returned created attribute.
+ * @param[in] ctx libyang context.
+ * @param[in] name Attribute name.
+ * @param[in] name_len Length of @p name, must be set correctly.
+ * @param[in] value String value to be parsed.
+ * @param[in] value_len Length of @p value, must be set correctly.
+ * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
+ * @param[in] format Input format of @p value and @p ns.
+ * @param[in] val_prefs Possible value prefixes, array is spent.
+ * @param[in] prefix Attribute prefix.
+ * @param[in] prefix_len Attribute prefix length.
+ * @param[in] ns Attribute namespace, meaning depends on @p format.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR value if an error occurred.
+ */
+LY_ERR ly_create_attr(struct lyd_node *parent, struct ly_attr **attr, const struct ly_ctx *ctx, const char *name,
+ size_t name_len, const char *value, size_t value_len, int *dynamic, LYD_FORMAT format,
+ struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *ns);
+
+/**
* @brief Validate, canonize and store the given @p value into the node according to the node's type's rules.
*
* @param[in] node Data node for the @p value.
@@ -270,7 +320,7 @@
* @param[in] ctx libyang context.
* @param[in] path The structure ([sized array](@ref sizedarrays)) to free.
*/
-void lyd_value_free_path(struct ly_ctx *ctx, struct lyd_value_path *path);
+void lyd_value_free_path(const struct ly_ctx *ctx, struct lyd_value_path *path);
/**
* @brief Find the node, in the list, satisfying the given restrictions.
diff --git a/src/tree_schema.h b/src/tree_schema.h
index d139498..0d23f0c 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -21,9 +21,9 @@
#include <stdint.h>
#include <stdio.h>
+#include "tree_data.h"
#include "log.h"
#include "tree.h"
-#include "tree_data.h"
struct ly_ctx;
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index a9649e3..5dff020 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -6995,7 +6995,7 @@
do {
LY_ARRAY_FOR(node->when, j) {
when = node->when[j];
- ret = lyxp_atomize(when->cond, LYD_UNKNOWN, when->module, when->context,
+ ret = lyxp_atomize(when->cond, LYD_SCHEMA, when->module, when->context,
when->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, LYXP_SCNODE_SCHEMA);
if (ret != LY_SUCCESS) {
LOGVAL(set->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when->cond->expr);
@@ -7099,7 +7099,7 @@
/* check "when" */
LY_ARRAY_FOR(when, i) {
- ret = lyxp_atomize(when[i]->cond, LYD_UNKNOWN, when[i]->module, when[i]->context,
+ ret = lyxp_atomize(when[i]->cond, LYD_SCHEMA, when[i]->module, when[i]->context,
when[i]->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, opts);
if (ret != LY_SUCCESS) {
LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when[i]->cond->expr);
@@ -7137,7 +7137,7 @@
check_musts:
/* check "must" */
LY_ARRAY_FOR(musts, i) {
- ret = lyxp_atomize(musts[i].cond, LYD_UNKNOWN, musts[i].module, node, LYXP_NODE_ELEM, &tmp_set, opts);
+ ret = lyxp_atomize(musts[i].cond, LYD_SCHEMA, musts[i].module, node, LYXP_NODE_ELEM, &tmp_set, opts);
if (ret != LY_SUCCESS) {
LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid must restriction \"%s\".", musts[i].cond->expr);
goto cleanup;
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 3fd214a..4c65540 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -1678,7 +1678,7 @@
* In this case the @p prefix is searched in the list of imports' prefixes (not the prefixes of the imported modules themselves).
*/
const struct lys_module *
-lys_resolve_prefix(struct ly_ctx *UNUSED(ctx), const char *prefix, size_t prefix_len, void *private)
+lys_resolve_prefix(const struct ly_ctx *UNUSED(ctx), const char *prefix, size_t prefix_len, void *private)
{
return lys_module_find_prefix((const struct lys_module*)private, prefix, prefix_len);
}
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 457a596..9b927e0 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -194,7 +194,7 @@
*
* In this case the @p prefix is searched in the list of imports' prefixes (not the prefixes of the imported modules themselves).
*/
-const struct lys_module *lys_resolve_prefix(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *private);
+const struct lys_module *lys_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *private);
/**
* @brief Check the currently present prefixes in the module for collision with the new one.
diff --git a/src/validation.c b/src/validation.c
index b8168dd..5be3030 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -12,10 +12,13 @@
* https://opensource.org/licenses/BSD-3-Clause
*/
+#include "common.h"
+
#include <assert.h>
#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
-#include "common.h"
#include "xpath.h"
#include "tree_data_internal.h"
#include "tree_schema_internal.h"
@@ -96,7 +99,7 @@
}
/* evaluate when */
- ret = lyxp_eval(when->cond, LYD_UNKNOWN, when->module, ctx_node, ctx_node ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG,
+ ret = lyxp_eval(when->cond, LYD_SCHEMA, when->module, ctx_node, ctx_node ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG,
*tree, &xp_set, LYXP_SCHEMA);
lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
diff --git a/src/xml.c b/src/xml.c
index a65c1ba..ff76c31 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -487,6 +487,38 @@
}
LY_ERR
+lyxml_skip_element(struct lyxml_context *context, const char **input)
+{
+ LY_ERR ret;
+ unsigned int parents_count = context->elements.count;
+
+ while (context->elements.count >= parents_count) {
+ /* skip attributes */
+ while (context->status == LYXML_ATTRIBUTE) {
+ LY_CHECK_RET(lyxml_get_attribute(context, input, NULL, NULL, NULL, NULL));
+ }
+
+ /* skip content */
+ if (context->status == LYXML_ELEM_CONTENT) {
+ ret = lyxml_get_string(context, input, NULL, NULL, NULL, NULL, NULL);
+ if (ret && (ret != LY_EINVAL)) {
+ return ret;
+ }
+ }
+
+ if (context->status != LYXML_ELEMENT) {
+ LOGINT(context->ctx);
+ return LY_EINT;
+ }
+
+ /* nested element/closing element */
+ LY_CHECK_RET(lyxml_get_element(context, input, NULL, NULL, NULL, NULL));
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
lyxml_get_string(struct lyxml_context *context, const char **input, char **buffer, size_t *buffer_size, char **output,
size_t *length, int *dynamic)
{
@@ -837,91 +869,92 @@
unsigned int c;
size_t endtag_len;
int is_ns = 0;
- const char *ns_prefix = NULL;
- size_t ns_prefix_len = 0;
+ const char *ns_prefix;
+ size_t ns_prefix_len;
-start:
/* initialize output variables */
(*prefix) = (*name) = NULL;
(*prefix_len) = (*name_len) = 0;
- /* skip initial whitespaces */
- ign_xmlws(context, in);
+ do {
+ /* skip initial whitespaces */
+ ign_xmlws(context, in);
- if (in[0] == '\0') {
- /* EOF - not expected at this place */
- LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_EOF);
- return LY_EVALID;
- }
+ if (in[0] == '\0') {
+ /* EOF - not expected at this place */
+ LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_EOF);
+ return LY_EVALID;
+ }
- /* remember the identifier start before checking its format */
- id = in;
- rc = lyxml_check_qname(context, &in, &c, &endtag_len);
- LY_CHECK_RET(rc);
- if (c == ':') {
- /* we have prefixed identifier */
- endtag = in - endtag_len;
-
+ /* remember the identifier start before checking its format */
+ id = in;
rc = lyxml_check_qname(context, &in, &c, &endtag_len);
LY_CHECK_RET(rc);
+ if (c == ':') {
+ /* we have prefixed identifier */
+ endtag = in - endtag_len;
- (*prefix) = id;
- (*prefix_len) = endtag - id;
- id = endtag + 1;
- }
- if (!is_xmlws(c) && c != '=') {
- in = in - endtag_len;
- LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in), in, "whitespace or '='");
- return LY_EVALID;
- }
- in = in - endtag_len;
- (*name) = id;
- (*name_len) = in - id;
+ rc = lyxml_check_qname(context, &in, &c, &endtag_len);
+ LY_CHECK_RET(rc);
- /* eat '=' and stop at the value beginning */
- ign_xmlws(context, in);
- if (in[0] != '=') {
- LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in), in, "'='");
- return LY_EVALID;
- }
- ++in;
- ign_xmlws(context, in);
- if (in[0] != '\'' && in[0] != '"') {
- LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP,
- LY_VCODE_INSTREXP_len(in), in, "either single or double quotation mark");
- return LY_EVALID;
- }
- context->status = LYXML_ATTR_CONTENT;
-
- is_ns = 0;
- if (*prefix && *prefix_len == 5 && !strncmp(*prefix, "xmlns", 5)) {
- is_ns = 1;
- ns_prefix = *name;
- ns_prefix_len = *name_len;
- } else if (*name_len == 5 && !strncmp(*name, "xmlns", 5)) {
- is_ns = 1;
- }
- if (is_ns) {
- /* instead of attribute, we have namespace specification,
- * so process it automatically and then move to another attribute (if any) */
- char *value = NULL;
- size_t value_len = 0;
- int dynamic = 0;
-
- LY_CHECK_RET(lyxml_get_string(context, &in, &value, &value_len, &value, &value_len, &dynamic));
- if ((rc = lyxml_ns_add(context, ns_prefix, ns_prefix_len, dynamic ? value : strndup(value, value_len)))) {
- if (dynamic) {
- free(value);
- return rc;
- }
+ (*prefix) = id;
+ (*prefix_len) = endtag - id;
+ id = endtag + 1;
}
- if (context->status == LYXML_ATTRIBUTE) {
- goto start;
- } else {
+ if (!is_xmlws(c) && c != '=') {
+ in = in - endtag_len;
+ LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in), in, "whitespace or '='");
+ return LY_EVALID;
+ }
+ in = in - endtag_len;
+ (*name) = id;
+ (*name_len) = in - id;
+
+ /* eat '=' and stop at the value beginning */
+ ign_xmlws(context, in);
+ if (in[0] != '=') {
+ LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in), in, "'='");
+ return LY_EVALID;
+ }
+ ++in;
+ ign_xmlws(context, in);
+ if (in[0] != '\'' && in[0] != '"') {
+ LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP,
+ LY_VCODE_INSTREXP_len(in), in, "either single or double quotation mark");
+ return LY_EVALID;
+ }
+ context->status = LYXML_ATTR_CONTENT;
+
+ is_ns = 0;
+ if (*prefix && *prefix_len == 5 && !strncmp(*prefix, "xmlns", 5)) {
+ is_ns = 1;
+ ns_prefix = *name;
+ ns_prefix_len = *name_len;
+ } else if (*name_len == 5 && !strncmp(*name, "xmlns", 5)) {
+ is_ns = 1;
+ ns_prefix = NULL;
+ ns_prefix_len = 0;
+ }
+ if (is_ns) {
+ /* instead of attribute, we have namespace specification,
+ * so process it automatically and then move to another attribute (if any) */
+ char *value = NULL;
+ size_t value_len = 0;
+ int dynamic = 0;
+
+ LY_CHECK_RET(lyxml_get_string(context, &in, &value, &value_len, &value, &value_len, &dynamic));
+ if ((rc = lyxml_ns_add(context, ns_prefix, ns_prefix_len, dynamic ? value : strndup(value, value_len)))) {
+ if (dynamic) {
+ free(value);
+ return rc;
+ }
+ }
+
+ /* do not return ns */
(*prefix) = (*name) = NULL;
(*prefix_len) = (*name_len) = 0;
}
- }
+ } while (is_ns && (context->status == LYXML_ATTRIBUTE));
/* move caller's input */
(*input) = in;
@@ -980,3 +1013,118 @@
return ret;
}
+LY_ERR
+lyxml_get_prefixes(struct lyxml_context *ctx, const char *value, size_t value_len, struct ly_prefix **val_prefs)
+{
+ LY_ERR ret;
+ uint32_t u, c;
+ const struct lyxml_ns *ns;
+ const char *start, *stop;
+ struct ly_prefix *prefixes = NULL;
+ size_t len;
+
+ for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
+ size_t bytes;
+ ly_getutf8(&stop, &c, &bytes);
+ if (is_xmlqnamestartchar(c)) {
+ for (ly_getutf8(&stop, &c, &bytes);
+ is_xmlqnamechar(c) && (size_t)(stop - value) < value_len;
+ ly_getutf8(&stop, &c, &bytes));
+ stop = stop - bytes;
+ if (*stop == ':') {
+ /* we have a possible prefix */
+ len = stop - start;
+ ns = lyxml_ns_get(ctx, start, len);
+ if (ns) {
+ struct ly_prefix *p = NULL;
+
+ /* check whether we do not already have this prefix stored */
+ LY_ARRAY_FOR(prefixes, u) {
+ if (!ly_strncmp(prefixes[u].pref, start, len)) {
+ p = &prefixes[u];
+ break;
+ }
+ }
+ if (!p) {
+ LY_ARRAY_NEW_GOTO(ctx->ctx, prefixes, p, ret, error);
+ p->pref = lydict_insert(ctx->ctx, start, len);
+ p->ns = lydict_insert(ctx->ctx, ns->uri, 0);
+ } /* else the prefix already present */
+ }
+ }
+ stop = stop + bytes;
+ }
+ }
+
+ *val_prefs = prefixes;
+ return LY_SUCCESS;
+
+error:
+ LY_ARRAY_FOR(prefixes, u) {
+ lydict_remove(ctx->ctx, prefixes[u].pref);
+ }
+ LY_ARRAY_FREE(prefixes);
+ return ret;
+}
+
+LY_ERR
+lyxml_value_compare(const char *value1, const struct ly_prefix *prefs1, const char *value2, const struct ly_prefix *prefs2)
+{
+ const char *ptr1, *ptr2, *ns1, *ns2;
+ uint32_t u1, u2;
+ int len;
+
+ if (!value1 && !value2) {
+ return LY_SUCCESS;
+ }
+ if ((value1 && !value2) || (!value1 && value2)) {
+ return LY_ENOT;
+ }
+
+ ptr1 = value1;
+ ptr2 = value2;
+ while (ptr1[0] && ptr2[0]) {
+ if (ptr1[0] != ptr2[0]) {
+ /* it can be a start of prefix that maps to the same module */
+ ns1 = ns2 = NULL;
+ if (prefs1) {
+ /* find module of the first prefix, if any */
+ LY_ARRAY_FOR(prefs1, u1) {
+ len = strlen(prefs1[u1].pref);
+ if (!strncmp(ptr1, prefs1[u1].pref, len) && (ptr1[len] == ':')) {
+ ns1 = prefs1[u1].ns;
+ break;
+ }
+ }
+ }
+ if (prefs2) {
+ /* find module of the second prefix, if any */
+ LY_ARRAY_FOR(prefs2, u2) {
+ len = strlen(prefs2[u2].pref);
+ if (!strncmp(ptr2, prefs2[u2].pref, len) && (ptr2[len] == ':')) {
+ ns2 = prefs2[u2].ns;
+ break;
+ }
+ }
+ }
+
+ if (!ns1 || !ns2 || (ns1 != ns2)) {
+ /* not a prefix or maps to different namespaces */
+ break;
+ }
+
+ /* skip prefixes in both values (':' is skipped as iter) */
+ ptr1 += strlen(prefs1[u1].pref);
+ ptr2 += strlen(prefs2[u2].pref);
+ }
+
+ ++ptr1;
+ ++ptr2;
+ }
+ if (ptr1[0] || ptr2[0]) {
+ /* not a match or simply different lengths */
+ return LY_ENOT;
+ }
+
+ return LY_SUCCESS;
+}
diff --git a/src/xml.h b/src/xml.h
index 7965e7e..f81c49b 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -22,6 +22,7 @@
#include "set.h"
struct lyout;
+struct ly_prefix;
/* Macro to test if character is whitespace */
#define is_xmlws(c) (c == 0x20 || c == 0x9 || c == 0xa || c == 0xd)
@@ -105,6 +106,15 @@
const char **prefix, size_t *prefix_len, const char **name, size_t *name_len);
/**
+ * @brief Skip an element after its opening tag was parsed.
+ *
+ * @param[in] context XML context.
+ * @param[in,out] input Input string to process, updated according to the read data.
+ * @return LY_ERR values.
+ */
+LY_ERR lyxml_skip_element(struct lyxml_context *context, const char **input);
+
+/**
* @brief Parse input expecting an XML attribute (including XML namespace).
*
* Input string is not being modified, so the returned values are not NULL-terminated, instead their length
@@ -193,4 +203,29 @@
*/
void lyxml_context_clear(struct lyxml_context *context);
+/**
+ * @brief Find all possible prefixes in a value.
+ *
+ * @param[in] ctx XML context to use.
+ * @param[in] value Value to check.
+ * @param[in] value_len Value length.
+ * @param[out] val_prefs Array of found prefixes.
+ * @return LY_ERR value.
+ */
+LY_ERR lyxml_get_prefixes(struct lyxml_context *ctx, const char *value, size_t value_len, struct ly_prefix **val_prefs);
+
+/**
+ * @brief Compare values and their prefix mappings.
+ *
+ * @param[in] value1 First value.
+ * @param[in] prefs1 First value prefixes.
+ * @param[in] value2 Second value.
+ * @param[in] prefs2 Second value prefixes.
+ * @return LY_SUCCESS if values are equal.
+ * @return LY_ENOT if values are not equal.
+ * @return LY_ERR on error.
+ */
+LY_ERR lyxml_value_compare(const char *value1, const struct ly_prefix *prefs1, const char *value2,
+ const struct ly_prefix *prefs2);
+
#endif /* LY_XML_H_ */
diff --git a/src/xpath.c b/src/xpath.c
index f9a8009..e84bad9 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -298,7 +298,7 @@
* @return LY_ERR
*/
static LY_ERR
-cast_string_realloc(struct ly_ctx *ctx, uint16_t needed, char **str, uint16_t *used, uint16_t *size)
+cast_string_realloc(const struct ly_ctx *ctx, uint16_t needed, char **str, uint16_t *used, uint16_t *size)
{
if (*size - *used < needed) {
do {
@@ -4127,13 +4127,13 @@
if (mod && name) {
switch (set->format) {
- case LYD_UNKNOWN:
+ case LYD_SCHEMA:
rc = asprintf(&str, "%s:%s", lys_prefix_find_module(set->local_mod, mod), name);
break;
case LYD_JSON:
rc = asprintf(&str, "%s:%s", mod->name, name);
break;
- default:
+ case LYD_XML:
LOGINT_RET(set->ctx);
}
LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
@@ -5164,7 +5164,7 @@
pref_len = ptr - *qname;
switch (set->format) {
- case LYD_UNKNOWN:
+ case LYD_SCHEMA:
/* schema, search all local module imports */
mod = lys_module_find_prefix(set->local_mod, *qname, pref_len);
break;
@@ -5174,7 +5174,7 @@
mod = ly_ctx_get_module(set->ctx, str, NULL);
free(str);
break;
- default:
+ case LYD_XML:
LOGINT_RET(set->ctx);
}
diff --git a/tests/config.h.in b/tests/config.h.in
index 5943c07..57c2bd1 100644
--- a/tests/config.h.in
+++ b/tests/config.h.in
@@ -14,6 +14,8 @@
#ifndef LYTEST_CONFIG_H_
#define LYTEST_CONFIG_H_
+#define _GNU_SOURCE
+
#define UNUSED(x) @COMPILER_UNUSED_ATTR@
#define TESTS_SRC "@CMAKE_CURRENT_SOURCE_DIR@"
diff --git a/tests/features/test_types.c b/tests/features/test_types.c
index 7ed3789..038dcdb 100644
--- a/tests/features/test_types.c
+++ b/tests/features/test_types.c
@@ -769,7 +769,7 @@
/* dummy get_prefix callback for test_instanceid() */
const struct lys_module *
-test_instanceid_getprefix(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *private)
+test_instanceid_getprefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *private)
{
(void)ctx;
(void)prefix;
diff --git a/tests/src/test_parser_xml.c b/tests/src/test_parser_xml.c
index b5c3f4c..247ff0a 100644
--- a/tests/src/test_parser_xml.c
+++ b/tests/src/test_parser_xml.c
@@ -12,6 +12,8 @@
* https://opensource.org/licenses/BSD-3-Clause
*/
+#include "tests/config.h"
+
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
@@ -20,10 +22,9 @@
#include <stdio.h>
#include <string.h>
-#include "tests/config.h"
-
#include "../../src/context.h"
#include "../../src/tree_data_internal.h"
+#include "../../src/printer_data.h"
#define BUFSIZE 1024
char logbuf[BUFSIZE] = {0};
@@ -161,19 +162,32 @@
{
*state = test_anydata;
- const char *data = "<any xmlns=\"urn:tests:a\">"
- "<element1><x:element2 x:attr2=\"test\" xmlns:x=\"urn:x\">x:data</x:element2></element1><element1a/>"
- "</any>";
+ const char *data;
+ char *str;
struct lyd_node *tree;
- struct lyd_node_any *any;
+ data =
+ "<any xmlns=\"urn:tests:a\">"
+ "<element1>"
+ "<x:element2 x:attr2=\"test\" xmlns:a=\"urn:tests:a\" xmlns:x=\"urn:x\">a:data</x:element2>"
+ "</element1>"
+ "<element1a/>"
+ "</any>";
assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
assert_non_null(tree);
assert_int_equal(LYS_ANYDATA, tree->schema->nodetype);
assert_string_equal("any", tree->schema->name);
- any = (struct lyd_node_any*)tree;
- assert_int_equal(LYD_ANYDATA_XML, any->value_type);
- assert_string_equal("<element1><x:element2 x:attr2=\"test\" xmlns:x=\"urn:x\">x:data</x:element2></element1><element1a/>", any->value.xml);
+
+ lyd_print_mem(&str, tree, LYD_XML, 0);
+ assert_string_equal(str,
+ "<any xmlns=\"urn:tests:a\">"
+ "<element1>"
+ "<element2 xmlns=\"urn:x\" xmlns:x=\"urn:x\" x:attr2=\"test\" xmlns:a=\"urn:tests:a\">a:data</element2>"
+ "</element1>"
+ "<element1a/>"
+ "</any>"
+ );
+ free(str);
lyd_free_all(tree);
*state = NULL;
diff --git a/tests/src/test_printer_xml.c b/tests/src/test_printer_xml.c
index 83e14dc..f6cca7b 100644
--- a/tests/src/test_printer_xml.c
+++ b/tests/src/test_printer_xml.c
@@ -206,6 +206,8 @@
assert_non_null(tree = lyd_parse_mem(s->ctx, data, LYD_XML, LYD_VALOPT_DATA_ONLY));
assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, 0)) >= 0);
assert_int_equal(len, strlen(printed));
+ /* canonized */
+ data = "<any xmlns=\"urn:tests:types\"><somexml xmlns=\"example.com\"><x xmlns=\"url:x\"/></somexml></any>";
assert_string_equal(printed, data);
free(printed);
lyd_free_all(tree);
@@ -218,6 +220,38 @@
free(printed);
lyd_free_all(tree);
+ data =
+ "<any xmlns=\"urn:tests:types\">"
+ "<cont>"
+ "<defs:elem1 xmlns:defs=\"urn:tests:defs\">"
+ "<elem2 xmlns:defaults=\"urn:defaults\" defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\">"
+ "</elem2>"
+ "</defs:elem1>"
+ "</cont>"
+ "</any>";
+ assert_non_null(tree = lyd_parse_mem(s->ctx, data, LYD_XML, LYD_VALOPT_DATA_ONLY));
+ /* cont should be normally parsed */
+ assert_string_equal(tree->schema->name, "any");
+ assert_int_equal(((struct lyd_node_any *)tree)->value_type, LYD_ANYDATA_DATATREE);
+ assert_string_equal(((struct lyd_node_any *)tree)->value.tree->schema->name, "cont");
+ /* but its children not */
+ assert_null(((struct lyd_node_inner *)(((struct lyd_node_any *)tree)->value.tree))->child->schema);
+ assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, 0)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ /* canonized */
+ data =
+ "<any xmlns=\"urn:tests:types\">"
+ "<cont>"
+ "<elem1 xmlns=\"urn:tests:defs\">"
+ "<elem2 xmlns=\"urn:tests:types\" xmlns:defs=\"urn:tests:defs\" xmlns:defaults=\"urn:defaults\""
+ " defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\"/>"
+ "</elem1>"
+ "</cont>"
+ "</any>";
+ assert_string_equal(printed, data);
+ free(printed);
+ lyd_free_all(tree);
+
s->func = NULL;
}
diff --git a/tests/src/test_set.c b/tests/src/test_set.c
index 3e288b5..a4e4332 100644
--- a/tests/src/test_set.c
+++ b/tests/src/test_set.c
@@ -113,8 +113,6 @@
assert_int_equal(-1, ly_set_add(NULL, NULL, 0));
assert_string_equal(logbuf, "Invalid argument set (ly_set_add()).");
- assert_int_equal(-1, ly_set_add(&set, NULL, 0));
- assert_string_equal(logbuf, "Invalid argument object (ly_set_add()).");
assert_int_equal(-1, ly_set_merge(NULL, NULL, 0, NULL));
assert_string_equal(logbuf, "Invalid argument trg (ly_set_merge()).");
diff --git a/tests/src/test_validation.c b/tests/src/test_validation.c
index d81ea74..4ba2e7c 100644
--- a/tests/src/test_validation.c
+++ b/tests/src/test_validation.c
@@ -12,6 +12,8 @@
* https://opensource.org/licenses/BSD-3-Clause
*/
+#include "tests/config.h"
+
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
@@ -20,8 +22,6 @@
#include <stdio.h>
#include <string.h>
-#include "tests/config.h"
-
#include "../../src/context.h"
#include "../../src/tree_data_internal.h"
#include "../../src/printer_data.h"
@@ -966,13 +966,13 @@
"<d xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>"
"<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>"
"<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>"
- "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
- "<ll1 ncwd:default=\"true\">def1</ll1>"
- "<ll1 ncwd:default=\"true\">def2</ll1>"
- "<ll1 ncwd:default=\"true\">def3</ll1>"
- "<d ncwd:default=\"true\">15</d>"
- "<ll2 ncwd:default=\"true\">dflt1</ll2>"
- "<ll2 ncwd:default=\"true\">dflt2</ll2>"
+ "<cont xmlns=\"urn:tests:f\">"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>"
+ "<d xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>"
+ "<ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>"
+ "<ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>"
"</cont>");
free(str);
@@ -988,13 +988,13 @@
"<d xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>"
"<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>"
"<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>"
- "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
- "<ll1 ncwd:default=\"true\">def1</ll1>"
- "<ll1 ncwd:default=\"true\">def2</ll1>"
- "<ll1 ncwd:default=\"true\">def3</ll1>"
- "<d ncwd:default=\"true\">15</d>"
- "<ll2 ncwd:default=\"true\">dflt1</ll2>"
- "<ll2 ncwd:default=\"true\">dflt2</ll2>"
+ "<cont xmlns=\"urn:tests:f\">"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>"
+ "<d xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>"
+ "<ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>"
+ "<ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>"
"</cont>"
"<l xmlns=\"urn:tests:f\">value</l>");
free(str);
@@ -1011,13 +1011,13 @@
/* check data tree */
lyd_print_mem(&str, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG);
assert_string_equal(str,
- "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
- "<ll1 ncwd:default=\"true\">def1</ll1>"
- "<ll1 ncwd:default=\"true\">def2</ll1>"
- "<ll1 ncwd:default=\"true\">def3</ll1>"
- "<d ncwd:default=\"true\">15</d>"
- "<ll2 ncwd:default=\"true\">dflt1</ll2>"
- "<ll2 ncwd:default=\"true\">dflt2</ll2>"
+ "<cont xmlns=\"urn:tests:f\">"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>"
+ "<d xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>"
+ "<ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>"
+ "<ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>"
"</cont>"
"<l xmlns=\"urn:tests:f\">value</l>"
"<d xmlns=\"urn:tests:f\">15</d>"
@@ -1034,13 +1034,13 @@
/* check data tree */
lyd_print_mem(&str, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG);
assert_string_equal(str,
- "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
- "<ll1 ncwd:default=\"true\">def1</ll1>"
- "<ll1 ncwd:default=\"true\">def2</ll1>"
- "<ll1 ncwd:default=\"true\">def3</ll1>"
- "<d ncwd:default=\"true\">15</d>"
- "<ll2 ncwd:default=\"true\">dflt1</ll2>"
- "<ll2 ncwd:default=\"true\">dflt2</ll2>"
+ "<cont xmlns=\"urn:tests:f\">"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>"
+ "<d xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>"
+ "<ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>"
+ "<ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>"
"</cont>"
"<l xmlns=\"urn:tests:f\">value</l>"
"<d xmlns=\"urn:tests:f\">15</d>"
@@ -1056,13 +1056,13 @@
/* check data tree */
lyd_print_mem(&str, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG);
assert_string_equal(str,
- "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
- "<ll1 ncwd:default=\"true\">def1</ll1>"
- "<ll1 ncwd:default=\"true\">def2</ll1>"
- "<ll1 ncwd:default=\"true\">def3</ll1>"
- "<d ncwd:default=\"true\">15</d>"
- "<ll2 ncwd:default=\"true\">dflt1</ll2>"
- "<ll2 ncwd:default=\"true\">dflt2</ll2>"
+ "<cont xmlns=\"urn:tests:f\">"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>"
+ "<ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>"
+ "<d xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>"
+ "<ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>"
+ "<ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>"
"</cont>"
"<l xmlns=\"urn:tests:f\">value</l>"
"<d xmlns=\"urn:tests:f\">15</d>"
@@ -1078,7 +1078,7 @@
/* check data tree */
lyd_print_mem(&str, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG);
assert_string_equal(str,
- "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
+ "<cont xmlns=\"urn:tests:f\">"
"<ll1>def3</ll1>"
"<d>5</d>"
"<ll2>non-dflt</ll2>"
diff --git a/tools/lint/commands.c b/tools/lint/commands.c
index 90affdd..3bf8fb8 100644
--- a/tools/lint/commands.c
+++ b/tools/lint/commands.c
@@ -540,7 +540,7 @@
return LYD_LYB;
#endif
} else {
- return LYD_UNKNOWN;
+ return 0;
}
}
@@ -548,13 +548,13 @@
parse_data(char *filepath, int *options, const struct lyd_node *tree, const char *rpc_act_file,
struct lyd_node **result)
{
- LYD_FORMAT informat = LYD_UNKNOWN;
+ LYD_FORMAT informat = 0;
struct lyd_node *data = NULL, *rpc_act = NULL;
int opts = *options;
/* detect input format according to file suffix */
informat = detect_data_format(filepath);
- if (informat == LYD_UNKNOWN) {
+ if (!informat) {
fprintf(stderr, "Unable to resolve format of the input file, please add \".xml\", \".json\", or \".lyb\" suffix.\n");
return EXIT_FAILURE;
}
@@ -698,7 +698,7 @@
const char *out_path = NULL;
struct lyd_node *data = NULL;
struct lyd_node *tree = NULL;
- LYD_FORMAT outformat = LYD_UNKNOWN;
+ LYD_FORMAT outformat = 0;
FILE *output = stdout;
static struct option long_options[] = {
{"defaults", required_argument, 0, 'd'},
@@ -841,7 +841,7 @@
}
}
- if (outformat != LYD_UNKNOWN) {
+ if (outformat) {
lyd_print_file(output, data, outformat, LYDP_WITHSIBLINGS | LYDP_FORMAT | printopt);
}