types FEATURE support for integer built-in types in data
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 389a8db..21aaf3e 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -236,7 +236,7 @@
value_len = 0;
}
ret = lyd_value_validate((struct lyd_node_term*)cur, value, value_len,
- LY_TYPE_VALIDATE_CANONIZE | (dynamic ? LY_TYPE_VALIDATE_DYNAMIC : 0));
+ LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_CANONIZE | (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | LY_TYPE_OPTS_STORE);
LY_CHECK_GOTO(ret, cleanup);
} else if (snode->nodetype & LYD_NODE_INNER) {
int dynamic = 0;
diff --git a/src/plugins_types.c b/src/plugins_types.c
index c8ea09f..e81f879 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -14,6 +14,7 @@
#include "common.h"
#include <ctype.h>
+#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
@@ -24,6 +25,90 @@
#include "tree_schema.h"
API LY_ERR
+parse_int(const char *datatype, int base, int64_t min, int64_t max, const char *value, size_t value_len, int64_t *ret, struct ly_err_item **err)
+{
+ char *errmsg = NULL;
+ char *strptr = NULL;
+ int64_t i;
+
+ LY_CHECK_ARG_RET(NULL, err, datatype, LY_EINVAL);
+ if (!value || !value[0] || !value_len) {
+ asprintf(&errmsg, "Invalid empty %s value.", datatype);
+ goto error;
+ }
+
+ /* convert to 64-bit integer, all the redundant characters are handled */
+ errno = 0;
+
+ /* parse the value */
+ i = strtoll(value, &strptr, base);
+ if (errno || (i < min) || (i > max)) {
+ goto error;
+ } else if (strptr && *strptr && strptr < value + value_len) {
+ while (isspace(*strptr)) {
+ ++strptr;
+ }
+ if (*strptr && strptr < value + value_len) {
+ goto error;
+ }
+ }
+
+ if (ret) {
+ *ret = i;
+ }
+ return LY_SUCCESS;
+
+error:
+ if (!errmsg) {
+ asprintf(&errmsg, "Invalid %s value %.*s.", datatype, (int)value_len, value);
+ }
+ *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ return LY_EVALID;;
+}
+
+API LY_ERR
+parse_uint(const char *datatype, int base, uint64_t min, uint64_t max, const char *value, size_t value_len, uint64_t *ret, struct ly_err_item **err)
+{
+ char *errmsg = NULL;
+ char *strptr = NULL;
+ uint64_t u;
+
+ LY_CHECK_ARG_RET(NULL, err, datatype, LY_EINVAL);
+ if (!value || !value[0] || !value_len) {
+ asprintf(&errmsg, "Invalid empty %s value.", datatype);
+ goto error;
+ }
+
+ *err = NULL;
+ errno = 0;
+ u = strtoull(value, &strptr, base);
+ if (errno || (u < min) || (u > max)) {
+ goto error;
+ } else if (strptr && *strptr && strptr < value + value_len) {
+ while (isspace(*strptr)) {
+ ++strptr;
+ }
+ if (*strptr && strptr < value + value_len) {
+ goto error;
+ }
+ } else if (u != 0 && value[0] == '-') {
+ goto error;
+ }
+
+ if (ret) {
+ *ret = u;
+ }
+ return LY_SUCCESS;
+
+error:
+ if (!errmsg) {
+ asprintf(&errmsg, "Invalid %s value %.*s.", datatype, (int)value_len, value);
+ }
+ *err = ly_err_new(LY_LLERR, LY_EINVAL, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ return LY_EVALID;;
+}
+
+API LY_ERR
ly_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, struct ly_err_item **err)
{
unsigned int u;
@@ -37,8 +122,8 @@
errmsg = strdup(range->emsg);
} else {
asprintf(&errmsg, "%s \"%"PRIu64"\" does not satisfy the %s constraint.",
- (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "Length" : "Value", (uint64_t)value,
- (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "length" : "range");
+ (basetype == LY_TYPE_BINARY || basetype == LY_TYPE_STRING) ? "Length" : "Value", (uint64_t)value,
+ (basetype == LY_TYPE_BINARY || basetype == LY_TYPE_STRING) ? "length" : "range");
}
goto error;
} else if ((uint64_t)value <= range->parts[u].max_u64) {
@@ -50,8 +135,8 @@
errmsg = strdup(range->emsg);
} else {
asprintf(&errmsg, "%s \"%"PRIu64"\" does not satisfy the %s constraint.",
- (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "Length" : "Value", (uint64_t)value,
- (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "length" : "range");
+ (basetype == LY_TYPE_BINARY || basetype == LY_TYPE_STRING) ? "Length" : "Value", (uint64_t)value,
+ (basetype == LY_TYPE_BINARY || basetype == LY_TYPE_STRING) ? "length" : "range");
}
goto error;
}
@@ -86,6 +171,164 @@
return LY_EVALID;
}
+static LY_ERR
+ly_type_parse_int_builtin(LY_DATA_TYPE basetype, const char *value, size_t value_len, int options, int64_t *val, struct ly_err_item **err)
+{
+ switch (basetype) {
+ case LY_TYPE_INT8:
+ return parse_int("int16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, __INT64_C(-128), __INT64_C(127), value, value_len, val, err);
+ case LY_TYPE_INT16:
+ return parse_int("int16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, __INT64_C(-32768), __INT64_C(32767), value, value_len, val, err);
+ case LY_TYPE_INT32:
+ return parse_int("int32", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10,
+ __INT64_C(-2147483648), __INT64_C(2147483647), value, value_len, val, err);
+ case LY_TYPE_INT64:
+ return parse_int("int64", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10,
+ __INT64_C(-9223372036854775807) - __INT64_C(1), __INT64_C(9223372036854775807), value, value_len, val, err);
+ default:
+ LOGINT(NULL);
+ return LY_EINVAL;
+ }
+}
+/**
+ * @brief Validate and canonize value of the YANG built-in signed integer types.
+ *
+ * Implementation of the ly_type_validate_clb.
+ */
+static LY_ERR
+ly_type_validate_int(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ const char **canonized, struct ly_err_item **err, void **priv)
+{
+ int64_t i;
+ struct lysc_type_num *type_num = (struct lysc_type_num *)type;
+
+ LY_CHECK_RET(ly_type_parse_int_builtin(type->basetype, value, value_len, options, &i, err));
+
+ /* range of the number */
+ if (type_num->range) {
+ LY_CHECK_RET(ly_type_validate_range(type->basetype, type_num->range, i, err));
+ }
+
+ if (options & LY_TYPE_OPTS_CANONIZE) {
+ char *str;
+ asprintf(&str, "%"PRId64, i);
+ *canonized = lydict_insert_zc(ctx, str);
+ }
+ if (options & LY_TYPE_OPTS_DYNAMIC) {
+ free((char*)value);
+ }
+ if (options & LY_TYPE_OPTS_STORE) {
+ /* save for the store callback */
+ *priv = malloc(sizeof i);
+ *(int64_t*)(*priv) = i;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Store value of the YANG built-in signed integer types.
+ *
+ * Implementation of the ly_type_store_clb.
+ */
+static LY_ERR
+ly_type_store_int(struct ly_ctx *UNUSED(ctx), struct lysc_type *type, int options,
+ struct lyd_value *value, struct ly_err_item **err, void **priv)
+{
+ int64_t i;
+
+ if (options & LY_TYPE_OPTS_VALIDATE) {
+ /* the value was prepared by ly_type_validate_int() */
+ i = *(int64_t*)(*priv);
+ free(*priv);
+ } else {
+ LY_CHECK_RET(ly_type_parse_int_builtin(type->basetype, value->canonized, strlen(value->canonized), options, &i, err));
+ }
+
+ /* store the result */
+ value->int64 = i;
+
+ return LY_SUCCESS;
+}
+
+static LY_ERR
+ly_type_parse_uint_builtin(LY_DATA_TYPE basetype, const char *value, size_t value_len, int options, uint64_t *val, struct ly_err_item **err)
+{
+ switch (basetype) {
+ case LY_TYPE_UINT8:
+ return parse_uint("uint16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, 0, __UINT64_C(255), value, value_len, val, err);
+ case LY_TYPE_UINT16:
+ return parse_uint("uint16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, 0, __UINT64_C(65535), value, value_len, val, err);
+ case LY_TYPE_UINT32:
+ return parse_uint("uint32", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, 0, __UINT64_C(4294967295), value, value_len, val, err);
+ case LY_TYPE_UINT64:
+ return parse_uint("uint64", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, 0, __UINT64_C(18446744073709551615), value, value_len, val, err);
+ default:
+ LOGINT(NULL);
+ return LY_EINVAL;
+ }
+}
+/**
+ * @brief Validate and canonize value of the YANG built-in unsigned integer types.
+ *
+ * Implementation of the ly_type_validate_clb.
+ */
+static LY_ERR
+ly_type_validate_uint(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ const char **canonized, struct ly_err_item **err, void **priv)
+{
+ uint64_t u;
+ struct lysc_type_num* type_num = (struct lysc_type_num*)type;
+
+ LY_CHECK_RET(ly_type_parse_uint_builtin(type->basetype, value, value_len, options, &u, err));
+
+ /* range of the number */
+ if (type_num->range) {
+ LY_CHECK_RET(ly_type_validate_range(type->basetype, type_num->range, u, err));
+ }
+
+ if (options & LY_TYPE_OPTS_CANONIZE) {
+ char *str;
+ asprintf(&str, "%"PRIu64, u);
+ *canonized = lydict_insert_zc(ctx, str);
+ }
+ if (options & LY_TYPE_OPTS_DYNAMIC) {
+ free((char*)value);
+ }
+ if (options & LY_TYPE_OPTS_STORE) {
+ /* save for the store callback */
+ *priv = malloc(sizeof u);
+ *(uint64_t*)(*priv) = u;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Store value of the YANG built-in unsigned integer types.
+ *
+ * Implementation of the ly_type_store_clb.
+ */
+static LY_ERR
+ly_type_store_uint(struct ly_ctx *UNUSED(ctx), struct lysc_type *type, int options,
+ struct lyd_value *value, struct ly_err_item **err, void **priv)
+{
+ uint64_t u;
+
+ if (options & LY_TYPE_OPTS_VALIDATE) {
+ /* the value was prepared by ly_type_validate_uint() */
+ u = *(uint64_t*)(*priv);
+ free(*priv);
+ } else {
+ LY_CHECK_RET(ly_type_parse_uint_builtin(type->basetype, value->canonized, strlen(value->canonized), options, &u, err));
+ }
+
+ /* store the result */
+ value->uint64 = u;
+
+ return LY_SUCCESS;
+}
+
/**
* @brief Validate and canonize value of the YANG built-in binary type.
*
@@ -93,7 +336,7 @@
*/
static LY_ERR
ly_type_validate_binary(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- const char **canonized, struct ly_err_item **err)
+ const char **canonized, struct ly_err_item **err, void **UNUSED(priv))
{
size_t start = 0, stop = 0, count = 0, u, termination = 0;
struct lysc_type_bin *type_bin = (struct lysc_type_bin *)type;
@@ -155,17 +398,17 @@
LY_CHECK_RET(ly_type_validate_range(LY_TYPE_BINARY, type_bin->length, len, err));
}
- if (options & LY_TYPE_VALIDATE_CANONIZE) {
+ if (options & LY_TYPE_OPTS_CANONIZE) {
if (start != 0 || stop != value_len) {
*canonized = lydict_insert_zc(ctx, strndup(&value[start], stop + 1 - start));
- } else if (options & LY_TYPE_VALIDATE_DYNAMIC) {
+ } else if (options & LY_TYPE_OPTS_DYNAMIC) {
*canonized = lydict_insert_zc(ctx, (char*)value);
value = NULL;
} else {
*canonized = lydict_insert(ctx, value_len ? value : "", value_len);
}
}
- if (options & LY_TYPE_VALIDATE_DYNAMIC) {
+ if (options & LY_TYPE_OPTS_DYNAMIC) {
free((char*)value);
}
@@ -182,10 +425,10 @@
struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT] = {
{0}, /* LY_TYPE_UNKNOWN */
{.type = LY_TYPE_BINARY, .validate = ly_type_validate_binary, .store = NULL},
- {0}, /* TODO LY_TYPE_UINT8 */
- {0}, /* TODO LY_TYPE_UINT16 */
- {0}, /* TODO LY_TYPE_UINT32 */
- {0}, /* TODO LY_TYPE_UINT64 */
+ {.type = LY_TYPE_UINT8, .validate = ly_type_validate_uint, .store = ly_type_store_uint},
+ {.type = LY_TYPE_UINT16, .validate = ly_type_validate_uint, .store = ly_type_store_uint},
+ {.type = LY_TYPE_UINT32, .validate = ly_type_validate_uint, .store = ly_type_store_uint},
+ {.type = LY_TYPE_UINT64, .validate = ly_type_validate_uint, .store = ly_type_store_uint},
{0}, /* TODO LY_TYPE_STRING */
{0}, /* TODO LY_TYPE_BITS */
{0}, /* TODO LY_TYPE_BOOL */
@@ -196,9 +439,9 @@
{0}, /* TODO LY_TYPE_INST */
{0}, /* TODO LY_TYPE_LEAFREF */
{0}, /* TODO LY_TYPE_UNION */
- {0}, /* TODO LY_TYPE_INT8 */
- {0}, /* TODO LY_TYPE_INT16 */
- {0}, /* TODO LY_TYPE_INT32 */
- {0} /* TODO LY_TYPE_INT64 */
+ {.type = LY_TYPE_INT8, .validate = ly_type_validate_int, .store = ly_type_store_int},
+ {.type = LY_TYPE_INT16, .validate = ly_type_validate_int, .store = ly_type_store_int},
+ {.type = LY_TYPE_INT32, .validate = ly_type_validate_int, .store = ly_type_store_int},
+ {.type = LY_TYPE_INT64, .validate = ly_type_validate_int, .store = ly_type_store_int},
};
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 0a84f3c..c106b64 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -47,16 +47,20 @@
void ly_err_free(void *ptr);
/**
- * @defgroup plugintypevalidateopts Options for type plugin validation callback.
- * Options applicable to ly_type_validate_clb().
+ * @defgroup plugintypeopts Options for type plugin callbacks. The same set of the options is passed to all the type's callbacks used together.
+ *
+ * Options applicable to ly_type_validate_clb() and ly_typestore_clb.
* @{
*/
-#define LY_TYPE_VALIDATE_CANONIZE 0x01 /**< Canonize the given value and store it (insert into the context's dictionary)
+#define LY_TYPE_OPTS_VALIDATE 0x01 /**< Flag announcing calling of ly_type_validate_clb() of the type */
+#define LY_TYPE_OPTS_CANONIZE 0x02 /**< Canonize the given value and store it (insert into the context's dictionary)
as the value's canonized string */
-#define LY_TYPE_VALIDATE_DYNAMIC 0x02 /**< Flag for the dynamically allocated string value, in this case the value is supposed to be freed
- or directly used to insert into the node's value structure in case of canonization.
+#define LY_TYPE_OPTS_DYNAMIC 0x04 /**< Flag for the dynamically allocated string value, in this case the value is supposed to be freed
+ or directly inserted into the context's dictionary (e.g. in case of canonization).
In any case, the caller of the callback does not free the provided string value after calling
- the ly_type_validate_clb() with this option */
+ the type's callbacks with this option */
+#define LY_TYPE_OPTS_STORE 0x08 /**< Flag announcing calling of ly_type_store_clb() */
+#define LY_TYPE_OPTS_SCHEMA 0x10 /**< Flag for the value used in schema instead of the data tree */
/**
* @}
@@ -82,15 +86,16 @@
* @param[in] type Type of the value being canonized.
* @param[in] value Lexical representation of the value to be validated (and canonized).
* @param[in] value_len Length of the given \p value.
- * @param[in] options [Type validation options ](@ref plugintypevalidateopts).
+ * @param[in] options [Type plugin options ](@ref plugintypeopts).
* @param[out] canonized If LY_TYPE_VALIDATE_CANONIZE option set, the canonized string stored in the @p ctx dictionary is returned via this parameter.
* @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
* The error structure can be created by ly_err_new().
+ * @param[out] priv Type's private data passed between all the callbacks. The last callback is supposed to free the data allocated beforehand.
* @return LY_SUCCESS on success
* @return LY_ERR value if an error occurred and the value could not be canonized following the type's rules.
*/
typedef LY_ERR (*ly_type_validate_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
- const char **canonized, struct ly_err_item **err);
+ const char **canonized, struct ly_err_item **err, void **priv);
/**
* @brief Callback for storing user type values.
@@ -100,14 +105,16 @@
*
* @param[in] ctx libyang ctx to enable correct manipulation with values that are in the dictionary.
* @param[in] type Type of the value being stored.
- * @param[in] value_str Canonized string value to be stored.
- * @param[in,out] value Value structure to store the data in the type plugin specific way.
+ * @param[in] options [Type plugin options ](@ref plugintypeopts).
+ * @param[in,out] value Value structure to store the data in the type's specific way. The structure already contains canonized value string to be processed.
* @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
* The error structure can be created by ly_err_new().
+ * @param[out] priv Type's private data passed between all the callbacks. The last callback is supposed to free the data allocated beforehand.
* @return LY_SUCCESS on success
* @return LY_ERR value if an error occurred and the value could not be stored for any reason.
*/
-typedef LY_ERR (*ly_type_store_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value_str, struct lyd_value *value, struct ly_err_item **err);
+typedef LY_ERR (*ly_type_store_clb)(struct ly_ctx *ctx, struct lysc_type *type, int options,
+ struct lyd_value *value, struct ly_err_item **err, void **priv);
/**
* @brief Hold type-specific functions for various operations with the data values.
@@ -129,13 +136,46 @@
extern struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT];
/**
+ * @brief Unsigned integer value parser and validator.
+ *
+ * @param[in] datatype Type of the integer for logging.
+ * @param[in] base Base of the integer's lexical representation. In case of built-in types, data must be represented in decimal format (base 10),
+ * but default values in schemas can be represented also as hexadecimal or octal values (base 0).
+ * @param[in] min Lower bound of the type.
+ * @param[in] max Upper bound of the type.
+ * @param[in] value Value string to parse.
+ * @param[in] value_len Length of the @p value (mandatory parameter).
+ * @param[out] ret Parsed integer value (optional).
+ * @param[out] err Error information in case of failure. The error structure can be freed by ly_err_free().
+ * @return LY_ERR value according to the result of the parsing and validation.
+ */
+LY_ERR parse_int(const char *datatype, int base, int64_t min, int64_t max, const char *value, size_t value_len,
+ int64_t *ret, struct ly_err_item **err);
+
+/**
+ * @brief Unsigned integer value parser and validator.
+ *
+ * @param[in] datatype Type of the unsigned integer for logging.
+ * @param[in] base Base of the integer's lexical representation. In case of built-in types, data must be represented in decimal format (base 10),
+ * but default values in schemas can be represented also as hexadecimal or octal values (base 0).
+ * @param[in] min Lower bound of the type.
+ * @param[in] max Upper bound of the type.
+ * @param[in] value Value string to parse.
+ * @param[in] value_len Length of the @p value (mandatory parameter).
+ * @param[out] ret Parsed unsigned integer value (optional).
+ * @param[out] err Error information in case of failure. The error structure can be freed by ly_err_free().
+ * @return LY_ERR value according to the result of the parsing and validation.
+ */
+LY_ERR parse_uint(const char *datatype, int base, uint64_t min, uint64_t max, const char *value, size_t value_len,
+ uint64_t *ret, struct ly_err_item **err);
+
+/**
* @brief Data type validator for a range/length-restricted values.
*
- * @param[in] ctx libyang context
+ * @param[in] basetype Base built-in type of the type with the range specified to get know if the @p range structure represents range or length restriction.
* @param[in] range Range (length) restriction information.
* @param[in] value Value to check. In case of basetypes using unsigned integer values, the value is actually cast to uint64_t.
- * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
- * The error structure can be created by ly_err_new().
+ * @param[out] err Error information in case of failure. The error structure can be freed by ly_err_free().
* @return LY_ERR value according to the result of the validation.
*/
LY_ERR ly_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, struct ly_err_item **err);
diff --git a/src/tree_data.h b/src/tree_data.h
index 9fe0af6..933d0d2 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -187,7 +187,6 @@
void *ptr; /**< generic data type structure used to store the data */
}; /**< The union is just a list of shorthands to possible values stored by a type's plugin. libyang works only with the canonized string,
this specific data type storage is just to simplify use of the values by the libyang users. */
- LY_DATA_TYPE type; /**< type of the value in the node, mainly for union to avoid repeating of type detection */
};
/**
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index fc4bf1c..3f385a2 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -90,22 +90,35 @@
struct ly_err_item *err = NULL;
struct ly_ctx *ctx;
struct lysc_type *type;
+ void *priv = NULL;
assert(node);
ctx = node->schema->module->ctx;
type = ((struct lysc_node_leaf*)node->schema)->type;
if (type->plugin->validate) {
- ret = type->plugin->validate(ctx, type, value, value_len, options, &node->value.canonized, &err);
+ ret = type->plugin->validate(ctx, type, value, value_len, options, &node->value.canonized, &err, &priv);
if (ret) {
ly_err_print(err);
LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
ly_err_free(err);
+ goto error;
}
- } else if (options & LY_TYPE_VALIDATE_CANONIZE) {
+ } else if (options & LY_TYPE_OPTS_CANONIZE) {
node->value.canonized = lydict_insert(ctx, value, value_len);
}
+ if ((options & LY_TYPE_OPTS_STORE) && type->plugin->store) {
+ ret = type->plugin->store(ctx, type, options, &node->value, &err, &priv);
+ if (ret) {
+ ly_err_print(err);
+ LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
+ ly_err_free(err);
+ goto error;
+ }
+ }
+
+error:
return ret;
}
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index ba0729e..f6be23c 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -42,7 +42,7 @@
*
* According to the given options, the value can be also canonized or stored into the node's value structure.
*
- * @param[in] options [Type validation options ](@ref plugintypevalidateopts).
+ * @param[in] options [Type validation options ](@ref plugintypeopts).
*/
LY_ERR lyd_value_validate(struct lyd_node_term *node, const char *value, size_t value_len, int options);
diff --git a/tests/features/test_types.c b/tests/features/test_types.c
index 1f1119a..80f4cd5 100644
--- a/tests/features/test_types.c
+++ b/tests/features/test_types.c
@@ -58,7 +58,15 @@
struct state_s *s;
const char *schema_a = "module types {namespace urn:tests:types;prefix t;yang-version 1.1;"
"leaf binary {type binary {length 5 {error-message \"This bas64 value must be of length 5.\";}}}"
- "leaf binary-norestr {type binary;}}";
+ "leaf binary-norestr {type binary;}"
+ "leaf int8 {type int8 {range 10..20;}}"
+ "leaf uint8 {type uint8 {range 150..200;}}"
+ "leaf int16 {type int16 {range -20..-10;}}"
+ "leaf uint16 {type uint16 {range 150..200;}}"
+ "leaf int32 {type int32;}"
+ "leaf uint32 {type uint32;}"
+ "leaf int64 {type int64;}"
+ "leaf uint64 {type uint64;}}";;
s = calloc(1, sizeof *s);
assert_non_null(s);
@@ -105,6 +113,88 @@
#endif
static void
+test_int(void **state)
+{
+ struct state_s *s = (struct state_s*)(*state);
+ s->func = test_int;
+
+ struct lyd_node *tree;
+ struct lyd_node_term *leaf;
+
+ const char *data = "<int8 xmlns=\"urn:tests:types\">\n 15 \t\n </int8>";
+
+ /* valid data */
+ assert_non_null(tree = lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+ assert_int_equal(LYS_LEAF, tree->schema->nodetype);
+ assert_string_equal("int8", tree->schema->name);
+ leaf = (struct lyd_node_term*)tree;
+ assert_string_equal("15", leaf->value.canonized);
+ assert_int_equal(15, leaf->value.int8);
+ lyd_free_all(tree);
+
+ /* invalid range */
+ data = "<int8 xmlns=\"urn:tests:types\">1</int8>";
+ assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+ logbuf_assert("Value \"1\" does not satisfy the range constraint. /");
+
+ data = "<int16 xmlns=\"urn:tests:types\">100</int16>";
+ assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+ logbuf_assert("Value \"100\" does not satisfy the range constraint. /");
+
+ /* invalid value */
+ data = "<int32 xmlns=\"urn:tests:types\">0x01</int32>";
+ assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+ logbuf_assert("Invalid int32 value 0x01. /");
+
+ data = "<int64 xmlns=\"urn:tests:types\"></int64>";
+ assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+ logbuf_assert("Invalid empty int64 value. /");
+
+ s->func = NULL;
+}
+
+static void
+test_uint(void **state)
+{
+ struct state_s *s = (struct state_s*)(*state);
+ s->func = test_uint;
+
+ struct lyd_node *tree;
+ struct lyd_node_term *leaf;
+
+ const char *data = "<uint8 xmlns=\"urn:tests:types\">\n 150 \t\n </uint8>";
+
+ /* valid data */
+ assert_non_null(tree = lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+ assert_int_equal(LYS_LEAF, tree->schema->nodetype);
+ assert_string_equal("uint8", tree->schema->name);
+ leaf = (struct lyd_node_term*)tree;
+ assert_string_equal("150", leaf->value.canonized);
+ assert_int_equal(150, leaf->value.uint8);
+ lyd_free_all(tree);
+
+ /* invalid range */
+ data = "<uint8 xmlns=\"urn:tests:types\">\n 15 \t\n </uint8>";
+ assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+ logbuf_assert("Value \"15\" does not satisfy the range constraint. /");
+
+ data = "<uint16 xmlns=\"urn:tests:types\">\n 1500 \t\n </uint16>";
+ assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+ logbuf_assert("Value \"1500\" does not satisfy the range constraint. /");
+
+ /* invalid value */
+ data = "<uint32 xmlns=\"urn:tests:types\">-10</uint32>";
+ assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+ logbuf_assert("Invalid uint32 value -10. /");
+
+ data = "<uint64 xmlns=\"urn:tests:types\"/>";
+ assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+ logbuf_assert("Invalid empty uint64 value. /");
+
+ s->func = NULL;
+}
+
+static void
test_binary(void **state)
{
struct state_s *s = (struct state_s*)(*state);
@@ -179,6 +269,8 @@
int main(void)
{
const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_int, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_uint, setup, teardown),
cmocka_unit_test_setup_teardown(test_binary, setup, teardown),
};