From d4cde643d8a4a1ab5edaa420c733ab8253daff25 Mon Sep 17 00:00:00 2001 From: steweg Date: Wed, 21 Feb 2024 08:34:16 +0100 Subject: [PATCH] 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 --- src/context.c | 7 +- src/context.h | 7 + src/diff.c | 34 ++-- src/parser_common.c | 7 +- src/parser_data.h | 3 + src/path.c | 10 +- src/plugins.c | 60 +++--- src/plugins_internal.h | 3 +- src/plugins_types.h | 1 + src/plugins_types/binary.c | 50 +++-- src/plugins_types/decimal64.c | 36 +++- src/plugins_types/integer.c | 119 ++++++++++-- src/plugins_types/string.c | 53 ++++-- src/plugins_types/union.c | 24 ++- src/tree_data.c | 15 +- src/tree_data.h | 221 +++++++++------------- src/tree_data_common.c | 9 +- src/tree_data_internal.h | 23 ++- src/tree_data_new.c | 295 +++++++++++++++--------------- src/tree_data_sorted.c | 2 +- src/xpath.c | 2 +- tests/utests/basic/test_context.c | 18 ++ tests/utests/data/test_new.c | 37 +++- tests/utests/types/binary.c | 9 + tests/utests/types/decimal64.c | 11 ++ tests/utests/types/inet_types.c | 53 ++++++ tests/utests/types/int8.c | 10 + tests/utests/types/string.c | 9 + tests/utests/types/uint8.c | 11 ++ 29 files changed, 711 insertions(+), 428 deletions(-) diff --git a/src/context.c b/src/context.c index a7902e9ef..97ba672af 100644 --- a/src/context.c +++ b/src/context.c @@ -283,6 +283,7 @@ ly_ctx_new(const char *search_dir, uint16_t options, struct ly_ctx **new_ctx) struct ly_in *in = NULL; LY_ERR rc = LY_SUCCESS; struct lys_glob_unres unres = {0}; + ly_bool builtin_plugins_only; LY_CHECK_ARG_RET(NULL, new_ctx, LY_EINVAL); @@ -293,7 +294,8 @@ ly_ctx_new(const char *search_dir, uint16_t options, struct ly_ctx **new_ctx) lydict_init(&ctx->dict); /* plugins */ - LY_CHECK_ERR_GOTO(lyplg_init(), LOGINT(NULL); rc = LY_EINT, cleanup); + builtin_plugins_only = (options & LY_CTX_BUILTIN_PLUGINS_ONLY) ? 1 : 0; + LY_CHECK_ERR_GOTO(lyplg_init(builtin_plugins_only), LOGINT(NULL); rc = LY_EINT, cleanup); if (options & LY_CTX_LEAFREF_LINKING) { ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec), ly_ctx_ht_leafref_links_equal_cb, NULL, 1); @@ -1234,8 +1236,7 @@ ly_ctx_get_yanglib_data(const struct ly_ctx *ctx, struct lyd_node **root_p, cons LY_CHECK_GOTO(ret = ylib_deviation(cont, mod, 0), error); /* conformance-type */ - LY_CHECK_GOTO(ret = lyd_new_term(cont, NULL, "conformance-type", mod->implemented ? "implement" : "import", 0, - NULL), error); + LY_CHECK_GOTO(ret = lyd_new_term(cont, NULL, "conformance-type", mod->implemented ? "implement" : "import", 0, NULL), error); /* submodule list */ LY_CHECK_GOTO(ret = ylib_submodules(cont, mod->parsed, 0), error); diff --git a/src/context.h b/src/context.h index 8e8b205ff..9f1b8e6de 100644 --- a/src/context.h +++ b/src/context.h @@ -202,6 +202,13 @@ struct ly_ctx; 'require-instance false;'. It also enables usage of [lyd_leafref_get_links](@ref lyd_leafref_get_links) and [lyd_leafref_link_node_tree](@ref lyd_leafref_link_node_tree) APIs. */ +#define LY_CTX_BUILTIN_PLUGINS_ONLY 0x0800 /**< By default, context loads all available built-in plugins and extensions. This + options prohibits loading of built-in non-YANG plugin types and extensions (ipv4-address, + ipv6-address, etc.). Instead the value is processed by built-in YANG plugins (usually string) + with all its behavioral implications as hex-string comparison becoming case-sensitive. + Change of this flag during the lifetime of context is not fully supported. Once the non-YANG + plugins or extensions are loaded during context creation, they will be used regardless of this + flag. Therefore it is recommended to set this flag during the first context creation. */ /** @} contextoptions */ diff --git a/src/diff.c b/src/diff.c index 079c89869..744f0391a 100644 --- a/src/diff.c +++ b/src/diff.c @@ -154,7 +154,7 @@ lyd_diff_add_create_nested_userord(struct lyd_node *node) } /* create the metadata */ - LY_CHECK_GOTO(rc = lyd_new_meta(NULL, node, NULL, meta_name, meta_val, 0, NULL), cleanup); + LY_CHECK_GOTO(rc = lyd_new_meta(NULL, node, NULL, meta_name, meta_val, LYD_NEW_VAL_STORE_ONLY, NULL), cleanup); cleanup: free(dyn); @@ -382,7 +382,7 @@ lyd_diff_add(const struct lyd_node *node, enum lyd_diff_op op, const char *orig_ } /* set the none operation */ - LY_CHECK_RET(lyd_new_meta(NULL, elem, NULL, "yang:operation", "none", 0, NULL)); + LY_CHECK_RET(lyd_new_meta(NULL, elem, NULL, "yang:operation", "none", LYD_NEW_VAL_STORE_ONLY, NULL)); } dup = diff_parent; @@ -424,12 +424,12 @@ lyd_diff_add(const struct lyd_node *node, enum lyd_diff_op op, const char *orig_ /* add parent operation, if any */ if (diff_parent && (diff_parent != dup)) { - LY_CHECK_RET(lyd_new_meta(NULL, diff_parent, NULL, "yang:operation", "none", 0, NULL)); + LY_CHECK_RET(lyd_new_meta(NULL, diff_parent, NULL, "yang:operation", "none", LYD_NEW_VAL_STORE_ONLY, NULL)); } } /* add subtree operation */ - LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:operation", lyd_diff_op2str(op), 0, NULL)); + LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:operation", lyd_diff_op2str(op), LYD_NEW_VAL_STORE_ONLY, NULL)); if (op == LYD_DIFF_OP_CREATE) { /* all nested user-ordered (leaf-)lists need special metadata for create op */ @@ -443,37 +443,37 @@ lyd_diff_add(const struct lyd_node *node, enum lyd_diff_op op, const char *orig_ /* orig-default */ if (orig_default) { - LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-default", orig_default, 0, NULL)); + LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-default", orig_default, LYD_NEW_VAL_STORE_ONLY, NULL)); } /* orig-value */ if (orig_value) { - LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-value", orig_value, 0, NULL)); + LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-value", orig_value, LYD_NEW_VAL_STORE_ONLY, NULL)); } /* key */ if (key) { - LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:key", key, 0, NULL)); + LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:key", key, LYD_NEW_VAL_STORE_ONLY, NULL)); } /* value */ if (value) { - LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:value", value, 0, NULL)); + LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:value", value, LYD_NEW_VAL_STORE_ONLY, NULL)); } /* position */ if (position) { - LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:position", position, 0, NULL)); + LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:position", position, LYD_NEW_VAL_STORE_ONLY, NULL)); } /* orig-key */ if (orig_key) { - LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-key", orig_key, 0, NULL)); + LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-key", orig_key, LYD_NEW_VAL_STORE_ONLY, NULL)); } /* orig-position */ if (orig_position) { - LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-position", orig_position, 0, NULL)); + LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-position", orig_position, LYD_NEW_VAL_STORE_ONLY, NULL)); } return LY_SUCCESS; @@ -1460,7 +1460,7 @@ lyd_diff_change_op(struct lyd_node *node, enum lyd_diff_op op) lyd_diff_del_meta(node, "operation"); if (node->schema) { - return lyd_new_meta(LYD_CTX(node), node, NULL, "yang:operation", lyd_diff_op2str(op), 0, NULL); + return lyd_new_meta(LYD_CTX(node), node, NULL, "yang:operation", lyd_diff_op2str(op), LYD_NEW_VAL_STORE_ONLY, NULL); } else { return lyd_new_attr(node, "yang", "operation", lyd_diff_op2str(op), NULL); } @@ -1685,7 +1685,7 @@ lyd_diff_merge_create(struct lyd_node **diff_match, struct lyd_node **diff, enum /* current value is the previous one (meta) */ LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), *diff_match, NULL, "yang:orig-value", - lyd_get_value(*diff_match), 0, NULL)); + lyd_get_value(*diff_match), LYD_NEW_VAL_STORE_ONLY, NULL)); /* update the value itself */ LY_CHECK_RET(lyd_change_term(*diff_match, lyd_get_value(src_diff))); @@ -1699,10 +1699,10 @@ lyd_diff_merge_create(struct lyd_node **diff_match, struct lyd_node **diff, enum to_free = *diff_match; *diff_match = src_dup; - r = lyd_new_meta(ctx, src_dup, NULL, "yang:orig-value", lyd_get_value(to_free), 0, NULL); + r = lyd_new_meta(ctx, src_dup, NULL, "yang:orig-value", lyd_get_value(to_free), LYD_NEW_VAL_STORE_ONLY, NULL); lyd_free_tree(to_free); LY_CHECK_RET(r); - LY_CHECK_RET(lyd_new_meta(ctx, src_dup, NULL, "yang:operation", lyd_diff_op2str(LYD_DIFF_OP_REPLACE), 0, NULL)); + LY_CHECK_RET(lyd_new_meta(ctx, src_dup, NULL, "yang:operation", lyd_diff_op2str(LYD_DIFF_OP_REPLACE), LYD_NEW_VAL_STORE_ONLY, NULL)); } } else { /* deleted + created -> operation NONE */ @@ -1713,7 +1713,7 @@ lyd_diff_merge_create(struct lyd_node **diff_match, struct lyd_node **diff, enum if ((*diff_match)->schema->nodetype & LYD_NODE_TERM) { /* add orig-dflt metadata */ LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), *diff_match, NULL, "yang:orig-default", - trg_flags & LYD_DEFAULT ? "true" : "false", 0, NULL)); + trg_flags & LYD_DEFAULT ? "true" : "false", LYD_NEW_VAL_STORE_ONLY, NULL)); /* update dflt flag itself */ (*diff_match)->flags &= ~LYD_DEFAULT; @@ -1763,7 +1763,7 @@ lyd_diff_merge_delete(struct lyd_node *diff_match, enum lyd_diff_op cur_op, cons if (diff_match->schema->nodetype & LYD_NODE_TERM) { /* add orig-default meta because it is expected */ LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), diff_match, NULL, "yang:orig-default", - src_diff->flags & LYD_DEFAULT ? "true" : "false", 0, NULL)); + src_diff->flags & LYD_DEFAULT ? "true" : "false", LYD_NEW_VAL_STORE_ONLY, NULL)); } break; case LYD_DIFF_OP_REPLACE: diff --git a/src/parser_common.c b/src/parser_common.c index dadd1d7ad..06544f16c 100644 --- a/src/parser_common.c +++ b/src/parser_common.c @@ -284,8 +284,10 @@ lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *schema, c { LY_ERR r; ly_bool incomplete; + ly_bool store_only = (lydctx->parse_opts & LYD_PARSE_STORE_ONLY) ? 1 : 0; - if ((r = lyd_create_term(schema, value, value_len, 1, dynamic, format, prefix_data, hints, &incomplete, node))) { + if ((r = lyd_create_term(schema, value, value_len, 1, store_only, dynamic, format, prefix_data, + hints, &incomplete, node))) { if (lydctx->data_ctx->ctx != schema->module->ctx) { /* move errors to the main context */ ly_err_move(schema->module->ctx, (struct ly_ctx *)lydctx->data_ctx->ctx); @@ -308,6 +310,7 @@ lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct l char *dpath = NULL, *path = NULL; ly_bool incomplete; struct lyd_meta *first = NULL; + ly_bool store_only = (lydctx->parse_opts & LYD_PARSE_STORE_ONLY) ? 1 : 0; if (meta && *meta) { /* remember the first metadata */ @@ -323,7 +326,7 @@ lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct l } ly_log_location(NULL, NULL, path, NULL); - LY_CHECK_GOTO(rc = lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, 1, dynamic, format, + LY_CHECK_GOTO(rc = lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, 1, store_only, dynamic, format, prefix_data, hints, ctx_node, 0, &incomplete), cleanup); if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) { diff --git a/src/parser_data.h b/src/parser_data.h index 8b61633fb..e782b4759 100644 --- a/src/parser_data.h +++ b/src/parser_data.h @@ -134,6 +134,7 @@ struct ly_in; * - when statements on existing nodes are evaluated, if not satisfied, a validation error is raised, * - invalid multiple data instances/data from several cases cause a validation error, * - implicit nodes (NP containers and default values) are added. + * - Validations based on leaf/leaf-list types restriction is being done regardless of setting LYD_PARSE_ONLY * @{ */ /* note: keep the lower 16bits free for use by LYD_VALIDATE_ flags. They are not supposed to be combined together, @@ -171,6 +172,8 @@ struct ly_in; #define LYD_PARSE_NO_NEW 0x1000000 /**< Do not set ::LYD_NEW (non-validated node flag) for any nodes. Use when parsing validated data to skip some validation tasks and modify some validation behavior (auto-deletion of cases). */ +#define LYD_PARSE_STORE_ONLY 0x2000000 /**< Perform only storing operation, no validation based on leaf/leaf-list type + restrictions will be performed. */ #define LYD_PARSE_OPTS_MASK 0xFFFF0000 /**< Mask for all the LYD_PARSE_ options. */ diff --git a/src/path.c b/src/path.c index 2214ed0a0..5fd33e6e2 100644 --- a/src/path.c +++ b/src/path.c @@ -710,8 +710,8 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_ if (key) { LOG_LOCSET(key, NULL); } - ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, 0, NULL, - format, prefix_data, LYD_HINT_DATA, key, NULL); + ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, 0, 0, + NULL, format, prefix_data, LYD_HINT_DATA, key, NULL); LOG_LOCBACK(key ? 1 : 0, 0); LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup); @@ -776,8 +776,8 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_ if (ctx_node) { LOG_LOCSET(ctx_node, NULL); } - ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, 0, NULL, - format, prefix_data, LYD_HINT_DATA, ctx_node, NULL); + ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, 0, 0, + NULL, format, prefix_data, LYD_HINT_DATA, ctx_node, NULL); LOG_LOCBACK(ctx_node ? 1 : 0, 0); LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup); ++(*tok_idx); @@ -1356,7 +1356,7 @@ ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, c case LY_PATH_PREDTYPE_LIST_VAR: case LY_PATH_PREDTYPE_LIST: /* we will use hashes to find one list instance */ - LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, &target)); + LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, 1, &target)); lyd_find_sibling_first(start, target, &node); lyd_free_tree(target); break; diff --git a/src/plugins.c b/src/plugins.c index c1bdad5e0..1f7604906 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -444,7 +444,7 @@ plugins_insert_dir(enum LYPLG type) #endif LY_ERR -lyplg_init(void) +lyplg_init(ly_bool builtin_plugins_only) { LY_ERR ret; @@ -470,34 +470,36 @@ lyplg_init(void) LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error); LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error); - /* yang */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error); - - /* ietf-inet-types */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error); - - /* ietf-yang-types */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error); - - /* ietf-netconf-acm */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error); - - /* lyds_tree */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_lyds_tree), error); - - /* internal extensions */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error); + if (!builtin_plugins_only) { + /* yang */ + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error); + + /* ietf-inet-types */ + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error); + + /* ietf-yang-types */ + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error); + + /* ietf-netconf-acm */ + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error); + + /* lyds_tree */ + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_lyds_tree), error); + + /* internal extensions */ + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error); + LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error); + } #ifndef STATIC /* external types */ diff --git a/src/plugins_internal.h b/src/plugins_internal.h index d13db1647..f624624c3 100644 --- a/src/plugins_internal.h +++ b/src/plugins_internal.h @@ -48,11 +48,12 @@ * * Covers both the types and extensions plugins. * + * @param[in] builtin_plugins_only Whether to load only built-in YANG plugin types and extensions. * @return LY_SUCCESS in case of success * @return LY_EINT in case of internal error * @return LY_EMEM in case of memory allocation failure. */ -LY_ERR lyplg_init(void); +LY_ERR lyplg_init(ly_bool builtin_plugins_only); /** * @brief Remove (unload) all the plugins currently available. diff --git a/src/plugins_types.h b/src/plugins_types.h index 4b8b1b9e8..184393c13 100644 --- a/src/plugins_types.h +++ b/src/plugins_types.h @@ -475,6 +475,7 @@ LIBYANG_API_DECL LY_ERR lyplg_type_print_xpath10_value(const struct lyd_value_xp #define LYPLG_TYPE_STORE_IMPLEMENT 0x02 /**< If a foreign module is needed to be implemented to successfully instantiate the value, make the module implemented. */ #define LYPLG_TYPE_STORE_IS_UTF8 0x04 /**< The value is guaranteed to be a valid UTF-8 string, if applicable for the type. */ +#define LYPLG_TYPE_STORE_ONLY 0x08 /**< The value is stored only. The validation must be done using [validate](@ref lyplg_type_validate_clb) */ /** @} plugintypestoreopts */ /** diff --git a/src/plugins_types/binary.c b/src/plugins_types/binary.c index a80114465..c2655119d 100644 --- a/src/plugins_types/binary.c +++ b/src/plugins_types/binary.c @@ -42,6 +42,8 @@ */ static const char b64_etable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static LY_ERR lyplg_type_validate_binary(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err); + /** * @brief Encode binary value into a base64 string value. * @@ -165,12 +167,11 @@ binary_base64_decode(const char *value, size_t value_len, void **data, size_t *s * * @param[in] value Value to validate. * @param[in] value_len Length of @p value. - * @param[in] type type of the value. * @param[out] err Error information. * @return LY_ERR value. */ static LY_ERR -binary_base64_validate(const char *value, size_t value_len, const struct lysc_type_bin *type, struct ly_err_item **err) +binary_base64_validate(const char *value, size_t value_len, struct ly_err_item **err) { uint32_t idx, pad; @@ -204,13 +205,6 @@ binary_base64_validate(const char *value, size_t value_len, const struct lysc_ty return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Base64 encoded value length must be divisible by 4."); } - /* length restriction of the binary value */ - if (type->length) { - const uint32_t octet_count = ((idx + pad) / 4) * 3 - pad; - - LY_CHECK_RET(lyplg_type_validate_range(LY_TYPE_BINARY, type->length, octet_count, value, value_len, err)); - } - return LY_SUCCESS; } @@ -266,7 +260,6 @@ lyplg_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type, struct ly_err_item **err) { LY_ERR ret = LY_SUCCESS; - struct lysc_type_bin *type_bin = (struct lysc_type_bin *)type; struct lyd_value_binary *val; /* init storage */ @@ -306,7 +299,7 @@ lyplg_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type, LY_CHECK_GOTO(ret, cleanup); /* validate */ - ret = binary_base64_validate(value, value_len, type_bin, err); + ret = binary_base64_validate(value, value_len, err); LY_CHECK_GOTO(ret, cleanup); } @@ -324,6 +317,12 @@ lyplg_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type, LY_CHECK_GOTO(ret, cleanup); } + if (!(options & LYPLG_TYPE_STORE_ONLY)) { + /* validate value */ + ret = lyplg_type_validate_binary(ctx, type, NULL, NULL, storage, err); + LY_CHECK_GOTO(ret, cleanup); + } + cleanup: if (options & LYPLG_TYPE_STORE_DYNAMIC) { free((void *)value); @@ -335,6 +334,33 @@ lyplg_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type, return ret; } +/** + * @brief Implementation of ::lyplg_type_validate_clb for the binary type. + */ +static LY_ERR +lyplg_type_validate_binary(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), + const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err) +{ + struct lysc_type_bin *type_bin = (struct lysc_type_bin *)type; + struct lyd_value_binary *val; + const void *value; + size_t value_len; + + LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL); + + val = LYPLG_TYPE_VAL_IS_DYN(val) ? (struct lyd_value_binary *)(storage->dyn_mem) : (struct lyd_value_binary *)(storage->fixed_mem); + value = storage->_canonical; + value_len = strlen(storage->_canonical); + *err = NULL; + + /* length restriction of the binary value */ + if (type_bin->length) { + LY_CHECK_RET(lyplg_type_validate_range(LY_TYPE_BINARY, type_bin->length, val->size, value, value_len, err)); + } + + return LY_SUCCESS; +} + LIBYANG_API_DEF LY_ERR lyplg_type_compare_binary(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2) { @@ -470,7 +496,7 @@ const struct lyplg_type_record plugins_binary[] = { .plugin.id = "libyang 2 - binary, version 1", .plugin.store = lyplg_type_store_binary, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_binary, .plugin.compare = lyplg_type_compare_binary, .plugin.sort = lyplg_type_sort_binary, .plugin.print = lyplg_type_print_binary, diff --git a/src/plugins_types/decimal64.c b/src/plugins_types/decimal64.c index 9edc968e9..0eb01a04f 100644 --- a/src/plugins_types/decimal64.c +++ b/src/plugins_types/decimal64.c @@ -33,6 +33,8 @@ * | 8 | yes | `int64_t *` | little-endian value represented without floating point | */ +static LY_ERR lyplg_type_validate_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err); + /** * @brief Convert decimal64 number to canonical string. * @@ -140,10 +142,9 @@ lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *typ LY_CHECK_GOTO(ret, cleanup); } - if (type_dec->range) { - /* check range of the number */ - ret = lyplg_type_validate_range(type->basetype, type_dec->range, num, storage->_canonical, - strlen(storage->_canonical), err); + if (!(options & LYPLG_TYPE_STORE_ONLY)) { + /* validate value */ + ret = lyplg_type_validate_decimal64(ctx, type, NULL, NULL, storage, err); LY_CHECK_GOTO(ret, cleanup); } @@ -158,6 +159,31 @@ lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *typ return ret; } +/** + * @brief Implementation of ::lyplg_type_validate_clb for the built-in decimal64 type. + */ +static LY_ERR +lyplg_type_validate_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), + const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err) +{ + LY_ERR ret; + struct lysc_type_dec *type_dec = (struct lysc_type_dec *)type; + int64_t num; + + LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL); + *err = NULL; + num = storage->dec64; + + if (type_dec->range) { + /* check range of the number */ + ret = lyplg_type_validate_range(type->basetype, type_dec->range, num, storage->_canonical, + strlen(storage->_canonical), err); + LY_CHECK_RET(ret); + } + + return LY_SUCCESS; +} + LIBYANG_API_DEF LY_ERR lyplg_type_compare_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2) @@ -236,7 +262,7 @@ const struct lyplg_type_record plugins_decimal64[] = { .plugin.id = "libyang 2 - decimal64, version 1", .plugin.store = lyplg_type_store_decimal64, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_decimal64, .plugin.compare = lyplg_type_compare_decimal64, .plugin.sort = lyplg_type_sort_decimal64, .plugin.print = lyplg_type_print_decimal64, diff --git a/src/plugins_types/integer.c b/src/plugins_types/integer.c index 73c4533b1..eb6649938 100644 --- a/src/plugins_types/integer.c +++ b/src/plugins_types/integer.c @@ -36,6 +36,9 @@ * | 1/2/4/8 | yes | pointer to the specific integer type | little-endian integer value | */ +static LY_ERR lyplg_type_validate_int(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err); +static LY_ERR lyplg_type_validate_uint(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err); + /** * @brief LYB value size of each integer type. */ @@ -54,7 +57,6 @@ lyplg_type_store_int(const struct ly_ctx *ctx, const struct lysc_type *type, con int64_t num = 0; int base = 1; char *canon = NULL; - struct lysc_type_num *type_num = (struct lysc_type_num *)type; /* init storage */ memset(storage, 0, sizeof *storage); @@ -154,10 +156,9 @@ lyplg_type_store_int(const struct ly_ctx *ctx, const struct lysc_type *type, con LY_CHECK_GOTO(ret, cleanup); } - /* validate range of the number */ - if (type_num->range) { - ret = lyplg_type_validate_range(type->basetype, type_num->range, num, storage->_canonical, - strlen(storage->_canonical), err); + if (!(options & LYPLG_TYPE_STORE_ONLY)) { + /* validate value */ + ret = lyplg_type_validate_int(ctx, type, NULL, NULL, storage, err); LY_CHECK_GOTO(ret, cleanup); } @@ -172,6 +173,48 @@ lyplg_type_store_int(const struct ly_ctx *ctx, const struct lysc_type *type, con return ret; } +/** + * @brief Implementation of ::lyplg_type_validate_clb for the signed interger types. + */ +static LY_ERR +lyplg_type_validate_int(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), + const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err) +{ + LY_ERR ret; + struct lysc_type_num *type_num = (struct lysc_type_num *)type; + int64_t num; + + LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL); + *err = NULL; + + /* set the value (matters for big-endian) and get the correct int64 number */ + switch (type->basetype) { + case LY_TYPE_INT8: + num = storage->int8; + break; + case LY_TYPE_INT16: + num = storage->int16; + break; + case LY_TYPE_INT32: + num = storage->int32; + break; + case LY_TYPE_INT64: + num = storage->int64; + break; + default: + return LY_EINVAL; + } + + /* validate range of the number */ + if (type_num->range) { + ret = lyplg_type_validate_range(type->basetype, type_num->range, num, storage->_canonical, + strlen(storage->_canonical), err); + LY_CHECK_RET(ret); + } + + return LY_SUCCESS; +} + LIBYANG_API_DEF LY_ERR lyplg_type_compare_int(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2) { @@ -318,7 +361,6 @@ lyplg_type_store_uint(const struct ly_ctx *ctx, const struct lysc_type *type, co uint64_t num = 0; int base = 0; char *canon; - struct lysc_type_num *type_num = (struct lysc_type_num *)type; /* init storage */ memset(storage, 0, sizeof *storage); @@ -398,10 +440,9 @@ lyplg_type_store_uint(const struct ly_ctx *ctx, const struct lysc_type *type, co LY_CHECK_GOTO(ret, cleanup); } - /* validate range of the number */ - if (type_num->range) { - ret = lyplg_type_validate_range(type->basetype, type_num->range, num, storage->_canonical, - strlen(storage->_canonical), err); + if (!(options & LYPLG_TYPE_STORE_ONLY)) { + /* validate value */ + ret = lyplg_type_validate_uint(ctx, type, NULL, NULL, storage, err); LY_CHECK_GOTO(ret, cleanup); } @@ -416,6 +457,48 @@ lyplg_type_store_uint(const struct ly_ctx *ctx, const struct lysc_type *type, co return ret; } +/** + * @brief Implementation of ::lyplg_type_validate_clb for the unsigned interger types. + */ +static LY_ERR +lyplg_type_validate_uint(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), + const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err) +{ + LY_ERR ret; + struct lysc_type_num *type_num = (struct lysc_type_num *)type; + uint64_t num; + + LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL); + *err = NULL; + + /* set the value (matters for big-endian) and get the correct int64 number */ + switch (type->basetype) { + case LY_TYPE_UINT8: + num = storage->uint8; + break; + case LY_TYPE_UINT16: + num = storage->uint16; + break; + case LY_TYPE_UINT32: + num = storage->uint32; + break; + case LY_TYPE_UINT64: + num = storage->uint64; + break; + default: + return LY_EINVAL; + } + + /* validate range of the number */ + if (type_num->range) { + ret = lyplg_type_validate_range(type->basetype, type_num->range, num, storage->_canonical, + strlen(storage->_canonical), err); + LY_CHECK_RET(ret); + } + + return LY_SUCCESS; +} + LIBYANG_API_DEF LY_ERR lyplg_type_compare_uint(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2) { @@ -563,7 +646,7 @@ const struct lyplg_type_record plugins_integer[] = { .plugin.id = "libyang 2 - integers, version 1", .plugin.store = lyplg_type_store_uint, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_uint, .plugin.compare = lyplg_type_compare_uint, .plugin.sort = lyplg_type_sort_uint, .plugin.print = lyplg_type_print_uint, @@ -577,7 +660,7 @@ const struct lyplg_type_record plugins_integer[] = { .plugin.id = "libyang 2 - integers, version 1", .plugin.store = lyplg_type_store_uint, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_uint, .plugin.compare = lyplg_type_compare_uint, .plugin.sort = lyplg_type_sort_uint, .plugin.print = lyplg_type_print_uint, @@ -591,7 +674,7 @@ const struct lyplg_type_record plugins_integer[] = { .plugin.id = "libyang 2 - integers, version 1", .plugin.store = lyplg_type_store_uint, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_uint, .plugin.compare = lyplg_type_compare_uint, .plugin.sort = lyplg_type_sort_uint, .plugin.print = lyplg_type_print_uint, @@ -605,7 +688,7 @@ const struct lyplg_type_record plugins_integer[] = { .plugin.id = "libyang 2 - integers, version 1", .plugin.store = lyplg_type_store_uint, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_uint, .plugin.compare = lyplg_type_compare_uint, .plugin.sort = lyplg_type_sort_uint, .plugin.print = lyplg_type_print_uint, @@ -619,7 +702,7 @@ const struct lyplg_type_record plugins_integer[] = { .plugin.id = "libyang 2 - integers, version 1", .plugin.store = lyplg_type_store_int, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_int, .plugin.compare = lyplg_type_compare_int, .plugin.sort = lyplg_type_sort_int, .plugin.print = lyplg_type_print_int, @@ -633,7 +716,7 @@ const struct lyplg_type_record plugins_integer[] = { .plugin.id = "libyang 2 - integers, version 1", .plugin.store = lyplg_type_store_int, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_int, .plugin.compare = lyplg_type_compare_int, .plugin.sort = lyplg_type_sort_int, .plugin.print = lyplg_type_print_int, @@ -647,7 +730,7 @@ const struct lyplg_type_record plugins_integer[] = { .plugin.id = "libyang 2 - integers, version 1", .plugin.store = lyplg_type_store_int, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_int, .plugin.compare = lyplg_type_compare_int, .plugin.sort = lyplg_type_sort_int, .plugin.print = lyplg_type_print_int, @@ -661,7 +744,7 @@ const struct lyplg_type_record plugins_integer[] = { .plugin.id = "libyang 2 - integers, version 1", .plugin.store = lyplg_type_store_int, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_int, .plugin.compare = lyplg_type_compare_int, .plugin.sort = lyplg_type_sort_int, .plugin.print = lyplg_type_print_int, diff --git a/src/plugins_types/string.c b/src/plugins_types/string.c index 5ae52049f..e4c1cb986 100644 --- a/src/plugins_types/string.c +++ b/src/plugins_types/string.c @@ -34,6 +34,8 @@ * | string length | yes | `char *` | string itself | */ +static LY_ERR lyplg_type_validate_string(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err); + /** * @brief Check string value for invalid characters. * @@ -64,7 +66,6 @@ lyplg_type_store_string(const struct ly_ctx *ctx, const struct lysc_type *type, struct ly_err_item **err) { LY_ERR ret = LY_SUCCESS; - struct lysc_type_str *type_str = (struct lysc_type_str *)type; /* init storage */ memset(storage, 0, sizeof *storage); @@ -80,17 +81,6 @@ lyplg_type_store_string(const struct ly_ctx *ctx, const struct lysc_type *type, ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err); LY_CHECK_GOTO(ret, cleanup); - /* length restriction of the string */ - if (type_str->length) { - /* value_len is in bytes, but we need number of characters here */ - ret = lyplg_type_validate_range(LY_TYPE_STRING, type_str->length, ly_utf8len(value, value_len), value, value_len, err); - LY_CHECK_GOTO(ret, cleanup); - } - - /* pattern restrictions */ - ret = lyplg_type_validate_patterns(type_str->patterns, value, value_len, err); - LY_CHECK_GOTO(ret, cleanup); - /* store canonical value */ if (options & LYPLG_TYPE_STORE_DYNAMIC) { ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical); @@ -101,6 +91,12 @@ lyplg_type_store_string(const struct ly_ctx *ctx, const struct lysc_type *type, LY_CHECK_GOTO(ret, cleanup); } + if (!(options & LYPLG_TYPE_STORE_ONLY)) { + /* validate value */ + ret = lyplg_type_validate_string(ctx, type, NULL, NULL, storage, err); + LY_CHECK_GOTO(ret, cleanup); + } + cleanup: if (options & LYPLG_TYPE_STORE_DYNAMIC) { free((void *)value); @@ -112,6 +108,37 @@ lyplg_type_store_string(const struct ly_ctx *ctx, const struct lysc_type *type, return ret; } +/** + * @brief Implementation of ::lyplg_type_validate_clb for the string type. + */ +static LY_ERR +lyplg_type_validate_string(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), + const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err) +{ + LY_ERR ret; + struct lysc_type_str *type_str = (struct lysc_type_str *)type; + const void *value; + size_t value_len; + + LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL); + value = storage->_canonical; + value_len = strlen(storage->_canonical); + *err = NULL; + + /* length restriction of the string */ + if (type_str->length) { + /* value_len is in bytes, but we need number of characters here */ + ret = lyplg_type_validate_range(LY_TYPE_STRING, type_str->length, ly_utf8len(value, value_len), value, value_len, err); + LY_CHECK_RET(ret); + } + + /* pattern restrictions */ + ret = lyplg_type_validate_patterns(type_str->patterns, value, value_len, err); + LY_CHECK_RET(ret); + + return LY_SUCCESS; +} + /** * @brief Plugin information for string type implementation. * @@ -127,7 +154,7 @@ const struct lyplg_type_record plugins_string[] = { .plugin.id = "libyang 2 - string, version 1", .plugin.store = lyplg_type_store_string, - .plugin.validate = NULL, + .plugin.validate = lyplg_type_validate_string, .plugin.compare = lyplg_type_compare_simple, .plugin.sort = lyplg_type_sort_simple, .plugin.print = lyplg_type_print_simple, diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c index 32c682c89..8dbc68bbf 100644 --- a/src/plugins_types/union.c +++ b/src/plugins_types/union.c @@ -156,6 +156,7 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c * @param[in] ctx libyang context. * @param[in] type Specific union type to use for storing. * @param[in] subvalue Union subvalue structure. + * @param[in] options The store options. * @param[in] resolve Whether the value needs to be resolved (validated by a callback). * @param[in] ctx_node Context node for prefix resolution. * @param[in] tree Data tree for resolving (validation). @@ -164,13 +165,14 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c * @return LY_ERR value. */ static LY_ERR -union_store_type(const struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value_union *subvalue, +union_store_type(const struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value_union *subvalue, uint32_t options, ly_bool resolve, const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lys_glob_unres *unres, struct ly_err_item **err) { LY_ERR ret; const void *value = NULL; size_t value_len = 0; + uint32_t opts; *err = NULL; @@ -181,7 +183,8 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type *type, struct lyd_va value_len = subvalue->orig_len; } - ret = type->plugin->store(ctx, type, value, value_len, 0, subvalue->format, subvalue->prefix_data, subvalue->hints, + opts = (options & LYPLG_TYPE_STORE_ONLY) ? LYPLG_TYPE_STORE_ONLY : 0; + ret = type->plugin->store(ctx, type, value, value_len, opts, subvalue->format, subvalue->prefix_data, subvalue->hints, subvalue->ctx_node, &subvalue->value, unres, err); if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) { /* clear any leftover/freed garbage */ @@ -207,6 +210,7 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type *type, struct lyd_va * @param[in] ctx libyang context. * @param[in] types Sized array of union types. * @param[in] subvalue Union subvalue structure. + * @param[in] options The store options. * @param[in] resolve Whether the value needs to be resolved (validated by a callback). * @param[in] ctx_node Context node for prefix resolution. * @param[in] tree Data tree for resolving (validation). @@ -217,8 +221,8 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type *type, struct lyd_va */ static LY_ERR union_find_type(const struct ly_ctx *ctx, struct lysc_type **types, struct lyd_value_union *subvalue, - ly_bool resolve, const struct lyd_node *ctx_node, const struct lyd_node *tree, uint32_t *type_idx, - struct lys_glob_unres *unres, struct ly_err_item **err) + uint32_t options, ly_bool resolve, const struct lyd_node *ctx_node, const struct lyd_node *tree, + uint32_t *type_idx, struct lys_glob_unres *unres, struct ly_err_item **err) { LY_ERR ret = LY_SUCCESS; LY_ARRAY_COUNT_TYPE u; @@ -242,7 +246,7 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type **types, struct lyd_v /* use the first usable subtype to store the value */ for (u = 0; u < LY_ARRAY_COUNT(types); ++u) { - ret = union_store_type(ctx, types[u], subvalue, resolve, ctx_node, tree, unres, &e); + ret = union_store_type(ctx, types[u], subvalue, options, resolve, ctx_node, tree, unres, &e); if ((ret == LY_SUCCESS) || (ret == LY_EINCOMPLETE)) { break; } @@ -330,7 +334,7 @@ lyb_fill_subvalue(const struct ly_ctx *ctx, struct lysc_type_union *type_u, cons } /* use the specific type to store the value */ - ret = union_store_type(ctx, type_u->types[type_idx], subvalue, 0, NULL, NULL, unres, err); + ret = union_store_type(ctx, type_u->types[type_idx], subvalue, *options, 0, NULL, NULL, unres, err); return ret; } @@ -368,7 +372,7 @@ lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, c LY_CHECK_GOTO(ret, cleanup); /* use the first usable subtype to store the value */ - ret = union_find_type(ctx, type_u->types, subvalue, 0, NULL, NULL, NULL, unres, err); + ret = union_find_type(ctx, type_u->types, subvalue, options, 0, NULL, NULL, NULL, unres, err); LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup); } @@ -406,11 +410,11 @@ lyplg_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type if (subvalue->format == LY_VALUE_LYB) { /* use the specific type to store the value */ lyb_parse_union(subvalue->original, 0, &type_idx, NULL, NULL); - ret = union_store_type(ctx, type_u->types[type_idx], subvalue, 1, ctx_node, tree, NULL, err); + ret = union_store_type(ctx, type_u->types[type_idx], subvalue, 0, 1, ctx_node, tree, NULL, err); LY_CHECK_RET(ret); } else { /* use the first usable subtype to store the value */ - ret = union_find_type(ctx, type_u->types, subvalue, 1, ctx_node, tree, NULL, NULL, err); + ret = union_find_type(ctx, type_u->types, subvalue, 0, 1, ctx_node, tree, NULL, NULL, err); LY_CHECK_RET(ret); } @@ -491,7 +495,7 @@ lyb_union_print(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct ctx = subvalue->ctx_node->module->ctx; } subvalue->value.realtype->plugin->free(ctx, &subvalue->value); - r = union_find_type(ctx, type_u->types, subvalue, 0, NULL, NULL, &type_idx, NULL, &err); + r = union_find_type(ctx, type_u->types, subvalue, 0, 0, NULL, NULL, &type_idx, NULL, &err); ly_err_free(err); LY_CHECK_RET((r != LY_SUCCESS) && (r != LY_EINCOMPLETE), NULL); diff --git a/src/tree_data.c b/src/tree_data.c index a5f27a3b2..a9146d48b 100644 --- a/src/tree_data.c +++ b/src/tree_data.c @@ -1344,8 +1344,9 @@ lyd_get_meta_annotation(const struct lys_module *mod, const char *name, size_t n LY_ERR lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name, - size_t name_len, const char *value, size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format, - void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt, ly_bool *incomplete) + size_t name_len, 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, const struct lysc_node *ctx_node, ly_bool clear_dflt, + ly_bool *incomplete) { LY_ERR ret = LY_SUCCESS; struct lysc_ext_instance *ant = NULL; @@ -1368,7 +1369,7 @@ lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct ly mt->parent = parent; mt->annotation = ant; lyplg_ext_get_storage(ant, LY_STMT_TYPE, sizeof ant_type, (const void **)&ant_type); - ret = lyd_value_store(mod->ctx, &mt->value, ant_type, value, value_len, is_utf8, dynamic, format, prefix_data, hints, + ret = lyd_value_store(mod->ctx, &mt->value, ant_type, value, value_len, is_utf8, store_only, dynamic, format, prefix_data, hints, ctx_node, incomplete); LY_CHECK_ERR_GOTO(ret, free(mt), cleanup); ret = lydict_insert(mod->ctx, name, name_len, &mt->name); @@ -2138,7 +2139,7 @@ lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_ /* store canonical value in the target context */ val_can = lyd_get_value(node); type = ((struct lysc_node_leaf *)term->schema)->type; - ret = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), 1, NULL, LY_VALUE_CANON, NULL, + ret = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), 1, 1, NULL, LY_VALUE_CANON, NULL, LYD_HINT_DATA, term->schema, NULL); LY_CHECK_GOTO(ret, error); } @@ -2467,7 +2468,7 @@ lyd_dup_meta_single_to_ctx(const struct ly_ctx *parent_ctx, const struct lyd_met /* duplicate callback expect only the same contexts, so use the store callback */ val_can = lyd_value_get_canonical(meta->annotation->module->ctx, &meta->value); - ret = lyd_value_store(parent_ctx, &mt->value, ant_type, val_can, strlen(val_can), 1, NULL, + ret = lyd_value_store(parent_ctx, &mt->value, ant_type, val_can, strlen(val_can), 1, 1, NULL, LY_VALUE_CANON, NULL, LYD_HINT_DATA, parent->schema, NULL); } else { /* annotation */ @@ -3201,11 +3202,11 @@ lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *sc /* create a data node and find the instance */ if (schema->nodetype == LYS_LEAFLIST) { /* target used attributes: schema, hash, value */ - rc = lyd_create_term(schema, key_or_value, val_len, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, NULL, &target); + rc = lyd_create_term(schema, key_or_value, val_len, 0, 1, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, NULL, &target); LY_CHECK_RET(rc); } else { /* target used attributes: schema, hash, child (all keys) */ - LY_CHECK_RET(lyd_create_list2(schema, key_or_value, val_len, &target)); + LY_CHECK_RET(lyd_create_list2(schema, key_or_value, val_len, 1, &target)); } /* find it */ diff --git a/src/tree_data.h b/src/tree_data.h index a7ce4bf3c..9084f8e5c 100644 --- a/src/tree_data.h +++ b/src/tree_data.h @@ -282,11 +282,10 @@ struct rb_node; * - ::lyd_new_inner() * - ::lyd_new_term() * - ::lyd_new_term_bin() - * - ::lyd_new_term_canon() * - ::lyd_new_list() - * - ::lyd_new_list_bin() - * - ::lyd_new_list_canon() * - ::lyd_new_list2() + * - ::lyd_new_list3() + * - ::lyd_new_list3_bin() * - ::lyd_new_any() * - ::lyd_new_opaq() * - ::lyd_new_opaq2() @@ -1248,37 +1247,44 @@ LIBYANG_API_DECL LY_ERR lyd_new_inner(struct lyd_node *parent, const struct lys_ LIBYANG_API_DECL LY_ERR lyd_new_ext_inner(const struct lysc_ext_instance *ext, const char *name, struct lyd_node **node); /** - * @brief Create a new list node in the data tree. + * @ingroup datatree + * @defgroup newvalueoptions New value creation options * - * @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[out] node Optional created node. - * @param[in] ... Ordered key values of the new list instance, all must be set. In case of an instance-identifier - * or identityref value, the JSON format is expected (module names instead of prefixes). No keys are expected for - * key-less lists. - * @return LY_ERR value. - */ -LIBYANG_API_DECL LY_ERR lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, - ly_bool output, struct lyd_node **node, ...); - -/** - * @brief Create a new list node in the data tree. + * Various options to change lyd_new_*() behavior. The LYD_NEW_VAL* can be used within any API, others + * are API specific * - * @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[out] node Optional created node. - * @param[in] ... Ordered binary key values of the new list instance, all must be set. Every key value must be followed - * by its length. No keys are expected for key-less lists. - * @return LY_ERR value. + * Default behavior: + * - the input data nodes or RPC/Action is taken into account + * - the value is being validated with all possible validations, which doesn't require existence of any other data nodes + * - the input value is expected to be in JSON format + * - if the target node already exists (and is not default), an error is returned. + * - the whole path to the target node is created (with any missing parents) if necessary. + * - RPC output schema children are completely ignored in all modules. Input is searched and nodes created normally. + * - during creation of new metadata, the nodes will have default flag set + * - value is copied and stored internally during any node creation + * @{ */ -LIBYANG_API_DECL 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, ...); + +#define LYD_NEW_VAL_OUTPUT 0x01 /**< 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. */ +#define LYD_NEW_VAL_STORE_ONLY 0x02 /**< Whether to perform only storing operation with no or minimum valitions */ +#define LYD_NEW_VAL_BIN_VALUE 0x04 /**< Interpret the provided leaf/leaf-list @p value as being in the binary + ::LY_VALUE_LYB format, to learn what exactly is expected see @ref howtoDataLYB. */ +#define LYD_NEW_VAL_CANON_VALUE 0x08 /**< Interpret the provided leaf/leaf-list @p value as being in the canonical + (or JSON if no defined) ::LY_VALUE_CANON format. If it is not, it may lead + to unexpected behavior. */ +#define LYD_NEW_META_CLEAR_DFLT 0x10 /**< Whether to clear the default flag starting from @p parent, recursively all NP containers. */ +#define LYD_NEW_PATH_UPDATE 0x20 /**< If the target node exists, is a leaf, and it is updated with a new value or its + default flag is changed, it is returned. If the target node exists and is not + a leaf or generally no change occurs in the @p parent tree, NULL is returned and + no error set. */ +#define LYD_NEW_PATH_OPAQ 0x40 /**< Enables the creation of opaque nodes with some specific rules. If the __last node__ + in the path is not uniquely defined ((leaf-)list without a predicate) or has an + invalid value (leaf/leaf-list), it is created as opaque. */ +#define LYD_NEW_PATH_WITH_OPAQ 0x80 /**< Consider opaque nodes normally when searching for existing nodes. */ +#define LYD_NEW_ANY_USE_VALUE 0x100 /**< Whether to use dynamic @p value or make a copy. */ + +/** @} newvalueoptions */ /** * @brief Create a new list node in the data tree. @@ -1286,15 +1292,15 @@ LIBYANG_API_DECL LY_ERR lyd_new_list_bin(struct lyd_node *parent, const struct l * @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 Optional created node. - * @param[in] ... Ordered canonical key values of the new list instance, all must be set. No keys are expected for - * key-less lists. + * @param[in] ... Ordered key values of the new list instance, all must be set. In case of an instance-identifier + * or identityref value, the JSON format is expected (module names instead of prefixes). No keys are expected for key-less lists. + * In case of format set to LY_FORMAT_LYB, every key value must be followed by its length. * @return LY_ERR value. */ -LIBYANG_API_DECL 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, ...); +LIBYANG_API_DECL LY_ERR lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, + uint32_t options, struct lyd_node **node, ...); /** * @brief Create a new top-level list node defined in the given extension instance. @@ -1304,13 +1310,15 @@ LIBYANG_API_DECL LY_ERR lyd_new_list_canon(struct lyd_node *parent, const struct * * @param[in] ext Extension instance where the list node being created is defined. * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST. + * @param[in] options Bitmask of options, see @ref newvalueoptions. * @param[out] node The created node. * @param[in] ... Ordered key values of the new list instance, all must be set. In case of an instance-identifier - * or identityref value, the JSON format is expected (module names instead of prefixes). No keys are expected for - * key-less lists. + * or identityref value, the JSON format is expected (module names instead of prefixes). No keys are expected for key-less lists. + * In case of format set to LY_FORMAT_LYB, every key value must be followed by its length. * @return LY_ERR value. */ -LIBYANG_API_DECL LY_ERR lyd_new_ext_list(const struct lysc_ext_instance *ext, const char *name, struct lyd_node **node, ...); +LIBYANG_API_DECL LY_ERR lyd_new_ext_list(const struct lysc_ext_instance *ext, const char *name, uint32_t options, + struct lyd_node **node, ...); /** * @brief Create a new list node in the data tree. @@ -1321,109 +1329,77 @@ LIBYANG_API_DECL LY_ERR lyd_new_ext_list(const struct lysc_ext_instance *ext, co * @param[in] keys All key values predicate in the form of "[key1='val1'][key2='val2']...", they do not have to be ordered. * In case of an instance-identifier or identityref value, the JSON format is expected (module names instead of prefixes). * Use NULL or string of length 0 in case of key-less 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 Optional created node. * @return LY_ERR value. */ LIBYANG_API_DECL 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); + const char *keys, uint32_t options, struct lyd_node **node); /** * @brief Create a new list node in the data tree. * + * To create a term node based on binary value, use ::lyd_new_list3_bin(). + * * @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] 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] 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. */ LIBYANG_API_DECL 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); - -/** - * @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] key_values Ordered key binary (LYB) values of the new list instance, all must be set. - * @param[in] value_lengths Array of lengths of each @p 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. - * @return LY_ERR value. - */ -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); + const char **key_values, uint32_t *value_lengths, uint32_t options, struct lyd_node **node); /** - * @brief Create a new list node in the data tree. + * @brief Create a new list node in the data tree based on binary value. * * @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] key_values Ordered key canonical values of the new list instance, all must be set. + * @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] 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. */ -LIBYANG_API_DECL 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); +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, uint32_t options, struct lyd_node **node); /** * @brief Create a new term node in the data tree. * * To create a top-level term node defined in an extension instance, use ::lyd_new_ext_term(). + * To create a term node based on binary value, use ::lyd_new_term_bin(). * * @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] val_str String value of the node. If it varies based on the format, ::LY_VALUE_JSON is expected. - * @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] value The value of the node in @p format. + * @param[in] options Bitmask of options, see @ref newvalueoptions. * @param[out] node Optional created node. * @return LY_ERR value. */ LIBYANG_API_DECL 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); + const char *value, uint32_t options, struct lyd_node **node); /** - * @brief Create a new term node in the data tree. + * @brief Create a new term node in the data tree based on binary value. * * @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 Binary value of the node. To learn what exactly is expected see @ref howtoDataLYB. + * @param[in] value The value of the node in @p format. * @param[in] value_len Length 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. */ 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, ly_bool output, struct lyd_node **node); - -/** - * @brief Create a new term 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 can be #LYS_LEAF or #LYS_LEAFLIST. - * @param[in] val_str Canonical string value of the node. If it is not, it may lead to unexpected behavior. - * @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. - * @return LY_ERR value. - */ -LIBYANG_API_DECL 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); + const void *value, size_t value_len, uint32_t options, struct lyd_node **node); /** * @brief Create a new top-level term node defined in the given extension instance. @@ -1434,12 +1410,14 @@ LIBYANG_API_DECL LY_ERR lyd_new_term_canon(struct lyd_node *parent, const struct * @param[in] ext Extension instance where the term node being created is defined. * @param[in] name Schema node name of the new data node. The node can be #LYS_LEAF or #LYS_LEAFLIST. * @param[in] val_str String form of the value of the node being created. In case of an instance-identifier or identityref - * value, the JSON format is expected (module names instead of prefixes). + * @param[in] value The value of the node in @p format. In case of an instance-identifier or identityref value, + * the JSON format is expected (module names instead of prefixes). + * @param[in] options Bitmask of options, see @ref newvalueoptions. * @param[out] node The created node. * @return LY_ERR value. */ -LIBYANG_API_DECL LY_ERR lyd_new_ext_term(const struct lysc_ext_instance *ext, const char *name, const char *val_str, - struct lyd_node **node); +LIBYANG_API_DECL LY_ERR 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); /** * @brief Create a new any node in the data tree. @@ -1450,15 +1428,13 @@ LIBYANG_API_DECL LY_ERR lyd_new_ext_term(const struct lysc_ext_instance *ext, co * @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_ANYDATA or #LYS_ANYXML. * @param[in] value Value for the node. Expected type is determined by @p value_type. - * @param[in] use_value Whether to use dynamic @p value or make a copy. + * @param[in] options Bitmask of options, see @ref newvalueoptions. * @param[in] value_type Type of the provided value in @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[out] node Optional created node. * @return LY_ERR value. */ LIBYANG_API_DECL 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); + const void *value, uint32_t options, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node); /** * @brief Create a new top-level any node defined in the given extension instance. @@ -1469,13 +1445,13 @@ LIBYANG_API_DECL LY_ERR lyd_new_any(struct lyd_node *parent, const struct lys_mo * @param[in] ext Extension instance where the any node being created is defined. * @param[in] name Schema node name of the new data node. The node can be #LYS_ANYDATA or #LYS_ANYXML. * @param[in] value Value for the node. Expected type is determined by @p value_type. - * @param[in] use_value Whether to use dynamic @p value or make a copy. + * @param[in] options Bitmask of options, see @ref newvalueoptions. * @param[in] value_type Type of the provided value in @p value. * @param[out] node The created node. * @return LY_ERR value. */ LIBYANG_API_DECL LY_ERR lyd_new_ext_any(const struct lysc_ext_instance *ext, const char *name, const void *value, - ly_bool use_value, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node); + uint32_t options, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node); /** * @brief Create new metadata. @@ -1487,26 +1463,26 @@ LIBYANG_API_DECL LY_ERR lyd_new_ext_any(const struct lysc_ext_instance *ext, con * If the prefix is specified it is always used but if not specified, @p module must be set. * @param[in] val_str String form of the value of the metadata. In case of an instance-identifier or identityref * value, the JSON format is expected (module names instead of prefixes). - * @param[in] clear_dflt Whether to clear the default flag starting from @p parent, recursively all NP containers. + * @param[in] options Bitmask of options, see @ref newvalueoptions. * @param[out] meta Optional created metadata. Must be set if @p parent is NULL. * @return LY_ERR value. */ LIBYANG_API_DECL 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 *name, const char *val_str, uint32_t options, struct lyd_meta **meta); /** * @brief Create new metadata from an opaque node attribute if possible. * * @param[in] ctx libyang context. * @param[in] parent Optional parent node for the metadata being created. Must be set if @p meta is NULL. - * @param[in] clear_dflt Whether to clear the default flag starting from @p parent, recursively all NP containers. + * @param[in] options Bitmask of options, see @ref newvalueoptions. * @param[in] attr Opaque node attribute to parse into metadata. * @param[out] meta Optional created metadata. Must be set if @p parent is NULL. * @return LY_SUCCESS on success. * @return LY_ENOT if the attribute could not be parsed into any metadata. * @return LY_ERR on error. */ -LIBYANG_API_DECL LY_ERR lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, ly_bool clear_dflt, +LIBYANG_API_DECL LY_ERR lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, uint32_t options, const struct lyd_attr *attr, struct lyd_meta **meta); /** @@ -1570,37 +1546,6 @@ LIBYANG_API_DECL LY_ERR lyd_new_attr(struct lyd_node *parent, const char *module LIBYANG_API_DECL LY_ERR lyd_new_attr2(struct lyd_node *parent, const char *module_ns, const char *name, const char *value, struct lyd_attr **attr); -/** - * @ingroup datatree - * @defgroup pathoptions Data path creation options - * - * Various options to change lyd_new_path*() behavior. - * - * Default behavior: - * - if the target node already exists (and is not default), an error is returned. - * - the whole path to the target node is created (with any missing parents) if necessary. - * - RPC output schema children are completely ignored in all modules. Input is searched and nodes created normally. - * @{ - */ - -#define LYD_NEW_PATH_UPDATE 0x01 /**< If the target node exists, is a leaf, and it is updated with a new value or its - default flag is changed, it is returned. If the target node exists and is not - a leaf or generally no change occurs in the @p parent tree, NULL is returned and - no error set. */ -#define LYD_NEW_PATH_OUTPUT 0x02 /**< Changes the behavior to ignoring RPC/action input schema nodes and using only - output ones. */ -#define LYD_NEW_PATH_OPAQ 0x04 /**< Enables the creation of opaque nodes with some specific rules. If the __last node__ - in the path is not uniquely defined ((leaf-)list without a predicate) or has an - invalid value (leaf/leaf-list), it is created as opaque. */ -#define LYD_NEW_PATH_BIN_VALUE 0x08 /**< Interpret the provided leaf/leaf-list @p value as being in the binary - ::LY_VALUE_LYB format, to learn what exactly is expected see @ref howtoDataLYB. */ -#define LYD_NEW_PATH_CANON_VALUE 0x10 /**< Interpret the provided leaf/leaf-list @p value as being in the canonical - (or JSON if no defined) ::LY_VALUE_CANON format. If it is not, it may lead - to unexpected behavior. */ -#define LYD_NEW_PATH_WITH_OPAQ 0x20 /**< Consider opaque nodes normally when searching for existing nodes. */ - -/** @} pathoptions */ - /** * @brief Create a new node in the data tree based on a path. If creating anyxml/anydata nodes, ::lyd_new_path2 * should be used instead, this function expects the value as string. @@ -1622,7 +1567,7 @@ LIBYANG_API_DECL LY_ERR lyd_new_attr2(struct lyd_node *parent, const char *modul * @param[in] path [Path](@ref howtoXPath) to create. * @param[in] value String value of the new leaf/leaf-list. If it varies based on the format, ::LY_VALUE_JSON is expected. * For other node types, it should be NULL. - * @param[in] options Bitmask of options, see @ref pathoptions. + * @param[in] options Bitmask of options, see @ref newvaloptions. * @param[out] node Optional first created node. * @return LY_SUCCESS on success. * @return LY_EEXIST if the final node to create exists (unless ::LYD_NEW_PATH_UPDATE is used). @@ -1648,7 +1593,7 @@ LIBYANG_API_DECL LY_ERR lyd_new_path(struct lyd_node *parent, const struct ly_ct * @param[in] value_len Length of @p value in bytes. May be 0 if @p value is a zero-terminated string. Ignored when * creating anyxml/anydata nodes. * @param[in] value_type Anyxml/anydata node @p value type. - * @param[in] options Bitmask of options, see @ref pathoptions. + * @param[in] options Bitmask of options, see @ref newvaloptions. * @param[out] new_parent Optional first parent node created. If only one node was created, equals to @p new_node. * @param[out] new_node Optional last node created. * @return LY_SUCCESS on success. @@ -1675,7 +1620,7 @@ LIBYANG_API_DECL LY_ERR lyd_new_path2(struct lyd_node *parent, const struct ly_c * @param[in] ext Extension instance where the node being created is defined. * @param[in] path [Path](@ref howtoXPath) to create. * @param[in] value Value of the new leaf/leaf-list. For other node types, it should be NULL. - * @param[in] options Bitmask of options, see @ref pathoptions. + * @param[in] options Bitmask of options, see @ref nevaloptions. * @param[out] node Optional first created node. * @return LY_SUCCESS on success. * @return LY_EEXIST if the final node to create exists (unless ::LYD_NEW_PATH_UPDATE is used). diff --git a/src/tree_data_common.c b/src/tree_data_common.c index eb1443313..9746faaa1 100644 --- a/src/tree_data_common.c +++ b/src/tree_data_common.c @@ -505,8 +505,8 @@ ly_err_print_build_path(const struct ly_ctx *ctx, const struct lyd_node *node, c LY_ERR lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value, - size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, - const struct lysc_node *ctx_node, ly_bool *incomplete) + 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, const struct lysc_node *ctx_node, ly_bool *incomplete) { LY_ERR ret; struct ly_err_item *err = NULL; @@ -525,6 +525,9 @@ lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct ly if (is_utf8) { options |= LYPLG_TYPE_STORE_IS_UTF8; } + if (store_only) { + options |= LYPLG_TYPE_STORE_ONLY; + } ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, hints, ctx_node, val, NULL, &err); if (dynamic) { @@ -688,7 +691,7 @@ lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t va /* store the value */ LOG_LOCSET(NULL, &node->node); - ret = lyd_value_store(ctx, &val, type, value, value_len, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL); + ret = lyd_value_store(ctx, &val, type, value, value_len, 0, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL); LOG_LOCBACK(0, 1); LY_CHECK_RET(ret); diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h index 57ec2c47d..2bfa66de7 100644 --- a/src/tree_data_internal.h +++ b/src/tree_data_internal.h @@ -225,6 +225,7 @@ const char *ly_format2str(LY_VALUE_FORMAT format); * @param[in] value String value to be parsed. * @param[in] value_len Length of @p value, must be set correctly. * @param[in] is_utf8 Whether @p value is a valid UTF-8 string, if applicable. + * @param[in] store_only Whether to perform storing operation only. * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed. * @param[in] format Input format of @p value. * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix). @@ -236,8 +237,8 @@ const char *ly_format2str(LY_VALUE_FORMAT format); * @return LY_ERR value if an error occurred. */ 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); + ly_bool store_only, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, + ly_bool *incomplete, struct lyd_node **node); /** * @brief Create a term (leaf/leaf-list) node from a parsed value by duplicating it. @@ -274,12 +275,13 @@ LY_ERR lyd_create_inner(const struct lysc_node *schema, struct lyd_node **node); * @param[in] schema Schema node of the new data node. * @param[in] predicates Compiled key list predicates. * @param[in] vars Array of defined variables to use in predicates, may be NULL. + * @param[in] store_only Whether to perform storing operation only. * @param[out] node Created node. * @return LY_SUCCESS on success. * @return LY_ERR value if an error occurred. */ 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); + const struct lyxp_var *vars, ly_bool store_only, struct lyd_node **node); /** * @brief Create a list with all its keys (cannot be used for key-less list). @@ -289,11 +291,13 @@ LY_ERR lyd_create_list(const struct lysc_node *schema, const struct ly_path_pred * @param[in] schema Schema node of the new data node. * @param[in] keys Key list predicates. * @param[in] keys_len Length of @p keys. + * @param[in] store_only Whether to perform storing operation only. * @param[out] node Created node. * @return LY_SUCCESS on success. * @return LY_ERR value if an error occurred. */ -LY_ERR lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_len, struct lyd_node **node); +LY_ERR lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_len, ly_bool store_only, + struct lyd_node **node); /** * @brief Create an anyxml/anydata node. @@ -464,6 +468,7 @@ void lyd_unlink_meta_single(struct lyd_meta *meta); * @param[in] value String value to be parsed. * @param[in] value_len Length of @p value, must be set correctly. * @param[in] is_utf8 Whether @p value is a valid UTF-8 string, if applicable. + * @param[in] store_only Whether to perform storing operation only. * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed. * @param[in] format Input format of @p value. * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix). @@ -476,8 +481,9 @@ void lyd_unlink_meta_single(struct lyd_meta *meta); * @return LY_ERR value if an error occurred. */ LY_ERR lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name, - size_t name_len, const char *value, size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format, - void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt, ly_bool *incomplete); + size_t name_len, 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, const struct lysc_node *ctx_node, ly_bool clear_dflt, + ly_bool *incomplete); /** * @brief Create a copy of the metadata. @@ -533,6 +539,7 @@ LY_ERR lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const st * @param[in] value Value to be parsed, must not be NULL. * @param[in] value_len Length of the give @p value, must be set correctly. * @param[in] is_utf8 Whether @p value is a valid UTF-8 string, if applicable. + * @param[in] store_only Whether to perform storing operation only. * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed. * @param[in] format Input format of @p value. * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix). @@ -543,8 +550,8 @@ LY_ERR lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const st * @return LY_ERR value on error. */ LY_ERR lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value, - size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, - const struct lysc_node *ctx_node, ly_bool *incomplete); + 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, const struct lysc_node *ctx_node, ly_bool *incomplete); /** * @brief Validate previously incompletely stored value. diff --git a/src/tree_data_new.c b/src/tree_data_new.c index bbe59f299..7a965a3c0 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 @@ lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_ 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 @@ lyd_create_inner(const struct lysc_node *schema, struct lyd_node **node) 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 @@ lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate * /* 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 @@ lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate * } 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 @@ lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_l 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 @@ lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, con 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 @@ lyd_new_ext_inner(const struct lysc_ext_instance *ext, const char *name, struct * @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 @@ _lyd_new_list_node(const struct ly_ctx *ctx, const struct lyd_node *parent, cons 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 @@ _lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const ch 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 @@ _lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const ch 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 @@ _lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const ch } cleanup: + va_end(ap); if (rc) { lyd_free_tree(ret); ret = NULL; @@ -644,61 +659,21 @@ _lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const ch } 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 @@ lyd_new_ext_list(const struct lysc_ext_instance *ext, const char *name, struct l /* 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 @@ lyd_new_ext_list(const struct lysc_ext_instance *ext, const char *name, struct l 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 @@ lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const ch } /* 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 @@ lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const ch 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 @@ lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const ch * @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 @@ _lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const c 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 @@ _lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const c 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 @@ _lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const c 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); -LIBYANG_API_DEF 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) -{ - return _lyd_new_list3(parent, module, name, LY_VALUE_LYB, key_values, value_lengths, output, node); + 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 -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) +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, uint32_t options, 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 @@ lyd_new_list3_canon(struct lyd_node *parent, const struct lys_module *module, co * * @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 @@ _lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const ch } 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 @@ _lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const ch } 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); -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); + 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_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) +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) { - return _lyd_new_term(parent, module, name, val_str, val_str ? strlen(val_str) : 0, LY_VALUE_CANON, output, 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_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 @@ lyd_new_ext_term(const struct lysc_ext_instance *ext, const char *name, const ch } 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 @@ lyd_new_ext_term(const struct lysc_ext_instance *ext, const char *name, const ch 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 @@ lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char 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 @@ lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char } 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 @@ lyd_new_ext_any(const struct lysc_ext_instance *ext, const char *name, const voi 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 @@ lyd_new_meta(const struct ly_ctx *ctx, struct lyd_node *parent, const struct lys 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 @@ lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, ly_bool clear_d } 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 @@ _lyd_change_term(struct lyd_node *term, const void *value, size_t value_len, LY_ /* 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 @@ lyd_change_meta(struct lyd_meta *meta, const char *val_str) /* 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 @@ lyd_new_path_check_find_lypath(struct ly_path *path, const char *str_path, const 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 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly 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 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly 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 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly 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_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly 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 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly 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 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly } /* 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 @@ lyd_new_path(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path 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 @@ lyd_new_path2(struct lyd_node *parent, const struct ly_ctx *ctx, const char *pat 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 @@ lyd_new_ext_path(struct lyd_node *parent, const struct lysc_ext_instance *ext, c 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); diff --git a/src/tree_data_sorted.c b/src/tree_data_sorted.c index 54ad2ff4b..182e9c5d4 100644 --- a/src/tree_data_sorted.c +++ b/src/tree_data_sorted.c @@ -1170,7 +1170,7 @@ lyds_create_metadata(struct lyd_node *leader, struct lyd_meta **meta_p) LY_CHECK_ERR_RET(!modyang, LOGERR(LYD_CTX(leader), LY_EINT, "The yang module is not installed."), LY_EINT); /* create new metadata, its rbt is NULL */ - ret = lyd_create_meta(leader, &meta, modyang, RB_NAME, RB_NAME_LEN, NULL, 0, 0, NULL, + ret = lyd_create_meta(leader, &meta, modyang, RB_NAME, RB_NAME_LEN, NULL, 0, 0, 1, NULL, LY_VALUE_CANON, NULL, LYD_HINT_DATA, NULL, 0, NULL); LY_CHECK_RET(ret); diff --git a/src/xpath.c b/src/xpath.c index bfadbb99c..57ba64ddb 100644 --- a/src/xpath.c +++ b/src/xpath.c @@ -6224,7 +6224,7 @@ moveto_node_hash_child(struct lyxp_set *set, const struct lysc_node *scnode, con /* create specific data instance if needed */ if (scnode->nodetype == LYS_LIST) { - LY_CHECK_GOTO(ret = lyd_create_list(scnode, predicates, NULL, &inst), cleanup); + LY_CHECK_GOTO(ret = lyd_create_list(scnode, predicates, NULL, 1, &inst), cleanup); } else if (scnode->nodetype == LYS_LEAFLIST) { LY_CHECK_GOTO(ret = lyd_create_term2(scnode, &predicates[0].value, &inst), cleanup); } diff --git a/tests/utests/basic/test_context.c b/tests/utests/basic/test_context.c index 789c80ab7..2126ffe98 100644 --- a/tests/utests/basic/test_context.c +++ b/tests/utests/basic/test_context.c @@ -222,11 +222,21 @@ test_options(void **state) assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_PREFER_SEARCHDIRS)); assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_PREFER_SEARCHDIRS); + /* LY_CTX_LEAFREF_EXTENDED */ + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_EXTENDED); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_LEAFREF_EXTENDED)); + assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_EXTENDED); + /* LY_CTX_LEAFREF_LINKING */ assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_LINKING); assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_LEAFREF_LINKING)); assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_LINKING); + /* LY_CTX_BUILTIN_PLUGINS_ONLY */ + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_BUILTIN_PLUGINS_ONLY); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_BUILTIN_PLUGINS_ONLY)); + assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_BUILTIN_PLUGINS_ONLY); + assert_int_equal(UTEST_LYCTX->flags, ly_ctx_get_options(UTEST_LYCTX)); /* set back */ @@ -250,10 +260,18 @@ test_options(void **state) assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_PREFER_SEARCHDIRS)); assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_PREFER_SEARCHDIRS); + /* LY_CTX_LEAFREF_EXTENDED */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_EXTENDED)); + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_EXTENDED); + /* LY_CTX_LEAFREF_LINKING */ assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_LINKING)); assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_LINKING); + /* LY_CTX_BUILTIN_PLUGINS_ONLY */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_BUILTIN_PLUGINS_ONLY)); + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_BUILTIN_PLUGINS_ONLY); + assert_int_equal(UTEST_LYCTX->flags, ly_ctx_get_options(UTEST_LYCTX)); } diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c index d75f6672b..df1d8c5ad 100644 --- a/tests/utests/data/test_new.c +++ b/tests/utests/data/test_new.c @@ -136,8 +136,27 @@ test_top_level(void **state) uint32_t val_lens[] = {1, 1}; + assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, val_lens, LYD_NEW_VAL_BIN_VALUE, &node), LY_EINVAL); + CHECK_LOG_CTX("Invalid argument !(options & 0x04) (lyd_new_list3()).", NULL, 0); assert_int_equal(lyd_new_list3_bin(NULL, mod, "l1", (const void **)key_vals, val_lens, 0, &node), LY_SUCCESS); lyd_free_tree(node); + assert_int_equal(lyd_new_list3_bin(NULL, mod, "l1", (const void **)key_vals, val_lens, LYD_NEW_VAL_STORE_ONLY, &node), LY_EINVAL); + CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (_lyd_new_list3()).", NULL, 0); + + assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, val_lens, LYD_NEW_VAL_CANON_VALUE, &node), LY_SUCCESS); + lyd_free_tree(node); + assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, val_lens, LYD_NEW_VAL_CANON_VALUE | LYD_NEW_VAL_STORE_ONLY, &node), LY_EINVAL); + CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (_lyd_new_list3()).", NULL, 0); + + assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_BIN_VALUE, &node, "val_a", 5, "val_b", 5), LY_SUCCESS); + lyd_free_tree(node); + assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_BIN_VALUE | LYD_NEW_VAL_STORE_ONLY, &node, "val_a", 5, "val_b", 5), LY_EINVAL); + CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (lyd_new_list()).", NULL, 0); + + assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_CANON_VALUE, &node, "val_a", "val_b"), LY_SUCCESS); + lyd_free_tree(node); + assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_CANON_VALUE | LYD_NEW_VAL_STORE_ONLY, &node, "val_a", "val_b"), LY_EINVAL); + CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (lyd_new_list()).", NULL, 0); /* leaf */ assert_int_equal(lyd_new_term(NULL, mod, "foo", "[a='a'][b='b'][c='c']", 0, &node), LY_EVALID); @@ -149,6 +168,18 @@ test_top_level(void **state) assert_int_equal(lyd_new_term(NULL, mod, "foo", "256", 0, &node), LY_SUCCESS); lyd_free_tree(node); + assert_int_equal(lyd_new_term(NULL, mod, "foo", "25", LYD_NEW_VAL_BIN_VALUE, &node), LY_EINVAL); + CHECK_LOG_CTX("Invalid argument !(options & 0x04) (lyd_new_term()).", NULL, 0); + assert_int_equal(lyd_new_term_bin(NULL, mod, "foo", "25", 2, LYD_NEW_VAL_BIN_VALUE, &node), LY_SUCCESS); + lyd_free_tree(node); + assert_int_equal(lyd_new_term_bin(NULL, mod, "foo", "25", 2, LYD_NEW_VAL_STORE_ONLY, &node), LY_EINVAL); + CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (_lyd_new_term()).", NULL, 0); + + assert_int_equal(lyd_new_term(NULL, mod, "foo", "25", LYD_NEW_VAL_CANON_VALUE, &node), LY_SUCCESS); + lyd_free_tree(node); + assert_int_equal(lyd_new_term(NULL, mod, "foo", "25", LYD_NEW_VAL_CANON_VALUE | LYD_NEW_VAL_STORE_ONLY, &node), LY_EINVAL); + CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (_lyd_new_term()).", NULL, 0); + /* leaf-list */ assert_int_equal(lyd_new_term(NULL, mod, "ll", "ahoy", 0, &node), LY_SUCCESS); lyd_free_tree(node); @@ -164,9 +195,9 @@ test_top_level(void **state) CHECK_LOG_CTX("Inner node (container, notif, RPC, or action) \"l2\" not found.", NULL, 0); /* anydata */ - assert_int_equal(lyd_new_any(NULL, mod, "any", "{\"node\":\"val\"}", 0, LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS); + assert_int_equal(lyd_new_any(NULL, mod, "any", "{\"node\":\"val\"}", 0, LYD_ANYDATA_STRING, &node), LY_SUCCESS); lyd_free_tree(node); - assert_int_equal(lyd_new_any(NULL, mod, "any", "val", 0, LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS); + assert_int_equal(lyd_new_any(NULL, mod, "any", "val", 0, LYD_ANYDATA_STRING, &node), LY_SUCCESS); lyd_free_tree(node); /* key-less list */ @@ -186,7 +217,7 @@ test_top_level(void **state) assert_int_equal(lyd_new_inner(NULL, mod, "oper", 0, &rpc), LY_SUCCESS); assert_int_equal(lyd_new_term(rpc, mod, "param", "22", 0, &node), LY_SUCCESS); assert_int_equal(LY_TYPE_STRING, ((struct lysc_node_leaf *)node->schema)->type->basetype); - assert_int_equal(lyd_new_term(rpc, mod, "param", "22", 1, &node), LY_SUCCESS); + assert_int_equal(lyd_new_term(rpc, mod, "param", "22", LYD_NEW_VAL_OUTPUT, &node), LY_SUCCESS); assert_int_equal(LY_TYPE_INT8, ((struct lysc_node_leaf *)node->schema)->type->basetype); lyd_free_tree(rpc); } diff --git a/tests/utests/types/binary.c b/tests/utests/types/binary.c index 35da7d56b..910f756eb 100644 --- a/tests/utests/types/binary.c +++ b/tests/utests/types/binary.c @@ -232,6 +232,15 @@ test_plugin_store(void **state) assert_int_equal(LY_EVALID, ly_ret); assert_string_equal(err->msg, "Unsatisfied length - string \"MTIz\" length is not allowed."); ly_err_free(err); + + /* LYPLG_TYPE_STORE_ONLY test */ + val = "MTIz"; + err = NULL; + ly_ret = type->store(UTEST_LYCTX, lysc_type2, val, strlen(val), + LYPLG_TYPE_STORE_ONLY, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err); + assert_int_equal(LY_SUCCESS, ly_ret); + type->free(UTEST_LYCTX, &value); + ly_err_free(err); } static void diff --git a/tests/utests/types/decimal64.c b/tests/utests/types/decimal64.c index ebfb2b08b..fdd118a87 100644 --- a/tests/utests/types/decimal64.c +++ b/tests/utests/types/decimal64.c @@ -60,6 +60,14 @@ lyd_free_all(tree_2); \ } +#define TEST_SUCCESS_PARSE_STORE_ONLY_XML(MOD_NAME, NODE_NAME, DATA) \ + {\ + struct lyd_node *tree; \ + const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA ""; \ + CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STORE_ONLY, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \ + lyd_free_all(tree); \ + } + static void test_data_xml(void **state) { @@ -94,6 +102,9 @@ test_data_xml(void **state) TEST_ERROR_XML("defs", "l1", "8.55 xxx"); CHECK_LOG_CTX("Value \"8.55\" of decimal64 type exceeds defined number (1) of fraction digits.", "/defs:l1", 1); + + /* LYPLG_TYPE_STORE_ONLY test */ + TEST_SUCCESS_PARSE_STORE_ONLY_XML("defs", "l1", "\n 15 \t\n "); } static void diff --git a/tests/utests/types/inet_types.c b/tests/utests/types/inet_types.c index 3874cc3d4..016d5bbf1 100644 --- a/tests/utests/types/inet_types.c +++ b/tests/utests/types/inet_types.c @@ -50,6 +50,31 @@ lyd_free_all(tree); \ } +#define TEST_ERROR_XML(MOD_NAME, NODE_NAME, DATA) \ + { \ + struct lyd_node *tree; \ + const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA ""; \ + CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \ + assert_null(tree); \ + } + +#define TEST_SUCCESS_PARSE_STORE_ONLY_XML(MOD_NAME, NODE_NAME, DATA, TYPE, ...) \ + { \ + struct lyd_node *tree; \ + const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA ""; \ + CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STORE_ONLY, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \ + CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 4, 0, 0, 0, 1, TYPE, __VA_ARGS__); \ + lyd_free_all(tree); \ + } + +#define TEST_ERROR_PARSE_STORE_ONLY_XML(MOD_NAME, NODE_NAME, DATA) \ + { \ + struct lyd_node *tree; \ + const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA ""; \ + CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STORE_ONLY, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \ + assert_null(tree); \ + } + #define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME, DATA) \ { \ struct lyd_node *tree_1; \ @@ -113,6 +138,33 @@ test_data_xml(void **state) TEST_SUCCESS_XML("a", "l7", "::C:D:E:f:a/55", STRING, "::/55"); } +static void +test_data_basic_plugins_only_xml(void **state) +{ + const char *schema; + + schema = MODULE_CREATE_YANG("a", "leaf l {type inet:ipv4-address;}"); + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + /* Stored via ipv4-address plugin */ + TEST_SUCCESS_XML("a", "l", "192.168.0.1", STRING, "192.168.0.1"); + TEST_ERROR_XML("a", "l", "192.168.0.333"); + TEST_ERROR_PARSE_STORE_ONLY_XML("a", "l", "192.168.0.333"); + + /* Recreate context to get rid of all plugins */ + ly_ctx_destroy(UTEST_LYCTX); + assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_BUILTIN_PLUGINS_ONLY, &UTEST_LYCTX)); + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + /* Stored via string plugin */ + TEST_SUCCESS_XML("a", "l", "192.168.0.1", STRING, "192.168.0.1"); + TEST_ERROR_XML("a", "l", "192.168.0.333"); + CHECK_LOG_CTX("Unsatisfied pattern - \"192.168.0.333\" does not conform to \"" + "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9]" + "[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(%[\\p{N}\\p{L}]+)?\".", "/a:l", 1); + TEST_SUCCESS_PARSE_STORE_ONLY_XML("a", "l", "192.168.0.333", STRING, "192.168.0.333"); +} + static void test_data_lyb(void **state) { @@ -278,6 +330,7 @@ main(void) UTEST(test_data_xml), UTEST(test_data_lyb), UTEST(test_plugin_sort), + UTEST(test_data_basic_plugins_only_xml), }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/tests/utests/types/int8.c b/tests/utests/types/int8.c index d369a0e56..d92d14666 100644 --- a/tests/utests/types/int8.c +++ b/tests/utests/types/int8.c @@ -1527,6 +1527,16 @@ test_plugin_store(void **state) assert_int_equal(LY_EVALID, ly_ret); ly_err_free(err); + /* LYPLG_TYPE_STORE_ONLY test */ + val_text = "-60"; + err = NULL; + ly_ret = type->store(UTEST_LYCTX, lysc_type, val_text, strlen(val_text), + LYPLG_TYPE_STORE_ONLY, LY_VALUE_XML, NULL, LYD_VALHINT_DECNUM, NULL, + &value, NULL, &err); + assert_int_equal(LY_SUCCESS, ly_ret); + type->free(UTEST_LYCTX, &value); + ly_err_free(err); + UTEST_LOG_CTX_CLEAN; } diff --git a/tests/utests/types/string.c b/tests/utests/types/string.c index 73d9677fc..f5aec3467 100644 --- a/tests/utests/types/string.c +++ b/tests/utests/types/string.c @@ -1184,6 +1184,15 @@ test_plugin_store(void **state) assert_int_equal(LY_EVALID, ly_ret); ly_err_free(err); + /* LYPLG_TYPE_STORE_ONLY test */ + val_text = "10 \"| bcdei"; + err = NULL; + ly_ret = type->store(UTEST_LYCTX, lysc_type, val_text, strlen(val_text), + LYPLG_TYPE_STORE_ONLY, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, + &value, NULL, &err); + assert_int_equal(LY_SUCCESS, ly_ret); + type->free(UTEST_LYCTX, &value); + ly_err_free(err); } static void diff --git a/tests/utests/types/uint8.c b/tests/utests/types/uint8.c index 89b89a7f7..618e42274 100644 --- a/tests/utests/types/uint8.c +++ b/tests/utests/types/uint8.c @@ -50,6 +50,14 @@ assert_null(tree); \ } +#define TEST_SUCCESS_PARSE_STORE_ONLY_XML(MOD_NAME, DATA) \ + {\ + struct lyd_node *tree; \ + const char *data = "" DATA ""; \ + CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STORE_ONLY, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \ + lyd_free_all(tree); \ + } + static void test_data_xml(void **state) { @@ -63,6 +71,9 @@ test_data_xml(void **state) TEST_ERROR_XML("defs", "\n 15 \t\n "); CHECK_LOG_CTX("Unsatisfied range - value \"15\" is out of the allowed range.", "/defs:port", 3); + + /* LYPLG_TYPE_STORE_ONLY test */ + TEST_SUCCESS_PARSE_STORE_ONLY_XML("defs", "\n 15 \t\n "); } int