blob: b30dd98405220639664297cde36f07a7608c8763 [file] [log] [blame]
/**
* @file tree_data_helpers.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief Parsing and validation helper functions for data trees
*
* Copyright (c) 2015 - 2018 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
*/
#include "common.h"
#include <assert.h>
#include <stdlib.h>
#include "log.h"
#include "dict.h"
#include "plugins_types.h"
#include "tree_data.h"
#include "tree_schema.h"
struct lyd_node **
lyd_node_children_p(struct lyd_node *node)
{
assert(node);
switch (node->schema->nodetype) {
case LYS_CONTAINER:
case LYS_LIST:
return &((struct lyd_node_inner*)node)->child;
default:
return NULL;
}
}
API const struct lyd_node *
lyd_node_children(const struct lyd_node *node)
{
struct lyd_node **children;
if (!node) {
return NULL;
}
children = lyd_node_children_p((struct lyd_node*)node);
if (children) {
return *children;
} else {
return NULL;
}
}
LY_ERR
lyd_parse_check_options(struct ly_ctx *ctx, int options, const char *func)
{
int x = options & LYD_OPT_TYPEMASK;
/* LYD_OPT_WHENAUTODEL can be used only with LYD_OPT_DATA or LYD_OPT_CONFIG */
if (options & LYD_OPT_WHENAUTODEL) {
if ((x == LYD_OPT_EDIT) || (x == LYD_OPT_NOTIF_FILTER)) {
LOGERR(ctx, LY_EINVAL, "%s: Invalid options 0x%x (LYD_OPT_DATA_WHENAUTODEL can be used only with LYD_OPT_DATA or LYD_OPT_CONFIG)",
func, options);
return LY_EINVAL;
}
}
if (options & (LYD_OPT_DATA_ADD_YANGLIB | LYD_OPT_DATA_NO_YANGLIB)) {
if (x != LYD_OPT_DATA) {
LOGERR(ctx, LY_EINVAL, "%s: Invalid options 0x%x (LYD_OPT_DATA_*_YANGLIB can be used only with LYD_OPT_DATA)",
func, options);
return LY_EINVAL;
}
}
/* "is power of 2" algorithm, with 0 exception */
if (x && !(x && !(x & (x - 1)))) {
LOGERR(ctx, LY_EINVAL, "%s: Invalid options 0x%x (multiple data type flags set).", func, options);
return LY_EINVAL;
}
return LY_SUCCESS;
}
LY_ERR
lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int dynamic,
ly_type_resolve_prefix get_prefix, void *parser, struct lyd_node **trees)
{
LY_ERR ret = LY_SUCCESS, rc;
struct ly_err_item *err = NULL;
struct ly_ctx *ctx;
struct lysc_type *type;
void *priv = NULL;
int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE |
(dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
assert(node);
ctx = node->schema->module->ctx;
type = ((struct lysc_node_leaf*)node->schema)->type;
if (type->plugin->validate) {
rc = type->plugin->validate(ctx, type, value, value_len, options,
get_prefix, parser, (struct lyd_node*)node, trees,
&node->value.canonized, &err, &priv);
if (rc == LY_EINCOMPLETE) {
ret = rc;
/* continue with storing, just remember what to return if storing is ok */
} else if (rc) {
ret = rc;
if (err) {
ly_err_print(err);
LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
ly_err_free(err);
}
goto error;
}
} else if (dynamic) {
node->value.canonized = lydict_insert_zc(ctx, (char*)value);
} else {
node->value.canonized = lydict_insert(ctx, value, value_len);
}
if (type->plugin->store) {
rc = type->plugin->store(ctx, type, options, &node->value, &err, &priv);
if (rc) {
ret = rc;
if (err) {
ly_err_print(err);
LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
ly_err_free(err);
}
goto error;
}
}
error:
return ret;
}