types REFACTOR move union-specific functions into a standalone source file
Split the plugins_types.c file to distinct internal implementation of
plugins types API and the (base) type plugins themselves.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 34effe3..0e3fa94 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -145,6 +145,7 @@
src/plugins_types_integer.c
src/plugins_types_leafref.c
src/plugins_types_string.c
+ src/plugins_types_union.c
src/plugins_exts.c
src/plugins_exts_metadata.c
src/plugins_exts_nacm.c
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 6fff919..5d82244 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -809,235 +809,6 @@
return ret;
}
-static LY_ERR
-ly_type_union_store_type(const struct ly_ctx *ctx, struct lysc_type **types, struct lyd_value_subvalue *subvalue,
- 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 = LY_SUCCESS;
- LY_ARRAY_COUNT_TYPE u;
- uint32_t prev_lo;
-
- if (!types || !LY_ARRAY_COUNT(types)) {
- return LY_EINVAL;
- }
-
- /* turn logging off */
- prev_lo = ly_log_options(0);
-
- /* use the first usable subtype to store the value */
- for (u = 0; u < LY_ARRAY_COUNT(types); ++u) {
- ret = types[u]->plugin->store(ctx, types[u], subvalue->original, strlen(subvalue->original), 0, subvalue->format,
- subvalue->prefix_data, subvalue->hints, subvalue->ctx_node, &subvalue->value, unres, err);
- if ((ret == LY_SUCCESS) || (ret == LY_EINCOMPLETE)) {
- if (resolve && (ret == LY_EINCOMPLETE)) {
- /* we need the value resolved */
- ret = subvalue->value.realtype->plugin->validate(ctx, types[u], ctx_node, tree, &subvalue->value, err);
- if (!ret) {
- /* store and resolve successful */
- break;
- }
-
- /* resolve failed, we need to free the stored value */
- types[u]->plugin->free(ctx, &subvalue->value);
- } else {
- /* store successful */
- break;
- }
- }
- ly_err_free(*err);
- *err = NULL;
- }
-
- if (u == LY_ARRAY_COUNT(types)) {
- ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
- "Invalid union value \"%s\" - no matching subtype found.", subvalue->original);
- }
-
- /* restore logging */
- ly_log_options(prev_lo);
- return ret;
-}
-
-/**
- * @brief Store and canonize value of the YANG built-in union type.
- *
- * Implementation of the ly_type_store_clb.
- */
-static LY_ERR
-ly_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const char *value, size_t value_len,
- uint32_t options, LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
- struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
-{
- LY_ERR ret = LY_SUCCESS;
- struct lysc_type_union *type_u = (struct lysc_type_union *)type;
- struct lyd_value_subvalue *subvalue = NULL;
-
- /* prepare subvalue storage */
- subvalue = calloc(1, sizeof *subvalue);
- if (!subvalue) {
- ret = ly_err_new(err, LY_EMEM, 0, NULL, NULL, LY_EMEM_MSG);
- goto cleanup_value;
- }
-
- /* remember the original value */
- if (options & LY_TYPE_STORE_DYNAMIC) {
- ret = lydict_insert_zc(ctx, (char *)value, &subvalue->original);
- options &= ~LY_TYPE_STORE_DYNAMIC;
- LY_CHECK_GOTO(ret, cleanup);
- } else {
- ret = lydict_insert(ctx, value_len ? value : "", value_len, &subvalue->original);
- LY_CHECK_GOTO(ret, cleanup);
- }
-
- /* store format-specific data for later prefix resolution */
- ret = ly_type_prefix_data_add(ctx, subvalue->original, value_len, format, prefix_data, &subvalue->format,
- &subvalue->prefix_data);
- LY_CHECK_GOTO(ret, cleanup);
- subvalue->hints = hints;
- subvalue->ctx_node = ctx_node;
-
- /* use the first usable subtype to store the value */
- ret = ly_type_union_store_type(ctx, type_u->types, subvalue, 0, NULL, NULL, unres, err);
- LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup);
-
-cleanup:
- if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
- lydict_remove(ctx, subvalue->original);
- ly_type_prefix_data_free(subvalue->format, subvalue->prefix_data);
- free(subvalue);
- } else {
- /* store it as union, the specific type is in the subvalue, but canonical value is the specific type value */
- ret = lydict_insert(ctx, subvalue->value.canonical, 0, &storage->canonical);
- LY_CHECK_GOTO(ret, cleanup);
- storage->subvalue = subvalue;
- storage->realtype = type;
- }
-
-cleanup_value:
- if (options & LY_TYPE_STORE_DYNAMIC) {
- free((char *)value);
- }
-
- return ret;
-}
-
-/**
- * @brief Validate value of the YANG built-in union type.
- *
- * Implementation of the ly_type_validate_clb.
- */
-static LY_ERR
-ly_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
- const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err)
-{
- LY_ERR ret = LY_SUCCESS;
- struct lysc_type_union *type_u = (struct lysc_type_union *)storage->realtype;
- struct lyd_value_subvalue *subvalue = storage->subvalue;
-
- *err = NULL;
-
- if (!subvalue->value.realtype->plugin->validate) {
- /* nothing to resolve */
- return LY_SUCCESS;
- }
-
- /* resolve the stored value */
- if (!subvalue->value.realtype->plugin->validate(ctx, type, ctx_node, tree, &subvalue->value, err)) {
- /* resolve successful */
- return LY_SUCCESS;
- }
-
- /* Resolve failed, we have to try another subtype of the union.
- * Unfortunately, since the realtype can change (e.g. in leafref), we are not able to detect
- * which of the subtype's were tried the last time, so we have to try all of them again.
- */
- ly_err_free(*err);
- *err = NULL;
-
- /* store and resolve the value */
- ret = ly_type_union_store_type(ctx, type_u->types, subvalue, 1, ctx_node, tree, NULL, err);
- LY_CHECK_RET(ret);
-
- /* success, update the canonical value */
- lydict_remove(ctx, storage->canonical);
- LY_CHECK_RET(lydict_insert(ctx, subvalue->value.canonical, 0, &storage->canonical));
- return LY_SUCCESS;
-}
-
-/**
- * @brief Comparison callback checking the union value.
- *
- * Implementation of the ly_type_compare_clb.
- */
-static LY_ERR
-ly_type_compare_union(const struct lyd_value *val1, const struct lyd_value *val2)
-{
- if (val1->realtype != val2->realtype) {
- return LY_ENOT;
- }
-
- if (val1->subvalue->value.realtype != val2->subvalue->value.realtype) {
- return LY_ENOT;
- }
- return val1->subvalue->value.realtype->plugin->compare(&val1->subvalue->value, &val2->subvalue->value);
-}
-
-/**
- * @brief Printer callback printing the union value.
- *
- * Implementation of the ly_type_print_clb.
- */
-static const char *
-ly_type_print_union(const struct lyd_value *value, LY_PREFIX_FORMAT format, void *prefix_data, ly_bool *dynamic)
-{
- return value->subvalue->value.realtype->plugin->print(&value->subvalue->value, format, prefix_data, dynamic);
-}
-
-/**
- * @brief Duplication callback of the union values.
- *
- * Implementation of the ly_type_dup_clb.
- */
-static LY_ERR
-ly_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
-{
- LY_CHECK_RET(lydict_insert(ctx, original->canonical, strlen(original->canonical), &dup->canonical));
-
- dup->subvalue = calloc(1, sizeof *dup->subvalue);
- LY_CHECK_ERR_RET(!dup->subvalue, LOGMEM(ctx), LY_EMEM);
- LY_CHECK_RET(original->subvalue->value.realtype->plugin->duplicate(ctx, &original->subvalue->value, &dup->subvalue->value));
-
- LY_CHECK_RET(lydict_insert(ctx, original->subvalue->original, strlen(original->subvalue->original),
- &dup->subvalue->original));
- dup->subvalue->format = original->subvalue->format;
- LY_CHECK_RET(ly_type_prefix_data_dup(ctx, original->subvalue->format, original->subvalue->prefix_data,
- &dup->subvalue->prefix_data));
-
- dup->realtype = original->realtype;
- return LY_SUCCESS;
-}
-
-/**
- * @brief Free value of the YANG built-in union type.
- *
- * Implementation of the ly_type_free_clb.
- */
-static void
-ly_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
-{
- lydict_remove(ctx, value->canonical);
- if (value->subvalue) {
- if (value->subvalue->value.realtype) {
- value->subvalue->value.realtype->plugin->free(ctx, &value->subvalue->value);
- }
- ly_type_prefix_data_free(value->subvalue->format, value->subvalue->prefix_data);
- lydict_remove(ctx, value->subvalue->original);
- free(value->subvalue);
- value->subvalue = NULL;
- }
-}
-
/* plugins_types_binary.c */
extern LY_ERR ly_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type,
const char *value, size_t value_len, uint32_t options, LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints,
@@ -1116,6 +887,18 @@
extern LY_ERR ly_type_dup_leafref(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
extern void ly_type_free_leafref(const struct ly_ctx *ctx, struct lyd_value *value);
+/* plugins_types_union.c */
+extern LY_ERR ly_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type,
+ const char *value, size_t value_len, uint32_t options, LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints,
+ const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+extern LY_ERR ly_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type,
+ const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
+extern LY_ERR ly_type_compare_union(const struct lyd_value *val1, const struct lyd_value *val2);
+extern const char *ly_type_print_union(const struct lyd_value *value, LY_PREFIX_FORMAT format, void *prefix_data,
+ ly_bool *dynamic);
+extern LY_ERR ly_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+extern void ly_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value);
+
/**
* @brief Set of type plugins for YANG built-in types
*/
@@ -1163,9 +946,9 @@
{.type = LY_TYPE_LEAFREF, .store = ly_type_store_leafref, .validate = ly_type_validate_leafref,
.compare = ly_type_compare_leafref, .print = ly_type_print_leafref, .duplicate = ly_type_dup_leafref,
.free = ly_type_free_leafref, .id = "libyang 2 - leafref, version 1"},
- {.type = LY_TYPE_UNION, .store = ly_type_store_union, .validate = ly_type_validate_union, .compare = ly_type_compare_union,
- .print = ly_type_print_union, .duplicate = ly_type_dup_union, .free = ly_type_free_union,
- .id = "libyang 2 - union,version 1"},
+ {.type = LY_TYPE_UNION, .store = ly_type_store_union, .validate = ly_type_validate_union,
+ .compare = ly_type_compare_union, .print = ly_type_print_union, .duplicate = ly_type_dup_union,
+ .free = ly_type_free_union, .id = "libyang 2 - union,version 1"},
{.type = LY_TYPE_INT8, .store = ly_type_store_int, .validate = NULL, .compare = ly_type_compare_simple,
.print = ly_type_print_simple, .duplicate = ly_type_dup_simple, .free = ly_type_free_simple,
.id = "libyang 2 - integer, version 1"},
diff --git a/src/plugins_types_union.c b/src/plugins_types_union.c
new file mode 100644
index 0000000..7e6780f
--- /dev/null
+++ b/src/plugins_types_union.c
@@ -0,0 +1,257 @@
+/**
+ * @file plugins_types_union.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Built-in union type plugin.
+ *
+ * Copyright (c) 2019-2021 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#define _GNU_SOURCE
+
+#include "plugins_types.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libyang.h"
+
+/* additional internal headers for some useful simple macros */
+#include "common.h"
+#include "compat.h"
+
+static LY_ERR
+ly_type_union_store_type(const struct ly_ctx *ctx, struct lysc_type **types, struct lyd_value_subvalue *subvalue,
+ 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 = LY_SUCCESS;
+ LY_ARRAY_COUNT_TYPE u;
+ uint32_t prev_lo;
+
+ if (!types || !LY_ARRAY_COUNT(types)) {
+ return LY_EINVAL;
+ }
+
+ /* turn logging off */
+ prev_lo = ly_log_options(0);
+
+ /* use the first usable subtype to store the value */
+ for (u = 0; u < LY_ARRAY_COUNT(types); ++u) {
+ ret = types[u]->plugin->store(ctx, types[u], subvalue->original, strlen(subvalue->original), 0, subvalue->format,
+ subvalue->prefix_data, subvalue->hints, subvalue->ctx_node, &subvalue->value, unres, err);
+ if ((ret == LY_SUCCESS) || (ret == LY_EINCOMPLETE)) {
+ if (resolve && (ret == LY_EINCOMPLETE)) {
+ /* we need the value resolved */
+ ret = subvalue->value.realtype->plugin->validate(ctx, types[u], ctx_node, tree, &subvalue->value, err);
+ if (!ret) {
+ /* store and resolve successful */
+ break;
+ }
+
+ /* resolve failed, we need to free the stored value */
+ types[u]->plugin->free(ctx, &subvalue->value);
+ } else {
+ /* store successful */
+ break;
+ }
+ }
+ ly_err_free(*err);
+ *err = NULL;
+ }
+
+ if (u == LY_ARRAY_COUNT(types)) {
+ ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
+ "Invalid union value \"%s\" - no matching subtype found.", subvalue->original);
+ }
+
+ /* restore logging */
+ ly_log_options(prev_lo);
+ return ret;
+}
+
+/**
+ * @brief Store and canonize value of the YANG built-in union type.
+ *
+ * Implementation of the ly_type_store_clb.
+ */
+LY_ERR
+ly_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const char *value, size_t value_len,
+ uint32_t options, LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
+ struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lysc_type_union *type_u = (struct lysc_type_union *)type;
+ struct lyd_value_subvalue *subvalue = NULL;
+
+ /* prepare subvalue storage */
+ subvalue = calloc(1, sizeof *subvalue);
+ if (!subvalue) {
+ ret = ly_err_new(err, LY_EMEM, 0, NULL, NULL, LY_EMEM_MSG);
+ goto cleanup_value;
+ }
+
+ /* remember the original value */
+ if (options & LY_TYPE_STORE_DYNAMIC) {
+ ret = lydict_insert_zc(ctx, (char *)value, &subvalue->original);
+ options &= ~LY_TYPE_STORE_DYNAMIC;
+ LY_CHECK_GOTO(ret, cleanup);
+ } else {
+ ret = lydict_insert(ctx, value_len ? value : "", value_len, &subvalue->original);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ /* store format-specific data for later prefix resolution */
+ ret = ly_type_prefix_data_add(ctx, subvalue->original, value_len, format, prefix_data, &subvalue->format,
+ &subvalue->prefix_data);
+ LY_CHECK_GOTO(ret, cleanup);
+ subvalue->hints = hints;
+ subvalue->ctx_node = ctx_node;
+
+ /* use the first usable subtype to store the value */
+ ret = ly_type_union_store_type(ctx, type_u->types, subvalue, 0, NULL, NULL, unres, err);
+ LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup);
+
+cleanup:
+ if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
+ lydict_remove(ctx, subvalue->original);
+ ly_type_prefix_data_free(subvalue->format, subvalue->prefix_data);
+ free(subvalue);
+ } else {
+ /* store it as union, the specific type is in the subvalue, but canonical value is the specific type value */
+ ret = lydict_insert(ctx, subvalue->value.canonical, 0, &storage->canonical);
+ LY_CHECK_GOTO(ret, cleanup);
+ storage->subvalue = subvalue;
+ storage->realtype = type;
+ }
+
+cleanup_value:
+ if (options & LY_TYPE_STORE_DYNAMIC) {
+ free((char *)value);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Validate value of the YANG built-in union type.
+ *
+ * Implementation of the ly_type_validate_clb.
+ */
+LY_ERR
+ly_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
+ const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lysc_type_union *type_u = (struct lysc_type_union *)storage->realtype;
+ struct lyd_value_subvalue *subvalue = storage->subvalue;
+
+ *err = NULL;
+
+ if (!subvalue->value.realtype->plugin->validate) {
+ /* nothing to resolve */
+ return LY_SUCCESS;
+ }
+
+ /* resolve the stored value */
+ if (!subvalue->value.realtype->plugin->validate(ctx, type, ctx_node, tree, &subvalue->value, err)) {
+ /* resolve successful */
+ return LY_SUCCESS;
+ }
+
+ /* Resolve failed, we have to try another subtype of the union.
+ * Unfortunately, since the realtype can change (e.g. in leafref), we are not able to detect
+ * which of the subtype's were tried the last time, so we have to try all of them again.
+ */
+ ly_err_free(*err);
+ *err = NULL;
+
+ /* store and resolve the value */
+ ret = ly_type_union_store_type(ctx, type_u->types, subvalue, 1, ctx_node, tree, NULL, err);
+ LY_CHECK_RET(ret);
+
+ /* success, update the canonical value */
+ lydict_remove(ctx, storage->canonical);
+ LY_CHECK_RET(lydict_insert(ctx, subvalue->value.canonical, 0, &storage->canonical));
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Comparison callback checking the union value.
+ *
+ * Implementation of the ly_type_compare_clb.
+ */
+LY_ERR
+ly_type_compare_union(const struct lyd_value *val1, const struct lyd_value *val2)
+{
+ if (val1->realtype != val2->realtype) {
+ return LY_ENOT;
+ }
+
+ if (val1->subvalue->value.realtype != val2->subvalue->value.realtype) {
+ return LY_ENOT;
+ }
+ return val1->subvalue->value.realtype->plugin->compare(&val1->subvalue->value, &val2->subvalue->value);
+}
+
+/**
+ * @brief Printer callback printing the union value.
+ *
+ * Implementation of the ly_type_print_clb.
+ */
+const char *
+ly_type_print_union(const struct lyd_value *value, LY_PREFIX_FORMAT format, void *prefix_data, ly_bool *dynamic)
+{
+ return value->subvalue->value.realtype->plugin->print(&value->subvalue->value, format, prefix_data, dynamic);
+}
+
+/**
+ * @brief Duplication callback of the union values.
+ *
+ * Implementation of the ly_type_dup_clb.
+ */
+LY_ERR
+ly_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
+{
+ LY_CHECK_RET(lydict_insert(ctx, original->canonical, strlen(original->canonical), &dup->canonical));
+
+ dup->subvalue = calloc(1, sizeof *dup->subvalue);
+ LY_CHECK_ERR_RET(!dup->subvalue, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_RET(original->subvalue->value.realtype->plugin->duplicate(ctx, &original->subvalue->value, &dup->subvalue->value));
+
+ LY_CHECK_RET(lydict_insert(ctx, original->subvalue->original, strlen(original->subvalue->original),
+ &dup->subvalue->original));
+ dup->subvalue->format = original->subvalue->format;
+ LY_CHECK_RET(ly_type_prefix_data_dup(ctx, original->subvalue->format, original->subvalue->prefix_data,
+ &dup->subvalue->prefix_data));
+
+ dup->realtype = original->realtype;
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Free value of the YANG built-in union type.
+ *
+ * Implementation of the ly_type_free_clb.
+ */
+void
+ly_type_free_union(const struct ly_ctx *ctx, struct lyd_value *value)
+{
+ lydict_remove(ctx, value->canonical);
+ if (value->subvalue) {
+ if (value->subvalue->value.realtype) {
+ value->subvalue->value.realtype->plugin->free(ctx, &value->subvalue->value);
+ }
+ ly_type_prefix_data_free(value->subvalue->format, value->subvalue->prefix_data);
+ lydict_remove(ctx, value->subvalue->original);
+ free(value->subvalue);
+ value->subvalue = NULL;
+ }
+}