validation NEW state data checking

Separate flag for validation and parsers.
The reason is to allow not validating
parsed data but checking for state data
such as for <get-config> reply.
diff --git a/src/common.h b/src/common.h
index 57d1808..a556e5a 100644
--- a/src/common.h
+++ b/src/common.h
@@ -236,6 +236,7 @@
 #define LY_VCODE_DUP            LYVE_DATA, "Duplicate instance of \"%s\"."
 #define LY_VCODE_DUPCASE        LYVE_DATA, "Data for both cases \"%s\" and \"%s\" exist."
 #define LY_VCODE_NOIFF          LYVE_DATA, "Data are disabled by \"%s\" schema node if-feature."
+#define LY_VCODE_INSTATE        LYVE_DATA, "Invalid state data node \"%s\" found."
 
 /******************************************************************************
  * Context
diff --git a/src/parser_xml.c b/src/parser_xml.c
index c3f5f93..44fe075 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -266,6 +266,10 @@
             ret = LY_EVALID;
             goto cleanup;
         }
+        if ((ctx->options & LYD_OPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
+            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INSTATE, snode->name);
+            return LY_EVALID;
+        }
 
         /* create actual attributes so that prefixes are available in the context */
         if (attrs_data.count) {
@@ -470,7 +474,7 @@
     const struct lys_module *mod;
     struct lyd_node *first, *next, **first2;
 
-    xmlctx.options = options;
+    xmlctx.options = options & LYD_OPT_MASK;
     xmlctx.ctx = ctx;
     xmlctx.line = 1;
 
@@ -513,7 +517,7 @@
             LY_CHECK_GOTO(ret, cleanup);
 
             /* perform final validation that assumes the data tree is final */
-            ret = lyd_validate_siblings_r(*first2, NULL, mod, options);
+            ret = lyd_validate_siblings_r(*first2, NULL, mod, options & LYD_VALOPT_MASK);
             LY_CHECK_GOTO(ret, cleanup);
         }
     }
diff --git a/src/tree_data.c b/src/tree_data.c
index 976d9e2..9ab42ef 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -279,6 +279,11 @@
 
     LY_CHECK_ARG_RET(ctx, ctx, NULL);
 
+    if ((options & LYD_OPT_PARSE_ONLY) && (options & LYD_VALOPT_MASK)) {
+        LOGERR(ctx, LY_EINVAL, "Passing validation flags with LYD_OPT_PARSE_ONLY is not allowed.");
+        return NULL;
+    }
+
 #if 0
     if (options & LYD_OPT_RPCREPLY) {
         /* first item in trees is mandatory - the RPC/action request */
diff --git a/src/tree_data.h b/src/tree_data.h
index 9132f30..d56920b 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -402,9 +402,9 @@
 #define LYD_OPT_CONFIG     LYD_VALOPT_NO_STATE /**< A configuration datastore - complete datastore without state data. */
 #define LYD_OPT_GET        LYD_OPT_PARSE_ONLY /**< Data content from a NETCONF reply message to the NETCONF
                                 \<get\> operation. */
-#define LYD_OPT_GETCONFIG  LYD_OPT_PARSE_ONLY | LYD_VALOPT_NO_STATE /**< Data content from a NETCONF reply message to
+#define LYD_OPT_GETCONFIG  LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE /**< Data content from a NETCONF reply message to
                                 the NETCONF \<get-config\> operation. */
-#define LYD_OPT_EDIT       LYD_OPT_PARSE_ONLY | LYD_VALOPT_NO_STATE | LYD_OPT_EMPTY_INST /**< Content of
+#define LYD_OPT_EDIT       LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE | LYD_OPT_EMPTY_INST /**< Content of
                                 the NETCONF \<edit-config\>'s config element. */
 
 #define LYD_OPT_PARSE_ONLY      0x0001 /**< Data will be only parsed and no validation will be performed. When statements
@@ -416,9 +416,12 @@
                                             This flag can be used only with #LYD_OPT_PARSE_ONLY. */
 #define LYD_OPT_STRICT          0x0004 /**< Instead of silently ignoring data without schema definition raise an error. */
 #define LYD_OPT_EMPTY_INST      0x0008 /**< Allow leaf/leaf-list instances without values and lists without keys. */
+#define LYD_OPT_NO_STATE        0x0010 /**< Forbid state data in the parsed data. */
 //#define LYD_OPT_NOSIBLINGS 0x1000 /**< Parse only a single XML tree from the input. This option applies only to
 //                                       XML input data. */
 
+#define LYD_OPT_MASK            0xFFFF /**< Mask for all the parser options. */
+
 /** @} dataparseroptions */
 
 /**
@@ -448,6 +451,8 @@
 #define LYD_VALOPT_DATA_ONLY    0x00020000 /**< Validate only modules whose data actually exist. */
 //#define LYD_VALOPT_OBSOLETE   0x0800 /**< Raise an error when an obsolete statement (status set to obsolete) is used. */
 
+#define LYD_VALOPT_MASK         0xFFFF0000 /**< Mask for all the validation options. */
+
 /** @} datavalidationoptions */
 
 //#define LYD_OPT_VAL_DIFF 0x40000 /**< Flag only for validation, store all the data node changes performed by the validation
@@ -483,7 +488,7 @@
  * @param[in] ctx Context to connect with the data tree being built here.
  * @param[in] data Serialized data in the specified format.
  * @param[in] format Format of the input data to be parsed.
- * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_PARSE_ONLY implicitly.
+ * @param[in] options Parser and validation options, see @ref parseroptions.
  * @return Pointer to the built data tree or NULL in case of empty \p data. To free the returned structure,
  *         use lyd_free_all().
  * @return NULL in case of error. The error information can be then obtained using ly_err* functions.
diff --git a/src/validation.c b/src/validation.c
index eb28b7c..80766f9 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -782,6 +782,11 @@
             break;
         }
 
+        if ((val_opts & LYD_VALOPT_NO_STATE) && (node->schema->flags & LYS_CONFIG_R)) {
+            LOGVAL(node->schema->module->ctx, LY_VLOG_LYD, node, LY_VCODE_INSTATE, node->schema->name);
+            return LY_EVALID;
+        }
+
         /* node's schema if-features */
         if ((snode = lysc_node_is_disabled(node->schema, 1))) {
             LOGVAL(node->schema->module->ctx, LY_VLOG_LYD, node, LY_VCODE_NOIFF, snode->name);
@@ -790,7 +795,7 @@
 
         /* TODO node's must */
         /* TODO node status */
-        /* TODO list all keys existence */
+        /* TODO list all keys existence (take LYD_OPT_EMPTY_INST into consideration) */
         /* node value including if-feature is checked by plugins */
     }
 
@@ -921,6 +926,11 @@
 
     LY_CHECK_ARG_RET(NULL, tree, *tree || ctx || (modules && mod_count), LY_EINVAL);
 
+    if (val_opts & ~LYD_VALOPT_MASK) {
+        LOGERR(ctx, LY_EINVAL, "Some invalid flags passed to validation.");
+        return LY_EINVAL;
+    }
+
     next = *tree;
     while (1) {
         if (val_opts & LYD_VALOPT_DATA_ONLY) {
diff --git a/tests/src/test_validation.c b/tests/src/test_validation.c
index c6cf3c9..4d4c614 100644
--- a/tests/src/test_validation.c
+++ b/tests/src/test_validation.c
@@ -323,6 +323,21 @@
                 "}"
             "}"
         "}";
+    const char *schema_h =
+        "module h {"
+            "namespace urn:tests:h;"
+            "prefix h;"
+            "yang-version 1.1;"
+
+            "container cont {"
+                "container cont2 {"
+                    "config false;"
+                    "leaf l {"
+                        "type string;"
+                    "}"
+                "}"
+            "}"
+        "}";
 
 #if ENABLE_LOGGER_CHECKING
     ly_set_log_clb(logger, 1);
@@ -337,6 +352,7 @@
     assert_non_null(lys_parse_mem(ctx, schema_e, LYS_IN_YANG));
     assert_non_null(lys_parse_mem(ctx, schema_f, LYS_IN_YANG));
     assert_non_null(lys_parse_mem(ctx, schema_g, LYS_IN_YANG));
+    assert_non_null(lys_parse_mem(ctx, schema_h, LYS_IN_YANG));
 
     return 0;
 }
@@ -1177,6 +1193,39 @@
     *state = NULL;
 }
 
+static void
+test_state(void **state)
+{
+    *state = test_iffeature;
+
+    const char *data;
+    struct lyd_node *tree;
+
+    data =
+    "<cont xmlns=\"urn:tests:h\">"
+        "<cont2>"
+            "<l>val</l>"
+        "</cont2>"
+    "</cont>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE, &tree));
+    assert_null(tree);
+    logbuf_assert("Invalid state data node \"cont2\" found. Line number 1.");
+
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY | LYD_VALOPT_NO_STATE, &tree));
+    assert_null(tree);
+    logbuf_assert("Invalid state data node \"cont2\" found. /h:cont/cont2");
+
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_OPT_PARSE_ONLY, &tree));
+    assert_non_null(tree);
+
+    assert_int_equal(LY_EVALID, lyd_validate(&tree, NULL, LYD_VALOPT_DATA_ONLY | LYD_VALOPT_NO_STATE));
+    logbuf_assert("Invalid state data node \"cont2\" found. /h:cont/cont2");
+
+    lyd_free_siblings(tree);
+
+    *state = NULL;
+}
+
 int main(void)
 {
     const struct CMUnitTest tests[] = {
@@ -1188,6 +1237,7 @@
         cmocka_unit_test_teardown(test_dup, teardown_s),
         cmocka_unit_test_teardown(test_defaults, teardown_s),
         cmocka_unit_test_teardown(test_iffeature, teardown_s),
+        cmocka_unit_test_teardown(test_state, teardown_s),
     };
 
     return cmocka_run_group_tests(tests, setup, teardown);