schema tree BUGFIX accessible tree fixes
diff --git a/src/parser_stmt.c b/src/parser_stmt.c
index 4c14501..5703ffe 100644
--- a/src/parser_stmt.c
+++ b/src/parser_stmt.c
@@ -746,7 +746,7 @@
break;
case LY_STMT_PATH:
LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_PATH, 0, &str_path, Y_STR_ARG, &type->exts));
- ret = ly_path_parse(PARSER_CTX(ctx), str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ ret = ly_path_parse(PARSER_CTX(ctx), NULL, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
lydict_remove(PARSER_CTX(ctx), str_path);
LY_CHECK_RET(ret);
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 104786c..47833ab 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -2039,7 +2039,7 @@
}
LY_CHECK_RET(parse_text_field(ctx, in, LYEXT_SUBSTMT_PATH, 0, &str_path, Y_STR_ARG, &type->exts));
- ret = ly_path_parse(ctx->ctx, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ ret = ly_path_parse(ctx->ctx, NULL, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
lydict_remove(ctx->ctx, str_path);
LY_CHECK_RET(ret);
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 89dc4cf..a3d208d 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -465,7 +465,7 @@
const char *str_path;
LY_CHECK_RET(yin_parse_simple_element(ctx, kw, &str_path, YIN_ARG_VALUE, Y_STR_ARG, &type->exts));
- ret = ly_path_parse(ctx->xmlctx->ctx, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
+ ret = ly_path_parse(ctx->xmlctx->ctx, NULL, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
lydict_remove(ctx->xmlctx->ctx, str_path);
LY_CHECK_RET(ret);
diff --git a/src/path.c b/src/path.c
index 4017be7..7558f95 100644
--- a/src/path.c
+++ b/src/path.c
@@ -31,10 +31,13 @@
#include "tree_schema_internal.h"
#include "xpath.h"
+#define LOGVAL_P(CTX, CUR_NODE, CODE, FORMAT...) ly_vlog(CTX, (CUR_NODE) ? LY_VLOG_LYSC : LY_VLOG_NONE, CUR_NODE, CODE, ##FORMAT)
+
/**
* @brief Check predicate syntax.
*
* @param[in] ctx libyang context.
+ * @param[in] cur_node Current (original context) node.
* @param[in] exp Parsed predicate.
* @param[in,out] tok_idx Index in @p exp, is adjusted.
* @param[in] prefix Prefix option.
@@ -42,8 +45,8 @@
* @return LY_ERR value.
*/
static LY_ERR
-ly_path_check_predicate(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t *tok_idx, uint8_t prefix,
- uint8_t pred)
+ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lyxp_expr *exp,
+ uint16_t *tok_idx, uint8_t prefix, uint8_t pred)
{
struct ly_set *set = NULL;
uint32_t i;
@@ -64,8 +67,8 @@
/* check prefix based on the options */
name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
- exp->expr + exp->tok_pos[*tok_idx]);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
+ exp->expr + exp->tok_pos[*tok_idx]);
goto error;
}
if (!name) {
@@ -80,8 +83,7 @@
for (i = 0; i < set->count; ++i) {
/* all the keys must be from the same module so this comparison should be fine */
if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.",
- name_len, name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
goto error;
}
}
@@ -143,8 +145,7 @@
for (i = 0; i < set->count; ++i) {
/* all the keys must be from the same module so this comparison should be fine */
if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.",
- name_len, name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
goto error;
}
}
@@ -161,8 +162,8 @@
/* FuncName */
LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), error);
if ((exp->tok_len[*tok_idx] != 7) || strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", 7)) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
- exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
+ exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
goto error;
}
++(*tok_idx);
@@ -199,8 +200,8 @@
} while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
} else {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]),
- exp->expr + exp->tok_pos[*tok_idx]);
+ LOGVAL_P(ctx, cur_node, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]),
+ exp->expr + exp->tok_pos[*tok_idx]);
goto error;
}
}
@@ -214,8 +215,8 @@
}
LY_ERR
-ly_path_parse(const struct ly_ctx *ctx, const char *str_path, size_t path_len, uint8_t begin, uint8_t lref,
- uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
+ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
+ uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
{
struct lyxp_expr *exp;
uint16_t tok_idx;
@@ -250,23 +251,23 @@
/* check prefix based on the options */
if ((prefix == LY_PATH_PREFIX_MANDATORY) && !strnstr(exp->expr + exp->tok_pos[tok_idx], ":", exp->tok_len[tok_idx])) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[tok_idx],
- exp->expr + exp->tok_pos[tok_idx]);
+ LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[tok_idx],
+ exp->expr + exp->tok_pos[tok_idx]);
goto error;
}
++tok_idx;
/* Predicate* */
- LY_CHECK_GOTO(ly_path_check_predicate(ctx, exp, &tok_idx, prefix, pred), error);
+ LY_CHECK_GOTO(ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
/* '/' */
} while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
/* trailing token check */
if (exp->used > tok_idx) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.",
- exp->expr + exp->tok_pos[tok_idx]);
+ LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.",
+ exp->expr + exp->tok_pos[tok_idx]);
goto error;
}
@@ -279,8 +280,8 @@
}
LY_ERR
-ly_path_parse_predicate(const struct ly_ctx *ctx, const char *str_path, size_t path_len, uint8_t prefix, uint8_t pred,
- struct lyxp_expr **expr)
+ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const char *str_path,
+ size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
{
struct lyxp_expr *exp;
uint16_t tok_idx;
@@ -293,12 +294,12 @@
LY_CHECK_GOTO(!exp, error);
tok_idx = 0;
- LY_CHECK_GOTO(ly_path_check_predicate(ctx, exp, &tok_idx, prefix, pred), error);
+ LY_CHECK_GOTO(ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
/* trailing token check */
if (exp->used > tok_idx) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
- exp->expr + exp->tok_pos[tok_idx]);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
+ exp->expr + exp->tok_pos[tok_idx]);
goto error;
}
@@ -314,6 +315,7 @@
* @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
*
* @param[in] ctx libyang context.
+ * @param[in] cur_node Optional current (original context) node.
* @param[in] cur_mod Module of the current (original context) node. Needed for ::LYD_SCHEMA.
* @param[in] prev_ctx_node Previous context node. Needed for ::LYD_JSON.
* @param[in] expr Parsed path.
@@ -328,9 +330,10 @@
* @return LY_ERR value.
*/
static LY_ERR
-ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *prev_ctx_node,
- const struct lyxp_expr *expr, uint16_t tok_idx, uint8_t lref, ly_clb_resolve_prefix resolve_prefix,
- void *prefix_data, LYD_FORMAT format, const struct lys_module **mod, const char **name, size_t *name_len)
+ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
+ const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx,
+ uint8_t lref, ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format,
+ const struct lys_module **mod, const char **name, size_t *name_len)
{
const char *ptr;
size_t len;
@@ -345,12 +348,12 @@
if (ptr) {
*mod = resolve_prefix(ctx, expr->expr + expr->tok_pos[tok_idx], len, prefix_data);
if (!*mod) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Prefix \"%.*s\" not found of a module in path.",
- len, expr->expr + expr->tok_pos[tok_idx]);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Prefix \"%.*s\" not found of a module in path.",
+ len, expr->expr + expr->tok_pos[tok_idx]);
return LY_EVALID;
} else if (!(*mod)->implemented) {
if (lref == LY_PATH_LREF_FALSE) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
return LY_EVALID;
}
lys_set_implemented_internal((struct lys_module *)*mod, 2);
@@ -386,10 +389,10 @@
}
LY_ERR
-ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
- const struct lyxp_expr *expr, uint16_t *tok_idx, ly_clb_resolve_prefix resolve_prefix,
- void *prefix_data, LYD_FORMAT format, struct ly_path_predicate **predicates,
- enum ly_path_pred_type *pred_type)
+ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
+ const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx,
+ ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format,
+ struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
{
struct ly_path_predicate *p;
const struct lysc_node *key;
@@ -409,26 +412,26 @@
if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
if (ctx_node->nodetype != LYS_LIST) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
- lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
+ lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
return LY_EVALID;
} else if (ctx_node->flags & LYS_KEYLESS) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
- lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
+ lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
return LY_EVALID;
}
do {
/* NameTest, find the key */
- LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE, resolve_prefix,
- prefix_data, format, &mod, &name, &name_len));
+ LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE,
+ resolve_prefix, prefix_data, format, &mod, &name, &name_len));
key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
if (!key) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
return LY_ENOTFOUND;
} else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
- LOGVAL(ctx, LY_VLOG_LYSC, key, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
- lys_nodetype2str(key->nodetype), key->name);
+ LOGVAL_P(ctx, cur_node ? cur_node : key, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
+ lys_nodetype2str(key->nodetype), key->name);
return LY_EVALID;
}
++(*tok_idx);
@@ -465,8 +468,8 @@
}
if (LY_ARRAY_COUNT(*predicates) != key_count) {
/* names (keys) are unique - it was checked when parsing */
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
- lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
+ lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, NULL, *predicates);
*predicates = NULL;
return LY_EVALID;
@@ -474,8 +477,8 @@
} else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
if (ctx_node->nodetype != LYS_LEAFLIST) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
- lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
+ lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
return LY_EVALID;
}
++(*tok_idx);
@@ -500,12 +503,12 @@
} else {
assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
- lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
+ lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
return LY_EVALID;
} else if (ctx_node->flags & LYS_CONFIG_W) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Positional predicate defined for configuration"
- " %s \"%s\" in path.", lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
+ lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
return LY_EVALID;
}
@@ -554,26 +557,26 @@
}
if (ctx_node->nodetype != LYS_LIST) {
- LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
- lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
+ LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
+ lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
return LY_EVALID;
} else if (ctx_node->flags & LYS_KEYLESS) {
- LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
- lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
+ LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
+ lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
return LY_EVALID;
}
do {
/* NameTest, find the key */
- LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node->module, ctx_node, expr, *tok_idx,
+ LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx,
LY_PATH_LREF_TRUE, resolve_prefix, prefix_data, format, &mod, &name, &name_len));
key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
if (!key) {
- LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
+ LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
return LY_EVALID;
} else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
- LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
- lys_nodetype2str(key->nodetype), key->name);
+ LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
+ lys_nodetype2str(key->nodetype), key->name);
return LY_EVALID;
}
++(*tok_idx);
@@ -607,7 +610,7 @@
/* go to parent */
if (!node) {
- LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Too many parent references in path.");
+ LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
return LY_EVALID;
}
node = lysc_data_parent(node);
@@ -624,12 +627,11 @@
/* NameTest */
assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
- LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node->module, node, expr, *tok_idx,
+ LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node, cur_node->module, node, expr, *tok_idx,
LY_PATH_LREF_TRUE, resolve_prefix, prefix_data, format, &mod, &name, &name_len));
node2 = lys_find_child(node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
if (!node2) {
- LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.",
- name_len, name);
+ LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
return LY_EVALID;
}
node = node2;
@@ -638,8 +640,9 @@
/* check the last target node */
if (node->nodetype != LYS_LEAF) {
- LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in"
- " leafref predicate in path.", lys_nodetype2str(node->nodetype), node->name);
+ LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH,
+ "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
+ lys_nodetype2str(node->nodetype), node->name);
return LY_EVALID;
}
@@ -664,22 +667,24 @@
LY_ERR ret = LY_SUCCESS;
uint16_t tok_idx = 0;
const struct lys_module *mod;
- const struct lysc_node *node2, *cur_node;
+ const struct lysc_node *node2, *cur_node, *op;
struct ly_path *p = NULL;
int getnext_opts;
const char *name;
size_t name_len;
assert(ctx);
- assert((expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) || (lref == LY_PATH_LREF_FALSE) || ctx_node);
+ assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
- if (lref == LY_PATH_LREF_TRUE) {
- /* remember original context node */
- cur_node = ctx_node;
- }
+ /* find operation, if we are in any */
+ for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent);
+
+ /* remember original context node */
+ cur_node = ctx_node;
+
*path = NULL;
if (oper == LY_PATH_OPER_OUTPUT) {
@@ -697,7 +702,7 @@
/* relative path */
while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
if (!ctx_node) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Too many parent references in path.");
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
return LY_EVALID;
}
@@ -717,20 +722,20 @@
do {
/* check last compiled inner node, whether it is uniquely identified (even key-less list) */
if (p && (lref == LY_PATH_LREF_FALSE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
- lys_nodetype2str(p->node->nodetype), p->node->name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
+ lys_nodetype2str(p->node->nodetype), p->node->name);
return LY_EVALID;
}
/* get module and node name */
- LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_mod, ctx_node, expr, tok_idx, lref, resolve_prefix,
+ LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, lref, resolve_prefix,
prefix_data, format, &mod, &name, &name_len), cleanup);
++tok_idx;
/* find the next node */
node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
- if (!node2) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
+ if (!node2 || ((node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
ret = LY_EVALID;
goto cleanup;
}
@@ -744,8 +749,8 @@
if (lref == LY_PATH_LREF_TRUE) {
ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, resolve_prefix, prefix_data, format);
} else {
- ret = ly_path_compile_predicate(ctx, cur_mod, ctx_node, expr, &tok_idx, resolve_prefix, prefix_data, format,
- &p->predicates, &p->pred_type);
+ ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, resolve_prefix,
+ prefix_data, format, &p->predicates, &p->pred_type);
}
LY_CHECK_GOTO(ret, cleanup);
} while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
@@ -753,8 +758,8 @@
/* check last compiled node */
if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE)
&& (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
- lys_nodetype2str(p->node->nodetype), p->node->name);
+ LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
+ lys_nodetype2str(p->node->nodetype), p->node->name);
return LY_EVALID;
}
diff --git a/src/path.h b/src/path.h
index a60fdc6..2e32f91 100644
--- a/src/path.h
+++ b/src/path.h
@@ -93,6 +93,7 @@
* @brief Parse path into XPath token structure and perform all additional checks.
*
* @param[in] ctx libyang context.
+ * @param[in] ctx_node Optional context node.
* @param[in] str_path Path to parse.
* @param[in] path_len Length of @p str_path.
* @param[in] begin Begin option (@ref path_begin_options).
@@ -102,13 +103,14 @@
* @param[out] expr Parsed path.
* @return LY_ERR value.
*/
-LY_ERR ly_path_parse(const struct ly_ctx *ctx, const char *str_path, size_t path_len, uint8_t begin, uint8_t lref,
- uint8_t prefix, uint8_t pred, struct lyxp_expr **expr);
+LY_ERR ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
+ uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr);
/**
* @brief Parse predicate into XPath token structure and perform all additional checks.
*
* @param[in] ctx libyang context.
+ * @param[in] cur_node Optional current (original context) node.
* @param[in] str_path Path to parse.
* @param[in] path_len Length of @p str_path.
* @param[in] prefix Prefix option (@ref path_prefix_options).
@@ -116,8 +118,8 @@
* @param[out] expr Parsed path.
* @return LY_ERR value.
*/
-LY_ERR ly_path_parse_predicate(const struct ly_ctx *ctx, const char *str_path, size_t path_len, uint8_t prefix,
- uint8_t pred, struct lyxp_expr **expr);
+LY_ERR ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const char *str_path,
+ size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr);
/**
* @defgroup path_oper_options Path operation options.
@@ -142,7 +144,7 @@
*
* @param[in] ctx libyang context.
* @param[in] cur_mod Module of the current (original context) node. Used for nodes without prefix for ::LYD_SCHEMA format.
- * @param[in] ctx_node Context node. Can be NULL for absolute paths.
+ * @param[in] ctx_node Optional context node.
* @param[in] expr Parsed path.
* @param[in] lref Lref option (@ref path_lref_options).
* @param[in] oper Oper option (@ref path_oper_options).
@@ -161,6 +163,7 @@
* @brief Compile predicate into ly_path_predicate structure. Only simple predicates (not leafref) are supported.
*
* @param[in] ctx libyang context.
+ * @param[in] cur_node Optional current (original context) node.
* @param[in] cur_mod Module of the current (original context) node. Used for nodes without prefix for ::LYD_SCHEMA format.
* @param[in] ctx_node Context node, node for which the predicate is defined.
* @param[in] expr Parsed path.
@@ -172,7 +175,7 @@
* @param[out] pred_type Type of the compiled predicate(s).
* @return LY_ERR value.
*/
-LY_ERR ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lys_module *cur_mod,
+LY_ERR ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx,
ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format,
struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type);
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 429cf96..2b64a20 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -1493,6 +1493,8 @@
/* init */
*err = NULL;
+ ctx_scnode = (options & (LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_INCOMPLETE_DATA)) ?
+ (struct lysc_node *)context_node : ((struct lyd_node *)context_node)->schema;
if ((options & LY_TYPE_OPTS_SCHEMA) && (options & LY_TYPE_OPTS_INCOMPLETE_DATA)) {
/* we have incomplete schema tree, so we are actually just storing the original value for future validation */
@@ -1525,16 +1527,14 @@
prefixes = ly_type_get_prefixes(ctx, value, value_len, resolve_prefix, parser);
/* parse the value */
- ret = ly_path_parse(ctx, value, value_len, LY_PATH_BEGIN_ABSOLUTE, LY_PATH_LREF_FALSE, LY_PATH_PREFIX_MANDATORY,
- LY_PATH_PRED_SIMPLE, &exp);
+ ret = ly_path_parse(ctx, ctx_scnode, value, value_len, LY_PATH_BEGIN_ABSOLUTE, LY_PATH_LREF_FALSE,
+ LY_PATH_PREFIX_MANDATORY, LY_PATH_PRED_SIMPLE, &exp);
if (ret) {
erc = asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - syntax error.", (int)value_len, value);
goto error;
}
/* resolve it on schema tree */
- ctx_scnode = (options & (LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_INCOMPLETE_DATA)) ?
- (struct lysc_node *)context_node : ((struct lyd_node *)context_node)->schema;
ret = ly_path_compile(ctx, ctx_scnode->module, NULL, exp, LY_PATH_LREF_FALSE, lysc_is_output(ctx_scnode) ?
LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_SINGLE, ly_type_stored_prefixes_clb,
prefixes, format, &path);
diff --git a/src/tree_data.c b/src/tree_data.c
index 5b2d7f7..9dde20e 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -587,12 +587,12 @@
struct ly_path_predicate *predicates = NULL;
/* parse keys */
- LY_CHECK_GOTO(ret = ly_path_parse_predicate(schema->module->ctx, keys, keys_len, LY_PATH_PREFIX_OPTIONAL,
+ LY_CHECK_GOTO(ret = ly_path_parse_predicate(schema->module->ctx, NULL, keys, keys_len, LY_PATH_PREFIX_OPTIONAL,
LY_PATH_PRED_KEYS, &expr), cleanup);
/* compile them */
- LY_CHECK_GOTO(ret = ly_path_compile_predicate(schema->module->ctx, NULL, schema, expr, &exp_idx, lydjson_resolve_prefix,
- NULL, LYD_JSON, &predicates, &pred_type), cleanup);
+ LY_CHECK_GOTO(ret = ly_path_compile_predicate(schema->module->ctx, NULL, NULL, schema, expr, &exp_idx,
+ lydjson_resolve_prefix, NULL, LYD_JSON, &predicates, &pred_type), cleanup);
/* create the list node */
LY_CHECK_GOTO(ret = lyd_create_list(schema, predicates, node), cleanup);
@@ -1156,7 +1156,7 @@
}
/* parse path */
- LY_CHECK_GOTO(ret = ly_path_parse(ctx, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_FALSE,
+ LY_CHECK_GOTO(ret = ly_path_parse(ctx, NULL, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_FALSE,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &exp), cleanup);
/* compile path */
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index ca53a39..1b99187 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -6810,9 +6810,17 @@
struct lysc_when **when = NULL;
struct lysc_must *musts = NULL;
LY_ERR ret = LY_SUCCESS;
+ const struct lysc_node *op;
memset(&tmp_set, 0, sizeof tmp_set);
opts = LYXP_SCNODE_SCHEMA;
+ if (node->flags & LYS_CONFIG_R) {
+ for (op = node->parent; op && !(op->nodetype & (LYS_RPC | LYS_ACTION)); op = op->parent);
+ if (op) {
+ /* we are actually in output */
+ opts = LYXP_SCNODE_OUTPUT;
+ }
+ }
switch (node->nodetype) {
case LYS_CONTAINER:
@@ -6932,7 +6940,7 @@
static LY_ERR
lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, struct lysc_type_leafref *lref)
{
- const struct lysc_node *target = NULL;
+ const struct lysc_node *target = NULL, *siter;
struct ly_path *p;
struct lysc_type *type;
@@ -6965,8 +6973,9 @@
ctx->path[1] = '\0';
/* check config */
- if (lref->require_instance && (node->flags & LYS_CONFIG_W)) {
- if (target->flags & LYS_CONFIG_R) {
+ if (lref->require_instance) {
+ for (siter = node->parent; siter && !(siter->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); siter = siter->parent);
+ if (!siter && (node->flags & LYS_CONFIG_W) && (target->flags & LYS_CONFIG_R)) {
LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE, "Invalid leafref path \"%s\" - target is supposed"
" to represent configuration data (as the leafref does), but it does not.", lref->path->expr);
return LY_EVALID;
diff --git a/src/xpath.c b/src/xpath.c
index 55a0f6b..533e2da 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -773,6 +773,7 @@
new->ctx = set->ctx;
new->ctx_node = set->ctx_node;
new->root_type = set->root_type;
+ new->context_op = set->context_op;
new->local_mod = set->local_mod;
new->tree = set->tree;
new->format = set->format;
@@ -5360,14 +5361,15 @@
*
* @param[in] node Node to check.
* @param[in] root_type XPath root node type.
+ * @param[in] context_op XPath operation parent.
* @param[in] node_name Node name in the dictionary to move to, NULL for any node.
* @param[in] moveto_mod Expected module of the node, NULL for any.
* @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
* LY_EINVAL if netither node nor any children match)
*/
static LY_ERR
-moveto_node_check(const struct lyd_node *node, enum lyxp_node_type root_type, const char *node_name,
- const struct lys_module *moveto_mod)
+moveto_node_check(const struct lyd_node *node, enum lyxp_node_type root_type, const struct lysc_node *context_op,
+ const char *node_name, const struct lys_module *moveto_mod)
{
/* module check */
if (moveto_mod && (node->schema->module != moveto_mod)) {
@@ -5377,6 +5379,8 @@
/* context check */
if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
return LY_EINVAL;
+ } else if (context_op && (node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node->schema != context_op)) {
+ return LY_EINVAL;
}
/* name check */
@@ -5398,13 +5402,14 @@
*
* @param[in] node Schema node to check.
* @param[in] root_type XPath root node type.
+ * @param[in] context_op XPath operation parent.
* @param[in] node_name Node name in the dictionary to move to, NULL for any nodes.
* @param[in] moveto_mod Expected module of the node, NULL for any.
* @return LY_ERR (LY_ENOT if node does not match, LY_EINVAL if neither node nor any children match)
*/
static LY_ERR
-moveto_scnode_check(const struct lysc_node *node, enum lyxp_node_type root_type, const char *node_name,
- const struct lys_module *moveto_mod)
+moveto_scnode_check(const struct lysc_node *node, enum lyxp_node_type root_type, const struct lysc_node *context_op,
+ const char *node_name, const struct lys_module *moveto_mod)
{
/* module check */
if (moveto_mod && (node->module != moveto_mod)) {
@@ -5414,6 +5419,8 @@
/* context check */
if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
return LY_EINVAL;
+ } else if (context_op && (node->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node != context_op)) {
+ return LY_EINVAL;
}
/* name check */
@@ -5464,7 +5471,7 @@
}
for (sub = siblings; sub; sub = sub->next) {
- rc = moveto_node_check(sub, set->root_type, ncname, mod);
+ rc = moveto_node_check(sub, set->root_type, set->context_op, ncname, mod);
if (rc == LY_SUCCESS) {
if (!replaced) {
set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
@@ -5520,6 +5527,10 @@
if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (scnode->flags & LYS_CONFIG_R)) {
lyxp_set_free_content(set);
goto cleanup;
+ } else if (set->context_op && (scnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))
+ && (scnode != set->context_op)) {
+ lyxp_set_free_content(set);
+ goto cleanup;
}
/* create specific data instance if needed */
@@ -5624,7 +5635,7 @@
iter = NULL;
/* module may not be implemented */
while (mod->implemented && (iter = lys_getnext(iter, NULL, mod->compiled, getnext_opts))) {
- if (!moveto_scnode_check(iter, set->root_type, ncname, mod)) {
+ if (!moveto_scnode_check(iter, set->root_type, set->context_op, ncname, mod)) {
idx = lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM);
/* we need to prevent these nodes from being considered in this moveto */
if ((idx < orig_used) && (idx > i)) {
@@ -5645,7 +5656,7 @@
} else if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
iter = NULL;
while ((iter = lys_getnext(iter, start_parent, NULL, getnext_opts))) {
- if (!moveto_scnode_check(iter, set->root_type, ncname, (mod ? mod : set->local_mod))) {
+ if (!moveto_scnode_check(iter, set->root_type, set->context_op, ncname, (mod ? mod : set->local_mod))) {
idx = lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM);
if ((idx < orig_used) && (idx > i)) {
set->val.scnodes[idx].in_ctx = 2;
@@ -5705,7 +5716,7 @@
/* TREE DFS */
start = set->val.nodes[i].node;
for (elem = next = start; elem; elem = next) {
- rc = moveto_node_check(elem, set->root_type, ncname, mod);
+ rc = moveto_node_check(elem, set->root_type, set->context_op, ncname, mod);
if (!rc) {
/* add matching node into result set */
set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
@@ -5800,7 +5811,7 @@
goto next_iter;
}
- rc = moveto_scnode_check(elem, set->root_type, ncname, mod);
+ rc = moveto_scnode_check(elem, set->root_type, set->context_op, ncname, mod);
if (!rc) {
if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
set->val.scnodes[idx].in_ctx = 1;
@@ -6902,17 +6913,17 @@
prev_lo = ly_log_options(0);
/* parse the predicate(s) */
- LY_CHECK_GOTO(ret = ly_path_parse_predicate(scnode->module->ctx, exp->expr + exp->tok_pos[*tok_idx], pred_len,
+ LY_CHECK_GOTO(ret = ly_path_parse_predicate(scnode->module->ctx, scnode, exp->expr + exp->tok_pos[*tok_idx], pred_len,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &exp2), cleanup);
/* compile */
switch (format) {
case LYD_SCHEMA:
- ret = ly_path_compile_predicate(scnode->module->ctx, scnode->module, scnode, exp2, &pred_idx, lys_resolve_prefix,
- scnode->module, LYD_SCHEMA, predicates, pred_type);
+ ret = ly_path_compile_predicate(scnode->module->ctx, scnode, scnode->module, scnode, exp2, &pred_idx,
+ lys_resolve_prefix, scnode->module, LYD_SCHEMA, predicates, pred_type);
break;
case LYD_JSON:
- ret = ly_path_compile_predicate(scnode->module->ctx, scnode->module, scnode, exp2, &pred_idx,
+ ret = ly_path_compile_predicate(scnode->module->ctx, scnode, scnode->module, scnode, exp2, &pred_idx,
lydjson_resolve_prefix, NULL, LYD_JSON, predicates, pred_type);
break;
case LYD_XML:
@@ -7050,8 +7061,7 @@
if (i == -1) {
path = lysc_path(set->ctx_scnode, LYSC_PATH_LOG, NULL, 0);
LOGWRN(set->ctx, "Schema node \"%.*s\" not found (%.*s) with context node \"%s\".",
- exp->tok_len[*tok_idx], &exp->expr[exp->tok_pos[*tok_idx]],
- exp->tok_pos[*tok_idx] + exp->tok_len[*tok_idx], exp->expr, path);
+ ncname_len, ncname, ncname - exp->expr, exp->expr, path);
free(path);
}
} else {
@@ -8305,19 +8315,25 @@
static enum lyxp_node_type
lyxp_get_root_type(const struct lyd_node *ctx_node, const struct lysc_node *ctx_scnode, int options)
{
+ const struct lysc_node *op;
+
if (options & LYXP_SCNODE_ALL) {
- if (options & LYXP_SCNODE) {
+ for (op = ctx_scnode; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent);
+
+ if (op || (options & LYXP_SCNODE)) {
/* general root that can access everything */
return LYXP_NODE_ROOT;
} else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
/* root context node can access only config data (because we said so, it is unspecified) */
return LYXP_NODE_ROOT_CONFIG;
- } else {
- return LYXP_NODE_ROOT;
}
+ return LYXP_NODE_ROOT;
}
- if (!ctx_node || (ctx_node->schema->flags & LYS_CONFIG_W)) {
+ op = ctx_node ? ctx_node->schema : NULL;
+ for (; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent);
+
+ if (!ctx_node || (!op && (ctx_node->schema->flags & LYS_CONFIG_W))) {
/* root context node can access only config data (because we said so, it is unspecified) */
return LYXP_NODE_ROOT_CONFIG;
}
@@ -8350,6 +8366,9 @@
set->ctx = local_mod->ctx;
set->ctx_node = ctx_node;
set->root_type = lyxp_get_root_type(real_ctx_node, NULL, options);
+ for (set->context_op = ctx_node->schema;
+ set->context_op && !(set->context_op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF));
+ set->context_op = set->context_op->parent);
set->local_mod = local_mod;
set->tree = tree;
set->format = format;
@@ -8618,6 +8637,9 @@
set->ctx = ctx;
set->ctx_scnode = ctx_scnode;
set->root_type = lyxp_get_root_type(NULL, real_ctx_scnode, options);
+ for (set->context_op = ctx_scnode;
+ set->context_op && !(set->context_op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF));
+ set->context_op = set->context_op->parent);
set->local_mod = local_mod;
set->format = format;
diff --git a/src/xpath.h b/src/xpath.h
index 72858dd..a79ea82 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -256,6 +256,7 @@
const struct lysc_node *ctx_scnode;
};
enum lyxp_node_type root_type;
+ const struct lysc_node *context_op;
const struct lys_module *local_mod;
const struct lyd_node *tree;
LYD_FORMAT format;
diff --git a/tests/utests/schema/test_schema.c b/tests/utests/schema/test_schema.c
index 9a03332..d8da7d6 100644
--- a/tests/utests/schema/test_schema.c
+++ b/tests/utests/schema/test_schema.c
@@ -102,6 +102,7 @@
void test_date(void **state);
void test_revisions(void **state);
void test_typedef(void **state);
+void test_accessible_tree(void **state);
/* test_schema_stmts.c */
void test_identity(void **state);
@@ -115,6 +116,7 @@
cmocka_unit_test_setup_teardown(test_date, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_revisions, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_typedef, logger_setup, logger_teardown),
+ cmocka_unit_test_setup_teardown(test_accessible_tree, logger_setup, logger_teardown),
/** test_schema_stmts.c */
cmocka_unit_test_setup_teardown(test_identity, logger_setup, logger_teardown),
diff --git a/tests/utests/schema/test_schema_common.c b/tests/utests/schema/test_schema_common.c
index 5b75b9e..9e70bdc 100644
--- a/tests/utests/schema/test_schema_common.c
+++ b/tests/utests/schema/test_schema_common.c
@@ -314,3 +314,390 @@
*state = NULL;
ly_ctx_destroy(ctx, NULL);
}
+
+void
+test_accessible_tree(void **state)
+{
+ *state = test_accessible_tree;
+
+ struct ly_ctx *ctx = NULL;
+ const char *str;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
+ logbuf_clean();
+
+ /* config -> config */
+ str =
+ "module a {"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "container cont2 {"
+ "leaf l2 {"
+ "must ../../cont/l;"
+ "type leafref {"
+ "path /cont/l;"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("");
+
+ /* config -> state leafref */
+ str =
+ "module b {"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "config false;"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "container cont2 {"
+ "leaf l2 {"
+ "type leafref {"
+ "path /cont/l;"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_EVALID);
+ logbuf_assert("Invalid leafref path \"/cont/l\" - target is supposed to represent configuration data"
+ " (as the leafref does), but it does not. /b:cont2/l2");
+ logbuf_clean();
+
+ /* config -> state must */
+ str =
+ "module b {"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "config false;"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "container cont2 {"
+ "leaf l2 {"
+ "must ../../cont/l;"
+ "type empty;"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("Schema node \"l\" not found (../../cont/) with context node \"/b:cont2/l2\".");
+ logbuf_clean();
+
+ /* state -> config */
+ str =
+ "module c {"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "container cont2 {"
+ "config false;"
+ "leaf l2 {"
+ "must ../../cont/l;"
+ "type leafref {"
+ "path /cont/l;"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("");
+
+ /* notif -> state */
+ str =
+ "module d {"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "config false;"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "notification notif {"
+ "leaf l2 {"
+ "must ../../cont/l;"
+ "type leafref {"
+ "path /cont/l;"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("");
+
+ /* notif -> notif */
+ str =
+ "module e {"
+ "namespace urn:a;"
+ "prefix a;"
+ "notification notif {"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "leaf l2 {"
+ "must ../../notif/l;"
+ "type leafref {"
+ "path /notif/l;"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("");
+
+ /* rpc input -> state */
+ str =
+ "module f {"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "config false;"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "rpc rp {"
+ "input {"
+ "leaf l2 {"
+ "must ../../cont/l;"
+ "type leafref {"
+ "path /cont/l;"
+ "}"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("");
+
+ /* rpc input -> rpc input */
+ str =
+ "module g {"
+ "namespace urn:a;"
+ "prefix a;"
+ "rpc rp {"
+ "input {"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "leaf l2 {"
+ "must ../l;"
+ "type leafref {"
+ "path /rp/l;"
+ "}"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("");
+
+ /* rpc input -> rpc output leafref */
+ str =
+ "module h {"
+ "namespace urn:a;"
+ "prefix a;"
+ "rpc rp {"
+ "input {"
+ "leaf l2 {"
+ "type leafref {"
+ "path /rp/l;"
+ "}"
+ "}"
+ "}"
+ "output {"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_EVALID);
+ logbuf_assert("Not found node \"l\" in path. /h:rp/l2");
+ logbuf_clean();
+
+ /* rpc input -> rpc output must */
+ str =
+ "module h {"
+ "namespace urn:a;"
+ "prefix a;"
+ "rpc rp {"
+ "input {"
+ "leaf l2 {"
+ "must ../l;"
+ "type empty;"
+ "}"
+ "}"
+ "output {"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("Schema node \"l\" not found (../) with context node \"/h:rp/l2\".");
+ logbuf_clean();
+
+ /* rpc input -> notif leafref */
+ str =
+ "module i {"
+ "namespace urn:a;"
+ "prefix a;"
+ "rpc rp {"
+ "input {"
+ "leaf l2 {"
+ "type leafref {"
+ "path ../../notif/l;"
+ "}"
+ "}"
+ "}"
+ "}"
+ "notification notif {"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_EVALID);
+ logbuf_assert("Not found node \"notif\" in path. /i:rp/l2");
+ logbuf_clean();
+
+ /* rpc input -> notif must */
+ str =
+ "module i {"
+ "namespace urn:a;"
+ "prefix a;"
+ "rpc rp {"
+ "input {"
+ "leaf l2 {"
+ "must /notif/l;"
+ "type empty;"
+ "}"
+ "}"
+ "}"
+ "notification notif {"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("Schema node \"l\" not found (/notif/) with context node \"/i:rp/l2\".");
+ logbuf_clean();
+
+ /* action output -> state */
+ str =
+ "module j {"
+ "yang-version 1.1;"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "list ll {"
+ "key k;"
+ "leaf k {"
+ "type string;"
+ "}"
+ "action act {"
+ "output {"
+ "leaf l2 {"
+ "must /cont/l;"
+ "type leafref {"
+ "path ../../../l;"
+ "}"
+ "}"
+ "}"
+ "}"
+ "}"
+ "leaf l {"
+ "config false;"
+ "type empty;"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("");
+
+ /* action output -> action input leafref */
+ str =
+ "module k {"
+ "yang-version 1.1;"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "list ll {"
+ "key k;"
+ "leaf k {"
+ "type string;"
+ "}"
+ "action act {"
+ "input {"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "output {"
+ "leaf l2 {"
+ "type leafref {"
+ "path ../l;"
+ "}"
+ "}"
+ "}"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_EVALID);
+ logbuf_assert("Not found node \"l\" in path. /k:cont/ll/act/l2");
+ logbuf_clean();
+
+ /* action output -> action input must */
+ str =
+ "module k {"
+ "yang-version 1.1;"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "list ll {"
+ "key k;"
+ "leaf k {"
+ "type string;"
+ "}"
+ "action act {"
+ "input {"
+ "leaf l {"
+ "type empty;"
+ "}"
+ "}"
+ "output {"
+ "leaf l2 {"
+ "must /cont/ll/act/l;"
+ "type empty;"
+ "}"
+ "}"
+ "}"
+ "}"
+ "}"
+ "}";
+ assert_int_equal(lys_parse_mem(ctx, str, LYS_IN_YANG, NULL), LY_SUCCESS);
+ logbuf_assert("Schema node \"l\" not found (/cont/ll/act/) with context node \"/k:cont/ll/act/l2\".");
+ logbuf_clean();
+
+ *state = NULL;
+ ly_ctx_destroy(ctx, NULL);
+}
diff --git a/tests/utests/schema/test_schema_stmts.c b/tests/utests/schema/test_schema_stmts.c
index 97ad697..99137c7 100644
--- a/tests/utests/schema/test_schema_stmts.c
+++ b/tests/utests/schema/test_schema_stmts.c
@@ -154,7 +154,6 @@
ly_ctx_destroy(ctx, NULL);
}
-
void
test_feature(void **state)
{
diff --git a/tests/utests/schema/test_tree_schema_compile.c b/tests/utests/schema/test_tree_schema_compile.c
index e7c82e7..bade042 100644
--- a/tests/utests/schema/test_tree_schema_compile.c
+++ b/tests/utests/schema/test_tree_schema_compile.c
@@ -1739,17 +1739,17 @@
/* invalid paths */
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;container a {leaf target2 {type uint8;}}"
"leaf ref1 {type leafref {path ../a/invalid;}}}", LYS_IN_YANG, &mod));
- logbuf_assert("Not found node \"invalid\" in path.");
+ logbuf_assert("Not found node \"invalid\" in path. /aa:ref1");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;container a {leaf target2 {type uint8;}}"
"leaf ref1 {type leafref {path ../../toohigh;}}}", LYS_IN_YANG, &mod));
- logbuf_assert("Too many parent references in path.");
+ logbuf_assert("Too many parent references in path. /bb:ref1");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module cc {namespace urn:cc;prefix cc;container a {leaf target2 {type uint8;}}"
"leaf ref1 {type leafref {path /a:invalid;}}}", LYS_IN_YANG, &mod));
- logbuf_assert("Prefix \"a\" not found of a module in path.");
+ logbuf_assert("Prefix \"a\" not found of a module in path. /cc:ref1");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module dd {namespace urn:dd;prefix dd;leaf target1 {type string;}"
"container a {leaf target2 {type uint8;}} leaf ref1 {type leafref {"
"path '/a[target2 = current()/../target1]/target2';}}}", LYS_IN_YANG, &mod));
- logbuf_assert("List predicate defined for container \"a\" in path.");
+ logbuf_assert("List predicate defined for container \"a\" in path. /dd:ref1");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;container a {leaf target2 {type uint8;}}"
"leaf ref1 {type leafref {path /a!invalid;}}}", LYS_IN_YANG, &mod));
logbuf_assert("Invalid character 0x21 ('!'), perhaps \"a\" is supposed to be a function call.");
@@ -1799,14 +1799,14 @@
"leaf ifname{type leafref{ path \"../interface/name\";}}"
"leaf address {type leafref{ path \"/interface[x:name=current()/../ifname]/ip\";}}}",
LYS_IN_YANG, &mod));
- logbuf_assert("Prefix \"x\" not found of a module in path.");
+ logbuf_assert("Prefix \"x\" not found of a module in path. /pp:address");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module qq {namespace urn:qq;prefix qq;"
"list interface{key name;leaf name{type string;}leaf ip {type string;}}"
"leaf ifname{type leafref{ path \"../interface/name\";}}"
"leaf address {type leafref{ path \"/interface[id=current()/../ifname]/ip\";}}}",
LYS_IN_YANG, &mod));
- logbuf_assert("Not found node \"id\" in path.");
+ logbuf_assert("Not found node \"id\" in path. /qq:address");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module rr {namespace urn:rr;prefix rr;"
"list interface{key name;leaf name{type string;}leaf ip {type string;}}"
@@ -1862,32 +1862,32 @@
"leaf ifname{type leafref{ path \"../interface/name\";}}"
"leaf address {type leafref{ path \"/interface[name=current()/../x:ifname]/ip\";}}}",
LYS_IN_YANG, &mod));
- logbuf_assert("Prefix \"x\" not found of a module in path.");
+ logbuf_assert("Prefix \"x\" not found of a module in path. /yy:address");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module zz {namespace urn:zz;prefix zz;"
"list interface{key name;leaf name{type string;}leaf ip {type string;}}"
"leaf ifname{type leafref{ path \"../interface/name\";}}"
"leaf address {type leafref{ path \"/interface[name=current()/../xxx]/ip\";}}}",
LYS_IN_YANG, &mod));
- logbuf_assert("Not found node \"xxx\" in path.");
+ logbuf_assert("Not found node \"xxx\" in path. /zz:address");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module zza {namespace urn:zza;prefix zza;"
"list interface{key name;leaf name{type string;}leaf ip {type string;}}"
"leaf ifname{type leafref{ path \"../interface/name\";}}container c;"
"leaf address {type leafref{ path \"/interface[name=current()/../c]/ip\";}}}",
LYS_IN_YANG, &mod));
- logbuf_assert("Leaf expected instead of container \"c\" in leafref predicate in path.");
+ logbuf_assert("Leaf expected instead of container \"c\" in leafref predicate in path. /zza:address");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module zzb {namespace urn:zzb;prefix zzb;"
"list interface{key name;leaf name{type string;}leaf ip {type string;}container c;}"
"leaf ifname{type leafref{ path \"../interface/name\";}}"
"leaf address {type leafref{ path \"/interface[c=current()/../ifname]/ip\";}}}",
LYS_IN_YANG, &mod));
- logbuf_assert("Key expected instead of container \"c\" in path.");
+ logbuf_assert("Key expected instead of container \"c\" in path. /zzb:address");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module zzc {namespace urn:zzc;prefix zzc;"
"leaf source {type leafref {path \"../target\";}default true;}}", LYS_IN_YANG, &mod));
- logbuf_assert("Not found node \"target\" in path.");
+ logbuf_assert("Not found node \"target\" in path. /zzc:source");
assert_int_equal(LY_EVALID, lys_parse_mem(ctx, "module zzd {namespace urn:zzd;prefix zzd;"
"leaf source {type leafref {path \"../target\";}default true;}"