schema tree NEW when cyclic ref check
diff --git a/src/common.h b/src/common.h
index dc71b11..a3403b5 100644
--- a/src/common.h
+++ b/src/common.h
@@ -172,62 +172,64 @@
/* default maximum characters to print in LY_VCODE_INCHILDSTMT */
#define LY_VCODE_INSTREXP_MAXLEN 20
-#define LY_VCODE_INCHAR LYVE_SYNTAX, "Invalid character 0x%x."
-#define LY_VCODE_INSTREXP LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected %s."
-#define LY_VCODE_EOF LYVE_SYNTAX, "Unexpected end-of-input."
-#define LY_VCODE_NTERM LYVE_SYNTAX, "%s not terminated."
-#define LY_VCODE_NSUPP LYVE_SYNTAX, "%s not supported."
-#define LY_VCODE_MOD_SUBOMD LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\"."
-#define LY_VCODE_TRAILING_MOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input."
+#define LY_VCODE_INCHAR LYVE_SYNTAX, "Invalid character 0x%x."
+#define LY_VCODE_INSTREXP LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected %s."
+#define LY_VCODE_EOF LYVE_SYNTAX, "Unexpected end-of-input."
+#define LY_VCODE_NTERM LYVE_SYNTAX, "%s not terminated."
+#define LY_VCODE_NSUPP LYVE_SYNTAX, "%s not supported."
+#define LY_VCODE_MOD_SUBOMD LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\"."
+#define LY_VCODE_TRAILING_MOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input."
#define LY_VCODE_TRAILING_SUBMOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after submodule, expected end-of-input."
-#define LY_VCODE_INVAL_MINMAX LYVE_SEMANTICS, "Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u."
+#define LY_VCODE_INVAL_MINMAX LYVE_SEMANTICS, "Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u."
+#define LY_VCODE_CIRC_WHEN LYVE_SEMANTICS, "When condition of \"%s\" includes a self-reference (referenced by when of \"%s\")."
-#define LY_VCODE_INSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\"."
-#define LY_VCODE_INCHILDSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\"."
-#define LY_VCODE_INCHILDSTMT2 LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\" - the statement is allowed only in YANG 1.1 modules."
+#define LY_VCODE_INSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\"."
+#define LY_VCODE_INCHILDSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\"."
+#define LY_VCODE_INCHILDSTMT2 LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\" - the statement is allowed only in YANG 1.1 modules."
#define LY_VCODE_INCHILDSTMSCOMB LYVE_SYNTAX_YANG, "Invalid combination of keywords \"%s\" and \"%s\" as substatements of \"%s\"."
-#define LY_VCODE_DUPSTMT LYVE_SYNTAX_YANG, "Duplicate keyword \"%s\"."
-#define LY_VCODE_DUPIDENT LYVE_SYNTAX_YANG, "Duplicate identifier \"%s\" of %s statement."
-#define LY_VCODE_INVAL LYVE_SYNTAX_YANG, "Invalid value \"%.*s\" of \"%s\"."
-#define LY_VCODE_MISSTMT LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s\"."
-#define LY_VCODE_MISSCHILDSTMT LYVE_SYNTAX_YANG, "Missing %s substatement for %s%s."
-#define LY_VCODE_INORD LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", it cannot appear after \"%s\"."
-#define LY_VCODE_OOB LYVE_SYNTAX_YANG, "Value \"%.*s\" is out of \"%s\" bounds."
-#define LY_VCODE_INDEV LYVE_SYNTAX_YANG, "Deviate \"%s\" does not support keyword \"%s\"."
-#define LY_VCODE_INREGEXP LYVE_SYNTAX_YANG, "Regular expression \"%s\" is not valid (\"%s\": %s)."
+#define LY_VCODE_DUPSTMT LYVE_SYNTAX_YANG, "Duplicate keyword \"%s\"."
+#define LY_VCODE_DUPIDENT LYVE_SYNTAX_YANG, "Duplicate identifier \"%s\" of %s statement."
+#define LY_VCODE_INVAL LYVE_SYNTAX_YANG, "Invalid value \"%.*s\" of \"%s\"."
+#define LY_VCODE_MISSTMT LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s\"."
+#define LY_VCODE_MISSCHILDSTMT LYVE_SYNTAX_YANG, "Missing %s substatement for %s%s."
+#define LY_VCODE_INORD LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", it cannot appear after \"%s\"."
+#define LY_VCODE_OOB LYVE_SYNTAX_YANG, "Value \"%.*s\" is out of \"%s\" bounds."
+#define LY_VCODE_INDEV LYVE_SYNTAX_YANG, "Deviate \"%s\" does not support keyword \"%s\"."
+#define LY_VCODE_INREGEXP LYVE_SYNTAX_YANG, "Regular expression \"%s\" is not valid (\"%s\": %s)."
-#define LY_VCODE_INSUBELEM2 LYVE_SYNTAX_YIN, "Invalid sub-elemnt \"%s\" of \"%s\" element - this sub-element is allowed only in modules with version 1.1 or newer."
-#define LY_VCODE_INVAL_YIN LYVE_SYNTAX_YIN, "Invalid value \"%s\" of \"%s\" attribute in \"%s\" element."
-#define LY_VCODE_UNEXP_SUBELEM LYVE_SYNTAX_YIN, "Unexpected sub-element \"%.*s\" of \"%s\" element."
-#define LY_VCODE_INDEV_YIN LYVE_SYNTAX_YIN, "Deviate of this type doesn't allow \"%s\" as it's sub-element."
-#define LY_VCODE_INORDER_YIN LYVE_SYNTAX_YIN, "Invalid order of %s\'s sub-elements \"%s\" can't appear after \"%s\"."
-#define LY_VCODE_OOB_YIN LYVE_SYNTAX_YIN, "Value \"%s\" of \"%s\" attribute in \"%s\" element is out of bounds."
+#define LY_VCODE_INSUBELEM2 LYVE_SYNTAX_YIN, "Invalid sub-elemnt \"%s\" of \"%s\" element - this sub-element is allowed only in modules with version 1.1 or newer."
+#define LY_VCODE_INVAL_YIN LYVE_SYNTAX_YIN, "Invalid value \"%s\" of \"%s\" attribute in \"%s\" element."
+#define LY_VCODE_UNEXP_SUBELEM LYVE_SYNTAX_YIN, "Unexpected sub-element \"%.*s\" of \"%s\" element."
+#define LY_VCODE_INDEV_YIN LYVE_SYNTAX_YIN, "Deviate of this type doesn't allow \"%s\" as it's sub-element."
+#define LY_VCODE_INORDER_YIN LYVE_SYNTAX_YIN, "Invalid order of %s\'s sub-elements \"%s\" can't appear after \"%s\"."
+#define LY_VCODE_OOB_YIN LYVE_SYNTAX_YIN, "Value \"%s\" of \"%s\" attribute in \"%s\" element is out of bounds."
#define LY_VCODE_INCHILDSTMSCOMB_YIN LYVE_SYNTAX_YIN, "Invalid combination of sub-elemnts \"%s\" and \"%s\" in \"%s\" element."
-#define LY_VCODE_DUP_ATTR LYVE_SYNTAX_YIN, "Duplicit definition of \"%s\" attribute in \"%s\" element."
-#define LY_VCODE_UNEXP_ATTR LYVE_SYNTAX_YIN, "Unexpected attribute \"%.*s\" of \"%s\" element."
-#define LY_VCODE_MAND_SUBELEM LYVE_SYNTAX_YIN, "Missing mandatory sub-element \"%s\" of \"%s\" element."
-#define LY_VCODE_FIRT_SUBELEM LYVE_SYNTAX_YIN, "Sub-element \"%s\" of \"%s\" element must be defined as it's first sub-element."
-#define LY_VCODE_NAME_COL LYVE_SYNTAX_YIN, "Name collision between module and submodule of name \"%s\"."
-#define LY_VCODE_SUBELEM_REDEF LYVE_SYNTAX_YIN, "Redefinition of \"%s\" sub-element in \"%s\" element."
+#define LY_VCODE_DUP_ATTR LYVE_SYNTAX_YIN, "Duplicit definition of \"%s\" attribute in \"%s\" element."
+#define LY_VCODE_UNEXP_ATTR LYVE_SYNTAX_YIN, "Unexpected attribute \"%.*s\" of \"%s\" element."
+#define LY_VCODE_MAND_SUBELEM LYVE_SYNTAX_YIN, "Missing mandatory sub-element \"%s\" of \"%s\" element."
+#define LY_VCODE_FIRT_SUBELEM LYVE_SYNTAX_YIN, "Sub-element \"%s\" of \"%s\" element must be defined as it's first sub-element."
+#define LY_VCODE_NAME_COL LYVE_SYNTAX_YIN, "Name collision between module and submodule of name \"%s\"."
+#define LY_VCODE_SUBELEM_REDEF LYVE_SYNTAX_YIN, "Redefinition of \"%s\" sub-element in \"%s\" element."
-#define LY_VCODE_XP_EOE LYVE_XPATH, "Unterminated string delimited with %c (%.15s)."
-#define LY_VCODE_XP_INEXPR LYVE_XPATH, "Invalid character number %u of expression \'%s\'."
-#define LY_VCODE_XP_DUMMY LYVE_XPATH, "Accessing the value of the dummy node \"%s\"."
-#define LY_VCODE_XP_EOF LYVE_XPATH, "Unexpected XPath expression end."
-#define LY_VCODE_XP_INTOK LYVE_XPATH, "Unexpected XPath token %s (%.15s)."
-#define LY_VCODE_XP_INFUNC LYVE_XPATH, "Unknown XPath function \"%.*s\"."
-#define LY_VCODE_XP_INARGCOUNT LYVE_XPATH, "Invalid number of arguments (%d) for the XPath function %.*s."
-#define LY_VCODE_XP_INARGTYPE LYVE_XPATH, "Wrong type of argument #%d (%s) for the XPath function %s."
-#define LY_VCODE_XP_INCTX LYVE_XPATH, "Invalid context type %s in %s."
-#define LY_VCODE_XP_DUMMY LYVE_XPATH, "Accessing the value of the dummy node \"%s\"."
-#define LY_VCODE_XP_INOP_1 LYVE_XPATH, "Cannot apply XPath operation %s on %s."
-#define LY_VCODE_XP_INOP_2 LYVE_XPATH, "Cannot apply XPath operation %s on %s and %s."
-#define LY_VCODE_XP_INMOD LYVE_XPATH, "Unknown module \"%.*s\"."
+#define LY_VCODE_XP_EOE LYVE_XPATH, "Unterminated string delimited with %c (%.15s)."
+#define LY_VCODE_XP_INEXPR LYVE_XPATH, "Invalid character number %u of expression \'%s\'."
+#define LY_VCODE_XP_EOF LYVE_XPATH, "Unexpected XPath expression end."
+#define LY_VCODE_XP_INTOK LYVE_XPATH, "Unexpected XPath token %s (%.15s)."
+#define LY_VCODE_XP_INFUNC LYVE_XPATH, "Unknown XPath function \"%.*s\"."
+#define LY_VCODE_XP_INARGCOUNT LYVE_XPATH, "Invalid number of arguments (%d) for the XPath function %.*s."
+#define LY_VCODE_XP_INARGTYPE LYVE_XPATH, "Wrong type of argument #%d (%s) for the XPath function %s."
+#define LY_VCODE_XP_INCTX LYVE_XPATH, "Invalid context type %s in %s."
+#define LY_VCODE_XP_DUMMY LYVE_XPATH, "Accessing the value of the dummy node \"%s\"."
+#define LY_VCODE_XP_INOP_1 LYVE_XPATH, "Cannot apply XPath operation %s on %s."
+#define LY_VCODE_XP_INOP_2 LYVE_XPATH, "Cannot apply XPath operation %s on %s and %s."
+#define LY_VCODE_XP_INMOD LYVE_XPATH, "Unknown module \"%.*s\"."
-#define LY_VCODE_DEV_NODETYPE LYVE_REFERENCE, "Invalid deviation of %s node - it is not possible to %s \"%s\" property."
+#define LY_VCODE_DEV_NODETYPE LYVE_REFERENCE, "Invalid deviation of %s node - it is not possible to %s \"%s\" property."
#define LY_VCODE_DEV_NOT_PRESENT LYVE_REFERENCE, "Invalid deviation %s \"%s\" property \"%s\" which is not present."
+#define LY_VCODE_NOWHEN LYVE_DATA, "When condition \"%s\" not satisfied."
+
/******************************************************************************
* Context
*****************************************************************************/
diff --git a/src/log.h b/src/log.h
index c7ee0a3..e5f54b7 100644
--- a/src/log.h
+++ b/src/log.h
@@ -172,7 +172,7 @@
LYVE_XPATH, /**< invalid XPath expression */
LYVE_SEMANTICS, /**< generic semantic error */
LYVE_SYNTAX_XML, /**< XML-related syntax error */
- LYVE_RESTRICTION /**< YANG data does not reflect some of the module restrictions */
+ LYVE_DATA, /**< YANG data does not reflect some of the module restrictions */
} LY_VECODE;
/**
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 2b4e625..bf7c6ab 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -47,6 +47,7 @@
char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
struct ly_set incomplete_type_validation; /**< set of nodes validated with LY_EINCOMPLETE result */
struct ly_set incomplete_type_validation_attrs; /**< set of attributes validated with LY_EINCOMPLETE result */
+ struct ly_set when_check; /**< set of nodes with "when" conditions */
};
/**
@@ -289,7 +290,7 @@
switch (snode->nodetype) {
case LYS_ACTION:
if ((ctx->options & LYD_OPT_TYPEMASK) != LYD_OPT_RPC) {
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Unexpected RPC/action element \"%.*s\" in %s data set.",
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected RPC/action element \"%.*s\" in %s data set.",
name_len, name, lyd_parse_options_type2str(ctx->options & LYD_OPT_TYPEMASK));
goto error;
}
@@ -297,7 +298,7 @@
break;
case LYS_NOTIF:
if ((ctx->options & LYD_OPT_TYPEMASK) != LYD_OPT_RPC) {
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Unexpected Notification element \"%.*s\" in %s data set.",
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected Notification element \"%.*s\" in %s data set.",
name_len, name, lyd_parse_options_type2str(ctx->options));
goto error;
}
@@ -372,7 +373,7 @@
if (cur->next) {
last = prev;
if (ctx->options & LYD_OPT_STRICT) {
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Invalid position of the key \"%.*s\" in a list.",
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Invalid position of the key \"%.*s\" in a list.",
name_len, name);
goto error;
} else {
diff --git a/src/plugins_types.c b/src/plugins_types.c
index feb02f8..aa34d2e 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -143,7 +143,7 @@
}
error:
- *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_DATA, errmsg, NULL, NULL);
return LY_EVALID;
}
@@ -230,7 +230,7 @@
}
error:
- *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_DATA, errmsg, NULL, NULL);
return LY_EVALID;
}
@@ -330,7 +330,7 @@
error:
if (errmsg) {
- *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_DATA, errmsg, NULL, NULL);
}
return rc;
}
@@ -438,7 +438,7 @@
return LY_SUCCESS;
error:
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, range->eapptag ? strdup(range->eapptag) : NULL);
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, range->eapptag ? strdup(range->eapptag) : NULL);
return LY_EVALID;
}
@@ -647,7 +647,7 @@
}
if (!value || !value[0] || !value_len) {
- *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_RESTRICTION, strdup("Invalid empty decimal64 value."), NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_DATA, strdup("Invalid empty decimal64 value."), NULL, NULL);
return LY_EVALID;
}
@@ -811,7 +811,7 @@
error:
if (!*err) {
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
}
return (*err)->no;
}
@@ -1003,7 +1003,7 @@
return LY_SUCCESS;
error:
if (errmsg) {
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
}
ly_set_free(items, NULL);
ly_set_free(items_ordered, NULL);
@@ -1105,7 +1105,7 @@
error:
if (errmsg) {
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
}
return LY_EVALID;
}
@@ -1145,7 +1145,7 @@
} else {
char *errmsg;
asprintf(&errmsg, "Invalid boolean value \"%.*s\".", (int)value_len, value);
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
return LY_EVALID;
}
@@ -1195,7 +1195,7 @@
if (value_len) {
char *errmsg;
asprintf(&errmsg, "Invalid empty value \"%.*s\".", (int)value_len, value);
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
return LY_EVALID;
}
@@ -1326,7 +1326,7 @@
return LY_SUCCESS;
error:
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
return LY_EVALID;
}
@@ -1950,7 +1950,7 @@
lyd_value_free_path(ctx, target);
if (!*err) {
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
}
return ret;
}
@@ -2413,7 +2413,7 @@
error:
if (!*err) {
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
}
if (storage_dummy) {
storage->realtype->plugin->free(ctx, storage);
@@ -2559,7 +2559,7 @@
error:
if (!*err) {
- *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_DATA, errmsg, NULL, NULL);
}
LY_ARRAY_FOR(subvalue->prefixes, u) {
lydict_remove(ctx, subvalue->prefixes[u].prefix);
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 1c4fcee..4df1d94 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -114,7 +114,9 @@
data trees (checking require-instance), it returns LY_EINCOMPLETE.
Caller is supposed to call such validation callback again later with complete data trees. */
#define LY_TYPE_OPTS_SECOND_CALL 0x20 /**< Flag for the second call of the callback when the first call returns LY_EINCOMPLETE,
- other options should be the same as for the first call. */
+ other options should be the same as for the first call. **!!** Note that this second call
+ can occur even if the first call succeeded, in which case the plugin should immediately
+ return LY_SUCCESS. */
/** @} plugintypeopts */
diff --git a/src/tree_data.h b/src/tree_data.h
index 589a3e0..6820144 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -262,7 +262,8 @@
used to get know that nodes are not equal, it cannot be used to decide that the
nodes are equal due to possible collisions. */
uint32_t flags; /**< [data node flags](@ref dnodeflags) */
- const struct lysc_node *schema; /**< pointer to the schema definition of this node */
+ const struct lysc_node *schema; /**< pointer to the schema definition of this node, note that the target can be not just
+ ::struct lysc_node but ::struct lysc_action or ::struct lysc_notif as well */
struct lyd_node_inner *parent; /**< pointer to the parent node, NULL in case of root node */
struct lyd_node *next; /**< pointer to the next sibling node (NULL if there is no one) */
struct lyd_node *prev; /**< pointer to the previous sibling node \note Note that this pointer is
diff --git a/src/tree_schema.h b/src/tree_schema.h
index dc523cb..f8a2ab6 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -700,45 +700,41 @@
* 2 - choice 7 - case 12 - extension
* 3 - leaf 8 - notification 13 - bitenum
* 4 - leaflist 9 - rpc/action 14 - when
- * 5 - list 10 - feature 15 - must
+ * 5 - list 10 - feature
*
- * 1 1 1 1 1 1
- * bit name 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
- * ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 1 LYS_CONFIG_W |x|x|x|x|x|x|x| | | | | | | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 2 LYS_CONFIG_R |x|x|x|x|x|x|x| | | | | | | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 3 LYS_STATUS_CURR |x|x|x|x|x|x|x|x|x|x|x|x| | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 4 LYS_STATUS_DEPRC |x|x|x|x|x|x|x|x|x|x|x|x| | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 5 LYS_STATUS_OBSLT |x|x|x|x|x|x|x|x|x|x|x|x| | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 6 LYS_MAND_TRUE |x|x|x|x|x|x| | | | | | | | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 7 LYS_ORDBY_USER | | | |x|x| | | | | | | | | | |
- * LYS_MAND_FALSE | |x|x| | |x| | | | | | | | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 8 LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | | |
- * LYS_PRESENCE |x| | | | | | | | | | | | | | |
- * LYS_UNIQUE | | |x| | | | | | | | | | | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 9 LYS_KEY | | |x| | | | | | | | | | | | |
- * LYS_FENABLED | | | | | | | | | |x| | | | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 10 LYS_SET_DFLT | | |x|x| | |x| | | | | | | | |
- * LYS_ISENUM | | | | | | | | | | | | |x| | |
- * LYS_KEYLESS | | | | |x| | | | | | | | | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 11 LYS_SET_UNITS | | |x|x| | | | | | | | | | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 12 LYS_SET_CONFIG |x|x|x|x|x|x| | | | | | | | | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 13 LYS_XPATH_DEP |x|x|x|x|x|x|x|x| | | | | |x|x|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 14 LYS_LEAFREF_DEP | | |x|x| | | | | | | | | | | |
- * ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 1 1 1 1 1
+ * bit name 1 2 3 4 5 6 7 8 9 0 1 2 3 4
+ * ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 1 LYS_CONFIG_W |x|x|x|x|x|x|x| | | | | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 2 LYS_CONFIG_R |x|x|x|x|x|x|x| | | | | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 3 LYS_STATUS_CURR |x|x|x|x|x|x|x|x|x|x|x|x| |x|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 4 LYS_STATUS_DEPRC |x|x|x|x|x|x|x|x|x|x|x|x| |x|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 5 LYS_STATUS_OBSLT |x|x|x|x|x|x|x|x|x|x|x|x| |x|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 6 LYS_MAND_TRUE |x|x|x|x|x|x| | | | | | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 7 LYS_ORDBY_USER | | | |x|x| | | | | | | | | |
+ * LYS_MAND_FALSE | |x|x| | |x| | | | | | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 8 LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | |
+ * LYS_PRESENCE |x| | | | | | | | | | | | | |
+ * LYS_UNIQUE | | |x| | | | | | | | | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 9 LYS_KEY | | |x| | | | | | | | | | | |
+ * LYS_FENABLED | | | | | | | | | |x| | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 10 LYS_SET_DFLT | | |x|x| | |x| | | | | | | |
+ * LYS_ISENUM | | | | | | | | | | | | |x| |
+ * LYS_KEYLESS | | | | |x| | | | | | | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 11 LYS_SET_UNITS | | |x|x| | | | | | | | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 12 LYS_SET_CONFIG |x|x|x|x|x|x| | | | | | | | |
+ * ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
@@ -800,9 +796,6 @@
#define LYS_SET_UNITS 0x0400 /**< flag to know if the leaf's/leaflist's units are their own (flag set) or it is taken from the type. */
#define LYS_SET_CONFIG 0x0800 /**< flag to know if the config property was set explicitly (flag set) or it is inherited. */
-#define LYS_XPATH_DEP 0x1000 /**< flag for nodes with when/must with external data dependency. */
-#define LYS_LEAFREF_DEP 0x2000 /**< flag for leaves(-lists) with leafref with external dependency. */
-
#define LYS_SINGLEQUOTED 0x100 /**< flag for single-quoted argument of an extension instance's substatement, only when the source is YANG */
#define LYS_DOUBLEQUOTED 0x200 /**< flag for double-quoted argument of an extension instance's substatement, only when the source is YANG */
@@ -1170,7 +1163,7 @@
const char *ref; /**< reference */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
uint32_t refcount; /**< reference counter since some of the when statements are shared among several nodes */
- uint16_t flags; /**< [schema node flags](@ref snodeflags) - only LYS_XPATH_DEP and LYS_STATUS are allowed */
+ uint16_t flags; /**< [schema node flags](@ref snodeflags) - only LYS_STATUS is allowed */
};
/**
@@ -1262,7 +1255,6 @@
const char *emsg; /**< error-message */
const char *eapptag; /**< error-app-tag value */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
- uint16_t flags; /**< [schema node flags](@ref snodeflags) - only LYS_XPATH_DEP is allowed */
};
struct lysc_type {
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 59ab14d..574a49e 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -2644,52 +2644,6 @@
}
/**
- * @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)
-{
- 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 {
- /* if first_node parent is not op_node, it is external */
- for (node = first_node; node && (node != op_node); node = node->parent);
- if (!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).
@@ -2701,7 +2655,7 @@
lys_compile_leafref_validate(struct lysc_ctx *ctx, struct lysc_node *startnode, struct lysc_type_leafref *leafref,
const struct lysc_node **target)
{
- const struct lysc_node *node = NULL, *parent = NULL, *tmp_parent;
+ const struct lysc_node *node = NULL, *parent = NULL;
const struct lys_module *mod;
struct lysc_type *type;
const char *id, *prefix, *name;
@@ -2758,16 +2712,6 @@
}
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) {
@@ -6990,6 +6934,97 @@
}
/**
+ * @brief Check when for cyclic dependencies.
+ * @param[in] set Set with all the referenced nodes.
+ * @param[in] node Node whose "when" referenced nodes are in @p set.
+ * @return LY_ERR value
+ */
+static LY_ERR
+lys_compile_check_cyclic_when(struct lyxp_set *set, const struct lysc_node *node)
+{
+ struct lyxp_set tmp_set;
+ struct lyxp_set_scnode *xp_scnode;
+ uint32_t i, j;
+ int idx;
+ struct lysc_when *when;
+ LY_ERR ret = LY_SUCCESS;
+
+ memset(&tmp_set, 0, sizeof tmp_set);
+
+ /* prepare in_ctx of the set */
+ for (i = 0; i < set->used; ++i) {
+ xp_scnode = &set->val.scnodes[i];
+
+ if ((xp_scnode->type == LYXP_NODE_ELEM) && (xp_scnode->scnode == node)) {
+ /* node when was already checked */
+ xp_scnode->in_ctx = 2;
+ } else {
+ /* check node when */
+ xp_scnode->in_ctx = 1;
+ }
+ }
+
+ for (i = 0; i < set->used; ++i) {
+ xp_scnode = &set->val.scnodes[i];
+ if (xp_scnode->in_ctx != 1) {
+ /* already checked */
+ continue;
+ }
+
+ if ((xp_scnode->type != LYXP_NODE_ELEM) || !xp_scnode->scnode->when) {
+ /* no when to check */
+ xp_scnode->in_ctx = 0;
+ continue;
+ }
+
+ node = xp_scnode->scnode;
+ do {
+ LY_ARRAY_FOR(node->when, i) {
+ when = node->when[i];
+ ret = lyxp_atomize(when->cond, LYD_UNKNOWN, when->module, when->context,
+ when->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, LYXP_SCNODE_SCHEMA);
+ if (ret != LY_SUCCESS) {
+ LOGVAL(set->ctx, LY_VLOG_LYS, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when->cond->expr);
+ goto cleanup;
+ }
+
+ for (j = 0; j < tmp_set.used; ++j) {
+ /* skip roots'n'stuff */
+ if (tmp_set.val.scnodes[j].type == LYXP_NODE_ELEM) {
+ /* try to find this node in our set */
+ idx = lyxp_set_scnode_dup_node_check(set, tmp_set.val.scnodes[j].scnode, LYXP_NODE_ELEM, -1);
+ if ((idx > -1) && (set->val.scnodes[idx].in_ctx == 2)) {
+ LOGVAL(set->ctx, LY_VLOG_LYS, node, LY_VCODE_CIRC_WHEN, node->name, set->val.scnodes[idx].scnode->name);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* needs to be checked, if in both sets, will be ignored */
+ tmp_set.val.scnodes[j].in_ctx = 1;
+ } else {
+ /* no when, nothing to check */
+ tmp_set.val.scnodes[j].in_ctx = 0;
+ }
+ }
+
+ /* merge this set into the global when set */
+ lyxp_set_scnode_merge(set, &tmp_set);
+ }
+
+ /* check when of non-data parents as well */
+ node = node->parent;
+ } while (node && (node->nodetype & (LYS_CASE | LYS_CHOICE)));
+
+ /* this node when was checked */
+ xp_scnode->in_ctx = 2;
+ }
+
+cleanup:
+ lyxp_set_cast(&tmp_set, LYXP_SET_EMPTY);
+ return ret;
+}
+
+/**
* @brief Check when/must expressions of a node on a compiled schema tree.
* @param[in] ctx Compile context.
* @param[in] node Node to check.
@@ -6998,7 +7033,6 @@
static LY_ERR
lys_compile_check_xpath(struct lysc_ctx *ctx, const struct lysc_node *node)
{
- struct lysc_node *parent, *elem;
struct lyxp_set tmp_set;
uint32_t i, j;
int opts, input_done = 0;
@@ -7049,15 +7083,8 @@
break;
}
- /* find operation if in one, used later */
- for (parent = (struct lysc_node *)node;
- parent && !(parent->nodetype & (LYS_ACTION | LYS_NOTIF));
- parent = parent->parent);
-
-
/* check "when" */
LY_ARRAY_FOR(when, i) {
- lyxp_set_cast(&tmp_set, LYXP_SET_EMPTY);
ret = lyxp_atomize(when[i]->cond, LYD_UNKNOWN, when[i]->module, when[i]->context,
when[i]->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, opts);
if (ret != LY_SUCCESS) {
@@ -7068,31 +7095,30 @@
ctx->path[0] = '\0';
lysc_path((struct lysc_node *)node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
for (j = 0; j < tmp_set.used; ++j) {
- /* skip roots'n'stuff */
+ /* skip roots'n'stuff, set in_ctx for when checking */
if (tmp_set.val.scnodes[j].type == LYXP_NODE_ELEM) {
- /* XPath expression cannot reference "lower" status than the node that has the definition */
- ret = lysc_check_status(ctx, when[i]->flags, when[i]->module, node->name, tmp_set.val.scnodes[j].scnode->flags,
- tmp_set.val.scnodes[j].scnode->module, tmp_set.val.scnodes[j].scnode->name);
- LY_CHECK_GOTO(ret, cleanup);
+ struct lysc_node *schema = tmp_set.val.scnodes[j].scnode;
- if (parent) {
- for (elem = tmp_set.val.scnodes[j].scnode; elem && (elem != parent); elem = elem->parent);
- if (!elem) {
- /* not in node's RPC or notification subtree, set the correct dep flag */
- when[i]->flags |= LYS_XPATH_DEP;
- ((struct lysc_node *)node)->flags |= LYS_XPATH_DEP;
- }
- }
+ /* XPath expression cannot reference "lower" status than the node that has the definition */
+ ret = lysc_check_status(ctx, when[i]->flags, when[i]->module, node->name, schema->flags, schema->module,
+ schema->name);
+ LY_CHECK_GOTO(ret, cleanup);
}
}
+ /* check dummy node accessing */
+ /* TODO */
+
+ /* check cyclic dependencies */
+ ret = lys_compile_check_cyclic_when(&tmp_set, node);
+ LY_CHECK_GOTO(ret, cleanup);
+
lyxp_set_cast(&tmp_set, LYXP_SET_EMPTY);
}
check_musts:
/* check "must" */
LY_ARRAY_FOR(musts, i) {
- lyxp_set_cast(&tmp_set, LYXP_SET_EMPTY);
ret = lyxp_atomize(musts[i].cond, LYD_UNKNOWN, musts[i].module, node, LYXP_NODE_ELEM, &tmp_set, opts);
if (ret != LY_SUCCESS) {
LOGVAL(ctx->ctx, LY_VLOG_LYS, node, LYVE_SEMANTICS, "Invalid must restriction \"%s\".", musts[i].cond->expr);
@@ -7108,15 +7134,6 @@
ret = lysc_check_status(ctx, node->flags, musts[i].module, node->name, tmp_set.val.scnodes[j].scnode->flags,
tmp_set.val.scnodes[j].scnode->module, tmp_set.val.scnodes[j].scnode->name);
LY_CHECK_GOTO(ret, cleanup);
-
- if (parent) {
- for (elem = tmp_set.val.scnodes[j].scnode; elem && (elem != parent); elem = elem->parent);
- if (!elem) {
- /* not in node's RPC or notification subtree, set the correct dep flag */
- musts[i].flags |= LYS_XPATH_DEP;
- ((struct lysc_node *)node)->flags |= LYS_XPATH_DEP;
- }
- }
}
}
diff --git a/src/xpath.c b/src/xpath.c
index 4505141..995941c 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -35,7 +35,6 @@
#include "plugins_types.h"
static LY_ERR reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx);
-static int set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type);
static LY_ERR eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options);
/**
@@ -775,7 +774,7 @@
for (i = 0; i < set->used; ++i) {
if (set->val.scnodes[i].in_ctx == 1) {
- if (set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type)) {
+ if (lyxp_set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type)) {
lyxp_set_free(ret);
return NULL;
}
@@ -1050,17 +1049,8 @@
return LY_SUCCESS;
}
-/**
- * @brief Check for duplicates in a schema node set.
- *
- * @param[in] set Set to check.
- * @param[in] node Node to look for in @p set.
- * @param[in] node_type Type of @p node.
- * @param[in] skip_idx Index from @p set to skip.
- * @return Index of the found node, -1 if not found.
- */
-static int
-set_scnode_dup_node_check(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, int skip_idx)
+int
+lyxp_set_scnode_dup_node_check(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, int skip_idx)
{
uint32_t i;
@@ -1077,14 +1067,8 @@
return -1;
}
-/**
- * @brief Merge 2 schema node sets.
- *
- * @param[in] set1 Set to merge into.
- * @param[in] set2 Set to merge. Its content is freed.
- */
-static void
-set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
+void
+lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
{
uint32_t orig_used, i, j;
@@ -1185,22 +1169,14 @@
set_insert_node_hash(set, (struct lyd_node *)node, node_type);
}
-/**
- * @brief Insert schema node into set.
- *
- * @param[in] set Set to insert into.
- * @param[in] node Node to insert.
- * @param[in] node_type Node type of @p node.
- * @return Index of the inserted node in set.
- */
-static int
-set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type)
+int
+lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type)
{
int ret;
assert(set->type == LYXP_SET_SCNODE_SET);
- ret = set_scnode_dup_node_check(set, node, node_type, -1);
+ ret = lyxp_set_scnode_dup_node_check(set, node, node_type, -1);
if (ret > -1) {
set->val.scnodes[ret].in_ctx = 1;
} else {
@@ -3503,7 +3479,7 @@
if (options & LYXP_SCNODE_ALL) {
set_scnode_clear_ctx(set);
- set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
+ lyxp_set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
} else {
lyxp_set_cast(set, LYXP_SET_EMPTY);
@@ -3555,7 +3531,7 @@
rc = lys_compile_leafref_validate(&cctx, (struct lysc_node *)sleaf, (struct lysc_type_leafref *)sleaf->type, &target);
/* it was already validated, it must succeed */
if (rc == LY_SUCCESS) {
- set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
+ lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
}
}
@@ -5276,7 +5252,7 @@
if (options & LYXP_SCNODE_ALL) {
set_scnode_clear_ctx(set);
- set_scnode_insert_node(set, NULL, set->root_type);
+ lyxp_set_scnode_insert_node(set, NULL, set->root_type);
} else {
lyxp_set_cast(set, LYXP_SET_EMPTY);
set_insert_node(set, NULL, 0, set->root_type, 0);
@@ -5502,7 +5478,7 @@
sub = NULL;
while ((sub = lys_getnext(sub, NULL, moveto_mod->compiled, getnext_opts))) {
if (!moveto_scnode_check(sub, set->root_type, name_dict, moveto_mod)) {
- idx = set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
+ idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
/* we need to prevent these nodes from being considered in this moveto */
if ((idx < orig_used) && (idx > i)) {
set->val.scnodes[idx].in_ctx = 2;
@@ -5524,7 +5500,7 @@
sub = NULL;
while ((sub = lys_getnext(sub, start_parent, NULL, getnext_opts))) {
if (!moveto_scnode_check(sub, set->root_type, name_dict, (moveto_mod ? moveto_mod : set->local_mod))) {
- idx = set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
+ idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
if ((idx < orig_used) && (idx > i)) {
set->val.scnodes[idx].in_ctx = 2;
temp_ctx = 1;
@@ -5695,14 +5671,14 @@
rc = moveto_scnode_check(elem, set->root_type, qname, moveto_mod);
if (!rc) {
- if ((idx = set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
+ if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
set->val.scnodes[idx].in_ctx = 1;
if (idx > i) {
/* we will process it later in the set */
goto skip_children;
}
} else {
- set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
+ lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
}
} else if (rc == LY_EINVAL) {
goto skip_children;
@@ -6142,7 +6118,7 @@
continue;
}
- set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
+ lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
/* throw away the insert index, we want to consider that node again, recursively */
}
}
@@ -6287,7 +6263,7 @@
new_type = LYXP_NODE_ELEM;
}
- idx = set_scnode_insert_node(set, new_node, new_type);
+ idx = lyxp_set_scnode_insert_node(set, new_node, new_type);
if ((idx < orig_used) && (idx > i)) {
set->val.scnodes[idx].in_ctx = 2;
temp_ctx = 1;
@@ -7212,7 +7188,7 @@
/* merge all nodes from arg evaluations */
for (i = 0; i < arg_count; ++i) {
set_scnode_clear_ctx(args[i]);
- set_scnode_merge(set, args[i]);
+ lyxp_set_scnode_merge(set, args[i]);
}
}
} else {
@@ -7452,7 +7428,7 @@
/* eval */
if (options & LYXP_SCNODE_ALL) {
- set_scnode_merge(set, &set2);
+ lyxp_set_scnode_merge(set, &set2);
} else {
rc = moveto_union(set, &set2);
LY_CHECK_GOTO(rc, cleanup);
@@ -7565,7 +7541,7 @@
/* eval */
if (options & LYXP_SCNODE_ALL) {
warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
- set_scnode_merge(set, &set2);
+ lyxp_set_scnode_merge(set, &set2);
set_scnode_clear_ctx(set);
} else {
rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
@@ -7633,7 +7609,7 @@
/* eval */
if (options & LYXP_SCNODE_ALL) {
warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
- set_scnode_merge(set, &set2);
+ lyxp_set_scnode_merge(set, &set2);
set_scnode_clear_ctx(set);
} else {
rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
@@ -7703,7 +7679,7 @@
/* eval */
if (options & LYXP_SCNODE_ALL) {
warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
- set_scnode_merge(set, &set2);
+ lyxp_set_scnode_merge(set, &set2);
set_scnode_clear_ctx(set);
} else {
rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
@@ -7772,7 +7748,7 @@
warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
warn_equality_value(exp, set, *exp_idx - 1, this_op - 1, *exp_idx - 1);
warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *exp_idx - 1);
- set_scnode_merge(set, &set2);
+ lyxp_set_scnode_merge(set, &set2);
set_scnode_clear_ctx(set);
} else {
/* special handling of evaluations of identityref comparisons, always compare prefixed identites */
@@ -7860,7 +7836,7 @@
/* eval - just get boolean value actually */
if (set->type == LYXP_SET_SCNODE_SET) {
set_scnode_clear_ctx(&set2);
- set_scnode_merge(set, &set2);
+ lyxp_set_scnode_merge(set, &set2);
} else {
lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
set_fill_set(set, &set2);
@@ -7932,7 +7908,7 @@
/* eval - just get boolean value actually */
if (set->type == LYXP_SET_SCNODE_SET) {
set_scnode_clear_ctx(&set2);
- set_scnode_merge(set, &set2);
+ lyxp_set_scnode_merge(set, &set2);
} else {
lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
set_fill_set(set, &set2);
@@ -8047,29 +8023,20 @@
}
LY_ERR
-lyxp_eval(const char *expr, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
+lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
enum lyxp_node_type ctx_node_type, const struct lyd_node **trees, struct lyxp_set *set, int options)
{
- struct ly_ctx *ctx;
- struct lyxp_expr *exp;
uint16_t exp_idx = 0;
LY_ERR rc;
- LY_CHECK_ARG_RET(NULL, expr, local_mod, set, LY_EINVAL);
-
- ctx = local_mod->ctx;
-
- exp = lyxp_expr_parse(ctx, expr);
- if (!exp) {
- return LY_EINVAL;
- }
+ LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
/* prepare set for evaluation */
exp_idx = 0;
memset(set, 0, sizeof *set);
set->type = LYXP_SET_EMPTY;
set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node_type, options);
- set->ctx = ctx;
+ set->ctx = local_mod->ctx;
set->ctx_node = ctx_node;
set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
set->local_mod = local_mod;
@@ -8082,7 +8049,6 @@
lyxp_set_cast(set, LYXP_SET_EMPTY);
}
- lyxp_expr_free(ctx, exp);
return rc;
}
@@ -8340,7 +8306,7 @@
exp_idx = 0;
memset(set, 0, sizeof *set);
set->type = LYXP_SET_SCNODE_SET;
- set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
+ lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
set->ctx = ctx;
set->ctx_scnode = ctx_scnode;
set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
diff --git a/src/xpath.h b/src/xpath.h
index 527153c..1e27ab1 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -255,7 +255,7 @@
* @brief Evaluate an XPath expression on data. Be careful when using this function, the result can often
* be confusing without thorough understanding of XPath evaluation rules defined in RFC 7950.
*
- * @param[in] expr XPath expression to evaluate.
+ * @param[in] exp Parsed XPath expression to be evaluated.
* @param[in] format Format of the XPath expression (more specifcally, of any used prefixes).
* @param[in] local_mod Local module relative to the @p expr.
* @param[in] ctx_node Current (context) data node, NULL for root node.
@@ -271,9 +271,10 @@
* the @p set to empty (if allocated statically) or free it (if allocated dynamically) to
* prevent memory leaks.
* @param[in] options Whether to apply some evaluation restrictions.
- * @return LY_ERR
+ * @return LY_ERR (LY_EINVAL, LY_EMEM, LY_EINT, LY_EVALID for invalid argument types/count,
+ * LY_EINCOMPLETE for unresolved when).
*/
-LY_ERR lyxp_eval(const char *expr, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
+LY_ERR lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
enum lyxp_node_type ctx_node_type, const struct lyd_node **trees, struct lyxp_set *set, int options);
#define LYXP_SCHEMA 0x01 /**< Apply data node access restrictions defined for 'when' and 'must' evaluation. */
@@ -294,7 +295,7 @@
* the @p set to empty (if allocated statically) or free it (if allocated dynamically) to
* prevent memory leaks.
* @param[in] options Whether to apply some evaluation restrictions, one flag must always be used.
- * @return LY_ERR
+ * @return LY_ERR (same as lyxp_eval()).
*/
LY_ERR lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options);
@@ -317,6 +318,36 @@
LY_ERR lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target);
/**
+ * @brief Insert schema node into set.
+ *
+ * @param[in] set Set to insert into.
+ * @param[in] node Node to insert.
+ * @param[in] node_type Node type of @p node.
+ * @return Index of the inserted node in set.
+ */
+int lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type);
+
+/**
+ * @brief Check for duplicates in a schema node set.
+ *
+ * @param[in] set Set to check.
+ * @param[in] node Node to look for in @p set.
+ * @param[in] node_type Type of @p node.
+ * @param[in] skip_idx Index from @p set to skip.
+ * @return Index of the found node, -1 if not found.
+ */
+int lyxp_set_scnode_dup_node_check(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type,
+ int skip_idx);
+
+/**
+ * @brief Merge 2 schema node sets.
+ *
+ * @param[in] set1 Set to merge into.
+ * @param[in] set2 Set to merge. Its content is freed.
+ */
+void lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2);
+
+/**
* @brief Parse an XPath expression into a structure of tokens.
* Logs directly.
*
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index 20ef15b..de53e76 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -877,12 +877,10 @@
assert_non_null(rpc);
assert_int_equal(1, LY_ARRAY_SIZE(rpc));
assert_int_equal(LYS_ACTION, rpc->nodetype);
- assert_int_equal(LYS_STATUS_CURR | LYS_XPATH_DEP, rpc->flags);
+ assert_int_equal(LYS_STATUS_CURR, rpc->flags);
assert_string_equal("b", rpc->name);
assert_null(rpc->input.musts);
assert_int_equal(2, LY_ARRAY_SIZE(rpc->output.musts));
- assert_int_equal(0, rpc->output.musts[0].flags);
- assert_int_equal(LYS_XPATH_DEP, rpc->output.musts[1].flags);
/* invalid */
assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;container top {action x;}}", LYS_IN_YANG));
@@ -951,11 +949,10 @@
assert_non_null(notif->data);
assert_string_equal("x", notif->data->name);
assert_int_equal(LYS_NOTIF, notif[1].nodetype);
- assert_int_equal(LYS_STATUS_CURR | LYS_XPATH_DEP, notif[1].flags);
+ assert_int_equal(LYS_STATUS_CURR, notif[1].flags);
assert_string_equal("b2", notif[1].name);
assert_null(notif[1].data);
assert_int_equal(1, LY_ARRAY_SIZE(notif[1].musts));
- assert_int_equal(LYS_XPATH_DEP, notif[1].musts[0].flags);
/* invalid */
assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;container top {notification x;}}", LYS_IN_YANG));
@@ -3429,6 +3426,75 @@
ly_ctx_destroy(ctx, NULL);
}
+static void
+test_when(void **state)
+{
+ *state = test_when;
+
+ struct ly_ctx *ctx;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
+
+ assert_null(lys_parse_mem(ctx,
+ "module a {"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "leaf l {"
+ "when \"/cont/lst[val='25']\";"
+ "type empty;"
+ "}"
+ "list lst {"
+ "key \"k\";"
+ "leaf k {"
+ "type uint8;"
+ "}"
+ "leaf val {"
+ "when /cont2;"
+ "type int32;"
+ "}"
+ "}"
+ "}"
+ "container cont2 {"
+ "presence \"a\";"
+ "when ../cont/l;"
+ "}"
+ "}"
+ , LYS_IN_YANG));
+ logbuf_assert("When condition of \"cont2\" includes a self-reference (referenced by when of \"l\").");
+
+ assert_null(lys_parse_mem(ctx,
+ "module a {"
+ "namespace urn:a;"
+ "prefix a;"
+ "container cont {"
+ "leaf l {"
+ "when \"/cont/lst[val='25']\";"
+ "type empty;"
+ "}"
+ "list lst {"
+ "key \"k\";"
+ "leaf k {"
+ "type uint8;"
+ "}"
+ "leaf val {"
+ "when /cont2;"
+ "type int32;"
+ "}"
+ "}"
+ "}"
+ "container cont2 {"
+ "presence \"a\";"
+ "when ../cont/lst/val;"
+ "}"
+ "}"
+ , LYS_IN_YANG));
+ logbuf_assert("When condition of \"cont2\" includes a self-reference (referenced by when of \"val\").");
+
+ *state = NULL;
+ ly_ctx_destroy(ctx, NULL);
+}
+
int main(void)
{
const struct CMUnitTest tests[] = {
@@ -3460,6 +3526,7 @@
cmocka_unit_test_setup_teardown(test_refine, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_augment, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_deviation, logger_setup, logger_teardown),
+ cmocka_unit_test_setup_teardown(test_when, logger_setup, logger_teardown),
};
return cmocka_run_group_tests(tests, NULL, NULL);