tests NEW xml printer defaults
Also some parser bugfixes included and
extensions refactoring to fix invalid
memory access of reading freed extension definitions.
diff --git a/src/parser_xml.c b/src/parser_xml.c
index bc38598..da7ba5d 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -133,10 +133,9 @@
}
static LY_ERR
-lydxml_attributes(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, struct lyd_node *parent)
+lydxml_attributes(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, struct lyd_attr **attr)
{
LY_ERR ret = LY_EVALID, rc;
- struct lyd_attr *attr = NULL;
const struct lyxml_ns *ns;
struct lys_module *mod;
@@ -177,8 +176,8 @@
goto skip_attr;
}
- rc = lyd_create_attr(parent, mod, attr_data->name, attr_data->name_len, attr_data->value, attr_data->value_len,
- &attr_data->dynamic, lydxml_resolve_prefix, ctx, LYD_XML, &attr);
+ rc = lyd_create_attr(NULL, attr, mod, attr_data->name, attr_data->name_len, attr_data->value,
+ attr_data->value_len, &attr_data->dynamic, lydxml_resolve_prefix, ctx, LYD_XML);
if (rc == LY_EINCOMPLETE) {
ly_set_add(&ctx->incomplete_type_validation_attrs, attr, LY_SET_OPT_USEASLIST);
} else if (rc) {
@@ -217,6 +216,7 @@
size_t prefix_len, name_len;
struct ly_set attrs_data = {0};
const struct lyxml_ns *ns;
+ struct lyd_attr *attr;
const struct lysc_node *snode;
struct lys_module *mod;
unsigned int parents_count = ctx->elements.count;
@@ -237,11 +237,17 @@
continue;
}
}
+
+ attr = NULL;
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) {
ret = LY_EVALID;
goto cleanup;
}
+
+ /* create actual attributes so that prefixes are available in the context */
+ LY_CHECK_GOTO(ret = lydxml_attributes(ctx, &attrs_data, &attr), cleanup);
}
ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
@@ -397,7 +403,9 @@
}
/* add attributes */
- LY_CHECK_GOTO(ret = lydxml_attributes(ctx, &attrs_data, cur), cleanup);
+ assert(!cur->attr);
+ cur->attr = attr;
+ attr = NULL;
/* correct flags */
if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
@@ -425,6 +433,7 @@
cleanup:
free(buffer);
+ lyd_free_attr(ctx->ctx, attr, 1);
lyd_free_tree(cur);
for (unsigned int u = 0; u < attrs_data.count; ++u) {
if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index 2313821..0b2a5bd 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -129,6 +129,16 @@
void lysc_extension_instance_free(struct ly_ctx *ctx, struct lysc_ext_substmt *substmts);
/**
+ * @brief Duplicate the compiled extension (definition) structure.
+ * TODO should this be in API? currently required for nacm_compile()
+ * Instead of duplicating memory, the reference counter in the @p orig is increased.
+ *
+ * @param[in] orig The extension structure to duplicate.
+ * @return The duplicated structure to use.
+ */
+struct lysc_ext *lysc_ext_dup(struct lysc_ext *orig);
+
+/**
* @brief Update path in the compile context, which is used for logging where the compilation failed.
*
* @param[in] ctx Compile context with the path.
diff --git a/src/plugins_exts_nacm.c b/src/plugins_exts_nacm.c
index 992aa04..35b23d7 100644
--- a/src/plugins_exts_nacm.c
+++ b/src/plugins_exts_nacm.c
@@ -98,7 +98,7 @@
/* duplicate this one to inherit it to the child */
LY_ARRAY_NEW_RET(cctx->ctx, iter->exts, inherited, LY_EMEM);
- inherited->def = c_ext->def;
+ inherited->def = lysc_ext_dup(c_ext->def);
inherited->parent = iter;
inherited->parent_type = LYEXT_PAR_NODE;
if (c_ext->argument) {
diff --git a/src/printer.c b/src/printer.c
index 6efb076..6b03c01 100644
--- a/src/printer.c
+++ b/src/printer.c
@@ -64,14 +64,7 @@
{"unique", "tag", 0}, /**< LYEXT_SUBSTMT_UNIQUE */
};
-/**
- * @brief Check whether a node value equals to its default one.
- *
- * @param[in] node Term node to test.
- * @return 0 if no,
- * @return non-zero if yes.
- */
-static int
+int
ly_is_default(const struct lyd_node *node)
{
const struct lysc_node_leaf *leaf;
diff --git a/src/printer_internal.h b/src/printer_internal.h
index 7d1ecee..25b0afb 100644
--- a/src/printer_internal.h
+++ b/src/printer_internal.h
@@ -120,6 +120,15 @@
LY_ERR xml_print_data(struct lyout *out, const struct lyd_node *root, int options);
/**
+ * @brief Check whether a node value equals to its default one.
+ *
+ * @param[in] node Term node to test.
+ * @return 0 if no,
+ * @return non-zero if yes.
+ */
+int ly_is_default(const struct lyd_node *node);
+
+/**
* @brief Check whether the node should even be printed.
*
* @param[in] node Node to check.
diff --git a/src/printer_xml.c b/src/printer_xml.c
index 0e439d2..1dce096 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -80,11 +80,9 @@
{
struct lyd_node *next, *cur, *child;
struct lyd_attr *attr;
-
struct mlist *mlist = NULL, *miter;
-#if 0
const struct lys_module *wdmod = NULL;
-#endif
+
/* add node attribute modules */
for (attr = node->attr; attr; attr = attr->next) {
if (!strcmp(node->schema->name, "filter") &&
@@ -101,30 +99,28 @@
switch (node->schema->nodetype) {
case LYS_LEAFLIST:
case LYS_LEAF:
- /* TODO ietf-netconf-with-defaults namespace */
-#if 0
- if (node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) {
+ /* 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(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
+ wdmod = ly_ctx_get_module_latest(node->schema->module->ctx, "ietf-netconf-with-defaults");
if (wdmod && modlist_add(&mlist, wdmod)) {
goto print;
}
}
-#endif
break;
case LYS_CONTAINER:
case LYS_LIST:
case LYS_ACTION:
case LYS_NOTIF:
-#if 0
- if (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG)) {
+ if (ctx->options & (LYDP_WD_ALL_TAG | LYDP_WD_IMPL_TAG)) {
/* get with-defaults module and print its namespace */
- wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
+ wdmod = ly_ctx_get_module_latest(node->schema->module->ctx, "ietf-netconf-with-defaults");
if (wdmod && modlist_add(&mlist, wdmod)) {
goto print;
}
}
-#endif
+
LY_LIST_FOR(((struct lyd_node_inner*)node)->child, child) {
LYD_TREE_DFS_BEGIN(child, next, cur) {
for (attr = cur->attr; attr; attr = attr->next) {
@@ -176,12 +172,12 @@
xml_print_attrs(struct xmlpr_ctx *ctx, const struct lyd_node *node)
{
struct lyd_attr *attr;
+ const struct lys_module *wdmod = NULL;
#if 0
const char **prefs, **nss;
const char *xml_expr = NULL, *mod_name;
uint32_t ns_count, i;
int rpc_filter = 0;
- const struct lys_module *wdmod = NULL;
char *p;
size_t len;
#endif
@@ -189,20 +185,20 @@
int dynamic;
unsigned int u;
-#if 0
/* with-defaults */
- if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
- if ((node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) ||
- (!node->dflt && (options & LYP_WD_ALL_TAG) && lyd_wd_default((struct lyd_node_leaf_list *)node))) {
+ 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(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
+ 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(out, " %s:default=\"true\"", wdmod->prefix);
+ ly_print(ctx->out, " %s:default=\"true\"", wdmod->prefix);
}
}
}
+#if 0
/* technically, check for the extension get-filter-element-attributes from ietf-netconf */
if (!strcmp(node->schema->name, "filter")
&& (!strcmp(node->schema->module->name, "ietf-netconf") || !strcmp(node->schema->module->name, "notifications"))) {
@@ -303,12 +299,12 @@
const char *value;
LY_CHECK_RET(xml_print_node_open(ctx, (struct lyd_node *)node));
- value = node->value.realtype->plugin->print(&node->value, LYD_XML, xml_print_get_prefix, &ns_list, &dynamic);
+ 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 */
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, "%sxmlns:%s=\"%s\"", u ? " " : "", mod->prefix, mod->ns);
+ const struct lys_module *mod = (const struct lys_module *)ns_list.objs[u];
+ ly_print(ctx->out, " xmlns:%s=\"%s\"", mod->prefix, mod->ns);
}
ly_set_erase(&ns_list, NULL);
@@ -320,7 +316,7 @@
ly_print(ctx->out, "</%s>%s", node->schema->name, LEVEL ? "\n" : "");
}
if (dynamic) {
- free((void*)value);
+ free((void *)value);
}
return LY_SUCCESS;
@@ -474,7 +470,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, .toplevel = 1}, *ctx = &ctx_;
+ struct xmlpr_ctx ctx_ = {.out = out, .level = (options & LYDP_FORMAT ? 1 : 0), .options = options}, *ctx = &ctx_;
if (!root) {
if (out->type == LYOUT_MEMORY || out->type == LYOUT_CALLBACK) {
@@ -485,6 +481,7 @@
/* content */
LY_LIST_FOR(root, node) {
+ ctx_.toplevel = 1;
if (xml_print_node(ctx, node)) {
return EXIT_FAILURE;
}
diff --git a/src/tree_data.c b/src/tree_data.c
index b441363..f3c049f 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -877,15 +877,17 @@
}
LY_ERR
-lyd_create_attr(struct lyd_node *parent, 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, void *prefix_data,
- LYD_FORMAT format, struct lyd_attr **attr)
+lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, 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,
+ void *prefix_data, LYD_FORMAT format)
{
LY_ERR ret;
struct lysc_ext_instance *ant = NULL;
struct lyd_attr *at, *last;
uint32_t v;
+ assert(parent || attr);
+
LY_ARRAY_FOR(mod->compiled->exts, v) {
if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
!ly_strncmp(mod->compiled->exts[v].argument, name, name_len)) {
@@ -912,12 +914,17 @@
}
at->name = lydict_insert(mod->ctx, name, name_len);
- /* insert into parent as the last attribute */
- if (parent->attr) {
- for (last = parent->attr; last->next; last = last->next);
+ /* insert as the last attribute */
+ if (parent) {
+ if (parent->attr) {
+ for (last = parent->attr; last->next; last = last->next);
+ last->next = at;
+ } else {
+ parent->attr = at;
+ }
+ } else if (*attr) {
+ for (last = *attr; last->next; last = last->next);
last->next = at;
- } else {
- parent->attr = at;
}
/* remove default flags from NP containers */
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 8b53af2..3e6b1de 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -128,7 +128,8 @@
/**
* @brief Create and insert an attribute (last) into a parent.
*
- * @param[in] parent Parent of the attribute.
+ * @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] mod Attribute module (with the annotation definition).
* @param[in] name Attribute name.
* @param[in] name_len Length of @p name.
@@ -138,14 +139,13 @@
* @param[in] get_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[out] attr CReated attribute.
* @return LY_SUCCESS on success.
* @return LY_EINCOMPLETE in case data tree is needed to finish the validation.
* @return LY_ERR value if an error occurred.
*/
-LY_ERR lyd_create_attr(struct lyd_node *parent, 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, void *prefix_data,
- LYD_FORMAT format, struct lyd_attr **attr);
+LY_ERR lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, 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, void *prefix_data, LYD_FORMAT format);
/**
* @brief Validate, canonize and store the given @p value into the node according to the node's type's rules.
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 0182dea..ace3bfd 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1115,6 +1115,7 @@
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
struct lyext_plugin *plugin; /**< Plugin implementing the specific extension */
struct lys_module *module; /**< module structure */
+ uint32_t refcount; /**< reference counter since extension definition is shared among all its instances */
uint16_t flags; /**< LYS_STATUS_* value (@ref snodeflags) */
};
@@ -1644,7 +1645,7 @@
struct lysc_node *data; /**< list of module's top-level data nodes (linked list) */
struct lysc_action *rpcs; /**< list of RPCs ([sized array](@ref sizedarrays)) */
struct lysc_notif *notifs; /**< list of notifications ([sized array](@ref sizedarrays)) */
- struct lysc_ext *extensions; /**< list of the extension definitions ([sized array](@ref sizedarrays)) */
+ struct lysc_ext **extensions; /**< list of pointers to extension definitions ([sized array](@ref sizedarrays)) */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
};
@@ -1776,7 +1777,7 @@
from if-feature statements of the compiled schemas and their proper use in case
the module became implemented in future (no matter if implicitly via augment/deviate
or explicitly via ly_ctx_module_implement()). */
- struct lysc_ext *off_extensions; /**< List of pre-compiled extension definitions of the module in non-implemented modules
+ struct lysc_ext **off_extensions;/**< List of pointers to pre-compiled extension definitions of the module in non-implemented modules
([sized array](@ref sizedarrays)). These extensions are prepared to be linked with the extension instances,
but they are not implemented (connected with any extension plugin). In case the module become
implemented, the list is moved into the compiled module structure and available extension plugins
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index f18074c..064e6cd 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -101,7 +101,7 @@
LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
}
-#define COMPILE_CHECK_UNIQUENESS(CTX, ARRAY, MEMBER, EXCL, STMT, IDENT) \
+#define COMPILE_CHECK_UNIQUENESS_ARRAY(CTX, ARRAY, MEMBER, EXCL, STMT, IDENT) \
if (ARRAY) { \
for (unsigned int u__ = 0; u__ < LY_ARRAY_SIZE(ARRAY); ++u__) { \
if (&(ARRAY)[u__] != EXCL && (void*)((ARRAY)[u__].MEMBER) == (void*)(IDENT)) { \
@@ -111,10 +111,27 @@
} \
}
+#define COMPILE_CHECK_UNIQUENESS_PARRAY(CTX, ARRAY, MEMBER, EXCL, STMT, IDENT) \
+ if (ARRAY) { \
+ for (unsigned int u__ = 0; u__ < LY_ARRAY_SIZE(ARRAY); ++u__) { \
+ if (&(ARRAY)[u__] != EXCL && (void*)((ARRAY)[u__]->MEMBER) == (void*)(IDENT)) { \
+ LOGVAL((CTX)->ctx, LY_VLOG_STR, (CTX)->path, LY_VCODE_DUPIDENT, IDENT, STMT); \
+ return LY_EVALID; \
+ } \
+ } \
+ }
+
+struct lysc_ext *
+lysc_ext_dup(struct lysc_ext *orig)
+{
+ ++orig->refcount;
+ return orig;
+}
+
static struct lysc_ext_instance *
lysc_ext_instance_dup(struct ly_ctx *ctx, struct lysc_ext_instance *orig)
{
- /* TODO - extensions */
+ /* TODO - extensions, increase refcount */
(void) ctx;
(void) orig;
return NULL;
@@ -431,7 +448,7 @@
const char *name;
unsigned int u;
const struct lys_module *mod;
- struct lysc_ext *elist = NULL;
+ struct lysc_ext **elist = NULL;
const char *prefixed_name = NULL;
DUP_STRING(ctx->ctx, ext_p->argument, ext->argument);
@@ -494,8 +511,8 @@
elist = mod->compiled->extensions;
}
LY_ARRAY_FOR(elist, u) {
- if (!strcmp(name, elist[u].name)) {
- ext->def = &elist[u];
+ if (!strcmp(name, elist[u]->name)) {
+ ext->def = lysc_ext_dup(elist[u]);
break;
}
}
@@ -575,14 +592,16 @@
* @brief Fill in the prepared compiled extensions definition structure according to the parsed extension definition.
*/
static LY_ERR
-lys_compile_extension(struct lysc_ctx *ctx, struct lysp_ext *ext_p, struct lysc_ext *ext)
+lys_compile_extension(struct lysc_ctx *ctx, struct lysp_ext *ext_p, struct lysc_ext **ext)
{
LY_ERR ret = LY_SUCCESS;
- DUP_STRING(ctx->ctx, ext_p->name, ext->name);
- DUP_STRING(ctx->ctx, ext_p->argument, ext->argument);
- ext->module = ctx->mod_def;
- COMPILE_EXTS_GOTO(ctx, ext_p->exts, ext->exts, ext, LYEXT_PAR_EXT, ret, done);
+ *ext = calloc(1, sizeof **ext);
+ (*ext)->refcount = 1;
+ DUP_STRING(ctx->ctx, ext_p->name, (*ext)->name);
+ DUP_STRING(ctx->ctx, ext_p->argument, (*ext)->argument);
+ (*ext)->module = ctx->mod_def;
+ COMPILE_EXTS_GOTO(ctx, ext_p->exts, (*ext)->exts, *ext, LYEXT_PAR_EXT, ret, done);
done:
return ret;
@@ -594,21 +613,21 @@
* This is done only in the compiled (implemented) module. Extensions of a non-implemented modules
* are not connected with even available extension plugins.
*
- * @param[in] extensions List of extensions to be processed ([sized array](@ref sizedarrays)).
+ * @param[in] extensions List of pointers to extensions to be processed ([sized array](@ref sizedarrays)).
*/
static void
-lys_compile_extension_plugins(struct lysc_ext *extensions)
+lys_compile_extension_plugins(struct lysc_ext **extensions)
{
unsigned int u;
LY_ARRAY_FOR(extensions, u) {
- extensions[u].plugin = lyext_get_plugin(&extensions[u]);
+ extensions[u]->plugin = lyext_get_plugin(extensions[u]);
}
}
LY_ERR
lys_extension_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lys_module *module,
- struct lysp_ext *extensions_p, struct lysc_ext **extensions)
+ struct lysp_ext *extensions_p, struct lysc_ext ***extensions)
{
unsigned int offset = 0, u;
struct lysc_ctx context = {0};
@@ -636,8 +655,8 @@
LY_ARRAY_FOR(extensions_p, u) {
lysc_update_path(ctx_sc, NULL, extensions_p[u].name);
LY_ARRAY_INCREMENT(*extensions);
- COMPILE_CHECK_UNIQUENESS(ctx_sc, *extensions, name, &(*extensions)[offset + u], "extension", extensions_p[u].name);
LY_CHECK_RET(lys_compile_extension(ctx_sc, &extensions_p[u], &(*extensions)[offset + u]));
+ COMPILE_CHECK_UNIQUENESS_PARRAY(ctx_sc, *extensions, name, &(*extensions)[offset + u], "extension", extensions_p[u].name);
lysc_update_path(ctx_sc, NULL, NULL);
}
lysc_update_path(ctx_sc, NULL, NULL);
@@ -969,7 +988,7 @@
lysc_update_path(ctx, NULL, ident_p->name);
- COMPILE_CHECK_UNIQUENESS(ctx, idents, name, ident, "identity", ident_p->name);
+ COMPILE_CHECK_UNIQUENESS_ARRAY(ctx, idents, name, ident, "identity", ident_p->name);
DUP_STRING(ctx->ctx, ident_p->name, ident->name);
DUP_STRING(ctx->ctx, ident_p->dsc, ident->dsc);
DUP_STRING(ctx->ctx, ident_p->ref, ident->ref);
@@ -1175,7 +1194,7 @@
lysc_update_path(ctx_sc, NULL, features_p[u].name);
LY_ARRAY_INCREMENT(*features);
- COMPILE_CHECK_UNIQUENESS(ctx_sc, *features, name, &(*features)[offset + u], "feature", features_p[u].name);
+ COMPILE_CHECK_UNIQUENESS_ARRAY(ctx_sc, *features, name, &(*features)[offset + u], "feature", features_p[u].name);
DUP_STRING(ctx_sc->ctx, features_p[u].name, (*features)[offset + u].name);
DUP_STRING(ctx_sc->ctx, features_p[u].dsc, (*features)[offset + u].dsc);
DUP_STRING(ctx_sc->ctx, features_p[u].ref, (*features)[offset + u].ref);
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 2471de0..deaf20c 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -465,19 +465,24 @@
}
void
+lysc_extension_free(struct ly_ctx *ctx, struct lysc_ext **ext)
+{
+ if (--(*ext)->refcount) {
+ return;
+ }
+ FREE_STRING(ctx, (*ext)->name);
+ FREE_STRING(ctx, (*ext)->argument);
+ FREE_ARRAY(ctx, (*ext)->exts, lysc_ext_instance_free);
+ free(*ext);
+}
+
+void
lysc_ext_instance_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
{
if (ext->def && ext->def->plugin && ext->def->plugin->free) {
ext->def->plugin->free(ctx, ext);
}
- FREE_STRING(ctx, ext->argument);
- FREE_ARRAY(ctx, ext->exts, lysc_ext_instance_free);
-}
-
-void
-lysc_extension_free(struct ly_ctx *ctx, struct lysc_ext *ext)
-{
- FREE_STRING(ctx, ext->name);
+ lysc_extension_free(ctx, &ext->def);
FREE_STRING(ctx, ext->argument);
FREE_ARRAY(ctx, ext->exts, lysc_ext_instance_free);
}
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 25772e0..736629d 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -687,7 +687,7 @@
* @return LY_ERR value.
*/
LY_ERR lys_extension_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lys_module *module,
- struct lysp_ext *extensions_p, struct lysc_ext **extensions);
+ struct lysp_ext *extensions_p, struct lysc_ext ***extensions);
/**
* @brief Macro to free [sized array](@ref sizedarrays) of items using the provided free function. The ARRAY itself is also freed,
* but the memory is not sanitized.
diff --git a/tests/src/test_printer_xml.c b/tests/src/test_printer_xml.c
index c5c6714..83e14dc 100644
--- a/tests/src/test_printer_xml.c
+++ b/tests/src/test_printer_xml.c
@@ -20,6 +20,8 @@
#include <stdio.h>
#include <string.h>
+#include "tests/config.h"
+
#include "../../src/context.h"
#include "../../src/printer_data.h"
@@ -99,6 +101,24 @@
"type string {length 1..20;}}}"
"anydata any;"
"rpc sum {input {leaf x {type uint8;} leaf y {type uint8;}} output {leaf result {type uint16;}}}}";
+ const char *schema_c =
+ "module defaults {"
+ "namespace \"urn:defaults\";"
+ "prefix d;"
+ "leaf a {"
+ "type union {"
+ "type instance-identifier;"
+ "type string;"
+ "}"
+ "default \"/d:b\";"
+ "}"
+ "leaf b {"
+ "type string;"
+ "}"
+ "leaf c {"
+ "type string;"
+ "}"
+ "}";
s = calloc(1, sizeof *s);
assert_non_null(s);
@@ -107,9 +127,11 @@
ly_set_log_clb(logger, 1);
#endif
- assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &s->ctx));
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(TESTS_DIR_MODULES_YANG, 0, &s->ctx));
+ assert_non_null(ly_ctx_load_module(s->ctx, "ietf-netconf-with-defaults", "2011-06-01"));
assert_non_null(lys_parse_mem(s->ctx, schema_a, LYS_IN_YANG));
assert_non_null(lys_parse_mem(s->ctx, schema_b, LYS_IN_YANG));
+ assert_non_null(lys_parse_mem(s->ctx, schema_c, LYS_IN_YANG));
*state = s;
@@ -199,6 +221,112 @@
s->func = NULL;
}
+static void
+test_defaults(void **state)
+{
+ struct state_s *s = (struct state_s*)(*state);
+ struct lyd_node *tree;
+ const char *data;
+ char *printed;
+ ssize_t len;
+
+ s->func = test_defaults;
+
+ /* standard default value */
+ data = "<c xmlns=\"urn:defaults\">aa</c>";
+ 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, LYDP_WITHSIBLINGS | LYDP_WD_TRIM)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, data);
+ free(printed);
+
+ assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_ALL)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ data = "<c xmlns=\"urn:defaults\">aa</c><a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a>";
+ assert_string_equal(printed, data);
+ free(printed);
+
+ assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_ALL_TAG)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ data = "<c xmlns=\"urn:defaults\">aa</c>"
+ "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
+ " ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>";
+ assert_string_equal(printed, data);
+ free(printed);
+
+ assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ data = "<c xmlns=\"urn:defaults\">aa</c>"
+ "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
+ " ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>";
+ assert_string_equal(printed, data);
+ free(printed);
+
+ lyd_free_all(tree);
+
+ /* string value equal to the default but default is an unresolved instance-identifier, so they are not considered equal */
+ data = "<c xmlns=\"urn:defaults\">aa</c><a xmlns=\"urn:defaults\">/d:b</a>";
+ 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, LYDP_WITHSIBLINGS | LYDP_WD_TRIM)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, data);
+ free(printed);
+
+ assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_ALL)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, data);
+ free(printed);
+
+ assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_ALL_TAG)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, data);
+ free(printed);
+
+ assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, data);
+ free(printed);
+
+ lyd_free_all(tree);
+
+ /* instance-identifier value equal to the default, should be considered equal */
+ data = "<c xmlns=\"urn:defaults\">aa</c><a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b>";
+ 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, LYDP_WITHSIBLINGS | LYDP_WD_TRIM)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ data = "<c xmlns=\"urn:defaults\">aa</c><b xmlns=\"urn:defaults\">val</b>";
+ assert_string_equal(printed, data);
+ free(printed);
+
+ assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_ALL)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ data = "<c xmlns=\"urn:defaults\">aa</c><a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b>";
+ assert_string_equal(printed, data);
+ free(printed);
+
+ assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_ALL_TAG)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ data = "<c xmlns=\"urn:defaults\">aa</c>"
+ "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
+ " ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
+ "<b xmlns=\"urn:defaults\">val</b>";
+ assert_string_equal(printed, data);
+ free(printed);
+
+ assert_true((len = lyd_print_mem(&printed, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ data = "<c xmlns=\"urn:defaults\">aa</c><a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b>";
+ assert_string_equal(printed, data);
+ free(printed);
+
+ lyd_free_all(tree);
+
+ s->func = NULL;
+}
+
#if 0
static void
@@ -286,6 +414,7 @@
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(test_leaf, setup, teardown),
cmocka_unit_test_setup_teardown(test_anydata, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_defaults, setup, teardown),
};
return cmocka_run_group_tests(tests, NULL, NULL);