summaryrefslogtreecommitdiffstats
path: root/src/tree_data_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tree_data_common.c')
-rw-r--r--src/tree_data_common.c458
1 files changed, 317 insertions, 141 deletions
diff --git a/src/tree_data_common.c b/src/tree_data_common.c
index f35f8f5..672f720 100644
--- a/src/tree_data_common.c
+++ b/src/tree_data_common.c
@@ -44,32 +44,65 @@
#include "xpath.h"
/**
+ * @brief Callback for checking first instance hash table values equivalence.
+ *
+ * @param[in] val1_p If not @p mod, pointer to the first instance.
+ * @param[in] val2_p If not @p mod, pointer to the found dup inst item.
+ */
+static ly_bool
+lyht_dup_inst_ht_equal_cb(void *val1_p, void *val2_p, ly_bool mod, void *UNUSED(cb_data))
+{
+ if (mod) {
+ struct lyd_dup_inst **item1 = val1_p, **item2 = val2_p;
+
+ /* equal on 2 dup inst items */
+ return *item1 == *item2 ? 1 : 0;
+ } else {
+ struct lyd_node **first_inst = val1_p;
+ struct lyd_dup_inst **item = val2_p;
+
+ /* equal on dup inst item and a first instance */
+ return (*item)->set->dnodes[0] == *first_inst ? 1 : 0;
+ }
+}
+
+/**
* @brief Find an entry in duplicate instance cache for an instance. Create it if it does not exist.
*
- * @param[in] first_inst Instance of the cache entry.
- * @param[in,out] dup_inst_cache Duplicate instance cache.
+ * @param[in] first_inst First instance of the cache entry.
+ * @param[in] dup_inst_ht Duplicate instance cache hash table.
* @return Instance cache entry.
*/
static struct lyd_dup_inst *
-lyd_dup_inst_get(const struct lyd_node *first_inst, struct lyd_dup_inst **dup_inst_cache)
+lyd_dup_inst_get(const struct lyd_node *first_inst, struct ly_ht **dup_inst_ht)
{
- struct lyd_dup_inst *item;
- LY_ARRAY_COUNT_TYPE u;
+ struct lyd_dup_inst **item_p, *item;
- LY_ARRAY_FOR(*dup_inst_cache, u) {
- if ((*dup_inst_cache)[u].inst_set->dnodes[0] == first_inst) {
- return &(*dup_inst_cache)[u];
+ if (*dup_inst_ht) {
+ /* find the item of the first instance */
+ if (!lyht_find(*dup_inst_ht, &first_inst, first_inst->hash, (void **)&item_p)) {
+ return *item_p;
}
+ } else {
+ /* create the hash table */
+ *dup_inst_ht = lyht_new(2, sizeof item, lyht_dup_inst_ht_equal_cb, NULL, 1);
+ LY_CHECK_RET(!*dup_inst_ht, NULL);
}
- /* it was not added yet, add it now */
- LY_ARRAY_NEW_RET(LYD_CTX(first_inst), *dup_inst_cache, item, NULL);
+ /* first instance has no dup inst item, create it */
+ item = calloc(1, sizeof *item);
+ LY_CHECK_RET(!item, NULL);
+
+ /* add into the hash table */
+ if (lyht_insert(*dup_inst_ht, &item, first_inst->hash, NULL)) {
+ return NULL;
+ }
return item;
}
LY_ERR
-lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct lyd_dup_inst **dup_inst_cache)
+lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struct ly_ht **dup_inst_ht)
{
struct lyd_dup_inst *dup_inst;
@@ -80,40 +113,47 @@ lyd_dup_inst_next(struct lyd_node **inst, const struct lyd_node *siblings, struc
/* there can be more exact same instances (even if not allowed in invalid data) and we must make sure we do not
* match a single node more times */
- dup_inst = lyd_dup_inst_get(*inst, dup_inst_cache);
+ dup_inst = lyd_dup_inst_get(*inst, dup_inst_ht);
LY_CHECK_ERR_RET(!dup_inst, LOGMEM(LYD_CTX(siblings)), LY_EMEM);
if (!dup_inst->used) {
/* we did not cache these instances yet, do so */
- lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->inst_set);
- assert(dup_inst->inst_set->count && (dup_inst->inst_set->dnodes[0] == *inst));
+ lyd_find_sibling_dup_inst_set(siblings, *inst, &dup_inst->set);
+ assert(dup_inst->set->count && (dup_inst->set->dnodes[0] == *inst));
}
- if (dup_inst->used == dup_inst->inst_set->count) {
+ if (dup_inst->used == dup_inst->set->count) {
if (lysc_is_dup_inst_list((*inst)->schema)) {
/* we have used all the instances */
*inst = NULL;
} /* else just keep using the last (ideally only) instance */
} else {
- assert(dup_inst->used < dup_inst->inst_set->count);
+ assert(dup_inst->used < dup_inst->set->count);
/* use another instance */
- *inst = dup_inst->inst_set->dnodes[dup_inst->used];
+ *inst = dup_inst->set->dnodes[dup_inst->used];
++dup_inst->used;
}
return LY_SUCCESS;
}
-void
-lyd_dup_inst_free(struct lyd_dup_inst *dup_inst)
+/**
+ * @brief Callback for freeing first instance hash table values.
+ */
+static void
+lyht_dup_inst_ht_free_cb(void *val_p)
{
- LY_ARRAY_COUNT_TYPE u;
+ struct lyd_dup_inst **item = val_p;
- LY_ARRAY_FOR(dup_inst, u) {
- ly_set_free(dup_inst[u].inst_set, NULL);
- }
- LY_ARRAY_FREE(dup_inst);
+ ly_set_free((*item)->set, NULL);
+ free(*item);
+}
+
+void
+lyd_dup_inst_free(struct ly_ht *dup_inst_ht)
+{
+ lyht_free(dup_inst_ht, lyht_dup_inst_ht_free_cb);
}
struct lyd_node *
@@ -180,12 +220,12 @@ lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
return LY_EINVAL;
}
- /* If variable is already defined then change its value. */
- if (*vars && !lyxp_vars_find(*vars, name, 0, &item)) {
+ /* if variable is already defined then change its value */
+ if (*vars && !lyxp_vars_find(NULL, *vars, name, 0, &item)) {
var_value = strdup(value);
LY_CHECK_RET(!var_value, LY_EMEM);
- /* Set new value. */
+ /* update value */
free(item->value);
item->value = var_value;
} else {
@@ -193,7 +233,7 @@ lyxp_vars_set(struct lyxp_var **vars, const char *name, const char *value)
var_value = strdup(value);
LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
- /* Add new variable. */
+ /* add new variable */
LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
item->name = var_name;
item->value = var_value;
@@ -260,21 +300,68 @@ lyd_owner_module(const struct lyd_node *node)
return NULL;
}
+ while (!node->schema && node->parent) {
+ node = lyd_parent(node);
+ }
+
if (!node->schema) {
+ /* top-level opaque node */
opaq = (struct lyd_node_opaq *)node;
switch (opaq->format) {
case LY_VALUE_XML:
- return opaq->name.module_ns ? ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns) : NULL;
+ if (opaq->name.module_ns) {
+ return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
+ }
+ break;
case LY_VALUE_JSON:
- return opaq->name.module_name ? ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name) : NULL;
+ if (opaq->name.module_name) {
+ return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
+ }
+ break;
default:
return NULL;
}
+
+ return NULL;
}
return lysc_owner_module(node->schema);
}
+LIBYANG_API_DEF const struct lys_module *
+lyd_node_module(const struct lyd_node *node)
+{
+ const struct lyd_node_opaq *opaq;
+
+ while (node) {
+ /* data node */
+ if (node->schema) {
+ return node->schema->module;
+ }
+
+ /* opaque node */
+ opaq = (struct lyd_node_opaq *)node;
+ switch (opaq->format) {
+ case LY_VALUE_XML:
+ if (opaq->name.module_ns) {
+ return ly_ctx_get_module_implemented_ns(LYD_CTX(node), opaq->name.module_ns);
+ }
+ break;
+ case LY_VALUE_JSON:
+ if (opaq->name.module_name) {
+ return ly_ctx_get_module_implemented(LYD_CTX(node), opaq->name.module_name);
+ }
+ break;
+ default:
+ break;
+ }
+
+ node = lyd_parent(node);
+ }
+
+ return NULL;
+}
+
void
lyd_first_module_sibling(struct lyd_node **node, const struct lys_module *mod)
{
@@ -389,12 +476,12 @@ lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
LY_ERR
lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value,
- size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+ size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
const struct lysc_node *ctx_node, ly_bool *incomplete)
{
LY_ERR ret;
struct ly_err_item *err = NULL;
- uint32_t options = (dynamic && *dynamic ? LYPLG_TYPE_STORE_DYNAMIC : 0);
+ uint32_t options = 0;
if (!value) {
value = "";
@@ -403,6 +490,13 @@ lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct ly
*incomplete = 0;
}
+ if (dynamic && *dynamic) {
+ options |= LYPLG_TYPE_STORE_DYNAMIC;
+ }
+ if (is_utf8) {
+ options |= LYPLG_TYPE_STORE_IS_UTF8;
+ }
+
ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, hints, ctx_node, val, NULL, &err);
if (dynamic) {
*dynamic = 0;
@@ -440,8 +534,8 @@ lyd_value_validate_incomplete(const struct ly_ctx *ctx, const struct lysc_type *
LOGVAL_ERRITEM(ctx, err);
ly_err_free(err);
} else {
- LOGVAL(ctx, LYVE_OTHER, "Resolving value \"%s\" failed.", type->plugin->print(ctx, val, LY_VALUE_CANON,
- NULL, NULL, NULL));
+ LOGVAL(ctx, LYVE_OTHER, "Resolving value \"%s\" failed.",
+ (char *)type->plugin->print(ctx, val, LY_VALUE_CANON, NULL, NULL, NULL));
}
return ret;
}
@@ -450,15 +544,15 @@ lyd_value_validate_incomplete(const struct ly_ctx *ctx, const struct lysc_type *
}
LY_ERR
-lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
- LY_VALUE_FORMAT format, void *prefix_data)
+ly_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
+ LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints)
{
LY_ERR rc = LY_SUCCESS;
struct ly_err_item *err = NULL;
struct lyd_value storage;
struct lysc_type *type;
- LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
+ LY_CHECK_ARG_RET(ctx, node, LY_EINVAL);
if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
LOGARG(ctx, node);
@@ -466,8 +560,8 @@ lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const
}
type = ((struct lysc_node_leaf *)node)->type;
- rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data,
- LYD_HINT_SCHEMA, node, &storage, NULL, &err);
+ rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data, hints, node,
+ &storage, NULL, &err);
if (rc == LY_EINCOMPLETE) {
/* actually success since we do not provide the context tree and call validation with
* LY_TYPE_OPTS_INCOMPLETE_DATA */
@@ -478,14 +572,13 @@ lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const
if (err->path) {
LOG_LOCSET(NULL, NULL, err->path, NULL);
} else {
- /* use at least the schema path */
LOG_LOCSET(node, NULL, NULL, NULL);
}
LOGVAL_ERRITEM(ctx, err);
if (err->path) {
LOG_LOCBACK(0, 0, 1, 0);
} else {
- LOG_LOCBACK(1, 0, 0, 0);
+ LOG_LOCBACK(1, 0, 1, 0);
}
}
ly_err_free(err);
@@ -590,7 +683,7 @@ lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t va
/* store the value */
LOG_LOCSET(node->schema, &node->node, NULL, NULL);
- ret = lyd_value_store(ctx, &val, type, value, value_len, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
+ ret = lyd_value_store(ctx, &val, type, value, value_len, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
LOG_LOCBACK(1, 1, 0, 0);
LY_CHECK_RET(ret);
@@ -704,24 +797,15 @@ lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *s
assert(!node->schema);
/* get all keys into a set */
- while ((key = lys_getnext(key, snode, NULL, 0)) && (snode->flags & LYS_KEY)) {
- LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)snode, 1, NULL), cleanup);
+ while ((key = lys_getnext(key, snode, NULL, 0)) && (key->flags & LYS_KEY)) {
+ LY_CHECK_GOTO(ret = ly_set_add(&key_set, (void *)key, 1, NULL), cleanup);
}
LY_LIST_FOR(lyd_child(node), child) {
- if (child->schema) {
- LOGERR(LYD_CTX(node), LY_EINVAL, "Unexpected node %s \"%s\".", lys_nodetype2str(child->schema->nodetype),
- LYD_NAME(child));
- ret = LY_EINVAL;
- goto cleanup;
- }
-
- opaq_k = (struct lyd_node_opaq *)child;
-
/* find the key schema node */
for (i = 0; i < key_set.count; ++i) {
key = key_set.snodes[i];
- if (!strcmp(key->name, opaq_k->name.name)) {
+ if (!strcmp(key->name, LYD_NAME(child))) {
break;
}
}
@@ -733,9 +817,15 @@ lyd_parse_opaq_list_error(const struct lyd_node *node, const struct lysc_node *s
/* key found */
ly_set_rm_index(&key_set, i, NULL);
+ if (child->schema) {
+ /* valid key */
+ continue;
+ }
+
/* check value */
- ret = lys_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
- opaq_k->val_prefix_data);
+ opaq_k = (struct lyd_node_opaq *)child;
+ ret = ly_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
+ opaq_k->val_prefix_data, opaq_k->hints);
LY_CHECK_GOTO(ret, cleanup);
}
@@ -754,93 +844,124 @@ cleanup:
LIBYANG_API_DEF LY_ERR
lyd_parse_opaq_error(const struct lyd_node *node)
{
+ LY_ERR rc = LY_SUCCESS;
const struct ly_ctx *ctx;
const struct lyd_node_opaq *opaq;
const struct lyd_node *parent;
const struct lys_module *mod;
- const struct lysc_node *snode;
+ const struct lysc_node *sparent, *snode;
+ uint32_t loc_node = 0, loc_path = 0;
- LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, !lyd_parent(node) || lyd_parent(node)->schema, LY_EINVAL);
+ LY_CHECK_ARG_RET(LYD_CTX(node), node, !node->schema, LY_EINVAL);
ctx = LYD_CTX(node);
opaq = (struct lyd_node_opaq *)node;
parent = lyd_parent(node);
+ sparent = lyd_node_schema(parent);
+
+ if (parent) {
+ LOG_LOCSET(NULL, parent, NULL, NULL);
+ ++loc_node;
+ } else {
+ LOG_LOCSET(NULL, NULL, "/", NULL);
+ ++loc_path;
+ }
if (!opaq->name.module_ns) {
LOGVAL(ctx, LYVE_REFERENCE, "Unknown module of node \"%s\".", opaq->name.name);
- return LY_EVALID;
+ rc = LY_EVALID;
+ goto cleanup;
}
/* module */
switch (opaq->format) {
case LY_VALUE_XML:
- if (!parent || strcmp(opaq->name.module_ns, parent->schema->module->ns)) {
+ if (!sparent || strcmp(opaq->name.module_ns, sparent->module->ns)) {
mod = ly_ctx_get_module_implemented_ns(ctx, opaq->name.module_ns);
if (!mod) {
LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module with namespace \"%s\" of node \"%s\" in the context.",
opaq->name.module_ns, opaq->name.name);
- return LY_EVALID;
+ rc = LY_EVALID;
+ goto cleanup;
}
} else {
/* inherit */
- mod = parent->schema->module;
+ mod = sparent->module;
}
break;
case LY_VALUE_JSON:
case LY_VALUE_LYB:
- if (!parent || strcmp(opaq->name.module_name, parent->schema->module->name)) {
+ if (!sparent || strcmp(opaq->name.module_name, sparent->module->name)) {
mod = ly_ctx_get_module_implemented(ctx, opaq->name.module_name);
if (!mod) {
LOGVAL(ctx, LYVE_REFERENCE, "No (implemented) module named \"%s\" of node \"%s\" in the context.",
opaq->name.module_name, opaq->name.name);
- return LY_EVALID;
+ rc = LY_EVALID;
+ goto cleanup;
}
} else {
/* inherit */
- mod = parent->schema->module;
+ mod = sparent->module;
}
break;
default:
LOGERR(ctx, LY_EINVAL, "Unsupported value format.");
- return LY_EINVAL;
+ rc = LY_EINVAL;
+ goto cleanup;
}
/* schema */
- snode = lys_find_child(parent ? parent->schema : NULL, mod, opaq->name.name, 0, 0, 0);
- if (!snode && parent && parent->schema && (parent->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
+ snode = lys_find_child(sparent, mod, opaq->name.name, 0, 0, 0);
+ if (!snode && sparent && (sparent->nodetype & (LYS_RPC | LYS_ACTION))) {
/* maybe output node */
- snode = lys_find_child(parent->schema, mod, opaq->name.name, 0, 0, LYS_GETNEXT_OUTPUT);
+ snode = lys_find_child(sparent, mod, opaq->name.name, 0, 0, LYS_GETNEXT_OUTPUT);
}
if (!snode) {
- if (parent) {
+ if (sparent) {
LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found as a child of \"%s\" node.", opaq->name.name,
- LYD_NAME(parent));
+ sparent->name);
} else {
LOGVAL(ctx, LYVE_REFERENCE, "Node \"%s\" not found in the \"%s\" module.", opaq->name.name, mod->name);
}
- return LY_EVALID;
+ rc = LY_EVALID;
+ goto cleanup;
}
+ /* schema node exists */
+ LOG_LOCBACK(0, loc_node, loc_path, 0);
+ loc_node = 0;
+ loc_path = 0;
+ LOG_LOCSET(NULL, node, NULL, NULL);
+ ++loc_node;
+
if (snode->nodetype & LYD_NODE_TERM) {
/* leaf / leaf-list */
- LY_CHECK_RET(lys_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data));
+ rc = ly_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data, opaq->hints);
+ LY_CHECK_GOTO(rc, cleanup);
} else if (snode->nodetype == LYS_LIST) {
/* list */
- LY_CHECK_RET(lyd_parse_opaq_list_error(node, snode));
+ rc = lyd_parse_opaq_list_error(node, snode);
+ LY_CHECK_GOTO(rc, cleanup);
} else if (snode->nodetype & LYD_NODE_INNER) {
/* inner node */
if (opaq->value) {
LOGVAL(ctx, LYVE_DATA, "Invalid value \"%s\" for %s \"%s\".", opaq->value,
lys_nodetype2str(snode->nodetype), snode->name);
- return LY_EVALID;
+ rc = LY_EVALID;
+ goto cleanup;
}
} else {
LOGERR(ctx, LY_EINVAL, "Unexpected opaque schema node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
- return LY_EINVAL;
+ rc = LY_EINVAL;
+ goto cleanup;
}
LOGERR(ctx, LY_EINVAL, "Unexpected valid opaque node %s \"%s\".", lys_nodetype2str(snode->nodetype), snode->name);
- return LY_EINVAL;
+ rc = LY_EINVAL;
+
+cleanup:
+ LOG_LOCBACK(0, loc_node, loc_path, 0);
+ return rc;
}
LIBYANG_API_DEF const char *
@@ -970,7 +1091,7 @@ lyd_any_copy_value(struct lyd_node *trg, const union lyd_any_value *value, LYD_A
return LY_SUCCESS;
}
-const struct lysc_node *
+LIBYANG_API_DEF const struct lysc_node *
lyd_node_schema(const struct lyd_node *node)
{
const struct lysc_node *schema = NULL;
@@ -983,27 +1104,30 @@ lyd_node_schema(const struct lyd_node *node)
return node->schema;
}
+ /* find the first schema node in the parents */
+ for (iter = lyd_parent(node); iter && !iter->schema; iter = lyd_parent(iter)) {}
+ if (iter) {
+ prev_iter = iter;
+ schema = prev_iter->schema;
+ }
+
/* get schema node of an opaque node */
do {
/* get next data node */
for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
- /* get equivalent schema node */
- if (iter->schema) {
- schema = iter->schema;
- } else {
- /* get module */
- mod = lyd_owner_module(iter);
- if (!mod && !schema) {
- /* top-level opaque node has unknown module */
- break;
- }
-
- /* get schema node */
- schema = lys_find_child(schema, mod ? mod : schema->module, LYD_NAME(iter), 0, 0, 0);
+ /* get module */
+ mod = lyd_node_module(iter);
+ if (!mod) {
+ /* unknown module, no schema node */
+ schema = NULL;
+ break;
}
- /* remember to move to the descendant */
+ /* get schema node */
+ schema = lys_find_child(schema, mod, LYD_NAME(iter), 0, 0, 0);
+
+ /* move to the descendant */
prev_iter = iter;
} while (schema && (iter != node));
@@ -1068,9 +1192,7 @@ lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node
{
struct lyd_node **match_p;
struct lyd_node_inner *parent;
- const struct lysc_node *cur_schema;
uint32_t hash;
- lyht_value_equal_cb ht_cb;
assert(schema);
if (!siblings) {
@@ -1084,23 +1206,17 @@ lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node
parent = siblings->parent;
if (parent && parent->schema && parent->children_ht) {
/* calculate our hash */
- hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
- hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
- hash = dict_hash_multi(hash, NULL, 0);
-
- /* use special hash table function */
- ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
+ hash = lyht_hash_multi(0, schema->module->name, strlen(schema->module->name));
+ hash = lyht_hash_multi(hash, schema->name, strlen(schema->name));
+ hash = lyht_hash_multi(hash, NULL, 0);
- /* find by hash */
- if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
+ /* find by hash but use special hash table function (and stay thread-safe) */
+ if (!lyht_find_with_val_cb(parent->children_ht, &schema, hash, lyd_hash_table_schema_val_equal, (void **)&match_p)) {
siblings = *match_p;
} else {
/* not found */
siblings = NULL;
}
-
- /* set the original hash table compare function back */
- lyht_set_cb(parent->children_ht, ht_cb);
} else {
/* find first sibling */
if (siblings->parent) {
@@ -1111,25 +1227,22 @@ lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node
}
}
- /* search manually without hashes */
- for ( ; siblings; siblings = siblings->next) {
- cur_schema = lyd_node_schema(siblings);
- if (!cur_schema) {
- /* some unknown opaque node */
- continue;
- }
-
+ /* search manually without hashes and ignore opaque nodes (cannot be found by hashes) */
+ for ( ; siblings && siblings->schema; siblings = siblings->next) {
/* schema match is enough */
- if (cur_schema->module->ctx == schema->module->ctx) {
- if (cur_schema == schema) {
+ if (LYD_CTX(siblings) == schema->module->ctx) {
+ if (siblings->schema == schema) {
break;
}
} else {
- if (!strcmp(cur_schema->name, schema->name) && !strcmp(cur_schema->module->name, schema->module->name)) {
+ if (!strcmp(LYD_NAME(siblings), schema->name) && !strcmp(siblings->schema->module->name, schema->module->name)) {
break;
}
}
}
+ if (siblings && !siblings->schema) {
+ siblings = NULL;
+ }
}
if (!siblings) {
@@ -1468,6 +1581,52 @@ ly_format2str(LY_VALUE_FORMAT format)
return NULL;
}
+LIBYANG_API_DEF int
+ly_time_tz_offset(void)
+{
+ return ly_time_tz_offset_at(time(NULL));
+}
+
+LIBYANG_API_DEF int
+ly_time_tz_offset_at(time_t time)
+{
+ struct tm tm_local, tm_utc;
+ int result = 0;
+
+ /* init timezone */
+ tzset();
+
+ /* get local and UTC time */
+ localtime_r(&time, &tm_local);
+ gmtime_r(&time, &tm_utc);
+
+ /* account for year/month/day change by adding/subtracting from the hours, the change cannot be more than 1 day */
+ if (tm_local.tm_year < tm_utc.tm_year) {
+ tm_utc.tm_hour += 24;
+ } else if (tm_local.tm_year > tm_utc.tm_year) {
+ tm_local.tm_hour += 24;
+ } else if (tm_local.tm_mon < tm_utc.tm_mon) {
+ tm_utc.tm_hour += 24;
+ } else if (tm_local.tm_mon > tm_utc.tm_mon) {
+ tm_local.tm_hour += 24;
+ } else if (tm_local.tm_mday < tm_utc.tm_mday) {
+ tm_utc.tm_hour += 24;
+ } else if (tm_local.tm_mday > tm_utc.tm_mday) {
+ tm_local.tm_hour += 24;
+ }
+
+ /* hours shift in seconds */
+ result += (tm_local.tm_hour - tm_utc.tm_hour) * 3600;
+
+ /* minutes shift in seconds */
+ result += (tm_local.tm_min - tm_utc.tm_min) * 60;
+
+ /* seconds shift */
+ result += tm_local.tm_sec - tm_utc.tm_sec;
+
+ return result;
+}
+
LIBYANG_API_DEF LY_ERR
ly_time_str2time(const char *value, time_t *time, char **fractions_s)
{
@@ -1486,6 +1645,28 @@ ly_time_str2time(const char *value, time_t *time, char **fractions_s)
tm.tm_min = atoi(&value[14]);
tm.tm_sec = atoi(&value[17]);
+ /* explicit checks for some gross errors */
+ if (tm.tm_mon > 11) {
+ LOGERR(NULL, LY_EINVAL, "Invalid date-and-time month \"%d\".", tm.tm_mon);
+ return LY_EINVAL;
+ }
+ if ((tm.tm_mday < 1) || (tm.tm_mday > 31)) {
+ LOGERR(NULL, LY_EINVAL, "Invalid date-and-time day of month \"%d\".", tm.tm_mday);
+ return LY_EINVAL;
+ }
+ if (tm.tm_hour > 23) {
+ LOGERR(NULL, LY_EINVAL, "Invalid date-and-time hours \"%d\".", tm.tm_hour);
+ return LY_EINVAL;
+ }
+ if (tm.tm_min > 59) {
+ LOGERR(NULL, LY_EINVAL, "Invalid date-and-time minutes \"%d\".", tm.tm_min);
+ return LY_EINVAL;
+ }
+ if (tm.tm_sec > 60) {
+ LOGERR(NULL, LY_EINVAL, "Invalid date-and-time seconds \"%d\".", tm.tm_sec);
+ return LY_EINVAL;
+ }
+
t = timegm(&tm);
i = 19;
@@ -1506,12 +1687,24 @@ ly_time_str2time(const char *value, time_t *time, char **fractions_s)
shift = 0;
} else {
shift = strtol(&value[i], NULL, 10);
+ if (shift > 23) {
+ LOGERR(NULL, LY_EINVAL, "Invalid date-and-time timezone hour \"%" PRIi64 "\".", shift);
+ return LY_EINVAL;
+ }
shift = shift * 60 * 60; /* convert from hours to seconds */
- shift_m = strtol(&value[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
+
+ shift_m = strtol(&value[i + 4], NULL, 10);
+ if (shift_m > 59) {
+ LOGERR(NULL, LY_EINVAL, "Invalid date-and-time timezone minutes \"%" PRIi64 "\".", shift_m);
+ return LY_EINVAL;
+ }
+ shift_m *= 60; /* convert from minutes to seconds */
+
/* correct sign */
if (shift < 0) {
shift_m *= -1;
}
+
/* connect hours and minutes of the shift */
shift = shift + shift_m;
}
@@ -1535,41 +1728,24 @@ LIBYANG_API_DEF LY_ERR
ly_time_time2str(time_t time, const char *fractions_s, char **str)
{
struct tm tm;
- char zoneshift[8];
- int32_t zonediff_h, zonediff_m;
+ char zoneshift[12];
+ int zonediff_s, zonediff_h, zonediff_m;
LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
- /* initialize the local timezone */
+ /* init timezone */
tzset();
-#ifdef HAVE_TM_GMTOFF
/* convert */
if (!localtime_r(&time, &tm)) {
return LY_ESYS;
}
- /* get timezone offset */
- if (tm.tm_gmtoff == 0) {
- /* time is Zulu (UTC) */
- zonediff_h = 0;
- zonediff_m = 0;
- } else {
- /* timezone offset */
- zonediff_h = tm.tm_gmtoff / 60 / 60;
- zonediff_m = tm.tm_gmtoff / 60 % 60;
- }
+ /* get timezone offset (do not use tm_gmtoff to avoid portability problems) */
+ zonediff_s = ly_time_tz_offset_at(time);
+ zonediff_h = zonediff_s / 60 / 60;
+ zonediff_m = zonediff_s / 60 % 60;
sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m);
-#else
- /* convert */
- if (!gmtime_r(&time, &tm)) {
- return LY_ESYS;
- }
-
- (void)zonediff_h;
- (void)zonediff_m;
- sprintf(zoneshift, "-00:00");
-#endif
/* print */
if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s",