data tree NEW functions for searching in siblings
... using hashes if possible. Other refactoring
included.
diff --git a/src/log.h b/src/log.h
index e5f54b7..74a12c4 100644
--- a/src/log.h
+++ b/src/log.h
@@ -48,7 +48,7 @@
* @param[in] level Verbosity level.
* @return Previous verbosity level.
*/
-LY_LOG_LEVEL ly_verb (LY_LOG_LEVEL level);
+LY_LOG_LEVEL ly_verb(LY_LOG_LEVEL level);
/**
* @defgroup logopts Logging options
@@ -75,7 +75,7 @@
* @param[in] opts Bitfield of @ref logopts.
* @return Previous logger options.
*/
-int ly_log_options (int opts);
+int ly_log_options(int opts);
#ifndef NDEBUG
@@ -102,7 +102,7 @@
* @brief Enable specific debugging messages (independent of log level).
* @param[in] dbg_groups Bitfield of enabled debug message groups (see @ref dbggroup).
*/
-void ly_verb_dbg (int dbg_groups);
+void ly_verb_dbg(int dbg_groups);
#endif
@@ -120,13 +120,13 @@
* presence) or it can be NULL, so consider it as an optional parameter. If the flag is 0, libyang will
* not bother with resolving the path.
*/
-void ly_set_log_clb (void(*clb) (LY_LOG_LEVEL level, const char *msg, const char *path), int path);
+void ly_set_log_clb(void(*clb)(LY_LOG_LEVEL level, const char *msg, const char *path), int path);
/**
* @brief Get logger callback.
* @return Logger callback (can be NULL).
*/
-void (*ly_get_log_clb (void)) (LY_LOG_LEVEL, const char *, const char *);
+void (*ly_get_log_clb(void))(LY_LOG_LEVEL, const char *, const char *);
/** @} log */
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 1508e78..c150f42 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -281,7 +281,7 @@
LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
goto error;
}
- snode = lys_child(parent ? parent->schema : NULL, mod, name, name_len, 0, 0);
+ snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, 0);
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);
goto error;
@@ -490,7 +490,7 @@
ly_set_add(&ctx->when_check, cur, LY_SET_OPT_USEASLIST);
}
- /* calculate the hash and insert it into parent (list with keys is handled when its keys are inserted) */
+ /* calculate the hash and insert it into parent */
lyd_hash(cur);
lyd_insert_hash(cur);
diff --git a/src/plugins_types.c b/src/plugins_types.c
index aa34d2e..a741889 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -58,6 +58,24 @@
}
/**
+ * @brief Generic has_canon callback returning always true.
+ */
+static int
+ly_type_canon_true(struct lysc_type *UNUSED(type))
+{
+ return 1;
+}
+
+/**
+ * @brief Generic has_canon callback returning always false.
+ */
+static int
+ly_type_canon_false(struct lysc_type *UNUSED(type))
+{
+ return 0;
+}
+
+/**
* @brief Generic duplication callback of the original value only.
*
* Implementation of the ly_type_dup_clb.
@@ -218,7 +236,7 @@
}
*err = NULL;
- switch(ly_parse_uint(value, value_len, max, base, ret)) {
+ switch (ly_parse_uint(value, value_len, max, base, ret)) {
case LY_EDENIED:
asprintf(&errmsg, "Value \"%.*s\" is out of %s's min/max bounds.", (int)value_len, value, datatype);
goto error;
@@ -1445,7 +1463,7 @@
if ((options & LY_TYPE_OPTS_INCOMPLETE_DATA) || (options & LY_TYPE_OPTS_SCHEMA) || !require_instance) {
/* a) in schema tree */
- *node_s = lys_child(*node_s, mod, id, id_len, 0, 0);
+ *node_s = lys_find_child(*node_s, mod, id, id_len, 0, 0);
if (!(*node_s)) {
asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value - path \"%.*s\" does not exists in the YANG schema.",
(int)orig_len, orig, (int)(*token - orig), orig);
@@ -1455,8 +1473,8 @@
/* b) in data tree */
if (*node_d) {
/* internal node */
- const struct lyd_node *children = lyd_node_children(*node_d);
- if (!children || !(*node_d = lyd_search(children, mod, id, id_len, 0, NULL, 0))) {
+ lyd_find_sibling_next(lyd_node_children(*node_d), mod, id, id_len, NULL, 0, (struct lyd_node **)node_d);
+ if (!*node_d) {
asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value - path \"%.*s\" does not exists in the data tree(s).",
(int)orig_len, orig, (int)(*token - orig), orig);
return LY_EVALID;
@@ -1464,7 +1482,7 @@
} else {
/* top-level node */
LY_ARRAY_FOR(trees, u) {
- *node_d = lyd_search(trees[u], mod, id, id_len, 0, NULL, 0);
+ lyd_find_sibling_next(trees[u], mod, id, id_len, NULL, 0, (struct lyd_node **)node_d);
if (*node_d) {
break;
}
@@ -1746,7 +1764,7 @@
}
/* go to another instance */
t = start;
- node_d = lyd_search(node_d->next, node_s->module, node_s->name, strlen(node_s->name), LYS_LIST, NULL, 0);
+ lyd_find_sibling_next(node_d->next, node_s->module, node_s->name, 0, NULL, 0, (struct lyd_node **)&node_d);
if (node_d) {
/* reset variables to the first predicate of this list to check it completely */
key_d = node_d;
@@ -1823,7 +1841,7 @@
break;
}
/* go to another instance */
- key_d = lyd_search(key_d->next, node_s->module, node_s->name, strlen(node_s->name), LYS_LEAFLIST, NULL, 0);
+ lyd_find_sibling_next(key_d->next, node_s->module, node_s->name, 0, NULL, 0, (struct lyd_node **)&key_d);
}
if (!key_d) {
asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - leaf-list-predicate \"%.*s\" does not match any \"%s\" instance.",
@@ -1871,7 +1889,7 @@
if (node_d) {
/* get the correct instance */
for (uint64_t u = pos; u > 1; u--) {
- node_d = lyd_search(node_d->next, node_s->module, node_s->name, strlen(node_s->name), node_s->nodetype, NULL, 0);
+ lyd_find_sibling_next(node_d->next, node_s->module, node_s->name, 0, NULL, 0, (struct lyd_node **)&node_d);
if (!node_d) {
asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - "
"position-predicate %"PRIu64" is bigger than number of instances in the data tree (%"PRIu64").",
@@ -2213,7 +2231,7 @@
start_search = lyd_node_children(node);
next_instance_inner:
if (start_search) {
- node = lyd_search(start_search, mod_node, id, id_len, 0, NULL, 0);
+ lyd_find_sibling_next(start_search, mod_node, id, id_len, NULL, 0, (struct lyd_node **)&node);
} else {
node = NULL;
}
@@ -2222,7 +2240,7 @@
LY_ARRAY_FOR(trees, u) {
start_search = trees[u];
next_instance_toplevel:
- node = lyd_search(start_search, mod_node, id, id_len, 0, NULL, 0);
+ lyd_find_sibling_next(start_search, mod_node, id, id_len, NULL, 0, (struct lyd_node **)&node);
if (node) {
break;
}
@@ -2270,7 +2288,7 @@
ly_parse_nodeid(&token, &src_prefix, &src_prefix_len, &src, &src_len);
mod_pred = lys_module_find_prefix(mod_context, src_prefix, src_prefix_len);
- key = (const struct lyd_node_term*)lyd_search(lyd_node_children(node), mod_pred, src, src_len, LYS_LEAF, NULL, 0);
+ lyd_find_sibling_next(lyd_node_children(node), mod_pred, src, src_len, NULL, 0, (struct lyd_node **)&key);
if (!key) {
asprintf(errmsg, "Internal error - missing expected list's key \"%.*s\" in module \"%s\" (%s:%d).",
(int)src_len, src, mod_pred->name, __FILE__, __LINE__);
@@ -2300,14 +2318,14 @@
if (!value) {
/* top-level search */
LY_ARRAY_FOR(trees, u) {
- value = lyd_search(trees[u], mod_pred, src, src_len, 0, NULL, 0);
+ lyd_find_sibling_next(trees[u], mod_pred, src, src_len, NULL, 0, (struct lyd_node **)&value);
if (value) {
break;
}
}
} else {
/* inner node */
- value = lyd_search(lyd_node_children(value), mod_pred, src, src_len, 0, NULL, 0);
+ lyd_find_sibling_next(lyd_node_children(value), mod_pred, src, src_len, NULL, 0, (struct lyd_node **)&value);
}
if (!value) {
/* node not found - try another instance */
@@ -2388,8 +2406,8 @@
/* check value according to the real type of the leafref target */
ret = type_lr->realtype->plugin->store(ctx, type_lr->realtype, value, value_len, options,
- resolve_prefix, parser, format, context_node, trees,
- storage, canonized, err);
+ resolve_prefix, parser, format, context_node, trees,
+ storage, canonized, err);
if (ret != LY_SUCCESS && ret != LY_EINCOMPLETE) {
return ret;
}
@@ -2467,6 +2485,18 @@
}
/**
+ * @brief Has canonical of the YANG built-in leafref type.
+ */
+static int
+ly_type_canon_leafref(struct lysc_type *type)
+{
+ struct lysc_type_leafref *lref_type;
+
+ lref_type = (struct lysc_type_leafref *)type;
+ return lref_type->realtype->plugin->has_canon(lref_type->realtype);
+}
+
+/**
* @brief Validate, canonize and store value of the YANG built-in union type.
*
* Implementation of the ly_type_store_clb.
@@ -2652,46 +2682,86 @@
}
/**
+ * @brief Has canonical of the YANG built-in union type.
+ */
+static int
+ly_type_canon_union(struct lysc_type *type)
+{
+ struct lysc_type_union *uni_type;
+ uint16_t i;
+
+ uni_type = (struct lysc_type_union *)type;
+
+ LY_ARRAY_FOR(uni_type->types, i) {
+ if (!uni_type->types[i]->plugin->has_canon(uni_type->types[i])) {
+ return 0;
+ }
+ }
+
+ /* all types have canonical value */
+ return 1;
+}
+
+/**
* @brief Set of type plugins for YANG built-in types
*/
struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT] = {
{0}, /* LY_TYPE_UNKNOWN */
- {.type = LY_TYPE_BINARY, .store = ly_type_store_binary, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_canonical, .free = ly_type_free_canonical, .id = "libyang 2 - binary, version 1"},
- {.type = LY_TYPE_UINT8, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical, .id = "libyang 2 - unsigned integer, version 1"},
- {.type = LY_TYPE_UINT16, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical, .id = "libyang 2 - unsigned integer, version 1"},
- {.type = LY_TYPE_UINT32, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical, .id = "libyang 2 - unsigned integer, version 1"},
- {.type = LY_TYPE_UINT64, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical, .id = "libyang 2 - unsigned integer, version 1"},
- {.type = LY_TYPE_STRING, .store = ly_type_store_string, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_original, .free = ly_type_free_original, .id = "libyang 2 - string, version 1"},
- {.type = LY_TYPE_BITS, .store = ly_type_store_bits, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_bits, .free = ly_type_free_bits, .id = "libyang 2 - bits, version 1"},
- {.type = LY_TYPE_BOOL, .store = ly_type_store_boolean, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_boolean, .free = ly_type_free_original, .id = "libyang 2 - boolean, version 1"},
- {.type = LY_TYPE_DEC64, .store = ly_type_store_decimal64, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_decimal64, .free = ly_type_free_canonical, .id = "libyang 2 - decimal64, version 1"},
- {.type = LY_TYPE_EMPTY, .store = ly_type_store_empty, .compare = ly_type_compare_empty, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_original, .free = ly_type_free_original, .id = "libyang 2 - empty, version 1"},
- {.type = LY_TYPE_ENUM, .store = ly_type_store_enum, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_enum, .free = ly_type_free_original, .id = "libyang 2 - enumeration, version 1"},
- {.type = LY_TYPE_IDENT, .store = ly_type_store_identityref, .compare = ly_type_compare_identityref, .print = ly_type_print_identityref,
- .duplicate = ly_type_dup_identityref, .free = ly_type_free_canonical, .id = "libyang 2 - identityref, version 1"},
- {.type = LY_TYPE_INST, .store = ly_type_store_instanceid, .compare = ly_type_compare_instanceid, .print = ly_type_print_instanceid,
- .duplicate = ly_type_dup_instanceid, .free = ly_type_free_instanceid, .id = "libyang 2 - instance-identifier, version 1"},
- {.type = LY_TYPE_LEAFREF, .store = ly_type_store_leafref, .compare = ly_type_compare_leafref, .print = ly_type_print_leafref,
- .duplicate = ly_type_dup_leafref, .free = ly_type_free_leafref, .id = "libyang 2 - leafref, version 1"},
- {.type = LY_TYPE_UNION, .store = ly_type_store_union, .compare = ly_type_compare_union, .print = ly_type_print_union,
- .duplicate = ly_type_dup_union, .free = ly_type_free_union, .id = "libyang 2 - union,version 1"},
- {.type = LY_TYPE_INT8, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_int, .free = ly_type_free_canonical, .id = "libyang 2 - integer, version 1"},
- {.type = LY_TYPE_INT16, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_int, .free = ly_type_free_canonical, .id = "libyang 2 - integer, version 1"},
- {.type = LY_TYPE_INT32, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_int, .free = ly_type_free_canonical, .id = "libyang 2 - integer, version 1"},
- {.type = LY_TYPE_INT64, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
- .duplicate = ly_type_dup_int, .free = ly_type_free_canonical, .id = "libyang 2 - integer, version 1"},
+ {.type = LY_TYPE_BINARY, .store = ly_type_store_binary, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_canonical, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - binary, version 1"},
+ {.type = LY_TYPE_UINT8, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - unsigned integer, version 1"},
+ {.type = LY_TYPE_UINT16, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - unsigned integer, version 1"},
+ {.type = LY_TYPE_UINT32, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - unsigned integer, version 1"},
+ {.type = LY_TYPE_UINT64, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - unsigned integer, version 1"},
+ {.type = LY_TYPE_STRING, .store = ly_type_store_string, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_original, .free = ly_type_free_original,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - string, version 1"},
+ {.type = LY_TYPE_BITS, .store = ly_type_store_bits, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_bits, .free = ly_type_free_bits,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - bits, version 1"},
+ {.type = LY_TYPE_BOOL, .store = ly_type_store_boolean, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_boolean, .free = ly_type_free_original,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - boolean, version 1"},
+ {.type = LY_TYPE_DEC64, .store = ly_type_store_decimal64, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_decimal64, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - decimal64, version 1"},
+ {.type = LY_TYPE_EMPTY, .store = ly_type_store_empty, .compare = ly_type_compare_empty,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_original, .free = ly_type_free_original,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - empty, version 1"},
+ {.type = LY_TYPE_ENUM, .store = ly_type_store_enum, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_enum, .free = ly_type_free_original,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - enumeration, version 1"},
+ {.type = LY_TYPE_IDENT, .store = ly_type_store_identityref, .compare = ly_type_compare_identityref,
+ .print = ly_type_print_identityref, .duplicate = ly_type_dup_identityref, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_false, .id = "libyang 2 - identityref, version 1"},
+ {.type = LY_TYPE_INST, .store = ly_type_store_instanceid, .compare = ly_type_compare_instanceid,
+ .print = ly_type_print_instanceid, .duplicate = ly_type_dup_instanceid, .free = ly_type_free_instanceid,
+ .has_canon = ly_type_canon_false, .id = "libyang 2 - instance-identifier, version 1"},
+ {.type = LY_TYPE_LEAFREF, .store = ly_type_store_leafref, .compare = ly_type_compare_leafref,
+ .print = ly_type_print_leafref, .duplicate = ly_type_dup_leafref, .free = ly_type_free_leafref,
+ .has_canon = ly_type_canon_leafref, .id = "libyang 2 - leafref, version 1"},
+ {.type = LY_TYPE_UNION, .store = ly_type_store_union, .compare = ly_type_compare_union,
+ .print = ly_type_print_union, .duplicate = ly_type_dup_union, .free = ly_type_free_union,
+ .has_canon = ly_type_canon_union, .id = "libyang 2 - union,version 1"},
+ {.type = LY_TYPE_INT8, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - integer, version 1"},
+ {.type = LY_TYPE_INT16, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - integer, version 1"},
+ {.type = LY_TYPE_INT32, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - integer, version 1"},
+ {.type = LY_TYPE_INT64, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
+ .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+ .has_canon = ly_type_canon_true, .id = "libyang 2 - integer, version 1"},
};
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 4df1d94..3db7f36 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -95,13 +95,14 @@
/**
* @defgroup plugintypeopts Options for type plugin callbacks. The same set of the options is passed to all the type's callbacks used together.
*
- * Options applicable to ly_type_validate_clb() and ly_typestore_clb.
+ * Options applicable to ly_type_validate_clb() and ly_type_store_clb.
* @{
*/
#define LY_TYPE_OPTS_CANONIZE 0x01 /**< Canonize the given value and store it (insert into the context's dictionary)
as the value's canonized string */
-#define LY_TYPE_OPTS_DYNAMIC 0x02 /**< Flag for the dynamically allocated string value, in this case the value is supposed to be freed
- or directly inserted into the context's dictionary (e.g. in case of canonization).
+#define LY_TYPE_OPTS_DYNAMIC 0x02 /**< Flag for the dynamically allocated string value, in this case the value
+ is supposed to be freed or directly inserted into the context's dictionary
+ (e.g. in case of canonization).
In any case, the caller of the callback does not free the provided string value after calling
the type's callbacks with this option */
#define LY_TYPE_OPTS_STORE 0x04 /**< Flag announcing calling of ly_type_store_clb() */
@@ -130,22 +131,23 @@
* @param[in] value Lexical representation of the value to be validated (and canonized).
* It is never NULL, empty string is represented as "" with zero @p value_len.
* @param[in] value_len Length (number of bytes) of the given \p value.
- * @param[in] options [Type plugin options ](@ref plugintypeopts).
- *
+ * @param[in] options [Type plugin options](@ref plugintypeopts).
* @param[in] resolve_prefix Parser-specific callback to resolve prefixes used in the value strings.
* @param[in] parser Parser's data for @p resolve_prefix
* @param[in] format Input format of the data.
- * @param[in] context_node The @p value's node for the case that the require-instance restriction is supposed to be resolved. This argument is of
- * lys_node (in case LY_TYPE_OPTS_INCOMPLETE_DATA or LY_TYPE_OPTS_SCHEMA set in @p options) or lyd_node structure.
- * @param[in] trees ([Sized array](@ref sizedarrays)) of external data trees (e.g. when validating RPC/Notification) where the required data
- * instance can be placed.
- *
+ * @param[in] context_node The @p value's node for the case that the require-instance restriction is supposed to be resolved.
+ * This argument is a lys_node (in case LY_TYPE_OPTS_INCOMPLETE_DATA or LY_TYPE_OPTS_SCHEMA set in @p options)
+ * or lyd_node structure.
+ * @param[in] trees ([Sized array](@ref sizedarrays)) of external data trees (e.g. when validating RPC/Notification)
+ * where the required data instance can be placed.
* @param[in,out] storage If LY_TYPE_OPTS_STORE option set, the parsed data are stored into this structure in the type's specific way.
* If the @p canonized differs from the storage's canonized member, the canonized value is also stored here despite the
* LY_TYPE_OPTS_CANONIZE option.
- * @param[out] canonized If LY_TYPE_OPTS_CANONIZE option set, the canonized string stored in the @p ctx dictionary is returned via this parameter.
- * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
- * The error structure can be created by ly_err_new().
+ * @param[out] canonized If LY_TYPE_OPTS_CANONIZE option set, the canonized string stored in the @p ctx dictionary
+ * is returned via this parameter.
+ * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic
+ * error message is prepared instead.
+ * The error structure can be created by ly_err_new().
* @return LY_SUCCESS on success
* @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.
@@ -168,7 +170,7 @@
typedef LY_ERR (*ly_type_compare_clb)(const struct lyd_value *val1, const struct lyd_value *val2);
/**
- * @brief Callback to receive printed (canoncal) value of the data stored in @p value.
+ * @brief Callback to receive printed (canonical) value of the data stored in @p value.
*
* @param[in] value Value to print.
* @param[in] format Format in which the data are supposed to be printed.
@@ -181,7 +183,8 @@
* can be responsible for freeing allocated memory.
* @return NULL in case of error.
*/
-typedef const char *(*ly_type_print_clb)(const struct lyd_value *value, LYD_FORMAT format, ly_clb_get_prefix get_prefix, void *printer, int *dynamic);
+typedef const char *(*ly_type_print_clb)(const struct lyd_value *value, LYD_FORMAT format, ly_clb_get_prefix get_prefix,
+ void *printer, int *dynamic);
/**
* @brief Callback to duplicate data in data structure. Note that callback is even responsible for duplicating lyd_value::canonized.
@@ -204,6 +207,18 @@
typedef void (*ly_type_free_clb)(struct ly_ctx *ctx, struct lyd_value *value);
/**
+ * @brief Callback for returning information whether the type has a canonical value.
+ *
+ * Note that if it returns non-zero (true), this type's @p print and @p store callbacks must never use
+ * its @p format and @p get_prefix parameters! Also, @p print callback should never set @p dynamic to true!
+ *
+ * @param[in] type Type of the value.
+ * @return 0 if the type has no canonical value.
+ * @return non-zero if the type has a canonical value.
+ */
+typedef int (*ly_type_has_canon_clb)(struct lysc_type *type);
+
+/**
* @brief Hold type-specific functions for various operations with the data values.
*
* libyang includes set of plugins for all the built-in types. They are, by default, inherited to the derived types.
@@ -217,6 +232,7 @@
ly_type_print_clb print; /**< printer callback to get string representing the value */
ly_type_dup_clb duplicate; /**< data duplication callback */
ly_type_free_clb free; /**< optional function to free the type-spceific way stored value */
+ ly_type_has_canon_clb has_canon; /**< callback for checking whether a type has caonical value */
const char *id; /**< Plugin identification (mainly for distinguish incompatible versions when used by external tools) */
};
diff --git a/src/tree_data.c b/src/tree_data.c
index 61d9ca6..018259f 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -30,6 +30,16 @@
#include "tree_schema.h"
#include "plugins_exts_metadata.h"
+struct ly_keys {
+ char *str;
+ struct {
+ const struct lysc_node_leaf *schema;
+ char *value;
+ const char *can_val;
+ } *keys;
+ size_t key_count;
+};
+
API void
lyd_trees_free(const struct lyd_node **trees, int free_data)
{
@@ -103,49 +113,6 @@
return trees;
}
-API const struct lyd_node *
-lyd_search(const struct lyd_node *first, const struct lys_module *module,
- const char *name, size_t name_len, uint16_t nodetype, const char *value, size_t value_len)
-{
- const struct lyd_node *node = NULL;
- const struct lysc_node *snode;
-
- LY_CHECK_ARG_RET(NULL, module, name, NULL);
- if (!nodetype) {
- nodetype = 0xffff;
- }
-
- LY_LIST_FOR(first, node) {
- snode = node->schema;
- if (!(snode->nodetype & nodetype)) {
- continue;
- }
- if (snode->module != module) {
- continue;
- }
-
- if (ly_strncmp(snode->name, name, name_len)) {
- continue;
- }
-
- if (value) {
- if (snode->nodetype == LYS_LIST) {
- /* TODO handle value as keys of the list instance */
- } else if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
- if (ly_strncmp(((struct lyd_node_term*)node)->value.original, value, value_len)) {
- continue;
- }
- } else {
- continue;
- }
- }
-
- /* all criteria passed */
- return node;
- }
- return NULL;
-}
-
LY_ERR
lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int dynamic, int second,
ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
@@ -457,7 +424,8 @@
lyd_target(struct lyd_value_path *path, const struct lyd_node **trees)
{
unsigned int u, v, x;
- const struct lyd_node *node = NULL, *parent = NULL, *start_search;
+ const struct lyd_node *parent = NULL, *start_search;
+ struct lyd_node *node = NULL;
uint64_t pos = 1;
LY_CHECK_ARG_RET(NULL, path, trees, NULL);
@@ -466,13 +434,13 @@
if (parent) {
start_search = lyd_node_children(parent);
search_inner:
- node = lyd_search(start_search, path[u].node->module, path[u].node->name, strlen(path[u].node->name), path[u].node->nodetype, NULL, 0);
+ lyd_find_sibling_next(start_search, path[u].node->module, path[u].node->name, 0, NULL, 0, &node);
} else {
LY_ARRAY_FOR(trees, v) {
start_search = trees[v];
search_toplevel:
/* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
- node = lyd_search(start_search, path[u].node->module, path[u].node->name, strlen(path[u].node->name), path[u].node->nodetype, NULL, 0);
+ lyd_find_sibling_next(start_search, path[u].node->module, path[u].node->name, 0, NULL, 0, &node);
if (node) {
break;
}
@@ -495,9 +463,9 @@
} else if (path[u].predicates[x].type == 1) {
/* key-predicate */
struct lysc_type *type = ((struct lysc_node_leaf*)path[u].predicates[x].key)->type;
- const struct lyd_node *key = lyd_search(lyd_node_children(node), path[u].predicates[x].key->module,
- path[u].predicates[x].key->name, strlen(path[u].predicates[x].key->name),
- LYS_LEAF, NULL, 0);
+ struct lyd_node *key;
+ lyd_find_sibling_next(lyd_node_children(node), path[u].predicates[x].key->module,
+ path[u].predicates[x].key->name, 0, NULL, 0, &key);
if (!key) {
/* probably error and we shouldn't be here due to previous checks when creating path */
goto search_repeat;
@@ -1133,3 +1101,501 @@
return buffer;
}
+
+API struct ly_set *
+lyd_find_instance(const struct lyd_node *sibling, const struct lysc_node *schema)
+{
+ struct ly_set *ret, *ret_aux, *spath;
+ const struct lysc_node *siter, *sparent;
+ const struct lyd_node *iter;
+ unsigned int i, j;
+
+ LY_CHECK_ARG_RET(NULL, sibling, schema, NULL);
+ if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
+ LOGARG(schema->module->ctx, schema);
+ return NULL;
+ }
+
+ ret = ly_set_new();
+ spath = ly_set_new();
+ LY_CHECK_ERR_GOTO(!ret || !spath, LOGMEM(schema->module->ctx), error);
+
+ /* build schema path until sibling parent */
+ sparent = sibling->parent ? sibling->parent->schema : NULL;
+ for (siter = schema; siter && (siter != sparent); siter = siter->parent) {
+ if (siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC | LYS_ACTION)) {
+ /* standard data node */
+ ly_set_add(spath, (void *)siter, LY_SET_OPT_USEASLIST);
+
+ } /* else skip the rest node types */
+ }
+ /* no valid path */
+ LY_CHECK_GOTO(!spath->count, error);
+
+ /* start searching */
+ LY_LIST_FOR(sibling, iter) {
+ if (iter->schema == spath->objs[spath->count - 1]) {
+ ly_set_add(ret, (void *)iter, LY_SET_OPT_USEASLIST);
+ }
+ }
+ for (i = spath->count - 1; i; i--) {
+ if (!ret->count) {
+ /* nothing found */
+ break;
+ }
+
+ ret_aux = ly_set_new();
+ LY_CHECK_ERR_GOTO(!ret_aux, LOGMEM(schema->module->ctx), error);
+ for (j = 0; j < ret->count; j++) {
+ LY_LIST_FOR(lyd_node_children(ret->objs[j]), iter) {
+ if (iter->schema == spath->objs[i - 1]) {
+ ly_set_add(ret_aux, (void *)iter, LY_SET_OPT_USEASLIST);
+ }
+ }
+ }
+ ly_set_free(ret, NULL);
+ ret = ret_aux;
+ }
+
+ ly_set_free(spath, NULL);
+ return ret;
+
+error:
+ ly_set_free(ret, NULL);
+ ly_set_free(spath, NULL);
+
+ return NULL;
+}
+
+static char *
+lyd_keys_parse_next(char **next_key, char **key_name)
+{
+ char *ptr, *ptr2, *val, quot;
+
+ ptr = *next_key;
+
+ /* "[" */
+ LY_CHECK_GOTO(ptr[0] != '[', error);
+ ++ptr;
+
+ /* key name */
+ ptr2 = strchr(ptr, '=');
+ LY_CHECK_GOTO(!ptr2, error);
+
+ *key_name = ptr;
+ ptr2[0] = '\0';
+
+ /* \0, was '=' */
+ ptr = ptr2 + 1;
+
+ /* quote */
+ LY_CHECK_GOTO((ptr[0] != '\'') && (ptr[0] != '\"'), error);
+ quot = ptr[0];
+ ++ptr;
+
+ /* value, terminate it */
+ val = ptr;
+ ptr2 = strchr(ptr, quot);
+ LY_CHECK_GOTO(!ptr2, error);
+ ptr2[0] = '\0';
+
+ /* \0, was quote */
+ ptr = ptr2 + 1;
+
+ /* "]" */
+ LY_CHECK_GOTO(ptr[0] != ']', error);
+ ++ptr;
+
+ *next_key = ptr;
+ return val;
+
+error:
+ LOGERR(NULL, LY_EINVAL, "Invalid arguments - keys at \"%s\" (%s()).", ptr, __func__);
+ return NULL;
+}
+
+static void
+ly_keys_clean(struct ly_keys *keys)
+{
+ size_t i;
+
+ for (i = 0; i < keys->key_count; ++i) {
+ lydict_remove(keys->keys[i].schema->module->ctx, keys->keys[i].can_val);
+ }
+ free(keys->str);
+ free(keys->keys);
+}
+
+static LY_ERR
+lyd_value_canonize(const struct lysc_node *schema, const char *value, size_t val_len, const char **can_val)
+{
+ LY_ERR rc = LY_SUCCESS;
+ struct lysc_type *type;
+ struct ly_err_item *err;
+
+ assert(schema->nodetype & (LYS_LEAF | LYS_LEAFLIST));
+
+ if (!val_len) {
+ val_len = strlen(value);
+ }
+
+ /* check canonical value exists */
+ type = (struct lysc_type *)&((struct lysc_node_leaf *)schema)->type;
+ if (!type->plugin->has_canon(type)) {
+ LOGERR(schema->module->ctx, LY_EINVAL, "Key \"%s\" has no canonical value.", schema->name);
+ return LY_EINVAL;
+ }
+
+ /* make the value canonical */
+ rc = type->plugin->store(schema->module->ctx, type, value, val_len, LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_SCHEMA,
+ NULL, NULL, 0, NULL, NULL, NULL, can_val, &err);
+ if (rc != LY_SUCCESS) {
+ ly_err_print(err);
+ ly_err_free(err);
+ return rc;
+ }
+
+ return LY_SUCCESS;
+}
+
+static LY_ERR
+ly_keys_parse(const struct lysc_node *list, const char *keys_str, size_t keys_len, int canonize, struct ly_keys *keys)
+{
+ LY_ERR rc = LY_SUCCESS;
+ char *next_key, *name;
+ const struct lysc_node *key;
+
+ assert(list->nodetype == LYS_LIST);
+
+ memset(keys, 0, sizeof *keys);
+
+ keys->str = strndup(keys_str, keys_len ? keys_len : strlen(keys_str));
+ LY_CHECK_ERR_GOTO(!keys->str, LOGMEM(list->module->ctx); rc = LY_EMEM, cleanup);
+
+ next_key = keys->str;
+ while (next_key[0]) {
+ /* new key */
+ keys->keys = ly_realloc(keys->keys, (keys->key_count + 1) * sizeof *keys->keys);
+ LY_CHECK_ERR_GOTO(!keys->keys, LOGMEM(list->module->ctx); rc = LY_EMEM, cleanup);
+
+ /* fill */
+ keys->keys[keys->key_count].value = lyd_keys_parse_next(&next_key, &name);
+
+ /* find schema node */
+ key = lys_find_child(list, list->module, name, 0, LYS_LEAF, 0);
+ if (!key) {
+ LOGERR(list->module->ctx, LY_EINVAL, "Node \"%s\" has no key \"%s\".", list->name, name);
+ rc = LY_EINVAL;
+ goto cleanup;
+ }
+ keys->keys[keys->key_count].schema = (const struct lysc_node_leaf *)key;
+
+ if (canonize) {
+ /* canonize the value */
+ rc = lyd_value_canonize(key, keys->keys[keys->key_count].value, 0, &keys->keys[keys->key_count].can_val);
+ LY_CHECK_GOTO(rc != LY_SUCCESS, cleanup);
+ }
+
+ /* another valid key */
+ ++keys->key_count;
+ }
+
+cleanup:
+ ly_keys_clean(keys);
+ return rc;
+}
+
+API LY_ERR
+lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name, size_t name_len,
+ const char *key_or_value, size_t val_len, struct lyd_node **match)
+{
+ LY_ERR rc;
+ const struct lyd_node *node = NULL;
+ struct lyd_node_term *term;
+ const struct lysc_node *schema;
+ struct ly_keys keys = {0};
+ const char *value = NULL, *node_val;
+ size_t i;
+ int dynamic;
+
+ LY_CHECK_ARG_RET(NULL, module, name, LY_EINVAL);
+
+ if (!first) {
+ /* no data */
+ *match = NULL;
+ return LY_ENOTFOUND;
+ }
+
+ /* find schema */
+ schema = lys_find_child(first->parent ? first->parent->schema : NULL, module, name, name_len, 0, 0);
+ if (!schema) {
+ LOGERR(module->ctx, LY_EINVAL, "Schema node not found.");
+ return LY_EINVAL;
+ }
+
+ if (key_or_value && !val_len) {
+ val_len = strlen(key_or_value);
+ }
+
+ if (key_or_value && (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
+ /* canonize the value */
+ LY_CHECK_GOTO(rc = lyd_value_canonize(schema, key_or_value, val_len, &value), cleanup);
+ } else if (key_or_value && (schema->nodetype == LYS_LIST)) {
+ /* parse keys into canonical values */
+ LY_CHECK_GOTO(rc = ly_keys_parse(schema, key_or_value, val_len, 1, &keys), cleanup);
+ }
+
+ /* find first matching value */
+ LY_LIST_FOR(first, node) {
+ if (node->schema != schema) {
+ continue;
+ }
+
+ if ((schema->nodetype == LYS_LIST) && keys.str) {
+ /* compare all set keys */
+ for (i = 0; i < keys.key_count; ++i) {
+ /* find key */
+ rc = lyd_find_sibling_val(lyd_node_children(node), (struct lysc_node *)keys.keys[i].schema, NULL, 0,
+ (struct lyd_node **)&term);
+ if (rc == LY_ENOTFOUND) {
+ /* all keys must always exist */
+ LOGINT_RET(module->ctx);
+ }
+ LY_CHECK_GOTO(rc, cleanup);
+
+ /* compare values */
+ node_val = term->value.realtype->plugin->print(&term->value, 0, NULL, NULL, &dynamic);
+ assert(!dynamic);
+ if (strcmp(node_val, keys.keys[i].can_val)) {
+ break;
+ }
+ }
+
+ if (i < keys.key_count) {
+ /* not a match */
+ continue;
+ }
+ } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && value) {
+ term = (struct lyd_node_term *)node;
+
+ /* compare values */
+ node_val = term->value.realtype->plugin->print(&term->value, 0, NULL, NULL, &dynamic);
+ assert(!dynamic);
+ if (strcmp(node_val, value)) {
+ /* not a match */
+ continue;
+ }
+ }
+
+ /* all criteria passed */
+ break;
+ }
+
+ if (!node) {
+ rc = LY_ENOTFOUND;
+ *match = NULL;
+ goto cleanup;
+ }
+
+ /* success */
+ *match = (struct lyd_node *)node;
+ rc = LY_SUCCESS;
+
+cleanup:
+ ly_keys_clean(&keys);
+ lydict_remove(module->ctx, value);
+ return rc;
+}
+
+API LY_ERR
+lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
+{
+ struct lyd_node **match_p;
+ struct lyd_node_inner *parent;
+
+ LY_CHECK_ARG_RET(NULL, target, match, LY_EINVAL);
+
+ if (!siblings) {
+ /* no data */
+ *match = NULL;
+ return LY_ENOTFOUND;
+ }
+
+ /* find first sibling */
+ if (siblings->parent) {
+ siblings = siblings->parent->child;
+ } else {
+ while (siblings->prev->next) {
+ siblings = siblings->prev;
+ }
+ }
+
+ parent = (struct lyd_node_inner *)siblings->parent;
+ if (parent && parent->children_ht) {
+ assert(target->hash);
+
+ /* find by hash */
+ if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
+ siblings = *match_p;
+ } else {
+ /* not found */
+ siblings = NULL;
+ }
+ } else {
+ /* no children hash table */
+ for (; siblings; siblings = siblings->next) {
+ if (!lyd_compare(siblings, target, 0)) {
+ break;
+ }
+ }
+ }
+
+ if (!siblings) {
+ *match = NULL;
+ return LY_ENOTFOUND;
+ }
+
+ *match = (struct lyd_node *)siblings;
+ return LY_SUCCESS;
+}
+
+API LY_ERR
+lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
+{
+ struct lyd_node_inner *parent;
+ struct lyd_node *match;
+ struct lyd_node **match_p;
+ struct ly_set *ret;
+
+ LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
+
+ if (!siblings) {
+ /* no data */
+ return LY_ENOTFOUND;
+ }
+
+ ret = ly_set_new();
+ LY_CHECK_ERR_RET(!ret, LOGMEM(target->schema->module->ctx), LY_EMEM);
+
+ /* find first sibling */
+ if (siblings->parent) {
+ siblings = siblings->parent->child;
+ } else {
+ while (siblings->prev->next) {
+ siblings = siblings->prev;
+ }
+ }
+
+ parent = (struct lyd_node_inner *)siblings->parent;
+ if (parent && parent->children_ht) {
+ assert(target->hash);
+
+ /* find by hash */
+ if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
+ match = *match_p;
+ } else {
+ /* not found */
+ match = NULL;
+ }
+ while (match) {
+ /* add all found nodes into the return set */
+ if (ly_set_add(ret, match, LY_SET_OPT_USEASLIST) == -1) {
+ goto error;
+ }
+
+ /* find next instance */
+ if (lyht_find_next(parent->children_ht, &match, match->hash, (void **)&match_p)) {
+ match = NULL;
+ } else {
+ match = *match_p;
+ }
+ }
+ } else {
+ /* no children hash table */
+ for (; siblings; siblings = siblings->next) {
+ if (!lyd_compare(siblings, target, 0)) {
+ /* a match */
+ if (ly_set_add(ret, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
+ goto error;
+ }
+ }
+ }
+ }
+
+ if (!ret->count) {
+ ly_set_free(ret, NULL);
+ return LY_ENOTFOUND;
+ }
+
+ *set = ret;
+ return LY_SUCCESS;
+
+error:
+ ly_set_free(ret, NULL);
+ return LY_EMEM;
+}
+
+API LY_ERR
+lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
+ size_t val_len, struct lyd_node **match)
+{
+ LY_ERR rc;
+ struct lyd_node *target = NULL;
+
+ LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
+ if ((schema->nodetype == LYS_LIST) && schema->flags & LYS_KEYLESS) {
+ LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
+ return LY_EINVAL;
+ } else if ((schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && !key_or_value) {
+ LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - no value/keys for a (leaf-)list (%s()).", __func__);
+ return LY_EINVAL;
+ } else if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
+ LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
+ lys_nodetype2str(schema->nodetype), __func__);
+ return LY_EINVAL;
+ }
+
+ if (!siblings) {
+ /* no data */
+ *match = NULL;
+ return LY_ENOTFOUND;
+ }
+
+ /* create data node */
+ switch (schema->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_ANYXML:
+ case LYS_ANYDATA:
+ case LYS_NOTIF:
+ case LYS_RPC:
+ /* target used attributes: schema, hash */
+ //TODO target = lyd_create(schema, 0);
+ LY_CHECK_RET(!target, LY_EMEM);
+ break;
+ case LYS_LEAF:
+ /* target used attributes: schema, hash */
+ //TODO target = lyd_create_term(schema, NULL, 0, 0);
+ LY_CHECK_RET(!target, LY_EMEM);
+ break;
+ case LYS_LEAFLIST:
+ /* target used attributes: schema, hash, value */
+ //TODO target = lyd_create_term(schema, key_or_value, val_len, 0);
+ LY_CHECK_RET(!target, LY_EMEM);
+ break;
+ case LYS_LIST:
+ /* target used attributes: schema, hash, child (all keys) */
+ //TODO target = lyd_create_list(schema, key_or_value, val_len);
+ LY_CHECK_RET(!target, LY_EMEM);
+ break;
+ default:
+ /* unreachable */
+ LOGINT(schema->module->ctx);
+ return LY_EINT;
+ }
+
+ /* find it */
+ rc = lyd_find_sibling_first(siblings, target, match);
+
+ lyd_free_tree(target);
+ return rc;
+}
diff --git a/src/tree_data.h b/src/tree_data.h
index 8b8b986..888b9e9 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -393,12 +393,14 @@
*/
#define LYD_OPT_DATA 0x00 /**< Default type of data - complete datastore content with configuration as well as
- state data. */
+ 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_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_PARSE_ONLY | LYD_OPT_EMPTY_INST /**< Content of the NETCONF \<edit-config\>'s config element. */
+ the NETCONF \<get-config\> operation. */
+#define LYD_OPT_EDIT LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE | LYD_OPT_EMPTY_INST /**< Content of
+ the NETCONF \<edit-config\>'s config element. */
#define LYD_OPT_STRICT 0x0001 /**< Instead of silent ignoring data without schema definition raise an error. */
#define LYD_OPT_PARSE_ONLY 0x0002 /**< Data will be only parsed and no (only required) validation will be performed. */
@@ -427,26 +429,6 @@
const struct lyd_node *lyd_node_children(const struct lyd_node *node);
/**
- * @brief Find the node, in the list, satisfying the given restrictions.
- *
- * @param[in] first Starting child node for search.
- * @param[in] module Module of the node to find (mandatory argument).
- * @param[in] name Name of the node to find (mandatory argument).
- * @param[in] name_len Optional length of the @p name argument in case it is not NULL-terminated string.
- * @param[in] nodetype Optional mask for the nodetype of the node to find, 0 is understood as all nodetypes.
- * @param[in] value Optional restriction for lyd_node_term nodes to select node with the specific value. Note that this
- * search restriction is limited to compare original string representation of the @p first value. Some of the types have
- * canonical representation defined so the same value can be represented by multiple lexical representation. In such a
- * case the @p value not matching the original representation of @p first may still be the same.
- * For such a case there is more advanced lyd_value_compare() to check if the values matches.
- * @param[in] value_len Optional length of the @p value argument in case it is not NULL-terminated string.
- * @return The sibling node of the @p first (or itself), satisfying the given restrictions.
- * @return NULL in case there is no node satisfying the restrictions.
- */
-const struct lyd_node *lyd_search(const struct lyd_node *first, const struct lys_module *module,
- const char *name, size_t name_len, uint16_t nodetype, const char *value, size_t value_len);
-
-/**
* @brief Parse (and validate) data from memory.
*
* In case of LY_XML format, the data string is parsed completely. It means that when it contains
@@ -739,6 +721,108 @@
*/
char *lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen);
+/**
+ * @brief Search in the given siblings for instances of the provided schema node, recursively.
+ * Does **not** use hashes - should not be used unless necessary for best performance.
+ *
+ * If \p sibling is the first top-level sibling, the whole data tree is effectively searched.
+ *
+ * @param[in] sibling Starting data sibling for the search.
+ * @param[in] schema Schema node of the data nodes caller wants to find.
+ * @return Set of found data nodes. If no data node is found, the returned set is empty.
+ * @return NULL in case of error.
+ */
+struct ly_set *lyd_find_instance(const struct lyd_node *sibling, const struct lysc_node *schema);
+
+/**
+ * @brief Find the node, in the list, satisfying the given restrictions.
+ * Does **not** use hashes - should not be used unless necessary for best performance.
+ *
+ * @param[in] first Starting sibling node for search, only succeeding ones are searched.
+ * @param[in] module Module of the node to find.
+ * @param[in] name Name of the node to find.
+ * @param[in] name_len Optional length of the @p name argument in case it is not NULL-terminated string.
+ * @param[in] key_or_value Expected value depends on the type of @p name node:
+ * LYS_CONTAINER:
+ * LYS_ANYXML:
+ * LYS_ANYDATA:
+ * LYS_NOTIF:
+ * LYS_RPC:
+ * LYS_ACTION:
+ * NULL should be always set, will be ignored.
+ * LYS_LEAF:
+ * LYS_LEAFLIST:
+ * Optional restriction on the specific leaf(-list) value. Can be set only if the node
+ * has a canonical value!
+ * LYS_LIST:
+ * Optional keys values of the matching list instances in the form of "[key1='val1'][key2='val2']...".
+ * The keys do not have to be ordered and not all keys need to be specified, but they must have
+ * a canonical value!
+ * @param[in] val_len Optional length of the @p key_or_value argument in case it is not NULL-terminated string.
+ * @param[out] match Found data node.
+ * @return LY_SUCCESS on success, @p match set.
+ * @return LY_ENOTFOUND if not found, @p match set to NULL.
+ * @return LY_ERR value if another error occurred.
+ */
+LY_ERR lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name,
+ size_t name_len, const char *key_or_value, size_t val_len, struct lyd_node **match);
+
+/**
+ * @brief Search in the given siblings (NOT recursively) for the first target instance.
+ * Uses hashes - should be used whenever possible for best performance.
+ *
+ * @param[in] siblings Siblings to search in including preceding and succeeding nodes.
+ * @param[in] target Target node to find.
+ * @param[out] match Found data node.
+ * @return LY_SUCCESS on success, @p match set.
+ * @return LY_ENOTFOUND if not found, @p match set to NULL.
+ * @return LY_ERR value if another error occurred.
+ */
+LY_ERR lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match);
+
+/**
+ * @brief Search in the given siblings for all target instances.
+ * Uses hashes - should be used whenever possible for best performance.
+ *
+ * @param[in] siblings Siblings to search in including preceding and succeeding nodes.
+ * @param[in] target Target node to find. Key-less lists are compared based on
+ * all its descendants (both direct and indirect).
+ * @param[out] set Found nodes in a set in case of success.
+ * @return LY_SUCCESS on success.
+ * @return LY_ENOTFOUND if no matching siblings found.
+ * @return LY_ERR value if another error occurred.
+ */
+LY_ERR lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set);
+
+/**
+ * @brief Search in the given siblings for the first schema instance.
+ * Uses hashes - should be used whenever possible for best performance.
+ *
+ * @param[in] siblings Siblings to search in including preceding and succeeding nodes.
+ * @param[in] schema Schema node of the data node to find.
+ * @param[in] key_or_value Expected value depends on the type of \p schema:
+ * LYS_CONTAINER:
+ * LYS_LEAF:
+ * LYS_ANYXML:
+ * LYS_ANYDATA:
+ * LYS_NOTIF:
+ * LYS_RPC:
+ * LYS_ACTION:
+ * NULL should be always set, will be ignored.
+ * LYS_LEAFLIST:
+ * Searched instance value.
+ * LYS_LIST:
+ * Searched instance all key values in the form of "[key1='val1'][key2='val2']...".
+ * The keys do not have to be ordered.
+ * @param[out] match Found data node.
+ * @return LY_SUCCESS on success, @p match set.
+ * @return LY_ENOTFOUND if not found, @p match set to NULL.
+ * @return LY_EINVAL if @p schema is a key-less list.
+ * @return LY_ERR value if another error occurred.
+ */
+LY_ERR lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
+ size_t val_len, struct lyd_node **match);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 370c73f..36c9d08 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -185,8 +185,8 @@
}
API const struct lysc_node *
-lys_child(const struct lysc_node *parent, const struct lys_module *module,
- const char *name, size_t name_len, uint16_t nodetype, int options)
+lys_find_child(const struct lysc_node *parent, const struct lys_module *module, const char *name, size_t name_len,
+ uint16_t nodetype, int options)
{
const struct lysc_node *node = NULL;
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 8f8b58a..0182dea 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1937,16 +1937,16 @@
* @param[in] options [ORed options](@ref sgetnextflags).
* @return Found node if any.
*/
-const struct lysc_node *lys_child(const struct lysc_node *parent, const struct lys_module *module,
- const char *name, size_t name_len, uint16_t nodetype, int options);
+const struct lysc_node *lys_find_child(const struct lysc_node *parent, const struct lys_module *module,
+ const char *name, size_t name_len, uint16_t nodetype, int options);
/**
* @brief Make the specific module implemented.
*
* @param[in] mod Module to make implemented. It is not an error
* to provide already implemented module, it just does nothing.
- * @return LY_SUCCESS or LY_EDENIED in case the context contains some other revision of the
- * same module which is already implemented.
+ * @return LY_SUCCESS on success.
+ * @return LY_EDENIED in case the context contains some other revision of the same module which is already implemented.
*/
LY_ERR lys_set_implemented(struct lys_module *mod);
@@ -1957,8 +1957,8 @@
* @param[in] node Schema node to check.
* @param[in] recursive - 0 to check if-feature only in the \p node schema node,
* - 1 to check if-feature in all ascendant schema nodes until there is a node possibly having an instance in a data tree
- * @return - NULL if enabled,
- * - pointer to the node with the unsatisfied (disabling) if-feature expression.
+ * @return NULL if enabled,
+ * @return pointer to the node with the unsatisfied (disabling) if-feature expression.
*/
const struct lysc_iffeature *lysc_node_is_disabled(const struct lysc_node *node, int recursive);
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 54c39af..f18074c 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -2493,7 +2493,7 @@
lys_set_implemented_internal((struct lys_module*)mod, 2);
}
- dst_node = lys_child(dst_node, mod, dst, dst_len, 0, LYS_GETNEXT_NOSTATECHECK);
+ dst_node = lys_find_child(dst_node, mod, dst, dst_len, 0, LYS_GETNEXT_NOSTATECHECK);
if (!dst_node) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
"Invalid leafref path predicate \"%.*s\" - unable to find node \"%.*s\" in the rel-path-keyexpr.",
@@ -2711,7 +2711,7 @@
lys_set_implemented_internal((struct lys_module*)mod, 2);
}
- node = lys_child(parent, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
+ node = lys_find_child(parent, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
if (!node) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
"Invalid leafref path - unable to find \"%.*s\".", id - leafref->path, leafref->path);
@@ -4089,7 +4089,7 @@
}
/* key node must be present */
- key = (struct lysc_node_leaf*)lys_child(node, node->module, keystr, len, LYS_LEAF, LYS_GETNEXT_NOCHOICE | LYS_GETNEXT_NOSTATECHECK);
+ key = (struct lysc_node_leaf*)lys_find_child(node, node->module, keystr, len, LYS_LEAF, LYS_GETNEXT_NOCHOICE | LYS_GETNEXT_NOSTATECHECK);
if (!(key)) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
"The list's key \"%.*s\" not found.", len, keystr);
@@ -4234,7 +4234,7 @@
prefix_len, prefix);
return LY_EVALID;
}
- ch->dflt = (struct lysc_node_case*)lys_child(node, node->module, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
+ ch->dflt = (struct lysc_node_case*)lys_find_child(node, node->module, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
if (!ch->dflt) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
"Default case \"%s\" not found.", dflt);
@@ -4285,7 +4285,7 @@
mod = ctx->mod;
}
/* get the default case */
- cs = (struct lysc_node_case*)lys_child((struct lysc_node*)ch, mod, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
+ cs = (struct lysc_node_case*)lys_find_child((struct lysc_node*)ch, mod, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
if (!cs) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
"Invalid deviation adding \"default\" property \"%s\" of choice - the specified case does not exists.", dflt);
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 4bf97aa..3fd214a 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -108,7 +108,7 @@
current_nodetype = LYS_INOUT;
} else {
getnext:
- context_node = lys_child(context_node, mod, name, name_len, 0,
+ context_node = lys_find_child(context_node, mod, name, name_len, 0,
getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
if (!context_node) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
diff --git a/src/validation.c b/src/validation.c
index 618e096..e2deb7a 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -516,7 +516,6 @@
lyd_validate_data(const struct lyd_node **trees, const struct lys_module **modules, int mod_count, struct ly_ctx *ctx,
int options)
{
- LY_ERR ret;
uint32_t i = 0, j;
const struct lys_module *mod;
struct lyd_node *tree;