libyang UPDATE optional value validation and context type plugins (#2171)

This patch separates the build-in type validations from store
operations to allow storing a node even if the value doesn't pass the
validations. To do multiple changes were done:
 - introduces LY_CTX_BASIC_PLUGINS_ONLY flag, which prevents loading of
   any advanced plugins
 - introduces LYPLG_TYPE_STORE_ONLY flag, which skip validation and
   perform just storing
 - introduces LYD_PARSE_STORE_ONLY flag, which implies usage of LYPLG_TYPE_STORE_ONLY
 - introduces options for lyd_new_* API
 - removes lyd_new_(term|list)_(bin|canon) API
 - added sanity checks within lyd_new_(term|list) APIs for proper
   combinations of options
 - refactored lyd_new_* APIs to use common flags to use common options attributes
diff --git a/src/tree_data_new.c b/src/tree_data_new.c
index bbe59f2..7a965a3 100644
--- a/src/tree_data_new.c
+++ b/src/tree_data_new.c
@@ -52,8 +52,8 @@
 #include "xpath.h"
 
 LY_ERR
-lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, ly_bool is_utf8, ly_bool *dynamic,
-        LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, ly_bool *incomplete, struct lyd_node **node)
+lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, ly_bool is_utf8, ly_bool store_only,
+        ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, ly_bool *incomplete, struct lyd_node **node)
 {
     LY_ERR ret;
     struct lyd_node_term *term;
@@ -69,7 +69,7 @@
 
     LOG_LOCSET(schema, NULL);
     ret = lyd_value_store(schema->module->ctx, &term->value, ((struct lysc_node_leaf *)term->schema)->type, value,
-            value_len, is_utf8, dynamic, format, prefix_data, hints, schema, incomplete);
+            value_len, is_utf8, store_only, dynamic, format, prefix_data, hints, schema, incomplete);
     LOG_LOCBACK(1, 0);
     LY_CHECK_ERR_RET(ret, free(term), ret);
     lyd_hash(&term->node);
@@ -136,7 +136,7 @@
 
 LY_ERR
 lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate *predicates, const struct lyxp_var *vars,
-        struct lyd_node **node)
+        ly_bool store_only, struct lyd_node **node)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *list = NULL, *key;
@@ -163,7 +163,7 @@
             /* store the value */
             LOG_LOCSET(predicates[u].key, NULL);
             ret = lyd_value_store(schema->module->ctx, &val, ((struct lysc_node_leaf *)predicates[u].key)->type,
-                    var->value, strlen(var->value), 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, predicates[u].key, NULL);
+                    var->value, strlen(var->value), 0, store_only, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, predicates[u].key, NULL);
             LOG_LOCBACK(1, 0);
             LY_CHECK_GOTO(ret, cleanup);
 
@@ -196,7 +196,7 @@
 }
 
 LY_ERR
-lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_len, struct lyd_node **node)
+lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_len, ly_bool store_only, struct lyd_node **node)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyxp_expr *expr = NULL;
@@ -214,7 +214,7 @@
             NULL, &predicates), cleanup);
 
     /* create the list node */
-    LY_CHECK_GOTO(ret = lyd_create_list(schema, predicates, NULL, node), cleanup);
+    LY_CHECK_GOTO(ret = lyd_create_list(schema, predicates, NULL, store_only, node), cleanup);
 
 cleanup:
     LOG_LOCBACK(1, 0);
@@ -471,6 +471,29 @@
     return ret;
 }
 
+/**
+ * @brief Gets format from lyd_new_* options
+ *
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
+ * @param[out] format The output format.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+_lyd_new_val_format(const uint32_t options, LY_VALUE_FORMAT *format)
+{
+    LY_CHECK_ARG_RET(NULL, format, !((options & LYD_NEW_VAL_BIN_VALUE) && (options & LYD_NEW_VAL_CANON_VALUE)), LY_EVALID);
+
+    if (options & LYD_NEW_VAL_BIN_VALUE) {
+        *format = LY_VALUE_LYB;
+    } else if (options & LYD_NEW_VAL_CANON_VALUE) {
+        *format = LY_VALUE_CANON;
+    } else {
+        *format = LY_VALUE_JSON;
+    }
+
+    return LY_SUCCESS;
+}
+
 LIBYANG_API_DEF LY_ERR
 lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name, ly_bool output,
         struct lyd_node **node)
@@ -546,25 +569,25 @@
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Created node.
  * @return LY_ERR value.
  */
 static LY_ERR
 _lyd_new_list_node(const struct ly_ctx *ctx, const struct lyd_node *parent, const struct lys_module *module,
-        const char *name, ly_bool output, struct lyd_node **node)
+        const char *name, uint32_t options, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct lysc_ext_instance *ext = NULL;
+    uint32_t getnext_opts = (options & LYD_NEW_VAL_OUTPUT) ? LYS_GETNEXT_OUTPUT : 0;
     LY_ERR r;
 
     if (!module) {
         module = parent->schema->module;
     }
 
-    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, output ? LYS_GETNEXT_OUTPUT : 0);
+    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, getnext_opts);
     if (!schema && parent) {
         r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name,
                 strlen(name), &schema, &ext);
@@ -583,23 +606,9 @@
     return LY_SUCCESS;
 }
 
-/**
- * @brief Create a new list node in the data tree.
- *
- * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
- * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] format Format of key values.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
- * @param[out] node Optional created node.
- * @param[in] ap Ordered key values of the new list instance, all must be set. For ::LY_VALUE_LYB, every value must
- * be followed by the value length.
- * @return LY_ERR value.
- */
-static LY_ERR
-_lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, LY_VALUE_FORMAT format,
-        ly_bool output, struct lyd_node **node, va_list ap)
+LIBYANG_API_DEF LY_ERR
+lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, uint32_t options,
+        struct lyd_node **node, ...)
 {
     struct lyd_node *ret = NULL, *key;
     const struct lysc_node *key_s;
@@ -607,13 +616,19 @@
     const void *key_val;
     uint32_t key_len;
     LY_ERR rc = LY_SUCCESS;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+    LY_VALUE_FORMAT format;
+    va_list ap;
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
+    LY_CHECK_RET(_lyd_new_val_format(options, &format));
+    LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
 
     /* create the list node */
-    LY_CHECK_RET(_lyd_new_list_node(ctx, parent, module, name, output, &ret));
+    LY_CHECK_RET(_lyd_new_list_node(ctx, parent, module, name, options, &ret));
 
+    va_start(ap, node);
     /* create and insert all the keys */
     for (key_s = lysc_node_child(ret->schema); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
         if (format == LY_VALUE_LYB) {
@@ -623,8 +638,7 @@
             key_val = va_arg(ap, const char *);
             key_len = key_val ? strlen((char *)key_val) : 0;
         }
-
-        rc = lyd_create_term(key_s, key_val, key_len, 0, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
+        rc = lyd_create_term(key_s, key_val, key_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
         LY_CHECK_GOTO(rc, cleanup);
         lyd_insert_node(ret, NULL, key, LYD_INSERT_NODE_LAST);
     }
@@ -634,6 +648,7 @@
     }
 
 cleanup:
+    va_end(ap);
     if (rc) {
         lyd_free_tree(ret);
         ret = NULL;
@@ -644,61 +659,21 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, ly_bool output,
-        struct lyd_node **node, ...)
-{
-    LY_ERR rc;
-    va_list ap;
-
-    va_start(ap, node);
-
-    rc = _lyd_new_list(parent, module, name, LY_VALUE_JSON, output, node, ap);
-
-    va_end(ap);
-    return rc;
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_list_bin(struct lyd_node *parent, const struct lys_module *module, const char *name, ly_bool output,
-        struct lyd_node **node, ...)
-{
-    LY_ERR rc;
-    va_list ap;
-
-    va_start(ap, node);
-
-    rc = _lyd_new_list(parent, module, name, LY_VALUE_LYB, output, node, ap);
-
-    va_end(ap);
-    return rc;
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_list_canon(struct lyd_node *parent, const struct lys_module *module, const char *name, ly_bool output,
-        struct lyd_node **node, ...)
-{
-    LY_ERR rc;
-    va_list ap;
-
-    va_start(ap, node);
-
-    rc = _lyd_new_list(parent, module, name, LY_VALUE_CANON, output, node, ap);
-
-    va_end(ap);
-    return rc;
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_ext_list(const struct lysc_ext_instance *ext, const char *name, struct lyd_node **node, ...)
+lyd_new_ext_list(const struct lysc_ext_instance *ext, const char *name, uint32_t options, struct lyd_node **node, ...)
 {
     struct lyd_node *ret = NULL, *key;
     const struct lysc_node *schema, *key_s;
     struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
     va_list ap;
     const char *key_val;
+    size_t key_len;
     LY_ERR rc = LY_SUCCESS;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+    LY_VALUE_FORMAT format;
 
     LY_CHECK_ARG_RET(ctx, ext, node, name, LY_EINVAL);
+    LY_CHECK_RET(_lyd_new_val_format(options, &format));
+    LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
 
     schema = lysc_ext_find_node(ext, NULL, name, 0, LYS_LIST, 0);
     if (!schema) {
@@ -717,10 +692,14 @@
 
     /* create and insert all the keys */
     for (key_s = lysc_node_child(schema); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
-        key_val = va_arg(ap, const char *);
-
-        rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA,
-                NULL, &key);
+        if (format == LY_VALUE_LYB) {
+            key_val = va_arg(ap, const void *);
+            key_len = va_arg(ap, uint32_t);
+        } else {
+            key_val = va_arg(ap, const char *);
+            key_len = key_val ? strlen((char *)key_val) : 0;
+        }
+        rc = lyd_create_term(key_s, key_val, key_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
         LY_CHECK_GOTO(rc, cleanup);
         lyd_insert_node(ret, NULL, key, LYD_INSERT_NODE_LAST);
     }
@@ -737,13 +716,14 @@
 
 LIBYANG_API_DEF LY_ERR
 lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys,
-        ly_bool output, struct lyd_node **node)
+        uint32_t options, struct lyd_node **node)
 {
     LY_ERR r;
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct lysc_ext_instance *ext = NULL;
     const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
+    uint32_t getnext_opts = (options & LYD_NEW_VAL_OUTPUT) ? LYS_GETNEXT_OUTPUT : 0;
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
@@ -756,7 +736,7 @@
     }
 
     /* find schema node */
-    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, output ? LYS_GETNEXT_OUTPUT : 0);
+    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, getnext_opts);
     if (!schema && parent) {
         r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name, strlen(name),
                 &schema, &ext);
@@ -769,7 +749,9 @@
         LY_CHECK_RET(lyd_create_inner(schema, &ret));
     } else {
         /* create the list node */
-        LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret));
+        ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+
+        LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), store_only, &ret));
     }
     if (ext) {
         ret->flags |= LYD_EXT;
@@ -790,17 +772,15 @@
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] format Format of key values.
- * @param[in] key_values Ordered key values of the new list instance, all must be set.
- * @param[in] value_lengths Lengths of @p key_values, required for ::LY_VALUE_LYB, optional otherwise.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] key_values Ordered key string values of the new list instance, all must be set.
+ * @param[in] value_lengths Array of lengths of each @p key_values, may be NULL if @p key_values are 0-terminated strings.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Optional created node.
  * @return LY_ERR value.
  */
 static LY_ERR
-_lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const char *name, LY_VALUE_FORMAT format,
-        const void **key_values, uint32_t *value_lengths, ly_bool output, struct lyd_node **node)
+_lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const char *name, const void **key_values,
+        uint32_t *value_lengths, uint32_t options, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL, *key;
     const struct lysc_node *key_s;
@@ -808,12 +788,16 @@
     const void *key_val;
     uint32_t key_len, i;
     LY_ERR rc = LY_SUCCESS;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+    LY_VALUE_FORMAT format;
 
+    LY_CHECK_RET(_lyd_new_val_format(options, &format));
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, (format != LY_VALUE_LYB) || value_lengths, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
+    LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
 
     /* create the list node */
-    LY_CHECK_RET(_lyd_new_list_node(ctx, parent, module, name, output, &ret));
+    LY_CHECK_RET(_lyd_new_list_node(ctx, parent, module, name, options, &ret));
 
     if (!(ret->schema->flags & LYS_KEYLESS) && !key_values) {
         LOGERR(ctx, LY_EINVAL, "Missing list \"%s\" keys.", LYD_NAME(ret));
@@ -827,7 +811,7 @@
         key_val = key_values[i] ? key_values[i] : "";
         key_len = value_lengths ? value_lengths[i] : strlen(key_val);
 
-        rc = lyd_create_term(key_s, key_val, key_len, 0, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
+        rc = lyd_create_term(key_s, key_val, key_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
         LY_CHECK_GOTO(rc, cleanup);
         lyd_insert_node(ret, NULL, key, LYD_INSERT_NODE_LAST);
     }
@@ -848,23 +832,21 @@
 
 LIBYANG_API_DEF LY_ERR
 lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const char *name, const char **key_values,
-        uint32_t *value_lengths, ly_bool output, struct lyd_node **node)
+        uint32_t *value_lengths, uint32_t options, struct lyd_node **node)
 {
-    return _lyd_new_list3(parent, module, name, LY_VALUE_JSON, (const void **)key_values, value_lengths, output, node);
+    const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
+
+    LY_CHECK_ARG_RET(ctx, !(options & LYD_NEW_VAL_BIN_VALUE), LY_EINVAL);
+
+    return _lyd_new_list3(parent, module, name, (const void **)key_values, value_lengths, options, node);
 }
 
-LIBYANG_API_DEF LY_ERR
+LIBYANG_API_DECL LY_ERR
 lyd_new_list3_bin(struct lyd_node *parent, const struct lys_module *module, const char *name, const void **key_values,
-        uint32_t *value_lengths, ly_bool output, struct lyd_node **node)
+        uint32_t *value_lengths, uint32_t options, struct lyd_node **node)
 {
-    return _lyd_new_list3(parent, module, name, LY_VALUE_LYB, key_values, value_lengths, output, node);
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_list3_canon(struct lyd_node *parent, const struct lys_module *module, const char *name, const char **key_values,
-        uint32_t *value_lengths, ly_bool output, struct lyd_node **node)
-{
-    return _lyd_new_list3(parent, module, name, LY_VALUE_CANON, (const void **)key_values, value_lengths, output, node);
+    options |= LYD_NEW_VAL_BIN_VALUE;
+    return _lyd_new_list3(parent, module, name, key_values, value_lengths, options, node);
 }
 
 /**
@@ -872,33 +854,36 @@
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
- * @param[in] name Schema node name of the new data node. The node can be ::LYS_LEAF or ::LYS_LEAFLIST.
- * @param[in] value Value of the node being created.
+ * @param[in] name Schema node name of the new data node. The node can be #LYS_LEAF or #LYS_LEAFLIST.
+ * @param[in] value The value of the node in @p format.
  * @param[in] value_len Length of @p value.
- * @param[in] format Format of @p value.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Optional created node.
  * @return LY_ERR value.
  */
 static LY_ERR
 _lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
-        size_t value_len, LY_VALUE_FORMAT format, ly_bool output, struct lyd_node **node)
+        size_t value_len, uint32_t options, struct lyd_node **node)
 {
     LY_ERR r;
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct lysc_ext_instance *ext = NULL;
     const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
+    uint32_t getnext_opts = (options & LYD_NEW_VAL_OUTPUT) ? LYS_GETNEXT_OUTPUT : 0;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+    LY_VALUE_FORMAT format;
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
+    LY_CHECK_RET(_lyd_new_val_format(options, &format));
+    LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
     }
 
-    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, output ? LYS_GETNEXT_OUTPUT : 0);
+    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, getnext_opts);
     if (!schema && parent) {
         r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name,
                 strlen(name), &schema, &ext);
@@ -906,7 +891,7 @@
     }
     LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), LY_ENOTFOUND);
 
-    LY_CHECK_RET(lyd_create_term(schema, value, value_len, 0, NULL, format, NULL, LYD_HINT_DATA, NULL, &ret));
+    LY_CHECK_RET(lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &ret));
     if (ext) {
         ret->flags |= LYD_EXT;
     }
@@ -921,35 +906,37 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
-        ly_bool output, struct lyd_node **node)
+lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *value,
+        uint32_t options, struct lyd_node **node)
 {
-    return _lyd_new_term(parent, module, name, val_str, val_str ? strlen(val_str) : 0, LY_VALUE_JSON, output, node);
+    const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
+
+    LY_CHECK_ARG_RET(ctx, !(options & LYD_NEW_VAL_BIN_VALUE), LY_EINVAL);
+    return _lyd_new_term(parent, module, name, value, value ? strlen(value) : 0, options, node);
+}
+
+LIBYANG_API_DECL LY_ERR
+lyd_new_term_bin(struct lyd_node *parent, const struct lys_module *module, const char *name,
+        const void *value, size_t value_len, uint32_t options, struct lyd_node **node)
+{
+    options |= LYD_NEW_VAL_BIN_VALUE;
+    return _lyd_new_term(parent, module, name, value, value_len, options, node);
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_new_term_bin(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
-        size_t value_len, ly_bool output, struct lyd_node **node)
-{
-    return _lyd_new_term(parent, module, name, value, value_len, LY_VALUE_LYB, output, node);
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_term_canon(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
-        ly_bool output, struct lyd_node **node)
-{
-    return _lyd_new_term(parent, module, name, val_str, val_str ? strlen(val_str) : 0, LY_VALUE_CANON, output, node);
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_ext_term(const struct lysc_ext_instance *ext, const char *name, const char *val_str, struct lyd_node **node)
+lyd_new_ext_term(const struct lysc_ext_instance *ext, const char *name, const void *value, size_t value_len,
+        uint32_t options, struct lyd_node **node)
 {
     LY_ERR rc;
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+    LY_VALUE_FORMAT format;
 
     LY_CHECK_ARG_RET(ctx, ext, node, name, LY_EINVAL);
+    LY_CHECK_RET(_lyd_new_val_format(options, &format));
+    LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
 
     schema = lysc_ext_find_node(ext, NULL, name, 0, LYD_NODE_TERM, 0);
     if (!schema) {
@@ -961,8 +948,7 @@
         }
         return LY_ENOTFOUND;
     }
-    rc = lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA,
-            NULL, &ret);
+    rc = lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &ret);
     LY_CHECK_RET(rc);
 
     *node = ret;
@@ -972,13 +958,15 @@
 
 LIBYANG_API_DEF LY_ERR
 lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
-        ly_bool use_value, LYD_ANYDATA_VALUETYPE value_type, ly_bool output, struct lyd_node **node)
+        uint32_t options, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
 {
     LY_ERR r;
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct lysc_ext_instance *ext = NULL;
     const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
+    uint32_t getnext_opts = (options & LYS_GETNEXT_OUTPUT) ? LYS_GETNEXT_OUTPUT : 0;
+    ly_bool use_value = (options & LYD_NEW_ANY_USE_VALUE) ? 1 : 0;
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name,
             (value_type == LYD_ANYDATA_DATATREE) || (value_type == LYD_ANYDATA_STRING) || value, LY_EINVAL);
@@ -988,7 +976,7 @@
         module = parent->schema->module;
     }
 
-    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, output ? LYS_GETNEXT_OUTPUT : 0);
+    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, getnext_opts);
     if (!schema && parent) {
         r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name,
                 strlen(name), &schema, &ext);
@@ -1011,12 +999,13 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_new_ext_any(const struct lysc_ext_instance *ext, const char *name, const void *value, ly_bool use_value,
+lyd_new_ext_any(const struct lysc_ext_instance *ext, const char *name, const void *value, uint32_t options,
         LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
+    ly_bool use_value = (options & LYD_NEW_ANY_USE_VALUE) ? 1 : 0;
 
     LY_CHECK_ARG_RET(ctx, ext, node, name, LY_EINVAL);
 
@@ -1039,10 +1028,12 @@
 
 LIBYANG_API_DEF LY_ERR
 lyd_new_meta(const struct ly_ctx *ctx, struct lyd_node *parent, const struct lys_module *module, const char *name,
-        const char *val_str, ly_bool clear_dflt, struct lyd_meta **meta)
+        const char *val_str, uint32_t options, struct lyd_meta **meta)
 {
     const char *prefix, *tmp;
     size_t pref_len, name_len;
+    ly_bool clear_dflt = options & LYD_NEW_META_CLEAR_DFLT;
+    ly_bool store_only = options & LYD_NEW_VAL_STORE_ONLY;
 
     LY_CHECK_ARG_RET(ctx, ctx || parent, name, module || strchr(name, ':'), parent || meta, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
@@ -1076,15 +1067,16 @@
         val_str = "";
     }
 
-    return lyd_create_meta(parent, meta, module, name, name_len, val_str, strlen(val_str), 0, NULL, LY_VALUE_JSON,
+    return lyd_create_meta(parent, meta, module, name, name_len, val_str, strlen(val_str), 0, store_only, NULL, LY_VALUE_JSON,
             NULL, LYD_HINT_DATA, parent ? parent->schema : NULL, clear_dflt, NULL);
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, ly_bool clear_dflt, const struct lyd_attr *attr,
-        struct lyd_meta **meta)
+lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, uint32_t options, const struct lyd_attr *attr, struct lyd_meta **meta)
 {
     const struct lys_module *mod;
+    ly_bool clear_dflt = options & LYD_NEW_META_CLEAR_DFLT;
+    ly_bool store_only = options & LYD_NEW_VAL_STORE_ONLY;
 
     LY_CHECK_ARG_RET(NULL, ctx, attr, parent || meta, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
@@ -1118,7 +1110,7 @@
     }
 
     return lyd_create_meta(parent, meta, mod, attr->name.name, strlen(attr->name.name), attr->value, strlen(attr->value),
-            0, NULL, attr->format, attr->val_prefix_data, attr->hints, parent ? parent->schema : NULL, clear_dflt, NULL);
+            0, store_only, NULL, attr->format, attr->val_prefix_data, attr->hints, parent ? parent->schema : NULL, clear_dflt, NULL);
 }
 
 LIBYANG_API_DEF LY_ERR
@@ -1355,7 +1347,7 @@
 
     /* parse the new value */
     LOG_LOCSET(term->schema, term);
-    ret = lyd_value_store(LYD_CTX(term), &val, type, value, value_len, 0, NULL, format, NULL, LYD_HINT_DATA,
+    ret = lyd_value_store(LYD_CTX(term), &val, type, value, value_len, 0, 0, NULL, format, NULL, LYD_HINT_DATA,
             term->schema, NULL);
     LOG_LOCBACK(1, 1);
     LY_CHECK_GOTO(ret, cleanup);
@@ -1445,7 +1437,7 @@
 
     /* parse the new value into a new meta structure */
     ret = lyd_create_meta(NULL, &m2, meta->annotation->module, meta->name, strlen(meta->name), val_str, strlen(val_str),
-            0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, meta->parent ? meta->parent->schema : NULL, 0, NULL);
+            0, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, meta->parent ? meta->parent->schema : NULL, 0, NULL);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* compare original and new value */
@@ -1600,7 +1592,7 @@
             if (!r) {
                 /* try to store the value */
                 LY_CHECK_RET(lyd_value_store(schema->module->ctx, &val, ((struct lysc_node_leaflist *)schema)->type,
-                        value, value_len, 0, NULL, format, NULL, LYD_HINT_DATA, schema, NULL));
+                        value, value_len, 0, 0, NULL, format, NULL, LYD_HINT_DATA, schema, NULL));
                 ++((struct lysc_type *)val.realtype)->refcount;
 
                 /* store the new predicate so that it is used when searching for this instance */
@@ -1660,12 +1652,13 @@
     struct lyd_node *nparent = NULL, *nnode = NULL, *node = NULL, *cur_parent;
     const struct lysc_node *schema;
     const struct lyd_value *val = NULL;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
     LY_ARRAY_COUNT_TYPE path_idx = 0, orig_count = 0;
     LY_VALUE_FORMAT format;
 
     assert(parent || ctx);
     assert(path && ((path[0] == '/') || parent));
-    assert(!(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE));
+    assert(!(options & LYD_NEW_VAL_BIN_VALUE) || !(options & LYD_NEW_VAL_CANON_VALUE));
 
     if (!ctx) {
         ctx = LYD_CTX(parent);
@@ -1673,9 +1666,9 @@
     if (value && !value_len) {
         value_len = strlen(value);
     }
-    if (options & LYD_NEW_PATH_BIN_VALUE) {
+    if (options & LYD_NEW_VAL_BIN_VALUE) {
         format = LY_VALUE_LYB;
-    } else if (options & LYD_NEW_PATH_CANON_VALUE) {
+    } else if (options & LYD_NEW_VAL_CANON_VALUE) {
         format = LY_VALUE_CANON;
     } else {
         format = LY_VALUE_JSON;
@@ -1686,7 +1679,7 @@
             LY_PATH_PRED_SIMPLE, &exp), cleanup);
 
     /* compile path */
-    LY_CHECK_GOTO(ret = ly_path_compile(ctx, NULL, lyd_node_schema(parent), ext, exp, options & LYD_NEW_PATH_OUTPUT ?
+    LY_CHECK_GOTO(ret = ly_path_compile(ctx, NULL, lyd_node_schema(parent), ext, exp, options & LYD_NEW_VAL_OUTPUT ?
             LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY, 0, LY_VALUE_JSON, NULL, &p), cleanup);
 
     /* check the compiled path before searching existing nodes, it may be shortened */
@@ -1751,7 +1744,7 @@
                         LYD_NODEHINT_LIST, &node), cleanup);
             } else {
                 /* create standard list instance */
-                LY_CHECK_GOTO(ret = lyd_create_list(schema, p[path_idx].predicates, NULL, &node), cleanup);
+                LY_CHECK_GOTO(ret = lyd_create_list(schema, p[path_idx].predicates, NULL, store_only, &node), cleanup);
             }
             break;
         case LYS_CONTAINER:
@@ -1787,8 +1780,7 @@
             if (val) {
                 LY_CHECK_GOTO(ret = lyd_create_term2(schema, val, &node), cleanup);
             } else {
-                LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, NULL, format, NULL, LYD_HINT_DATA,
-                        NULL, &node), cleanup);
+                LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &node), cleanup);
             }
             break;
         case LYS_LEAF:
@@ -1817,8 +1809,7 @@
             }
 
             /* create a leaf instance */
-            LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, NULL, format, NULL, LYD_HINT_DATA, NULL,
-                    &node), cleanup);
+            LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &node), cleanup);
             break;
         case LYS_ANYDATA:
         case LYS_ANYXML:
@@ -1876,7 +1867,7 @@
         struct lyd_node **node)
 {
     LY_CHECK_ARG_RET(ctx, parent || ctx, path, (path[0] == '/') || parent,
-            !(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE), LY_EINVAL);
+            !(options & LYD_NEW_VAL_BIN_VALUE) || !(options & LYD_NEW_VAL_CANON_VALUE), LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
 
     return lyd_new_path_(parent, ctx, NULL, path, value, 0, LYD_ANYDATA_STRING, options, node, NULL);
@@ -1888,7 +1879,7 @@
         struct lyd_node **new_node)
 {
     LY_CHECK_ARG_RET(ctx, parent || ctx, path, (path[0] == '/') || parent,
-            !(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE), LY_EINVAL);
+            !(options & LYD_NEW_VAL_BIN_VALUE) || !(options & LYD_NEW_VAL_CANON_VALUE), LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
 
     return lyd_new_path_(parent, ctx, NULL, path, value, value_len, value_type, options, new_parent, new_node);
@@ -1901,7 +1892,7 @@
     const struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
 
     LY_CHECK_ARG_RET(ctx, ext, path, (path[0] == '/') || parent,
-            !(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE), LY_EINVAL);
+            !(options & LYD_NEW_VAL_BIN_VALUE) || !(options & LYD_NEW_VAL_CANON_VALUE), LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
 
     return lyd_new_path_(parent, ctx, ext, path, value, 0, LYD_ANYDATA_STRING, options, node, NULL);