libyang NEW xpath evaluation
Not tested once.
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index f3fba16..d97328c 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -1788,13 +1788,14 @@
/**
* @brief Checks pattern syntax.
*
- * @param[in] ctx Compile context.
+ * @param[in] ctx Context.
+ * @param[in] log_path Path for logging errors.
* @param[in] pattern Pattern to check.
* @param[in,out] pcre2_code Compiled PCRE2 pattern. If NULL, the compiled information used to validate pattern are freed.
* @return LY_ERR value - LY_SUCCESS, LY_EMEM, LY_EVALID.
*/
-static LY_ERR
-lys_compile_type_pattern_check(struct lysc_ctx *ctx, const char *pattern, pcre2_code **code)
+LY_ERR
+lys_compile_type_pattern_check(struct ly_ctx *ctx, const char *log_path, const char *pattern, pcre2_code **code)
{
int idx, idx2, start, end, count;
char *perl_regex, *ptr;
@@ -1893,11 +1894,11 @@
/* adjust the expression to a Perl equivalent
* http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs */
- /* we need to replace all "$" with "\$", count them now */
+ /* we need to replace all "$" and "^" with "\$" and "\^", count them now */
for (count = 0, ptr = strpbrk(pattern, "^$"); ptr; ++count, ptr = strpbrk(ptr + 1, "^$"));
perl_regex = malloc((strlen(pattern) + 4 + count) * sizeof(char));
- LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx->ctx), LY_EMEM);
+ LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
perl_regex[0] = '\0';
ptr = perl_regex;
@@ -1921,7 +1922,7 @@
ptr = strchr(ptr, '}');
if (!ptr) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_INREGEXP,
+ LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP,
pattern, perl_regex + start + 2, "unterminated character property");
free(perl_regex);
return LY_EVALID;
@@ -1931,7 +1932,7 @@
/* need more space */
if (end - start < URANGE_LEN) {
perl_regex = ly_realloc(perl_regex, strlen(perl_regex) + (URANGE_LEN - (end - start)) + 1);
- LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx->ctx); free(perl_regex), LY_EMEM);
+ LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx); free(perl_regex), LY_EMEM);
}
/* find our range */
@@ -1941,7 +1942,7 @@
}
}
if (!ublock2urange[idx][0]) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_INREGEXP,
+ LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP,
pattern, perl_regex + start + 5, "unknown block name");
free(perl_regex);
return LY_EVALID;
@@ -1973,7 +1974,7 @@
if (!code_local) {
PCRE2_UCHAR err_msg[256] = {0};
pcre2_get_error_message(err_code, err_msg, 256);
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_INREGEXP, pattern, perl_regex + err_offset, err_msg);
+ LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP, pattern, perl_regex + err_offset, err_msg);
free(perl_regex);
return LY_EVALID;
}
@@ -2018,7 +2019,7 @@
*pattern = calloc(1, sizeof **pattern);
++(*pattern)->refcount;
- ret = lys_compile_type_pattern_check(ctx, &patterns_p[u].arg[1], &(*pattern)->code);
+ ret = lys_compile_type_pattern_check(ctx->ctx, ctx->path, &patterns_p[u].arg[1], &(*pattern)->code);
LY_CHECK_RET(ret);
if (patterns_p[u].arg[0] == 0x15) {
@@ -2219,7 +2220,7 @@
#define MOVE_PATH_PARENT(NODE, LIMIT_COND, TERM, ERR_MSG, ...) \
for ((NODE) = (NODE)->parent; \
- (NODE) && !((NODE)->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_ACTION)); \
+ (NODE) && !((NODE)->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_NOTIF | LYS_ACTION)); \
(NODE) = (NODE)->parent); \
if (!(NODE) && (LIMIT_COND)) { /* we are going higher than top-level */ \
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, ERR_MSG, ##__VA_ARGS__); \
@@ -2580,6 +2581,54 @@
}
/**
+ * @brief Check whether a leafref has an external dependency or not.
+ *
+ * @param[in] startnode Node with the leafref.
+ * @param[in] local_mod Local module for the leafref path.
+ * @param[in] first_node First found node when resolving the leafref.
+ * @param[in] abs_path Whether the leafref path is absolute or relative.
+ * @return 0 is the leafref does not require an external dependency, non-zero is it requires.
+ */
+static int
+lys_compile_leafref_has_dep_flag(const struct lysc_node *startnode, const struct lys_module *local_mod,
+ const struct lysc_node *first_node, int abs_path)
+{
+ int dep1, dep2;
+ const struct lysc_node *op_node, *node;
+
+ /* find operation schema we are in */
+ for (op_node = startnode->parent;
+ op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF));
+ op_node = op_node->parent);
+
+ if (!op_node) {
+ /* leafref pointing to a different module */
+ if (local_mod != first_node->module) {
+ return 1;
+ }
+ } else if (op_node->parent) {
+ /* inner operation (notif/action) */
+ if (abs_path) {
+ return 1;
+ } else {
+ /* compare depth of both nodes */
+ for (dep1 = 0, node = op_node; node->parent; node = node->parent);
+ for (dep2 = 0, node = first_node; node->parent; node = node->parent);
+ if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
+ return 1;
+ }
+ }
+ } else {
+ /* top-level operation (notif/rpc) */
+ if (op_node != first_node) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
* @brief Validate the leafref path.
* @param[in] ctx Compile context
* @param[in] startnode Path context node (where the leafref path begins/is placed).
@@ -2589,7 +2638,7 @@
static LY_ERR
lys_compile_leafref_validate(struct lysc_ctx *ctx, struct lysc_node *startnode, struct lysc_type_leafref *leafref)
{
- const struct lysc_node *node = NULL, *parent = NULL;
+ const struct lysc_node *node = NULL, *parent = NULL, *tmp_parent;
const struct lys_module *mod;
struct lysc_type *type;
const char *id, *prefix, *name;
@@ -2603,7 +2652,7 @@
assert(leafref);
ctx->path[0] = '\0';
- lysc_path(startnode, LY_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
+ lysc_path(startnode, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
ctx->path_len = strlen(ctx->path);
iter = 0;
@@ -2646,6 +2695,16 @@
}
parent = node;
+ if (!iter) {
+ /* find module whose data will actually contain this leafref */
+ for (tmp_parent = parent; tmp_parent->parent; tmp_parent = tmp_parent->parent);
+
+ /* set external dependency flag, we can decide based on the first found node */
+ if (lys_compile_leafref_has_dep_flag(startnode, tmp_parent->module, node, (parent_times == -1 ? 1 : 0))) {
+ startnode->flags |= LYS_LEAFREF_DEP;
+ }
+ }
+
if (has_predicate) {
/* we have predicate, so the current result must be list */
if (node->nodetype != LYS_LIST) {
@@ -6995,7 +7054,7 @@
if (err) {
ly_err_print(err);
ctx.path[0] = '\0';
- lysc_path(r->context_node, LY_PATH_LOG, ctx.path, LYSC_CTX_BUFSIZE);
+ lysc_path(r->context_node, LYSC_PATH_LOG, ctx.path, LYSC_CTX_BUFSIZE);
LOGVAL(ctx.ctx, LY_VLOG_STR, ctx.path, LYVE_SEMANTICS,
"Invalid default - value does not fit the type (%s).", err->msg);
ly_err_free(err);