blob: 7dfae9e62abf55cfd1b9cb05110e889002b2b9d2 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
Michal Vaskob1b5c262020-03-05 14:29:47 +01002 * @file tree_data.c
Radek Krejcie7b95092019-05-15 11:03:07 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Schema tree implementation
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Radek Krejci535ea9f2020-05-29 16:01:05 +020015#define _GNU_SOURCE
16
17#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020018
Radek Krejci084289f2019-07-09 17:35:30 +020019#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020020#include <ctype.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <stdarg.h>
24#include <stdint.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020025#include <stdio.h>
26#include <stdlib.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include <string.h>
28#include <unistd.h>
29
Radek Krejci535ea9f2020-05-29 16:01:05 +020030#include "common.h"
31#include "config.h"
32#include "context.h"
33#include "dict.h"
Michal Vasko90932a92020-02-12 14:33:03 +010034#include "hash_table.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020035#include "log.h"
Michal Vasko004d3152020-06-11 19:59:22 +020036#include "path.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020037#include "plugins_exts.h"
Radek Krejci38d85362019-09-05 16:26:38 +020038#include "plugins_exts_metadata.h"
Michal Vasko90932a92020-02-12 14:33:03 +010039#include "plugins_exts_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020040#include "plugins_types.h"
41#include "set.h"
42#include "tree.h"
43#include "tree_data_internal.h"
44#include "tree_schema.h"
45#include "tree_schema_internal.h"
46#include "xml.h"
47#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020048
Radek Krejci084289f2019-07-09 17:35:30 +020049LY_ERR
Michal Vasko90932a92020-02-12 14:33:03 +010050lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second,
Michal Vaskof03ed032020-03-04 13:31:44 +010051 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +020052{
Michal Vasko90932a92020-02-12 14:33:03 +010053 LY_ERR ret = LY_SUCCESS;
Radek Krejci084289f2019-07-09 17:35:30 +020054 struct ly_err_item *err = NULL;
55 struct ly_ctx *ctx;
56 struct lysc_type *type;
Radek Krejci3c9758d2019-07-11 16:49:10 +020057 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
Michal Vaskof03ed032020-03-04 13:31:44 +010058 (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +020059 assert(node);
60
61 ctx = node->schema->module->ctx;
Radek Krejci084289f2019-07-09 17:35:30 +020062
Radek Krejci73dead22019-07-11 16:46:16 +020063 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci62903c32019-07-15 14:42:05 +020064 if (!second) {
65 node->value.realtype = type;
66 }
Michal Vasko90932a92020-02-12 14:33:03 +010067 ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
Michal Vasko004d3152020-06-11 19:59:22 +020068 tree ? (void *)node : (void *)node->schema, tree, &node->value, NULL, &err);
Michal Vasko90932a92020-02-12 14:33:03 +010069 if (ret && (ret != LY_EINCOMPLETE)) {
Radek Krejci73dead22019-07-11 16:46:16 +020070 if (err) {
Michal Vasko3544d1e2020-05-27 11:17:51 +020071 /* node may not be connected yet so use the schema node */
Michal Vaskof872e202020-05-27 11:49:06 +020072 if (!node->parent && lysc_data_parent(node->schema)) {
73 LOGVAL(ctx, LY_VLOG_LYSC, node->schema, err->vecode, err->msg);
74 } else {
75 LOGVAL(ctx, LY_VLOG_LYD, node, err->vecode, err->msg);
76 }
Radek Krejci73dead22019-07-11 16:46:16 +020077 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +020078 }
Radek Krejci73dead22019-07-11 16:46:16 +020079 goto error;
Michal Vasko90932a92020-02-12 14:33:03 +010080 } else if (dynamic) {
81 *dynamic = 0;
Radek Krejci084289f2019-07-09 17:35:30 +020082 }
83
84error:
85 return ret;
86}
87
Michal Vasko00cbf532020-06-15 13:58:47 +020088/* similar to lyd_value_parse except can be used just to store the value, hence also does not support a second call */
Michal Vasko004d3152020-06-11 19:59:22 +020089LY_ERR
Michal Vasko90932a92020-02-12 14:33:03 +010090lyd_value_store(struct lyd_value *val, const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
91 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format)
92{
93 LY_ERR ret = LY_SUCCESS;
94 struct ly_err_item *err = NULL;
95 struct ly_ctx *ctx;
96 struct lysc_type *type;
97 int options = LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA | (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0);
98
99 assert(val && schema && (schema->nodetype & LYD_NODE_TERM));
100
101 ctx = schema->module->ctx;
102 type = ((struct lysc_node_leaf *)schema)->type;
103 val->realtype = type;
104 ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format, (void *)schema, NULL,
105 val, NULL, &err);
106 if (ret == LY_EINCOMPLETE) {
107 /* this is fine, we do not need it resolved */
108 ret = LY_SUCCESS;
109 } else if (ret && err) {
110 ly_err_print(err);
111 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
112 ly_err_free(err);
113 }
114 if (!ret && dynamic) {
115 *dynamic = 0;
116 }
117
118 return ret;
119}
120
Radek Krejci38d85362019-09-05 16:26:38 +0200121LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100122lyd_value_parse_meta(struct ly_ctx *ctx, struct lyd_meta *meta, const char *value, size_t value_len, int *dynamic,
Michal Vasko8d544252020-03-02 10:19:52 +0100123 int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
Michal Vaskof03ed032020-03-04 13:31:44 +0100124 const struct lysc_node *ctx_snode, const struct lyd_node *tree)
Radek Krejci38d85362019-09-05 16:26:38 +0200125{
Michal Vasko90932a92020-02-12 14:33:03 +0100126 LY_ERR ret = LY_SUCCESS;
Radek Krejci38d85362019-09-05 16:26:38 +0200127 struct ly_err_item *err = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200128 struct lyext_metadata *ant;
129 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
Michal Vaskof03ed032020-03-04 13:31:44 +0100130 (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci38d85362019-09-05 16:26:38 +0200131
Michal Vasko9f96a052020-03-10 09:41:45 +0100132 assert(ctx && meta && ((tree && meta->parent) || ctx_snode));
Michal Vasko8d544252020-03-02 10:19:52 +0100133
Michal Vasko9f96a052020-03-10 09:41:45 +0100134 ant = meta->annotation->data;
Radek Krejci38d85362019-09-05 16:26:38 +0200135
136 if (!second) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100137 meta->value.realtype = ant->type;
Radek Krejci38d85362019-09-05 16:26:38 +0200138 }
Michal Vasko90932a92020-02-12 14:33:03 +0100139 ret = ant->type->plugin->store(ctx, ant->type, value, value_len, options, get_prefix, parser, format,
Michal Vasko9f96a052020-03-10 09:41:45 +0100140 tree ? (void *)meta->parent : (void *)ctx_snode, tree, &meta->value, NULL, &err);
Michal Vasko90932a92020-02-12 14:33:03 +0100141 if (ret && (ret != LY_EINCOMPLETE)) {
Radek Krejci38d85362019-09-05 16:26:38 +0200142 if (err) {
143 ly_err_print(err);
144 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
145 ly_err_free(err);
146 }
147 goto error;
Michal Vasko90932a92020-02-12 14:33:03 +0100148 } else if (dynamic) {
149 *dynamic = 0;
Radek Krejci38d85362019-09-05 16:26:38 +0200150 }
151
152error:
153 return ret;
154}
155
Radek Krejci084289f2019-07-09 17:35:30 +0200156API LY_ERR
Michal Vasko44685da2020-03-17 15:38:06 +0100157lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
Radek Krejci084289f2019-07-09 17:35:30 +0200158 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format)
159{
160 LY_ERR rc = LY_SUCCESS;
161 struct ly_err_item *err = NULL;
162 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200163
164 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
165
166 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
167 LOGARG(ctx, node);
168 return LY_EINVAL;
169 }
170
171 type = ((struct lysc_node_leaf*)node)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200172 /* just validate, no storing of enything */
173 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, LY_TYPE_OPTS_INCOMPLETE_DATA,
174 get_prefix, get_prefix_data, format, node, NULL, NULL, NULL, &err);
175 if (rc == LY_EINCOMPLETE) {
176 /* actually success since we do not provide the context tree and call validation with
177 * LY_TYPE_OPTS_INCOMPLETE_DATA */
178 rc = LY_SUCCESS;
179 } else if (rc && err) {
180 if (ctx) {
181 /* log only in case the ctx was provided as input parameter */
182 ly_err_print(err);
183 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200184 }
Radek Krejci73dead22019-07-11 16:46:16 +0200185 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200186 }
187
188 return rc;
189}
190
191API LY_ERR
Michal Vasko44685da2020-03-17 15:38:06 +0100192lyd_value_validate(const struct ly_ctx *ctx, const struct lyd_node_term *node, const char *value, size_t value_len,
Michal Vaskof03ed032020-03-04 13:31:44 +0100193 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +0200194{
195 LY_ERR rc;
196 struct ly_err_item *err = NULL;
197 struct lysc_type *type;
Michal Vaskof03ed032020-03-04 13:31:44 +0100198 int options = (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200199
200 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
201
202 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200203 rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
Michal Vaskof03ed032020-03-04 13:31:44 +0100204 get_prefix, get_prefix_data, format, tree ? (void*)node : (void*)node->schema, tree,
Radek Krejci73dead22019-07-11 16:46:16 +0200205 NULL, NULL, &err);
206 if (rc == LY_EINCOMPLETE) {
207 return rc;
208 } else if (rc) {
209 if (err) {
210 if (ctx) {
211 ly_err_print(err);
212 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200213 }
Radek Krejci73dead22019-07-11 16:46:16 +0200214 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200215 }
Radek Krejci73dead22019-07-11 16:46:16 +0200216 return rc;
Radek Krejci084289f2019-07-09 17:35:30 +0200217 }
218
219 return LY_SUCCESS;
220}
221
222API LY_ERR
223lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
Michal Vaskof03ed032020-03-04 13:31:44 +0100224 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +0200225{
226 LY_ERR ret = LY_SUCCESS, rc;
227 struct ly_err_item *err = NULL;
228 struct ly_ctx *ctx;
229 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200230 struct lyd_value data = {0};
Michal Vaskof03ed032020-03-04 13:31:44 +0100231 int options = LY_TYPE_OPTS_STORE | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200232
233 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
234
235 ctx = node->schema->module->ctx;
236 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200237 rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, get_prefix_data, format, (struct lyd_node*)node,
Michal Vaskof03ed032020-03-04 13:31:44 +0100238 tree, &data, NULL, &err);
Radek Krejci73dead22019-07-11 16:46:16 +0200239 if (rc == LY_EINCOMPLETE) {
240 ret = rc;
241 /* continue with comparing, just remember what to return if storing is ok */
242 } else if (rc) {
243 /* value to compare is invalid */
244 ret = LY_EINVAL;
245 if (err) {
246 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200247 }
Radek Krejci73dead22019-07-11 16:46:16 +0200248 goto cleanup;
Radek Krejci084289f2019-07-09 17:35:30 +0200249 }
250
251 /* compare data */
Radek Krejci5af04842019-07-12 11:32:07 +0200252 if (type->plugin->compare(&node->value, &data)) {
253 /* do not assign it directly from the compare callback to keep possible LY_EINCOMPLETE from validation */
254 ret = LY_EVALID;
255 }
Radek Krejci084289f2019-07-09 17:35:30 +0200256
257cleanup:
Radek Krejci62903c32019-07-15 14:42:05 +0200258 type->plugin->free(ctx, &data);
Radek Krejci084289f2019-07-09 17:35:30 +0200259
260 return ret;
261}
262
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200263API const char *
264lyd_value2str(const struct lyd_node_term *node, int *dynamic)
265{
266 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, dynamic, NULL);
267
268 return node->value.realtype->plugin->print(&node->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
269}
270
271API const char *
Michal Vasko9f96a052020-03-10 09:41:45 +0100272lyd_meta2str(const struct lyd_meta *meta, int *dynamic)
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200273{
Michal Vasko9f96a052020-03-10 09:41:45 +0100274 LY_CHECK_ARG_RET(meta ? meta->parent->schema->module->ctx : NULL, meta, dynamic, NULL);
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200275
Michal Vasko9f96a052020-03-10 09:41:45 +0100276 return meta->value.realtype->plugin->print(&meta->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200277}
278
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200279API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100280lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200281{
Radek Krejcie7b95092019-05-15 11:03:07 +0200282 struct lyd_node *result = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200283#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200284 const char *yang_data_name = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200285#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200286
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200287 LY_CHECK_ARG_RET(ctx, ctx, NULL);
288
Michal Vasko5b37a352020-03-06 13:38:33 +0100289 if ((options & LYD_OPT_PARSE_ONLY) && (options & LYD_VALOPT_MASK)) {
290 LOGERR(ctx, LY_EINVAL, "Passing validation flags with LYD_OPT_PARSE_ONLY is not allowed.");
291 return NULL;
292 }
293
Michal Vaskoa3881362020-01-21 15:57:35 +0100294#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200295 if (options & LYD_OPT_RPCREPLY) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200296 /* first item in trees is mandatory - the RPC/action request */
297 LY_CHECK_ARG_RET(ctx, trees, LY_ARRAY_SIZE(trees) >= 1, NULL);
298 if (!trees[0] || trees[0]->parent || !(trees[0]->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
299 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
300 lyd_parse_options_type2str(options));
Radek Krejcie7b95092019-05-15 11:03:07 +0200301 return NULL;
302 }
303 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200304
Radek Krejcie7b95092019-05-15 11:03:07 +0200305 if (options & LYD_OPT_DATA_TEMPLATE) {
306 yang_data_name = va_arg(ap, const char *);
307 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200308#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200309
310 if (!format) {
311 /* TODO try to detect format from the content */
312 }
313
314 switch (format) {
315 case LYD_XML:
Michal Vasko9f96a052020-03-10 09:41:45 +0100316 lyd_parse_xml_data(ctx, data, options, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200317 break;
318#if 0
319 case LYD_JSON:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200320 lyd_parse_json(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200321 break;
322 case LYD_LYB:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200323 lyd_parse_lyb(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200324 break;
325#endif
Michal Vasko52927e22020-03-16 17:26:14 +0100326 case LYD_SCHEMA:
Radek Krejcie7b95092019-05-15 11:03:07 +0200327 LOGINT(ctx);
328 break;
329 }
330
Radek Krejcie7b95092019-05-15 11:03:07 +0200331 return result;
332}
333
334API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100335lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200336{
337 struct lyd_node *result;
338 size_t length;
339 char *addr;
340
341 LY_CHECK_ARG_RET(ctx, ctx, NULL);
342 if (fd < 0) {
343 LOGARG(ctx, fd);
344 return NULL;
345 }
346
347 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
Michal Vaskoa3881362020-01-21 15:57:35 +0100348 result = lyd_parse_mem(ctx, addr ? addr : "", format, options);
Radek Krejcidf3da792019-05-17 10:32:24 +0200349 if (addr) {
350 ly_munmap(addr, length);
351 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200352
353 return result;
354}
355
356API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100357lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200358{
359 int fd;
360 struct lyd_node *result;
361 size_t len;
Radek Krejcie7b95092019-05-15 11:03:07 +0200362
363 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
364
365 fd = open(path, O_RDONLY);
366 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
367
368 if (!format) {
369 /* unknown format - try to detect it from filename's suffix */
370 len = strlen(path);
371
372 /* ignore trailing whitespaces */
373 for (; len > 0 && isspace(path[len - 1]); len--);
374
375 if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
376 format = LYD_XML;
377#if 0
378 } else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
379 format = LYD_JSON;
380 } else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
381 format = LYD_LYB;
382#endif
383 } /* else still unknown, try later to detect it from the content */
384 }
385
Michal Vaskoa3881362020-01-21 15:57:35 +0100386 result = lyd_parse_fd(ctx, fd, format, options);
Radek Krejcie7b95092019-05-15 11:03:07 +0200387 close(fd);
388
389 return result;
390}
Radek Krejci084289f2019-07-09 17:35:30 +0200391
Michal Vasko90932a92020-02-12 14:33:03 +0100392LY_ERR
393lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
394 ly_clb_resolve_prefix get_prefix, void *prefix_data, LYD_FORMAT format, struct lyd_node **node)
395{
396 LY_ERR ret;
397 struct lyd_node_term *term;
398
Michal Vasko9b368d32020-02-14 13:53:31 +0100399 assert(schema->nodetype & LYD_NODE_TERM);
400
Michal Vasko90932a92020-02-12 14:33:03 +0100401 term = calloc(1, sizeof *term);
402 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
403
404 term->schema = schema;
405 term->prev = (struct lyd_node *)term;
Michal Vasko9b368d32020-02-14 13:53:31 +0100406 term->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100407
408 ret = lyd_value_parse(term, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
409 if (ret && (ret != LY_EINCOMPLETE)) {
410 free(term);
411 return ret;
412 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100413 lyd_hash((struct lyd_node *)term);
414
415 *node = (struct lyd_node *)term;
416 return ret;
417}
418
419LY_ERR
420lyd_create_term2(const struct lysc_node *schema, const struct lyd_value *val, struct lyd_node **node)
421{
422 LY_ERR ret;
423 struct lyd_node_term *term;
424 struct lysc_type *type;
425
426 assert(schema->nodetype & LYD_NODE_TERM);
Michal Vasko00cbf532020-06-15 13:58:47 +0200427 assert(val && val->realtype);
Michal Vasko9b368d32020-02-14 13:53:31 +0100428
429 term = calloc(1, sizeof *term);
430 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
431
432 term->schema = schema;
433 term->prev = (struct lyd_node *)term;
434 term->flags = LYD_NEW;
435
436 type = ((struct lysc_node_leaf *)schema)->type;
437 ret = type->plugin->duplicate(schema->module->ctx, val, &term->value);
438 if (ret) {
439 LOGERR(schema->module->ctx, ret, "Value duplication failed.");
440 free(term);
441 return ret;
442 }
Michal Vasko00cbf532020-06-15 13:58:47 +0200443 term->value.realtype = val->realtype;
Michal Vasko9b368d32020-02-14 13:53:31 +0100444 lyd_hash((struct lyd_node *)term);
Michal Vasko90932a92020-02-12 14:33:03 +0100445
446 *node = (struct lyd_node *)term;
447 return ret;
448}
449
450LY_ERR
451lyd_create_inner(const struct lysc_node *schema, struct lyd_node **node)
452{
453 struct lyd_node_inner *in;
454
Michal Vasko9b368d32020-02-14 13:53:31 +0100455 assert(schema->nodetype & LYD_NODE_INNER);
456
Michal Vasko90932a92020-02-12 14:33:03 +0100457 in = calloc(1, sizeof *in);
458 LY_CHECK_ERR_RET(!in, LOGMEM(schema->module->ctx), LY_EMEM);
459
460 in->schema = schema;
461 in->prev = (struct lyd_node *)in;
Michal Vasko9b368d32020-02-14 13:53:31 +0100462 in->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100463
Michal Vasko9b368d32020-02-14 13:53:31 +0100464 /* do not hash list with keys, we need them for the hash */
465 if ((schema->nodetype != LYS_LIST) || (schema->flags & LYS_KEYLESS)) {
466 lyd_hash((struct lyd_node *)in);
467 }
Michal Vasko90932a92020-02-12 14:33:03 +0100468
469 *node = (struct lyd_node *)in;
470 return LY_SUCCESS;
471}
472
Michal Vasko90932a92020-02-12 14:33:03 +0100473LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +0200474lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate *predicates, struct lyd_node **node)
Michal Vasko90932a92020-02-12 14:33:03 +0100475{
476 LY_ERR ret = LY_SUCCESS;
Michal Vasko90932a92020-02-12 14:33:03 +0100477 struct lyd_node *list = NULL, *key;
Michal Vasko004d3152020-06-11 19:59:22 +0200478 LY_ARRAY_SIZE_TYPE u;
Michal Vasko90932a92020-02-12 14:33:03 +0100479
Michal Vasko004d3152020-06-11 19:59:22 +0200480 assert((schema->nodetype == LYS_LIST) && !(schema->flags & LYS_KEYLESS));
Michal Vasko90932a92020-02-12 14:33:03 +0100481
482 /* create list */
483 LY_CHECK_GOTO(ret = lyd_create_inner(schema, &list), cleanup);
484
Michal Vasko90932a92020-02-12 14:33:03 +0100485 /* create and insert all the keys */
Michal Vasko004d3152020-06-11 19:59:22 +0200486 LY_ARRAY_FOR(predicates, u) {
487 LY_CHECK_GOTO(ret = lyd_create_term2(predicates[u].key, &predicates[u].value, &key), cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100488 lyd_insert_node(list, NULL, key);
489 }
490
Michal Vasko9b368d32020-02-14 13:53:31 +0100491 /* hash having all the keys */
492 lyd_hash(list);
493
Michal Vasko90932a92020-02-12 14:33:03 +0100494 /* success */
495 *node = list;
496 list = NULL;
497
498cleanup:
499 lyd_free_tree(list);
Michal Vasko004d3152020-06-11 19:59:22 +0200500 return ret;
501}
502
503static LY_ERR
504lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_len, struct lyd_node **node)
505{
506 LY_ERR ret = LY_SUCCESS;
507 struct lyxp_expr *expr = NULL;
508 uint16_t exp_idx = 0;
509 enum ly_path_pred_type pred_type = 0;
510 struct ly_path_predicate *predicates = NULL;
511
512 /* parse keys */
513 LY_CHECK_GOTO(ret = ly_path_parse_predicate(schema->module->ctx, keys, keys_len, LY_PATH_PREFIX_OPTIONAL,
514 LY_PATH_PRED_KEYS, &expr), cleanup);
515
516 /* compile them */
Michal Vasko00cbf532020-06-15 13:58:47 +0200517 LY_CHECK_GOTO(ret = ly_path_compile_predicate(schema->module->ctx, NULL, schema, expr, &exp_idx, lydjson_resolve_prefix,
518 NULL, LYD_JSON, &predicates, &pred_type), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200519
520 /* create the list node */
521 LY_CHECK_GOTO(ret = lyd_create_list(schema, predicates, node), cleanup);
522
523cleanup:
524 lyxp_expr_free(schema->module->ctx, expr);
525 ly_path_predicates_free(schema->module->ctx, pred_type, NULL, predicates);
Michal Vasko90932a92020-02-12 14:33:03 +0100526 return ret;
527}
528
529LY_ERR
530lyd_create_any(const struct lysc_node *schema, const void *value, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
531{
532 struct lyd_node_any *any;
533
Michal Vasko9b368d32020-02-14 13:53:31 +0100534 assert(schema->nodetype & LYD_NODE_ANY);
535
Michal Vasko90932a92020-02-12 14:33:03 +0100536 any = calloc(1, sizeof *any);
537 LY_CHECK_ERR_RET(!any, LOGMEM(schema->module->ctx), LY_EMEM);
538
539 any->schema = schema;
540 any->prev = (struct lyd_node *)any;
Michal Vasko9b368d32020-02-14 13:53:31 +0100541 any->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100542
543 any->value.xml = value;
544 any->value_type = value_type;
Michal Vasko9b368d32020-02-14 13:53:31 +0100545 lyd_hash((struct lyd_node *)any);
Michal Vasko90932a92020-02-12 14:33:03 +0100546
547 *node = (struct lyd_node *)any;
548 return LY_SUCCESS;
549}
550
Michal Vasko52927e22020-03-16 17:26:14 +0100551LY_ERR
552lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *value, size_t value_len,
553 int *dynamic, LYD_FORMAT format, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
554 const char *ns, struct lyd_node **node)
555{
556 struct lyd_node_opaq *opaq;
557
558 assert(ctx && name && name_len && ns);
559
560 if (!value_len) {
561 value = "";
562 }
563
564 opaq = calloc(1, sizeof *opaq);
565 LY_CHECK_ERR_RET(!opaq, LOGMEM(ctx), LY_EMEM);
566
567 opaq->prev = (struct lyd_node *)opaq;
568
569 opaq->name = lydict_insert(ctx, name, name_len);
570 opaq->format = format;
571 if (pref_len) {
572 opaq->prefix.pref = lydict_insert(ctx, prefix, pref_len);
573 }
574 opaq->prefix.ns = lydict_insert(ctx, ns, 0);
575 opaq->val_prefs = val_prefs;
576 if (dynamic && *dynamic) {
577 opaq->value = lydict_insert_zc(ctx, (char *)value);
578 *dynamic = 0;
579 } else {
580 opaq->value = lydict_insert(ctx, value, value_len);
581 }
582 opaq->ctx = ctx;
583
584 *node = (struct lyd_node *)opaq;
585 return LY_SUCCESS;
586}
587
Michal Vasko013a8182020-03-03 10:46:53 +0100588API struct lyd_node *
589lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name)
590{
591 struct lyd_node *ret = NULL;
592 const struct lysc_node *schema;
593 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
594
595 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
596
Michal Vaskof03ed032020-03-04 13:31:44 +0100597 if (!module) {
598 module = parent->schema->module;
599 }
600
Michal Vasko1bf09392020-03-27 12:38:10 +0100601 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_CONTAINER | LYS_NOTIF | LYS_RPC | LYS_ACTION, 0);
Michal Vaskob00f3cf2020-05-27 11:20:13 +0200602 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Inner node (and not a list) \"%s\" not found.", name), NULL);
Michal Vasko013a8182020-03-03 10:46:53 +0100603
604 if (!lyd_create_inner(schema, &ret) && parent) {
605 lyd_insert_node(parent, NULL, ret);
606 }
607 return ret;
608}
609
610API struct lyd_node *
611lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, ...)
612{
613 struct lyd_node *ret = NULL, *key;
614 const struct lysc_node *schema, *key_s;
615 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
616 va_list ap;
617 const char *key_val;
618 LY_ERR rc = LY_SUCCESS;
619
620 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
621
Michal Vaskof03ed032020-03-04 13:31:44 +0100622 if (!module) {
623 module = parent->schema->module;
624 }
625
Michal Vasko013a8182020-03-03 10:46:53 +0100626 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
627 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
628
629 /* create list inner node */
630 LY_CHECK_RET(lyd_create_inner(schema, &ret), NULL);
631
632 va_start(ap, name);
633
634 /* create and insert all the keys */
635 for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
636 key_val = va_arg(ap, const char *);
637
Michal Vaskof03ed032020-03-04 13:31:44 +0100638 rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key);
Michal Vaskocbff3e92020-05-27 12:56:41 +0200639 LY_CHECK_GOTO(rc && (rc != LY_EINCOMPLETE), cleanup);
640 rc = LY_SUCCESS;
Michal Vasko013a8182020-03-03 10:46:53 +0100641 lyd_insert_node(ret, NULL, key);
642 }
643
644 /* hash having all the keys */
645 lyd_hash(ret);
646
647 if (parent) {
648 lyd_insert_node(parent, NULL, ret);
649 }
650
651cleanup:
652 if (rc) {
653 lyd_free_tree(ret);
654 ret = NULL;
655 }
656 va_end(ap);
657 return ret;
658}
659
660API struct lyd_node *
661lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys)
662{
663 struct lyd_node *ret = NULL;
664 const struct lysc_node *schema;
665 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
666
667 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
668
Michal Vaskof03ed032020-03-04 13:31:44 +0100669 if (!module) {
670 module = parent->schema->module;
671 }
Michal Vasko004d3152020-06-11 19:59:22 +0200672 if (!keys) {
673 keys = "";
674 }
Michal Vaskof03ed032020-03-04 13:31:44 +0100675
Michal Vasko004d3152020-06-11 19:59:22 +0200676 /* find schema node */
Michal Vasko013a8182020-03-03 10:46:53 +0100677 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
678 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
679
Michal Vasko004d3152020-06-11 19:59:22 +0200680 if ((schema->flags & LYS_KEYLESS) && !keys[0]) {
681 /* key-less list */
682 LY_CHECK_RET(lyd_create_inner(schema, &ret), NULL);
683 } else {
684 /* create the list node */
685 LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret), NULL);
686 }
687
688 if (parent) {
Michal Vasko013a8182020-03-03 10:46:53 +0100689 lyd_insert_node(parent, NULL, ret);
690 }
691 return ret;
692}
693
694API struct lyd_node *
695lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
696{
Michal Vaskocbff3e92020-05-27 12:56:41 +0200697 LY_ERR rc;
Michal Vasko013a8182020-03-03 10:46:53 +0100698 struct lyd_node *ret = NULL;
699 const struct lysc_node *schema;
700 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
701
702 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
703
Michal Vaskof03ed032020-03-04 13:31:44 +0100704 if (!module) {
705 module = parent->schema->module;
706 }
707
Michal Vasko013a8182020-03-03 10:46:53 +0100708 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, 0);
709 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), NULL);
710
Michal Vaskocbff3e92020-05-27 12:56:41 +0200711 rc = lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &ret);
712 LY_CHECK_RET(rc && (rc != LY_EINCOMPLETE), NULL);
713
714 if (parent) {
Michal Vasko013a8182020-03-03 10:46:53 +0100715 lyd_insert_node(parent, NULL, ret);
716 }
717 return ret;
718}
719
720API struct lyd_node *
721lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
722 LYD_ANYDATA_VALUETYPE value_type)
723{
724 struct lyd_node *ret = NULL;
725 const struct lysc_node *schema;
726 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
727
728 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
729
Michal Vaskof03ed032020-03-04 13:31:44 +0100730 if (!module) {
731 module = parent->schema->module;
732 }
733
Michal Vasko013a8182020-03-03 10:46:53 +0100734 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, 0);
735 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Any node \"%s\" not found.", name), NULL);
736
737 if (!lyd_create_any(schema, value, value_type, &ret) && parent) {
738 lyd_insert_node(parent, NULL, ret);
739 }
740 return ret;
741}
742
Michal Vasko4490d312020-06-16 13:08:55 +0200743/**
744 * @brief Update node value.
745 *
746 * @param[in] node Node to update.
747 * @param[in] value New value to set.
748 * @param[in] value_type Type of @p value for any node.
749 * @param[out] new_parent Set to @p node if the value was updated, otherwise set to NULL.
750 * @param[out] new_node Set to @p node if the value was updated, otherwise set to NULL.
751 * @return LY_ERR value.
752 */
Michal Vasko00cbf532020-06-15 13:58:47 +0200753static LY_ERR
754lyd_new_path_update(struct lyd_node *node, const void *value, LYD_ANYDATA_VALUETYPE value_type,
755 struct lyd_node **new_parent, struct lyd_node **new_node)
756{
757 LY_ERR ret = LY_SUCCESS;
758 struct lyd_node *new_any;
759
760 switch (node->schema->nodetype) {
761 case LYS_CONTAINER:
762 case LYS_NOTIF:
763 case LYS_RPC:
764 case LYS_ACTION:
765 case LYS_LIST:
766 case LYS_LEAFLIST:
767 /* if it exists, there is nothing to update */
768 *new_parent = NULL;
769 *new_node = NULL;
770 break;
771 case LYS_LEAF:
772 ret = lyd_change_term(node, value);
773 if ((ret == LY_SUCCESS) || (ret == LY_EEXIST)) {
774 /* there was an actual change (at least of the default flag) */
775 *new_parent = node;
776 *new_node = node;
777 ret = LY_SUCCESS;
778 } else if (ret == LY_ENOT) {
779 /* no change */
780 *new_parent = NULL;
781 *new_node = NULL;
782 ret = LY_SUCCESS;
783 } /* else error */
784 break;
785 case LYS_ANYDATA:
786 case LYS_ANYXML:
787 /* create a new any node */
788 LY_CHECK_RET(lyd_create_any(node->schema, value, value_type, &new_any));
789
790 /* compare with the existing one */
791 if (lyd_compare(node, new_any, 0)) {
792 /* not equal, switch values (so that we can use generic node free) */
793 ((struct lyd_node_any *)new_any)->value = ((struct lyd_node_any *)node)->value;
794 ((struct lyd_node_any *)new_any)->value_type = ((struct lyd_node_any *)node)->value_type;
795 ((struct lyd_node_any *)node)->value.str = value;
796 ((struct lyd_node_any *)node)->value_type = value_type;
797
798 *new_parent = node;
799 *new_node = node;
800 } else {
801 /* they are equal */
802 *new_parent = NULL;
803 *new_node = NULL;
804 }
805 lyd_free_tree(new_any);
806 break;
807 default:
808 LOGINT(LYD_NODE_CTX(node));
809 ret = LY_EINT;
810 break;
811 }
812
813 return ret;
814}
815
Michal Vaskod86997b2020-05-26 15:19:54 +0200816API struct lyd_meta *
817lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
818{
819 struct lyd_meta *ret = NULL;
Michal Vasko00cbf532020-06-15 13:58:47 +0200820 const struct ly_ctx *ctx;
Michal Vaskod86997b2020-05-26 15:19:54 +0200821 const char *prefix, *tmp;
822 char *str;
823 size_t pref_len, name_len;
824
Michal Vasko00cbf532020-06-15 13:58:47 +0200825 LY_CHECK_ARG_RET(NULL, parent, name, module || strchr(name, ':'), NULL);
826
827 ctx = LYD_NODE_CTX(parent);
Michal Vaskod86997b2020-05-26 15:19:54 +0200828
829 /* parse the name */
830 tmp = name;
831 if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
832 LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
833 return NULL;
834 }
835
836 /* find the module */
837 if (prefix) {
838 str = strndup(name, name_len);
839 module = ly_ctx_get_module_implemented(ctx, str);
840 free(str);
Michal Vasko004d3152020-06-11 19:59:22 +0200841 LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%.*s\" not found.", pref_len, prefix), NULL);
Michal Vaskod86997b2020-05-26 15:19:54 +0200842 }
843
844 /* set value if none */
845 if (!val_str) {
846 val_str = "";
847 }
848
849 lyd_create_meta(parent, &ret, module, name, name_len, val_str, strlen(val_str), NULL, lydjson_resolve_prefix, NULL,
850 LYD_JSON, parent->schema);
851 return ret;
852}
853
Michal Vasko00cbf532020-06-15 13:58:47 +0200854API struct lyd_node *
855lyd_new_opaq(struct lyd_node *parent, const struct ly_ctx *ctx, const char *name, const char *value,
856 const char *module_name)
857{
858 struct lyd_node *ret = NULL;
859
860 LY_CHECK_ARG_RET(ctx, parent || ctx, name, module_name, NULL);
861
862 if (!ctx) {
863 ctx = LYD_NODE_CTX(parent);
864 }
865 if (!value) {
866 value = "";
867 }
868
869 if (!lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), NULL, LYD_JSON, NULL, NULL, 0, module_name, &ret)
870 && parent) {
871 lyd_insert_node(parent, NULL, ret);
872 }
873 return ret;
874}
875
876API struct ly_attr *
877lyd_new_attr(struct lyd_node *parent, const char *module_name, const char *name, const char *val_str)
878{
879 struct ly_attr *ret = NULL;
880 const struct ly_ctx *ctx;
881 const char *prefix, *tmp;
882 size_t pref_len, name_len;
883
884 LY_CHECK_ARG_RET(NULL, parent, !parent->schema, name, NULL);
885
886 ctx = LYD_NODE_CTX(parent);
887
888 /* parse the name */
889 tmp = name;
890 if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
891 LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
892 return NULL;
893 }
894
895 /* set value if none */
896 if (!val_str) {
897 val_str = "";
898 }
899
900 ly_create_attr(parent, &ret, ctx, name, name_len, val_str, strlen(val_str), NULL, LYD_JSON, NULL, prefix,
901 pref_len, module_name);
902 return ret;
903}
904
905API LY_ERR
906lyd_change_term(struct lyd_node *term, const char *val_str)
907{
908 LY_ERR ret = LY_SUCCESS;
909 struct lysc_type *type;
910 struct lyd_node_term *t;
911 struct lyd_node *parent;
912 struct lyd_value val = {0};
913 int dflt_change, val_change;
914
915 LY_CHECK_ARG_RET(NULL, term, term->schema, term->schema->nodetype & LYD_NODE_TERM, LY_EINVAL);
916
917 if (!val_str) {
918 val_str = "";
919 }
920 t = (struct lyd_node_term *)term;
921 type = ((struct lysc_node_leaf *)term->schema)->type;
922
923 /* parse the new value */
924 LY_CHECK_GOTO(ret = lyd_value_store(&val, term->schema, val_str, strlen(val_str), NULL, lydjson_resolve_prefix, NULL,
925 LYD_JSON), cleanup);
926
927 /* compare original and new value */
928 if (type->plugin->compare(&t->value, &val)) {
929 /* values differ, switch them */
930 type->plugin->free(LYD_NODE_CTX(term), &t->value);
931 t->value = val;
932 memset(&val, 0, sizeof val);
933 val_change = 1;
934 } else {
935 val_change = 0;
936 }
937
938 /* always clear the default flag */
939 if (term->flags & LYD_DEFAULT) {
940 for (parent = term; parent; parent = (struct lyd_node *)parent->parent) {
941 parent->flags &= ~LYD_DEFAULT;
942 }
943 dflt_change = 1;
944 } else {
945 dflt_change = 0;
946 }
947
948 if (val_change || dflt_change) {
949 /* make the node non-validated */
950 term->flags &= LYD_NEW;
951 }
952
953 if (val_change) {
954 if (term->schema->nodetype == LYS_LEAFLIST) {
955 /* leaf-list needs to be hashed again and re-inserted into parent */
956 lyd_unlink_hash(term);
957 lyd_hash(term);
958 LY_CHECK_GOTO(ret = lyd_insert_hash(term), cleanup);
959 } else if ((term->schema->flags & LYS_KEY) && term->parent) {
960 /* list needs to be updated if its key was changed */
961 assert(term->parent->schema->nodetype == LYS_LIST);
962 lyd_unlink_hash((struct lyd_node *)term->parent);
963 lyd_hash((struct lyd_node *)term->parent);
964 LY_CHECK_GOTO(ret = lyd_insert_hash((struct lyd_node *)term->parent), cleanup);
965 } /* else leaf that is not a key, its value is not used for its hash so it does not change */
966 }
967
968 /* retrun value */
969 if (!val_change) {
970 if (dflt_change) {
971 /* only default flag change */
972 ret = LY_EEXIST;
973 } else {
974 /* no change */
975 ret = LY_ENOT;
976 }
977 } /* else value changed, LY_SUCCESS */
978
979cleanup:
980 type->plugin->free(LYD_NODE_CTX(term), &val);
981 return ret;
982}
983
984API struct lyd_node *
985lyd_new_path(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const char *value, int options)
986{
Michal Vaskoa8f9eb32020-06-16 13:07:12 +0200987 struct lyd_node *new_parent = NULL;
Michal Vasko00cbf532020-06-15 13:58:47 +0200988
Michal Vaskoa8f9eb32020-06-16 13:07:12 +0200989 lyd_new_path2(parent, ctx, path, value, 0, options, &new_parent, NULL);
990 return new_parent;
Michal Vasko00cbf532020-06-15 13:58:47 +0200991}
992
993API struct lyd_node *
994lyd_new_path_any(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const void *value,
995 LYD_ANYDATA_VALUETYPE value_type, int options)
996{
Michal Vaskoa8f9eb32020-06-16 13:07:12 +0200997 struct lyd_node *new_parent = NULL;
Michal Vasko00cbf532020-06-15 13:58:47 +0200998
Michal Vaskoa8f9eb32020-06-16 13:07:12 +0200999 lyd_new_path2(parent, ctx, path, value, value_type, options, &new_parent, NULL);
1000 return new_parent;
Michal Vasko00cbf532020-06-15 13:58:47 +02001001}
1002
1003API LY_ERR
1004lyd_new_path2(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const void *value,
1005 LYD_ANYDATA_VALUETYPE value_type, int options, struct lyd_node **new_parent, struct lyd_node **new_node)
1006{
1007 LY_ERR ret = LY_SUCCESS, r;
1008 struct lyxp_expr *exp = NULL;
1009 struct ly_path *p = NULL;
1010 struct lyd_node *nparent = NULL, *nnode = NULL, *node = NULL, *cur_parent;
1011 const struct lysc_node *schema;
1012 LY_ARRAY_SIZE_TYPE path_idx = 0;
1013 struct ly_path_predicate *pred;
1014
1015 LY_CHECK_ARG_RET(ctx, parent || ctx, path, (path[0] == '/') || parent, LY_EINVAL);
1016
1017 if (!ctx) {
1018 ctx = LYD_NODE_CTX(parent);
1019 }
1020
1021 /* parse path */
1022 LY_CHECK_GOTO(ret = ly_path_parse(ctx, path, strlen(path), LY_PATH_BEGIN_EITHER, LY_PATH_LREF_FALSE,
1023 LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &exp), cleanup);
1024
1025 /* compile path */
1026 LY_CHECK_GOTO(ret = ly_path_compile(ctx, NULL, parent ? parent->schema : NULL, exp, LY_PATH_LREF_FALSE,
1027 options & LYD_NEWOPT_OUTPUT ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT,
1028 LY_PATH_TARGET_MANY, lydjson_resolve_prefix, NULL, LYD_JSON, &p), cleanup);
1029
1030 schema = p[LY_ARRAY_SIZE(p) - 1].node;
1031 if ((schema->nodetype == LYS_LIST) && (p[LY_ARRAY_SIZE(p) - 1].pred_type == LY_PATH_PREDTYPE_NONE)
1032 && !(options & LYD_NEWOPT_OPAQ)) {
1033 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
1034 lys_nodetype2str(schema->nodetype), schema->name);
1035 ret = LY_EINVAL;
1036 goto cleanup;
1037 } else if ((schema->nodetype == LYS_LEAFLIST) && (p[LY_ARRAY_SIZE(p) - 1].pred_type == LY_PATH_PREDTYPE_NONE)) {
1038 /* parse leafref value into a predicate, if not defined in the path */
1039 p[LY_ARRAY_SIZE(p) - 1].pred_type = LY_PATH_PREDTYPE_LEAFLIST;
1040 LY_ARRAY_NEW_GOTO(ctx, p[LY_ARRAY_SIZE(p) - 1].predicates, pred, ret, cleanup);
1041
1042 if (!value) {
1043 value = "";
1044 }
1045
1046 r = LY_SUCCESS;
1047 if (options & LYD_NEWOPT_OPAQ) {
1048 r = lys_value_validate(NULL, schema, value, strlen(value), lydjson_resolve_prefix, NULL, LYD_JSON);
1049 }
1050 if (!r) {
1051 LY_CHECK_GOTO(ret = lyd_value_store(&pred->value, schema, value, strlen(value), NULL, lydjson_resolve_prefix,
1052 NULL, LYD_JSON), cleanup);
1053 } /* else we have opaq flag and the value is not valid, leavne no predicate and then create an opaque node */
1054 }
1055
1056 /* try to find any existing nodes in the path */
1057 if (parent) {
1058 ret = ly_path_eval_partial(p, parent, &path_idx, &node);
1059 if (ret == LY_SUCCESS) {
1060 /* the node exists, are we supposed to update it or is it just a default? */
1061 if (!(options & LYD_NEWOPT_UPDATE) && !(node->flags & LYD_DEFAULT)) {
1062 LOGERR(ctx, LY_EEXIST, "Path \"%s\" already exists", path);
1063 ret = LY_EEXIST;
1064 goto cleanup;
1065 }
1066
1067 /* update the existing node */
1068 ret = lyd_new_path_update(node, value, value_type, &nparent, &nnode);
1069 goto cleanup;
1070 } else if (ret == LY_EINCOMPLETE) {
1071 /* some nodes were found, adjust the iterator to the next segment */
1072 ++path_idx;
1073 } else if (ret == LY_ENOTFOUND) {
1074 /* we will create the nodes from top-level, default behavior (absolute path), or from the parent (relative path) */
1075 if (lysc_data_parent(p[LY_ARRAY_SIZE(p) - 1].node)) {
1076 node = parent;
1077 }
1078 } else {
1079 /* error */
1080 goto cleanup;
1081 }
1082 }
1083
1084 /* create all the non-existing nodes in a loop */
1085 for (; path_idx < LY_ARRAY_SIZE(p); ++path_idx) {
1086 cur_parent = node;
1087 schema = p[path_idx].node;
1088
1089 switch (schema->nodetype) {
1090 case LYS_LIST:
1091 if (!(schema->flags & LYS_KEYLESS)) {
1092 if ((options & LYD_NEWOPT_OPAQ) && (p[path_idx].pred_type == LY_PATH_PREDTYPE_NONE)) {
1093 /* creating opaque list without keys */
1094 LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL,
1095 LYD_JSON, NULL, NULL, 0, schema->module->name, &node), cleanup);
1096 } else {
1097 assert(p[path_idx].pred_type == LY_PATH_PREDTYPE_LIST);
1098 LY_CHECK_GOTO(ret = lyd_create_list(schema, p[path_idx].predicates, &node), cleanup);
1099 }
1100 break;
1101 }
1102 /* fallthrough */
1103 case LYS_CONTAINER:
1104 case LYS_NOTIF:
1105 case LYS_RPC:
1106 case LYS_ACTION:
1107 LY_CHECK_GOTO(ret = lyd_create_inner(schema, &node), cleanup);
1108 break;
1109 case LYS_LEAFLIST:
1110 if ((options & LYD_NEWOPT_OPAQ) && (p[path_idx].pred_type == LY_PATH_PREDTYPE_NONE)) {
1111 /* creating opaque leaf-list without value */
1112 LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL,
1113 LYD_JSON, NULL, NULL, 0, schema->module->name, &node), cleanup);
1114 } else {
1115 assert(p[path_idx].pred_type == LY_PATH_PREDTYPE_LEAFLIST);
1116 LY_CHECK_GOTO(ret = lyd_create_term2(schema, &p[path_idx].predicates[0].value, &node), cleanup);
1117 }
1118 break;
1119 case LYS_LEAF:
1120 /* make there is some value */
1121 if (!value) {
1122 value = "";
1123 }
1124
1125 r = LY_SUCCESS;
1126 if (options & LYD_NEWOPT_OPAQ) {
1127 r = lys_value_validate(NULL, schema, value, strlen(value), lydjson_resolve_prefix, NULL, LYD_JSON);
1128 }
1129 if (!r) {
1130 LY_CHECK_GOTO(ret = lyd_create_term(schema, value, strlen(value), NULL, lydjson_resolve_prefix, NULL,
1131 LYD_JSON, &node), cleanup);
1132 } else {
1133 /* creating opaque leaf without value */
1134 LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL,
1135 LYD_JSON, NULL, NULL, 0, schema->module->name, &node), cleanup);
1136 }
1137 break;
1138 case LYS_ANYDATA:
1139 case LYS_ANYXML:
1140 LY_CHECK_GOTO(ret = lyd_create_any(schema, value, value_type, &node), cleanup);
1141 break;
1142 default:
1143 LOGINT(ctx);
1144 ret = LY_EINT;
1145 goto cleanup;
1146 }
1147
1148 if (cur_parent) {
1149 /* connect to the parent */
1150 lyd_insert_node(cur_parent, NULL, node);
1151 } else if (parent) {
1152 /* connect to top-level siblings */
1153 lyd_insert_node(NULL, &parent, node);
1154 }
1155
1156 /* update remembered nodes */
1157 if (!nparent) {
1158 nparent = node;
1159 }
1160 nnode = node;
1161 }
1162
1163cleanup:
1164 lyxp_expr_free(ctx, exp);
1165 ly_path_free(ctx, p);
1166 if (!ret) {
1167 /* set out params only on success */
1168 if (new_parent) {
1169 *new_parent = nparent;
1170 }
1171 if (new_node) {
1172 *new_node = nnode;
1173 }
1174 }
1175 return ret;
1176}
1177
Michal Vasko90932a92020-02-12 14:33:03 +01001178struct lyd_node *
1179lyd_get_prev_key_anchor(const struct lyd_node *first_sibling, const struct lysc_node *new_key)
1180{
1181 const struct lysc_node *prev_key;
1182 struct lyd_node *match = NULL;
1183
1184 if (!first_sibling) {
1185 return NULL;
1186 }
1187
1188 for (prev_key = new_key->prev; !match && prev_key->next; prev_key = prev_key->prev) {
1189 lyd_find_sibling_val(first_sibling, prev_key, NULL, 0, &match);
1190 }
1191
1192 return match;
1193}
1194
1195/**
1196 * @brief Insert node after a sibling.
1197 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001198 * Handles inserting into NP containers and key-less lists.
1199 *
Michal Vasko90932a92020-02-12 14:33:03 +01001200 * @param[in] sibling Sibling to insert after.
1201 * @param[in] node Node to insert.
1202 */
1203static void
Michal Vaskof03ed032020-03-04 13:31:44 +01001204lyd_insert_after_node(struct lyd_node *sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +01001205{
Michal Vasko0249f7c2020-03-05 16:36:40 +01001206 struct lyd_node_inner *par;
1207
Michal Vasko90932a92020-02-12 14:33:03 +01001208 assert(!node->next && (node->prev == node));
1209
1210 node->next = sibling->next;
1211 node->prev = sibling;
1212 sibling->next = node;
1213 if (node->next) {
1214 /* sibling had a succeeding node */
1215 node->next->prev = node;
1216 } else {
1217 /* sibling was last, find first sibling and change its prev */
1218 if (sibling->parent) {
1219 sibling = sibling->parent->child;
1220 } else {
1221 for (; sibling->prev->next != node; sibling = sibling->prev);
1222 }
1223 sibling->prev = node;
1224 }
1225 node->parent = sibling->parent;
Michal Vasko0249f7c2020-03-05 16:36:40 +01001226
Michal Vasko9f96a052020-03-10 09:41:45 +01001227 for (par = node->parent; par; par = par->parent) {
1228 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
1229 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +01001230 par->flags &= ~LYD_DEFAULT;
1231 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001232 if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
1233 /* rehash key-less list */
1234 lyd_hash((struct lyd_node *)par);
1235 }
Michal Vasko0249f7c2020-03-05 16:36:40 +01001236 }
1237
1238 /* insert into hash table */
1239 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +01001240}
1241
1242/**
1243 * @brief Insert node before a sibling.
1244 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001245 * Handles inserting into NP containers and key-less lists.
1246 *
Michal Vasko90932a92020-02-12 14:33:03 +01001247 * @param[in] sibling Sibling to insert before.
1248 * @param[in] node Node to insert.
1249 */
1250static void
Michal Vaskof03ed032020-03-04 13:31:44 +01001251lyd_insert_before_node(struct lyd_node *sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +01001252{
Michal Vasko0249f7c2020-03-05 16:36:40 +01001253 struct lyd_node_inner *par;
1254
Michal Vasko90932a92020-02-12 14:33:03 +01001255 assert(!node->next && (node->prev == node));
1256
1257 node->next = sibling;
1258 /* covers situation of sibling being first */
1259 node->prev = sibling->prev;
1260 sibling->prev = node;
1261 if (node->prev->next) {
1262 /* sibling had a preceding node */
1263 node->prev->next = node;
1264 } else if (sibling->parent) {
1265 /* sibling was first and we must also change parent child pointer */
1266 sibling->parent->child = node;
1267 }
1268 node->parent = sibling->parent;
Michal Vasko0249f7c2020-03-05 16:36:40 +01001269
Michal Vasko9f96a052020-03-10 09:41:45 +01001270 for (par = node->parent; par; par = par->parent) {
1271 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
1272 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +01001273 par->flags &= ~LYD_DEFAULT;
1274 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001275 if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
1276 /* rehash key-less list */
1277 lyd_hash((struct lyd_node *)par);
1278 }
Michal Vasko0249f7c2020-03-05 16:36:40 +01001279 }
1280
1281 /* insert into hash table */
1282 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +01001283}
1284
1285/**
1286 * @brief Insert node as the last child of a parent.
1287 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001288 * Handles inserting into NP containers and key-less lists.
1289 *
Michal Vasko90932a92020-02-12 14:33:03 +01001290 * @param[in] parent Parent to insert into.
1291 * @param[in] node Node to insert.
1292 */
1293static void
Michal Vaskof03ed032020-03-04 13:31:44 +01001294lyd_insert_last_node(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +01001295{
1296 struct lyd_node_inner *par;
1297
Michal Vasko0249f7c2020-03-05 16:36:40 +01001298 assert(parent && !node->next && (node->prev == node));
Michal Vasko52927e22020-03-16 17:26:14 +01001299 assert(!parent->schema || (parent->schema->nodetype & LYD_NODE_INNER));
Michal Vasko90932a92020-02-12 14:33:03 +01001300
1301 par = (struct lyd_node_inner *)parent;
1302
1303 if (!par->child) {
1304 par->child = node;
1305 } else {
1306 node->prev = par->child->prev;
1307 par->child->prev->next = node;
1308 par->child->prev = node;
1309 }
1310 node->parent = par;
Michal Vasko0249f7c2020-03-05 16:36:40 +01001311
Michal Vasko9f96a052020-03-10 09:41:45 +01001312 for (; par; par = par->parent) {
1313 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
1314 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +01001315 par->flags &= ~LYD_DEFAULT;
1316 }
Michal Vasko52927e22020-03-16 17:26:14 +01001317 if (par->schema && (par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001318 /* rehash key-less list */
1319 lyd_hash((struct lyd_node *)par);
1320 }
Michal Vasko0249f7c2020-03-05 16:36:40 +01001321 }
1322
1323 /* insert into hash table */
1324 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +01001325}
1326
1327void
Michal Vasko9b368d32020-02-14 13:53:31 +01001328lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +01001329{
Michal Vasko9b368d32020-02-14 13:53:31 +01001330 struct lyd_node *anchor;
Michal Vasko9f96a052020-03-10 09:41:45 +01001331 const struct lysc_node *skey = NULL;
1332 int has_keys;
Michal Vasko90932a92020-02-12 14:33:03 +01001333
Michal Vasko52927e22020-03-16 17:26:14 +01001334 assert((parent || first_sibling) && node && (node->hash || !node->schema));
Michal Vasko9b368d32020-02-14 13:53:31 +01001335
1336 if (!parent && first_sibling && (*first_sibling) && (*first_sibling)->parent) {
1337 parent = (struct lyd_node *)(*first_sibling)->parent;
1338 }
Michal Vasko90932a92020-02-12 14:33:03 +01001339
1340 if (parent) {
Michal Vasko52927e22020-03-16 17:26:14 +01001341 if (node->schema && (node->schema->flags & LYS_KEY)) {
Michal Vasko90932a92020-02-12 14:33:03 +01001342 /* it is key and we need to insert it at the correct place */
Michal Vasko9b368d32020-02-14 13:53:31 +01001343 anchor = lyd_get_prev_key_anchor(lyd_node_children(parent), node->schema);
1344 if (anchor) {
Michal Vaskof03ed032020-03-04 13:31:44 +01001345 lyd_insert_after_node(anchor, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001346 } else if (lyd_node_children(parent)) {
Radek Krejcidae0ee82020-05-06 16:53:24 +02001347 lyd_insert_before_node(lyd_node_children(parent), node);
Michal Vasko90932a92020-02-12 14:33:03 +01001348 } else {
Michal Vaskof03ed032020-03-04 13:31:44 +01001349 lyd_insert_last_node(parent, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001350 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001351
1352 /* hash list if all its keys were added */
1353 assert(parent->schema->nodetype == LYS_LIST);
Radek Krejcidae0ee82020-05-06 16:53:24 +02001354 anchor = lyd_node_children(parent);
Michal Vasko9f96a052020-03-10 09:41:45 +01001355 has_keys = 1;
1356 while ((skey = lys_getnext(skey, parent->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
1357 if (!anchor || (anchor->schema != skey)) {
1358 /* key missing */
1359 has_keys = 0;
1360 break;
1361 }
1362
1363 anchor = anchor->next;
1364 }
1365 if (has_keys) {
1366 lyd_hash(parent);
1367 }
1368
Michal Vasko90932a92020-02-12 14:33:03 +01001369 } else {
1370 /* last child */
Michal Vaskof03ed032020-03-04 13:31:44 +01001371 lyd_insert_last_node(parent, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001372 }
Michal Vasko9b368d32020-02-14 13:53:31 +01001373 } else if (*first_sibling) {
Michal Vaskob1b5c262020-03-05 14:29:47 +01001374 /* top-level siblings */
Michal Vasko9b368d32020-02-14 13:53:31 +01001375 anchor = (*first_sibling)->prev;
Michal Vaskoc193ce92020-03-06 11:04:48 +01001376 while (anchor->prev->next && (lyd_owner_module(anchor) != lyd_owner_module(node))) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001377 anchor = anchor->prev;
1378 }
1379
Michal Vaskoc193ce92020-03-06 11:04:48 +01001380 if (lyd_owner_module(anchor) == lyd_owner_module(node)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +01001381 /* insert after last sibling from this module */
1382 lyd_insert_after_node(anchor, node);
1383 } else {
1384 /* no data from this module, insert at the last position */
1385 lyd_insert_after_node((*first_sibling)->prev, node);
1386 }
Michal Vasko90932a92020-02-12 14:33:03 +01001387 } else {
Michal Vasko9b368d32020-02-14 13:53:31 +01001388 /* the only sibling */
1389 *first_sibling = node;
Michal Vasko90932a92020-02-12 14:33:03 +01001390 }
Michal Vasko90932a92020-02-12 14:33:03 +01001391}
1392
Michal Vaskof03ed032020-03-04 13:31:44 +01001393static LY_ERR
1394lyd_insert_check_schema(const struct lysc_node *parent, const struct lysc_node *schema)
1395{
1396 const struct lysc_node *par2;
1397
1398 assert(schema);
Michal Vasko62ed12d2020-05-21 10:08:25 +02001399 assert(!parent || !(parent->nodetype & (LYS_CASE | LYS_CHOICE)));
Michal Vaskof03ed032020-03-04 13:31:44 +01001400
1401 /* find schema parent */
Michal Vasko62ed12d2020-05-21 10:08:25 +02001402 par2 = lysc_data_parent(schema);
Michal Vaskof03ed032020-03-04 13:31:44 +01001403
1404 if (parent) {
1405 /* inner node */
1406 if (par2 != parent) {
1407 LOGERR(parent->module->ctx, LY_EINVAL, "Cannot insert, parent of \"%s\" is not \"%s\".", schema->name, parent->name);
1408 return LY_EINVAL;
1409 }
1410 } else {
1411 /* top-level node */
1412 if (par2) {
1413 LOGERR(parent->module->ctx, LY_EINVAL, "Cannot insert, node \"%s\" is not top-level.", schema->name);
1414 return LY_EINVAL;
1415 }
1416 }
1417
1418 return LY_SUCCESS;
1419}
1420
1421API LY_ERR
1422lyd_insert(struct lyd_node *parent, struct lyd_node *node)
1423{
1424 struct lyd_node *iter;
1425
1426 LY_CHECK_ARG_RET(NULL, parent, node, !(parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
1427
1428 LY_CHECK_RET(lyd_insert_check_schema(parent->schema, node->schema));
1429
1430 if (node->schema->flags & LYS_KEY) {
1431 LOGERR(parent->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1432 return LY_EINVAL;
1433 }
1434
1435 if (node->parent || node->prev->next) {
1436 lyd_unlink_tree(node);
1437 }
1438
1439 while (node) {
1440 iter = node->next;
1441 lyd_unlink_tree(node);
1442 lyd_insert_node(parent, NULL, node);
1443 node = iter;
1444 }
1445 return LY_SUCCESS;
1446}
1447
1448API LY_ERR
Michal Vaskob1b5c262020-03-05 14:29:47 +01001449lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node)
1450{
1451 struct lyd_node *iter;
1452
1453 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1454
Michal Vasko62ed12d2020-05-21 10:08:25 +02001455 LY_CHECK_RET(lyd_insert_check_schema(lysc_data_parent(sibling->schema), node->schema));
Michal Vaskob1b5c262020-03-05 14:29:47 +01001456
1457 if (node->schema->flags & LYS_KEY) {
1458 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1459 return LY_EINVAL;
1460 }
1461
1462 if (node->parent || node->prev->next) {
1463 lyd_unlink_tree(node);
1464 }
1465
1466 while (node) {
1467 iter = node->next;
1468 lyd_unlink_tree(node);
1469 lyd_insert_node(NULL, &sibling, node);
1470 node = iter;
1471 }
1472 return LY_SUCCESS;
1473}
1474
Michal Vasko0249f7c2020-03-05 16:36:40 +01001475static LY_ERR
1476lyd_insert_after_check_place(struct lyd_node *anchor, struct lyd_node *sibling, struct lyd_node *node)
1477{
1478 if (sibling->parent) {
1479 /* nested, we do not care for the order */
1480 return LY_SUCCESS;
1481 }
1482
1483 if (anchor) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001484 if (anchor->next && (lyd_owner_module(anchor) == lyd_owner_module(anchor->next))
1485 && (lyd_owner_module(node) != lyd_owner_module(anchor))) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001486 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert top-level module \"%s\" data into module \"%s\" data.",
Michal Vaskoc193ce92020-03-06 11:04:48 +01001487 lyd_owner_module(node)->name, lyd_owner_module(anchor)->name);
Michal Vasko0249f7c2020-03-05 16:36:40 +01001488 return LY_EINVAL;
1489 }
1490
Michal Vaskoc193ce92020-03-06 11:04:48 +01001491 if ((lyd_owner_module(node) == lyd_owner_module(anchor))
1492 || (anchor->next && (lyd_owner_module(node) == lyd_owner_module(anchor->next)))) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001493 /* inserting before/after its module data */
1494 return LY_SUCCESS;
1495 }
1496 }
1497
1498 /* find first sibling */
1499 while (sibling->prev->next) {
1500 sibling = sibling->prev;
1501 }
1502
1503 if (!anchor) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001504 if (lyd_owner_module(node) == lyd_owner_module(sibling)) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001505 /* inserting before its module data */
1506 return LY_SUCCESS;
1507 }
1508 }
1509
1510 /* check there are no data of this module */
1511 LY_LIST_FOR(sibling, sibling) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001512 if (lyd_owner_module(node) == lyd_owner_module(sibling)) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001513 /* some data of this module found */
1514 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Top-level data of module \"%s\" already exist,"
Michal Vaskoc193ce92020-03-06 11:04:48 +01001515 " they must be directly connected.", lyd_owner_module(node)->name);
Michal Vasko0249f7c2020-03-05 16:36:40 +01001516 return LY_EINVAL;
1517 }
1518 }
1519
1520 return LY_SUCCESS;
1521}
1522
Michal Vaskob1b5c262020-03-05 14:29:47 +01001523API LY_ERR
Michal Vaskof03ed032020-03-04 13:31:44 +01001524lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
1525{
1526 struct lyd_node *iter;
1527
1528 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1529
Michal Vasko62ed12d2020-05-21 10:08:25 +02001530 LY_CHECK_RET(lyd_insert_check_schema(lysc_data_parent(sibling->schema), node->schema));
Michal Vaskof03ed032020-03-04 13:31:44 +01001531
1532 if (node->schema->flags & LYS_KEY) {
1533 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1534 return LY_EINVAL;
1535 } else if (sibling->schema->flags & LYS_KEY) {
1536 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert into keys.");
1537 return LY_EINVAL;
1538 }
1539
Michal Vasko0249f7c2020-03-05 16:36:40 +01001540 LY_CHECK_RET(lyd_insert_after_check_place(sibling->prev->next ? sibling->prev : NULL, sibling, node));
1541
Michal Vaskof03ed032020-03-04 13:31:44 +01001542 if (node->parent || node->prev->next) {
1543 lyd_unlink_tree(node);
1544 }
1545
1546 /* insert in reverse order to get the original order */
1547 node = node->prev;
1548 while (node) {
1549 iter = node->prev;
1550 lyd_unlink_tree(node);
1551
1552 lyd_insert_before_node(sibling, node);
1553 /* move the anchor accordingly */
1554 sibling = node;
1555
1556 node = (iter == node) ? NULL : iter;
1557 }
1558 return LY_SUCCESS;
1559}
1560
1561API LY_ERR
1562lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
1563{
1564 struct lyd_node *iter;
1565
1566 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1567
Michal Vasko62ed12d2020-05-21 10:08:25 +02001568 LY_CHECK_RET(lyd_insert_check_schema(lysc_data_parent(sibling->schema), node->schema));
Michal Vaskof03ed032020-03-04 13:31:44 +01001569
1570 if (node->schema->flags & LYS_KEY) {
1571 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1572 return LY_EINVAL;
1573 } else if (sibling->next && (sibling->next->schema->flags & LYS_KEY)) {
1574 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert into keys.");
1575 return LY_EINVAL;
1576 }
1577
Michal Vasko0249f7c2020-03-05 16:36:40 +01001578 LY_CHECK_RET(lyd_insert_after_check_place(sibling, sibling, node));
1579
Michal Vaskof03ed032020-03-04 13:31:44 +01001580 if (node->parent || node->prev->next) {
1581 lyd_unlink_tree(node);
1582 }
1583
1584 while (node) {
1585 iter = node->next;
1586 lyd_unlink_tree(node);
1587
1588 lyd_insert_after_node(sibling, node);
1589 /* move the anchor accordingly */
1590 sibling = node;
1591
1592 node = iter;
1593 }
1594 return LY_SUCCESS;
1595}
1596
1597API void
1598lyd_unlink_tree(struct lyd_node *node)
1599{
1600 struct lyd_node *iter;
1601
1602 if (!node) {
1603 return;
1604 }
1605
1606 /* unlink from siblings */
1607 if (node->prev->next) {
1608 node->prev->next = node->next;
1609 }
1610 if (node->next) {
1611 node->next->prev = node->prev;
1612 } else {
1613 /* unlinking the last node */
1614 if (node->parent) {
1615 iter = node->parent->child;
1616 } else {
1617 iter = node->prev;
1618 while (iter->prev != node) {
1619 iter = iter->prev;
1620 }
1621 }
1622 /* update the "last" pointer from the first node */
1623 iter->prev = node->prev;
1624 }
1625
1626 /* unlink from parent */
1627 if (node->parent) {
1628 if (node->parent->child == node) {
1629 /* the node is the first child */
1630 node->parent->child = node->next;
1631 }
1632
1633 lyd_unlink_hash(node);
1634
1635 /* check for keyless list and update its hash */
1636 for (iter = (struct lyd_node *)node->parent; iter; iter = (struct lyd_node *)iter->parent) {
Michal Vasko413c7f22020-05-05 12:34:06 +02001637 if (iter->schema && (iter->schema->flags & LYS_KEYLESS)) {
Michal Vaskof03ed032020-03-04 13:31:44 +01001638 lyd_hash(iter);
1639 }
1640 }
1641
1642 node->parent = NULL;
1643 }
1644
1645 node->next = NULL;
1646 node->prev = node;
1647}
1648
Michal Vasko90932a92020-02-12 14:33:03 +01001649LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +01001650lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
Michal Vasko52927e22020-03-16 17:26:14 +01001651 size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix resolve_prefix,
Michal Vasko8d544252020-03-02 10:19:52 +01001652 void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode)
Michal Vasko90932a92020-02-12 14:33:03 +01001653{
1654 LY_ERR ret;
1655 struct lysc_ext_instance *ant = NULL;
Michal Vasko9f96a052020-03-10 09:41:45 +01001656 struct lyd_meta *mt, *last;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001657 LY_ARRAY_SIZE_TYPE u;
Michal Vasko90932a92020-02-12 14:33:03 +01001658
Michal Vasko9f96a052020-03-10 09:41:45 +01001659 assert((parent || meta) && mod);
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001660
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001661 LY_ARRAY_FOR(mod->compiled->exts, u) {
1662 if (mod->compiled->exts[u].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
1663 !ly_strncmp(mod->compiled->exts[u].argument, name, name_len)) {
Michal Vasko90932a92020-02-12 14:33:03 +01001664 /* we have the annotation definition */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001665 ant = &mod->compiled->exts[u];
Michal Vasko90932a92020-02-12 14:33:03 +01001666 break;
1667 }
1668 }
1669 if (!ant) {
1670 /* attribute is not defined as a metadata annotation (RFC 7952) */
1671 LOGERR(mod->ctx, LY_EINVAL, "Annotation definition for attribute \"%s:%.*s\" not found.",
1672 mod->name, name_len, name);
1673 return LY_EINVAL;
1674 }
1675
Michal Vasko9f96a052020-03-10 09:41:45 +01001676 mt = calloc(1, sizeof *mt);
1677 LY_CHECK_ERR_RET(!mt, LOGMEM(mod->ctx), LY_EMEM);
1678 mt->parent = parent;
1679 mt->annotation = ant;
Michal Vasko52927e22020-03-16 17:26:14 +01001680 ret = lyd_value_parse_meta(mod->ctx, mt, value, value_len, dynamic, 0, resolve_prefix, prefix_data, format, ctx_snode, NULL);
Michal Vasko90932a92020-02-12 14:33:03 +01001681 if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001682 free(mt);
Michal Vasko90932a92020-02-12 14:33:03 +01001683 return ret;
1684 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001685 mt->name = lydict_insert(mod->ctx, name, name_len);
Michal Vasko90932a92020-02-12 14:33:03 +01001686
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001687 /* insert as the last attribute */
1688 if (parent) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001689 if (parent->meta) {
1690 for (last = parent->meta; last->next; last = last->next);
1691 last->next = mt;
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001692 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01001693 parent->meta = mt;
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001694 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001695 } else if (*meta) {
1696 for (last = *meta; last->next; last = last->next);
1697 last->next = mt;
Michal Vasko90932a92020-02-12 14:33:03 +01001698 }
1699
1700 /* remove default flags from NP containers */
1701 while (parent && (parent->flags & LYD_DEFAULT)) {
1702 parent->flags &= ~LYD_DEFAULT;
1703 parent = (struct lyd_node *)parent->parent;
1704 }
1705
Michal Vasko9f96a052020-03-10 09:41:45 +01001706 if (meta) {
1707 *meta = mt;
Michal Vasko90932a92020-02-12 14:33:03 +01001708 }
1709 return ret;
1710}
1711
Michal Vasko52927e22020-03-16 17:26:14 +01001712LY_ERR
1713ly_create_attr(struct lyd_node *parent, struct ly_attr **attr, const struct ly_ctx *ctx, const char *name,
1714 size_t name_len, const char *value, size_t value_len, int *dynamic, LYD_FORMAT format,
1715 struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *ns)
1716{
1717 struct ly_attr *at, *last;
1718 struct lyd_node_opaq *opaq;
1719
1720 assert(ctx && (parent || attr) && (!parent || !parent->schema));
1721 assert(name && name_len);
1722 assert((prefix_len && ns) || (!prefix_len && !ns));
1723
1724 if (!value_len) {
1725 value = "";
1726 }
1727
1728 at = calloc(1, sizeof *at);
1729 LY_CHECK_ERR_RET(!at, LOGMEM(ctx), LY_EMEM);
1730 at->parent = (struct lyd_node_opaq *)parent;
1731 at->name = lydict_insert(ctx, name, name_len);
1732 if (dynamic && *dynamic) {
1733 at->value = lydict_insert_zc(ctx, (char *)value);
1734 *dynamic = 0;
1735 } else {
1736 at->value = lydict_insert(ctx, value, value_len);
1737 }
1738
1739 at->format = format;
1740 at->val_prefs = val_prefs;
1741 if (ns) {
1742 at->prefix.pref = lydict_insert(ctx, prefix, prefix_len);
1743 at->prefix.ns = lydict_insert(ctx, ns, 0);
1744 }
1745
1746 /* insert as the last attribute */
1747 if (parent) {
1748 opaq = (struct lyd_node_opaq *)parent;
1749 if (opaq->attr) {
1750 for (last = opaq->attr; last->next; last = last->next);
1751 last->next = at;
1752 } else {
1753 opaq->attr = at;
1754 }
1755 } else if (*attr) {
1756 for (last = *attr; last->next; last = last->next);
1757 last->next = at;
1758 }
1759
1760 if (attr) {
1761 *attr = at;
1762 }
1763 return LY_SUCCESS;
1764}
1765
Radek Krejci084289f2019-07-09 17:35:30 +02001766API const struct lyd_node_term *
Michal Vasko004d3152020-06-11 19:59:22 +02001767lyd_target(const struct ly_path *path, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +02001768{
Michal Vasko004d3152020-06-11 19:59:22 +02001769 struct lyd_node *target;
Radek Krejci084289f2019-07-09 17:35:30 +02001770
Michal Vasko004d3152020-06-11 19:59:22 +02001771 if (ly_path_eval(path, tree, &target)) {
1772 return NULL;
Radek Krejci084289f2019-07-09 17:35:30 +02001773 }
1774
Michal Vasko004d3152020-06-11 19:59:22 +02001775 return (struct lyd_node_term *)target;
Radek Krejci084289f2019-07-09 17:35:30 +02001776}
1777
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001778API LY_ERR
1779lyd_compare(const struct lyd_node *node1, const struct lyd_node *node2, int options)
1780{
1781 const struct lyd_node *iter1, *iter2;
1782 struct lyd_node_term *term1, *term2;
1783 struct lyd_node_any *any1, *any2;
Michal Vasko52927e22020-03-16 17:26:14 +01001784 struct lyd_node_opaq *opaq1, *opaq2;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001785 size_t len1, len2;
Radek Krejci084289f2019-07-09 17:35:30 +02001786
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001787 if (!node1 || !node2) {
1788 if (node1 == node2) {
1789 return LY_SUCCESS;
1790 } else {
1791 return LY_ENOT;
1792 }
1793 }
1794
Michal Vasko52927e22020-03-16 17:26:14 +01001795 if ((LYD_NODE_CTX(node1) != LYD_NODE_CTX(node2)) || (node1->schema != node2->schema)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001796 return LY_ENOT;
1797 }
1798
1799 if (node1->hash != node2->hash) {
1800 return LY_ENOT;
1801 }
Michal Vasko52927e22020-03-16 17:26:14 +01001802 /* equal hashes do not mean equal nodes, they can be just in collision (or both be 0) so the nodes must be checked explicitly */
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001803
Michal Vasko52927e22020-03-16 17:26:14 +01001804 if (!node1->schema) {
1805 opaq1 = (struct lyd_node_opaq *)node1;
1806 opaq2 = (struct lyd_node_opaq *)node2;
1807 if ((opaq1->name != opaq2->name) || (opaq1->prefix.ns != opaq2->prefix.ns) || (opaq1->format != opaq2->format)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001808 return LY_ENOT;
1809 }
Michal Vasko52927e22020-03-16 17:26:14 +01001810 switch (opaq1->format) {
1811 case LYD_XML:
1812 if (lyxml_value_compare(opaq1->value, opaq1->val_prefs, opaq2->value, opaq2->val_prefs)) {
1813 return LY_ENOT;
1814 }
1815 break;
1816 case LYD_SCHEMA:
1817 /* not allowed */
1818 LOGINT(LYD_NODE_CTX(node1));
1819 return LY_EINT;
1820 }
1821 if (options & LYD_COMPARE_FULL_RECURSION) {
1822 iter1 = opaq1->child;
1823 iter2 = opaq2->child;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001824 goto all_children_compare;
Michal Vasko52927e22020-03-16 17:26:14 +01001825 }
1826 return LY_SUCCESS;
1827 } else {
1828 switch (node1->schema->nodetype) {
1829 case LYS_LEAF:
1830 case LYS_LEAFLIST:
1831 if (options & LYD_COMPARE_DEFAULTS) {
1832 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1833 return LY_ENOT;
1834 }
1835 }
1836
Michal Vasko1a2bf2e2020-06-16 13:07:48 +02001837 term1 = (struct lyd_node_term *)node1;
1838 term2 = (struct lyd_node_term *)node2;
1839 if (term1->value.realtype != term2->value.realtype) {
1840 return LY_ENOT;
1841 }
Michal Vasko52927e22020-03-16 17:26:14 +01001842
Michal Vasko1a2bf2e2020-06-16 13:07:48 +02001843 return term1->value.realtype->plugin->compare(&term1->value, &term2->value);
Michal Vasko52927e22020-03-16 17:26:14 +01001844 case LYS_CONTAINER:
1845 if (options & LYD_COMPARE_DEFAULTS) {
1846 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1847 return LY_ENOT;
1848 }
1849 }
1850 if (options & LYD_COMPARE_FULL_RECURSION) {
1851 iter1 = ((struct lyd_node_inner*)node1)->child;
1852 iter2 = ((struct lyd_node_inner*)node2)->child;
1853 goto all_children_compare;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001854 }
1855 return LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +01001856 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +01001857 case LYS_ACTION:
1858 if (options & LYD_COMPARE_FULL_RECURSION) {
1859 /* TODO action/RPC
1860 goto all_children_compare;
1861 */
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001862 }
1863 return LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +01001864 case LYS_NOTIF:
1865 if (options & LYD_COMPARE_FULL_RECURSION) {
1866 /* TODO Notification
1867 goto all_children_compare;
1868 */
1869 }
1870 return LY_SUCCESS;
1871 case LYS_LIST:
1872 iter1 = ((struct lyd_node_inner*)node1)->child;
1873 iter2 = ((struct lyd_node_inner*)node2)->child;
1874
1875 if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
1876 /* lists with keys, their equivalence is based on their keys */
1877 for (struct lysc_node *key = ((struct lysc_node_list*)node1->schema)->child;
1878 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1879 key = key->next) {
1880 if (lyd_compare(iter1, iter2, options)) {
1881 return LY_ENOT;
1882 }
1883 iter1 = iter1->next;
1884 iter2 = iter2->next;
1885 }
1886 } else {
1887 /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
1888
1889 all_children_compare:
1890 if (!iter1 && !iter2) {
1891 /* no children, nothing to compare */
1892 return LY_SUCCESS;
1893 }
1894
1895 for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
1896 if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
1897 return LY_ENOT;
1898 }
1899 }
1900 if (iter1 || iter2) {
1901 return LY_ENOT;
1902 }
1903 }
1904 return LY_SUCCESS;
1905 case LYS_ANYXML:
1906 case LYS_ANYDATA:
1907 any1 = (struct lyd_node_any*)node1;
1908 any2 = (struct lyd_node_any*)node2;
1909
1910 if (any1->value_type != any2->value_type) {
1911 return LY_ENOT;
1912 }
1913 switch (any1->value_type) {
1914 case LYD_ANYDATA_DATATREE:
1915 iter1 = any1->value.tree;
1916 iter2 = any2->value.tree;
1917 goto all_children_compare;
1918 case LYD_ANYDATA_STRING:
1919 case LYD_ANYDATA_XML:
1920 case LYD_ANYDATA_JSON:
1921 len1 = strlen(any1->value.str);
1922 len2 = strlen(any2->value.str);
1923 if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
1924 return LY_ENOT;
1925 }
1926 return LY_SUCCESS;
1927 #if 0 /* TODO LYB format */
1928 case LYD_ANYDATA_LYB:
1929 int len1 = lyd_lyb_data_length(any1->value.mem);
1930 int len2 = lyd_lyb_data_length(any2->value.mem);
1931 if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
1932 return LY_ENOT;
1933 }
1934 return LY_SUCCESS;
1935 #endif
1936 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001937 }
1938 }
1939
Michal Vasko52927e22020-03-16 17:26:14 +01001940 LOGINT(LYD_NODE_CTX(node1));
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001941 return LY_EINT;
1942}
Radek Krejci22ebdba2019-07-25 13:59:43 +02001943
1944/**
Michal Vasko52927e22020-03-16 17:26:14 +01001945 * @brief Duplicate a single node and connect it into @p parent (if present) or last of @p first siblings.
Radek Krejci22ebdba2019-07-25 13:59:43 +02001946 *
1947 * Ignores LYD_DUP_WITH_PARENTS and LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
Radek Krejcif8b95172020-05-15 14:51:06 +02001948 *
1949 * @param[in] node Original node to duplicate
1950 * @param[in] parent Parent to insert into, NULL for top-level sibling.
1951 * @param[in,out] first First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
1952 * @param[in] options Bitmask of options flags, see @ref dupoptions.
1953 * @param[out] dup_p Pointer where the created duplicated node is placed (besides connecting it int @p parent / @p first sibling).
1954 * @return LY_ERR value
Radek Krejci22ebdba2019-07-25 13:59:43 +02001955 */
Michal Vasko52927e22020-03-16 17:26:14 +01001956static LY_ERR
1957lyd_dup_recursive(const struct lyd_node *node, struct lyd_node *parent, struct lyd_node **first, int options,
1958 struct lyd_node **dup_p)
Radek Krejci22ebdba2019-07-25 13:59:43 +02001959{
Michal Vasko52927e22020-03-16 17:26:14 +01001960 LY_ERR ret;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001961 struct lyd_node *dup = NULL;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001962 LY_ARRAY_SIZE_TYPE u;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001963
Michal Vasko52927e22020-03-16 17:26:14 +01001964 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001965
Michal Vasko52927e22020-03-16 17:26:14 +01001966 if (!node->schema) {
1967 dup = calloc(1, sizeof(struct lyd_node_opaq));
1968 } else {
1969 switch (node->schema->nodetype) {
Michal Vasko1bf09392020-03-27 12:38:10 +01001970 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +01001971 case LYS_ACTION:
1972 case LYS_NOTIF:
1973 case LYS_CONTAINER:
1974 case LYS_LIST:
1975 dup = calloc(1, sizeof(struct lyd_node_inner));
1976 break;
1977 case LYS_LEAF:
1978 case LYS_LEAFLIST:
1979 dup = calloc(1, sizeof(struct lyd_node_term));
1980 break;
1981 case LYS_ANYDATA:
1982 case LYS_ANYXML:
1983 dup = calloc(1, sizeof(struct lyd_node_any));
1984 break;
1985 default:
1986 LOGINT(LYD_NODE_CTX(node));
1987 ret = LY_EINT;
1988 goto error;
1989 }
Radek Krejci22ebdba2019-07-25 13:59:43 +02001990 }
Michal Vasko52927e22020-03-16 17:26:14 +01001991 LY_CHECK_ERR_GOTO(!dup, LOGMEM(LYD_NODE_CTX(node)); ret = LY_EMEM, error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001992
Michal Vaskof6df0a02020-06-16 13:08:34 +02001993 if (options & LYD_DUP_WITH_FLAGS) {
1994 dup->flags = node->flags;
1995 } else {
1996 dup->flags = (node->flags & LYD_DEFAULT) | LYD_NEW;
1997 }
Radek Krejci22ebdba2019-07-25 13:59:43 +02001998 dup->schema = node->schema;
Michal Vasko52927e22020-03-16 17:26:14 +01001999 dup->prev = dup;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002000
2001 /* TODO duplicate attributes, implement LYD_DUP_NO_ATTR */
2002
2003 /* nodetype-specific work */
Michal Vasko52927e22020-03-16 17:26:14 +01002004 if (!dup->schema) {
2005 struct lyd_node_opaq *opaq = (struct lyd_node_opaq *)dup;
2006 struct lyd_node_opaq *orig = (struct lyd_node_opaq *)node;
2007 struct lyd_node *child;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002008
2009 if (options & LYD_DUP_RECURSIVE) {
2010 /* duplicate all the children */
2011 LY_LIST_FOR(orig->child, child) {
Michal Vasko52927e22020-03-16 17:26:14 +01002012 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
2013 }
2014 }
2015 opaq->name = lydict_insert(LYD_NODE_CTX(node), orig->name, 0);
2016 opaq->format = orig->format;
2017 if (orig->prefix.pref) {
2018 opaq->prefix.pref = lydict_insert(LYD_NODE_CTX(node), orig->prefix.pref, 0);
2019 }
2020 if (orig->prefix.ns) {
2021 opaq->prefix.ns = lydict_insert(LYD_NODE_CTX(node), orig->prefix.ns, 0);
2022 }
2023 if (orig->val_prefs) {
2024 LY_ARRAY_CREATE_GOTO(LYD_NODE_CTX(node), opaq->val_prefs, LY_ARRAY_SIZE(orig->val_prefs), ret, error);
2025 LY_ARRAY_FOR(orig->val_prefs, u) {
2026 opaq->val_prefs[u].pref = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].pref, 0);
2027 opaq->val_prefs[u].ns = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].ns, 0);
2028 LY_ARRAY_INCREMENT(opaq->val_prefs);
2029 }
2030 }
2031 opaq->value = lydict_insert(LYD_NODE_CTX(node), orig->value, 0);
2032 opaq->ctx = orig->ctx;
2033 } else if (dup->schema->nodetype & LYD_NODE_TERM) {
2034 struct lyd_node_term *term = (struct lyd_node_term *)dup;
2035 struct lyd_node_term *orig = (struct lyd_node_term *)node;
2036
2037 term->hash = orig->hash;
2038 term->value.realtype = orig->value.realtype;
2039 LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &orig->value, &term->value),
2040 LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."); ret = LY_EINT, error);
2041 } else if (dup->schema->nodetype & LYD_NODE_INNER) {
2042 struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
2043 struct lyd_node *child;
2044
2045 if (options & LYD_DUP_RECURSIVE) {
2046 /* duplicate all the children */
2047 LY_LIST_FOR(orig->child, child) {
2048 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002049 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02002050 } else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02002051 /* always duplicate keys of a list */
Radek Krejci22ebdba2019-07-25 13:59:43 +02002052 child = orig->child;
Michal Vasko52927e22020-03-16 17:26:14 +01002053 for (struct lysc_node *key = ((struct lysc_node_list *)dup->schema)->child;
Radek Krejci0fe9b512019-07-26 17:51:05 +02002054 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
2055 key = key->next) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02002056 if (!child) {
2057 /* possibly not keys are present in filtered tree */
2058 break;
Radek Krejci0fe9b512019-07-26 17:51:05 +02002059 } else if (child->schema != key) {
2060 /* possibly not all keys are present in filtered tree,
2061 * but there can be also some non-key nodes */
2062 continue;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002063 }
Michal Vasko52927e22020-03-16 17:26:14 +01002064 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002065 child = child->next;
2066 }
2067 }
2068 lyd_hash(dup);
2069 } else if (dup->schema->nodetype & LYD_NODE_ANY) {
Michal Vasko52927e22020-03-16 17:26:14 +01002070 struct lyd_node_any *any = (struct lyd_node_any *)dup;
2071 struct lyd_node_any *orig = (struct lyd_node_any *)node;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002072
2073 any->hash = orig->hash;
2074 any->value_type = orig->value_type;
2075 switch (any->value_type) {
2076 case LYD_ANYDATA_DATATREE:
2077 if (orig->value.tree) {
2078 any->value.tree = lyd_dup(orig->value.tree, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_SIBLINGS);
Radek Krejci25dc3432020-05-15 14:42:12 +02002079 if (!any->value.tree) {
2080 /* get the last error's error code recorded by lyd_dup */
2081 struct ly_err_item *ei = ly_err_first(LYD_NODE_CTX(node));
2082 ret = ei ? ei->prev->no : LY_EOTHER;
2083 goto error;
2084 }
2085 LY_CHECK_ERR_GOTO(!any->value.tree, ret = 0 ,error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002086 }
2087 break;
2088 case LYD_ANYDATA_STRING:
2089 case LYD_ANYDATA_XML:
2090 case LYD_ANYDATA_JSON:
2091 if (orig->value.str) {
Michal Vasko52927e22020-03-16 17:26:14 +01002092 any->value.str = lydict_insert(LYD_NODE_CTX(node), orig->value.str, strlen(orig->value.str));
Radek Krejci22ebdba2019-07-25 13:59:43 +02002093 }
2094 break;
2095 }
2096 }
2097
Michal Vasko52927e22020-03-16 17:26:14 +01002098 /* insert */
2099 lyd_insert_node(parent, first, dup);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002100 lyd_insert_hash(dup);
Michal Vasko52927e22020-03-16 17:26:14 +01002101
2102 if (dup_p) {
2103 *dup_p = dup;
2104 }
2105 return LY_SUCCESS;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002106
2107error:
Michal Vasko52927e22020-03-16 17:26:14 +01002108 lyd_free_tree(dup);
2109 return ret;
Radek Krejci22ebdba2019-07-25 13:59:43 +02002110}
2111
2112API struct lyd_node *
2113lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
2114{
2115 struct ly_ctx *ctx;
2116 const struct lyd_node *orig; /* original node to be duplicated */
2117 struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
Radek Krejci22ebdba2019-07-25 13:59:43 +02002118 struct lyd_node *top = NULL; /* the most higher created node */
2119 struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
2120 int keyless_parent_list = 0;
2121
2122 LY_CHECK_ARG_RET(NULL, node, NULL);
2123 ctx = node->schema->module->ctx;
2124
2125 if (options & LYD_DUP_WITH_PARENTS) {
2126 struct lyd_node_inner *orig_parent, *iter;
2127 int repeat = 1;
2128 for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
2129 if (parent && parent->schema == orig_parent->schema) {
2130 /* stop creating parents, connect what we have into the provided parent */
2131 iter = parent;
2132 repeat = 0;
2133 /* get know if there is a keyless list which we will have to rehash */
2134 for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02002135 if (piter->schema->nodetype == LYS_LIST && (piter->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02002136 keyless_parent_list = 1;
2137 break;
2138 }
2139 }
2140 } else {
Michal Vasko52927e22020-03-16 17:26:14 +01002141 iter = NULL;
2142 LY_CHECK_GOTO(lyd_dup_recursive((struct lyd_node *)orig_parent, NULL, (struct lyd_node **)&iter, 0,
2143 (struct lyd_node **)&iter), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002144 }
2145 if (!local_parent) {
2146 local_parent = iter;
2147 }
2148 if (iter->child) {
2149 /* 1) list - add after keys
2150 * 2) provided parent with some children */
2151 iter->child->prev->next = top;
2152 if (top) {
2153 top->prev = iter->child->prev;
2154 iter->child->prev = top;
2155 }
2156 } else {
2157 iter->child = top;
2158 if (iter->schema->nodetype == LYS_LIST) {
2159 /* keyless list - we will need to rehash it since we are going to add nodes into it */
2160 keyless_parent_list = 1;
2161 }
2162 }
2163 if (top) {
2164 top->parent = iter;
2165 }
2166 top = (struct lyd_node*)iter;
2167 }
2168 if (repeat && parent) {
2169 /* given parent and created parents chain actually do not interconnect */
2170 LOGERR(ctx, LY_EINVAL, "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
2171 goto error;
2172 }
2173 } else {
2174 local_parent = parent;
2175 }
2176
Radek Krejci22ebdba2019-07-25 13:59:43 +02002177 LY_LIST_FOR(node, orig) {
Michal Vasko52927e22020-03-16 17:26:14 +01002178 /* if there is no local parent, it will be inserted into first */
2179 LY_CHECK_GOTO(lyd_dup_recursive(orig, (struct lyd_node *)local_parent, &first, options, first ? NULL : &first), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002180 if (!(options & LYD_DUP_WITH_SIBLINGS)) {
2181 break;
2182 }
2183 }
2184 if (keyless_parent_list) {
2185 /* rehash */
2186 for (; local_parent; local_parent = local_parent->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02002187 if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02002188 lyd_hash((struct lyd_node*)local_parent);
2189 }
2190 }
2191 }
2192 return first;
2193
2194error:
2195 if (top) {
2196 lyd_free_tree(top);
2197 } else {
Michal Vaskof03ed032020-03-04 13:31:44 +01002198 lyd_free_siblings(first);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002199 }
2200 return NULL;
2201}
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002202
Michal Vasko4490d312020-06-16 13:08:55 +02002203/**
2204 * @brief Merge a source sibling into target siblings.
2205 *
2206 * @param[in,out] first_trg First target sibling, is updated if top-level.
2207 * @param[in] parent_trg Target parent.
2208 * @param[in,out] sibling_src Source sibling to merge, set to NULL if spent.
2209 * @param[in] options Merge options.
2210 * @return LY_ERR value.
2211 */
2212static LY_ERR
2213lyd_merge_sibling_r(struct lyd_node **first_trg, struct lyd_node *parent_trg, const struct lyd_node **sibling_src_p,
2214 int options)
2215{
2216 LY_ERR ret;
2217 const struct lyd_node *child_src, *tmp, *sibling_src;
2218 struct lyd_node *match_trg, *dup_src, *next, *elem;
2219 struct lysc_type *type;
2220 LYD_ANYDATA_VALUETYPE tmp_val_type;
2221 union lyd_any_value tmp_val;
2222
2223 sibling_src = *sibling_src_p;
2224 if (sibling_src->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
2225 /* try to find the exact instance */
2226 ret = lyd_find_sibling_first(*first_trg, sibling_src, &match_trg);
2227 } else {
2228 /* try to simply find the node, there cannot be more instances */
2229 ret = lyd_find_sibling_val(*first_trg, sibling_src->schema, NULL, 0, &match_trg);
2230 }
2231
2232 if (!ret) {
2233 /* node found, make sure even value matches for all node types */
2234 if ((match_trg->schema->nodetype == LYS_LEAF) && lyd_compare(sibling_src, match_trg, LYD_COMPARE_DEFAULTS)) {
2235 /* since they are different, they cannot both be default */
2236 assert(!(sibling_src->flags & LYD_DEFAULT) || !(match_trg->flags & LYD_DEFAULT));
2237
2238 /* update value (or only LYD_DEFAULT flag) only if no flag set or the source node is not default */
2239 if (!(options & LYD_MERGE_EXPLICIT) || !(sibling_src->flags & LYD_DEFAULT)) {
2240 type = ((struct lysc_node_leaf *)match_trg->schema)->type;
2241 type->plugin->free(LYD_NODE_CTX(match_trg), &((struct lyd_node_term *)match_trg)->value);
2242 LY_CHECK_RET(type->plugin->duplicate(LYD_NODE_CTX(match_trg), &((struct lyd_node_term *)sibling_src)->value,
2243 &((struct lyd_node_term *)match_trg)->value));
2244
2245 /* copy flags and add LYD_NEW */
2246 match_trg->flags = sibling_src->flags | LYD_NEW;
2247 }
2248 } else if ((match_trg->schema->nodetype & LYS_ANYDATA) && lyd_compare(sibling_src, match_trg, 0)) {
2249 if (options & LYD_MERGE_DESTRUCT) {
2250 dup_src = (struct lyd_node *)sibling_src;
2251 lyd_unlink_tree(dup_src);
2252 /* spend it */
2253 *sibling_src_p = NULL;
2254 } else {
2255 dup_src = lyd_dup(sibling_src, NULL, 0);
2256 LY_CHECK_RET(!dup_src, LY_EMEM);
2257 }
2258 /* just switch values */
2259 tmp_val_type = ((struct lyd_node_any *)match_trg)->value_type;
2260 tmp_val = ((struct lyd_node_any *)match_trg)->value;
2261 ((struct lyd_node_any *)match_trg)->value_type = ((struct lyd_node_any *)sibling_src)->value_type;
2262 ((struct lyd_node_any *)match_trg)->value = ((struct lyd_node_any *)sibling_src)->value;
2263 ((struct lyd_node_any *)sibling_src)->value_type = tmp_val_type;
2264 ((struct lyd_node_any *)sibling_src)->value = tmp_val;
2265
2266 /* copy flags and add LYD_NEW */
2267 match_trg->flags = sibling_src->flags | LYD_NEW;
2268
2269 /* dup_src is not needed, actually */
2270 lyd_free_tree(dup_src);
2271 } else {
2272 /* check descendants, recursively */
2273 LY_LIST_FOR_SAFE(lyd_node_children(sibling_src), tmp, child_src) {
2274 if ((child_src->schema->nodetype == LYS_LEAF) && (child_src->schema->flags & LYS_KEY)) {
2275 /* skip keys */
2276 continue;
2277 }
2278
2279 LY_CHECK_RET(lyd_merge_sibling_r(lyd_node_children_p(match_trg), match_trg, &child_src, options));
2280 }
2281 }
2282 } else {
2283 /* node not found, merge it */
2284 if (options & LYD_MERGE_DESTRUCT) {
2285 dup_src = (struct lyd_node *)sibling_src;
2286 lyd_unlink_tree(dup_src);
2287 /* spend it */
2288 *sibling_src_p = NULL;
2289 } else {
2290 dup_src = lyd_dup(sibling_src, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_FLAGS);
2291 LY_CHECK_RET(!dup_src, LY_EMEM);
2292 }
2293
2294 /* set LYD_NEW for all the new nodes, required for validation */
2295 LYD_TREE_DFS_BEGIN(dup_src, next, elem) {
2296 elem->flags |= LYD_NEW;
2297 LYD_TREE_DFS_END(dup_src, next, elem);
2298 }
2299
2300 lyd_insert_node(parent_trg, first_trg, dup_src);
2301 }
2302
2303 return LY_SUCCESS;
2304}
2305
2306API LY_ERR
2307lyd_merge(struct lyd_node **target, const struct lyd_node *source, int options)
2308{
2309 const struct lyd_node *sibling_src, *tmp;
2310 int first;
2311
2312 LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
2313
2314 if (!source) {
2315 /* nothing to merge */
2316 return LY_SUCCESS;
2317 }
2318
2319 if (lysc_data_parent((*target)->schema) || lysc_data_parent(source->schema)) {
2320 LOGERR(LYD_NODE_CTX(source), LY_EINVAL, "Invalid arguments - can merge only 2 top-level subtrees (%s()).", __func__);
2321 return LY_EINVAL;
2322 }
2323
2324 LY_LIST_FOR_SAFE(source, tmp, sibling_src) {
2325 first = sibling_src == source ? 1 : 0;
2326 LY_CHECK_RET(lyd_merge_sibling_r(target, NULL, &sibling_src, options));
2327 if (first && !sibling_src) {
2328 /* source was spent (unlinked), move to the next node */
2329 source = tmp;
2330 }
2331
2332 if (options & LYD_MERGE_NOSIBLINGS) {
2333 break;
2334 }
2335 }
2336
2337 if (options & LYD_MERGE_DESTRUCT) {
2338 /* free any leftover source data that were not merged */
2339 lyd_free_siblings((struct lyd_node *)source);
2340 }
2341
2342 return LY_SUCCESS;
2343}
2344
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002345static LY_ERR
2346lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
2347{
Michal Vasko14654712020-02-06 08:35:21 +01002348 /* ending \0 */
2349 ++reqlen;
2350
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002351 if (reqlen > *buflen) {
2352 if (is_static) {
2353 return LY_EINCOMPLETE;
2354 }
2355
2356 *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
2357 if (!*buffer) {
2358 return LY_EMEM;
2359 }
2360
2361 *buflen = reqlen;
2362 }
2363
2364 return LY_SUCCESS;
2365}
2366
2367/**
2368 * @brief Append all list key predicates to path.
2369 *
2370 * @param[in] node Node with keys to print.
2371 * @param[in,out] buffer Buffer to print to.
2372 * @param[in,out] buflen Current buffer length.
2373 * @param[in,out] bufused Current number of characters used in @p buffer.
2374 * @param[in] is_static Whether buffer is static or can be reallocated.
2375 * @return LY_ERR
2376 */
2377static LY_ERR
2378lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2379{
2380 const struct lyd_node *key;
2381 int dynamic = 0;
2382 size_t len;
2383 const char *val;
2384 char quot;
2385 LY_ERR rc;
2386
Michal Vasko14654712020-02-06 08:35:21 +01002387 for (key = lyd_node_children(node); key && (key->schema->flags & LYS_KEY); key = key->next) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002388 val = lyd_value2str((struct lyd_node_term *)key, &dynamic);
2389 len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
2390 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2391 if (rc != LY_SUCCESS) {
2392 if (dynamic) {
2393 free((char *)val);
2394 }
2395 return rc;
2396 }
2397
2398 quot = '\'';
2399 if (strchr(val, '\'')) {
2400 quot = '"';
2401 }
2402 *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
2403
2404 if (dynamic) {
2405 free((char *)val);
2406 }
2407 }
2408
2409 return LY_SUCCESS;
2410}
2411
2412/**
2413 * @brief Append leaf-list value predicate to path.
2414 *
2415 * @param[in] node Node to print.
2416 * @param[in,out] buffer Buffer to print to.
2417 * @param[in,out] buflen Current buffer length.
2418 * @param[in,out] bufused Current number of characters used in @p buffer.
2419 * @param[in] is_static Whether buffer is static or can be reallocated.
2420 * @return LY_ERR
2421 */
2422static LY_ERR
2423lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2424{
2425 int dynamic = 0;
2426 size_t len;
2427 const char *val;
2428 char quot;
2429 LY_ERR rc;
2430
2431 val = lyd_value2str((struct lyd_node_term *)node, &dynamic);
2432 len = 4 + strlen(val) + 2;
2433 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2434 if (rc != LY_SUCCESS) {
2435 goto cleanup;
2436 }
2437
2438 quot = '\'';
2439 if (strchr(val, '\'')) {
2440 quot = '"';
2441 }
2442 *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
2443
2444cleanup:
2445 if (dynamic) {
2446 free((char *)val);
2447 }
2448 return rc;
2449}
2450
2451/**
2452 * @brief Append node position (relative to its other instances) predicate to path.
2453 *
2454 * @param[in] node Node to print.
2455 * @param[in,out] buffer Buffer to print to.
2456 * @param[in,out] buflen Current buffer length.
2457 * @param[in,out] bufused Current number of characters used in @p buffer.
2458 * @param[in] is_static Whether buffer is static or can be reallocated.
2459 * @return LY_ERR
2460 */
2461static LY_ERR
2462lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2463{
2464 const struct lyd_node *first, *iter;
2465 size_t len;
2466 int pos;
2467 char *val = NULL;
2468 LY_ERR rc;
2469
2470 if (node->parent) {
2471 first = node->parent->child;
2472 } else {
2473 for (first = node; node->prev->next; node = node->prev);
2474 }
2475 pos = 1;
2476 for (iter = first; iter != node; iter = iter->next) {
2477 if (iter->schema == node->schema) {
2478 ++pos;
2479 }
2480 }
2481 if (asprintf(&val, "%d", pos) == -1) {
2482 return LY_EMEM;
2483 }
2484
2485 len = 1 + strlen(val) + 1;
2486 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2487 if (rc != LY_SUCCESS) {
2488 goto cleanup;
2489 }
2490
2491 *bufused += sprintf(*buffer + *bufused, "[%s]", val);
2492
2493cleanup:
2494 free(val);
2495 return rc;
2496}
2497
2498API char *
2499lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
2500{
Michal Vasko14654712020-02-06 08:35:21 +01002501 int is_static = 0, i, depth;
2502 size_t bufused = 0, len;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002503 const struct lyd_node *iter;
2504 const struct lys_module *mod;
2505 LY_ERR rc;
2506
2507 LY_CHECK_ARG_RET(NULL, node, NULL);
2508 if (buffer) {
2509 LY_CHECK_ARG_RET(node->schema->module->ctx, buflen > 1, NULL);
2510 is_static = 1;
Michal Vasko14654712020-02-06 08:35:21 +01002511 } else {
2512 buflen = 0;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002513 }
2514
2515 switch (pathtype) {
Michal Vasko14654712020-02-06 08:35:21 +01002516 case LYD_PATH_LOG:
2517 depth = 1;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002518 for (iter = node; iter->parent; iter = (const struct lyd_node *)iter->parent) {
2519 ++depth;
2520 }
2521
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002522 goto iter_print;
Michal Vasko14654712020-02-06 08:35:21 +01002523 while (depth) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002524 /* find the right node */
Michal Vasko14654712020-02-06 08:35:21 +01002525 for (iter = node, i = 1; i < depth; iter = (const struct lyd_node *)iter->parent, ++i);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002526iter_print:
2527 /* print prefix and name */
2528 mod = NULL;
2529 if (!iter->parent || (iter->schema->module != iter->parent->schema->module)) {
2530 mod = iter->schema->module;
2531 }
2532
2533 /* realloc string */
2534 len = 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(iter->schema->name);
2535 rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
2536 if (rc != LY_SUCCESS) {
2537 break;
2538 }
2539
2540 /* print next node */
2541 bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", iter->schema->name);
2542
2543 switch (iter->schema->nodetype) {
2544 case LYS_LIST:
2545 if (iter->schema->flags & LYS_KEYLESS) {
2546 /* print its position */
2547 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
2548 } else {
2549 /* print all list keys in predicates */
2550 rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
2551 }
2552 break;
2553 case LYS_LEAFLIST:
2554 if (iter->schema->flags & LYS_CONFIG_W) {
2555 /* print leaf-list value */
2556 rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
2557 } else {
2558 /* print its position */
2559 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
2560 }
2561 break;
2562 default:
2563 /* nothing to print more */
2564 rc = LY_SUCCESS;
2565 break;
2566 }
2567 if (rc != LY_SUCCESS) {
2568 break;
2569 }
2570
Michal Vasko14654712020-02-06 08:35:21 +01002571 --depth;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002572 }
2573 break;
2574 }
2575
2576 return buffer;
2577}
Michal Vaskoe444f752020-02-10 12:20:06 +01002578
Michal Vasko9b368d32020-02-14 13:53:31 +01002579LY_ERR
2580lyd_find_sibling_next2(const struct lyd_node *first, const struct lysc_node *schema, const char *key_or_value,
2581 size_t val_len, struct lyd_node **match)
Michal Vaskoe444f752020-02-10 12:20:06 +01002582{
2583 LY_ERR rc;
2584 const struct lyd_node *node = NULL;
2585 struct lyd_node_term *term;
Michal Vasko00cbf532020-06-15 13:58:47 +02002586 struct lyxp_expr *expr = NULL;
2587 uint16_t exp_idx = 0;
2588 struct ly_path_predicate *predicates = NULL;
2589 enum ly_path_pred_type pred_type = 0;
Michal Vasko90932a92020-02-12 14:33:03 +01002590 struct lyd_value val = {0};
Michal Vasko00cbf532020-06-15 13:58:47 +02002591 LY_ARRAY_SIZE_TYPE u;
Michal Vaskoe444f752020-02-10 12:20:06 +01002592
Michal Vasko9b368d32020-02-14 13:53:31 +01002593 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
Michal Vaskoe444f752020-02-10 12:20:06 +01002594
2595 if (!first) {
2596 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01002597 if (match) {
2598 *match = NULL;
2599 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002600 return LY_ENOTFOUND;
2601 }
2602
Michal Vaskoe444f752020-02-10 12:20:06 +01002603 if (key_or_value && !val_len) {
2604 val_len = strlen(key_or_value);
2605 }
2606
2607 if (key_or_value && (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko90932a92020-02-12 14:33:03 +01002608 /* store the value */
Michal Vasko9b368d32020-02-14 13:53:31 +01002609 LY_CHECK_GOTO(rc = lyd_value_store(&val, schema, key_or_value, val_len, 0, lydjson_resolve_prefix, NULL, LYD_JSON), cleanup);
Michal Vaskoe444f752020-02-10 12:20:06 +01002610 } else if (key_or_value && (schema->nodetype == LYS_LIST)) {
Michal Vasko00cbf532020-06-15 13:58:47 +02002611 /* parse keys */
2612 LY_CHECK_GOTO(rc = ly_path_parse_predicate(schema->module->ctx, key_or_value, val_len, LY_PATH_PREFIX_OPTIONAL,
2613 LY_PATH_PRED_KEYS, &expr), cleanup);
2614
2615 /* compile them */
2616 LY_CHECK_GOTO(rc = ly_path_compile_predicate(schema->module->ctx, NULL, schema, expr, &exp_idx, lydjson_resolve_prefix,
2617 NULL, LYD_JSON, &predicates, &pred_type), cleanup);
Michal Vaskoe444f752020-02-10 12:20:06 +01002618 }
2619
2620 /* find first matching value */
2621 LY_LIST_FOR(first, node) {
2622 if (node->schema != schema) {
2623 continue;
2624 }
2625
Michal Vasko00cbf532020-06-15 13:58:47 +02002626 if ((schema->nodetype == LYS_LIST) && predicates) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002627 /* compare all set keys */
Michal Vasko00cbf532020-06-15 13:58:47 +02002628 LY_ARRAY_FOR(predicates, u) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002629 /* find key */
Michal Vasko00cbf532020-06-15 13:58:47 +02002630 rc = lyd_find_sibling_val(lyd_node_children(node), predicates[u].key, NULL, 0, (struct lyd_node **)&term);
Michal Vaskoe444f752020-02-10 12:20:06 +01002631 if (rc == LY_ENOTFOUND) {
2632 /* all keys must always exist */
Michal Vasko9b368d32020-02-14 13:53:31 +01002633 LOGINT_RET(schema->module->ctx);
Michal Vaskoe444f752020-02-10 12:20:06 +01002634 }
2635 LY_CHECK_GOTO(rc, cleanup);
2636
2637 /* compare values */
Michal Vasko00cbf532020-06-15 13:58:47 +02002638 if (!term->value.realtype->plugin->compare(&term->value, &predicates[u].value)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002639 break;
2640 }
2641 }
2642
Michal Vasko00cbf532020-06-15 13:58:47 +02002643 if (u < LY_ARRAY_SIZE(predicates)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002644 /* not a match */
2645 continue;
2646 }
Michal Vasko90932a92020-02-12 14:33:03 +01002647 } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && val.realtype) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002648 term = (struct lyd_node_term *)node;
2649
2650 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01002651 if (!term->value.realtype->plugin->compare(&term->value, &val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002652 /* not a match */
2653 continue;
2654 }
2655 }
2656
2657 /* all criteria passed */
2658 break;
2659 }
2660
2661 if (!node) {
2662 rc = LY_ENOTFOUND;
Michal Vasko9b368d32020-02-14 13:53:31 +01002663 if (match) {
2664 *match = NULL;
2665 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002666 goto cleanup;
2667 }
2668
2669 /* success */
Michal Vasko9b368d32020-02-14 13:53:31 +01002670 if (match) {
2671 *match = (struct lyd_node *)node;
2672 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002673 rc = LY_SUCCESS;
2674
2675cleanup:
Michal Vasko00cbf532020-06-15 13:58:47 +02002676 ly_path_predicates_free(schema->module->ctx, pred_type, NULL, predicates);
2677 lyxp_expr_free(schema->module->ctx, expr);
Michal Vasko90932a92020-02-12 14:33:03 +01002678 if (val.realtype) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002679 val.realtype->plugin->free(schema->module->ctx, &val);
Michal Vasko90932a92020-02-12 14:33:03 +01002680 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002681 return rc;
2682}
2683
2684API LY_ERR
Michal Vasko9b368d32020-02-14 13:53:31 +01002685lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name, size_t name_len,
2686 const char *key_or_value, size_t val_len, struct lyd_node **match)
2687{
2688 const struct lysc_node *schema;
2689
2690 LY_CHECK_ARG_RET(NULL, module, name, match, LY_EINVAL);
2691
2692 if (!first) {
2693 /* no data */
2694 *match = NULL;
2695 return LY_ENOTFOUND;
2696 }
2697
2698 /* find schema */
2699 schema = lys_find_child(first->parent ? first->parent->schema : NULL, module, name, name_len, 0, 0);
2700 if (!schema) {
2701 LOGERR(module->ctx, LY_EINVAL, "Schema node not found.");
2702 return LY_EINVAL;
2703 }
2704
2705 return lyd_find_sibling_next2(first, schema, key_or_value, val_len, match);
2706}
2707
2708API LY_ERR
Michal Vaskoe444f752020-02-10 12:20:06 +01002709lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
2710{
2711 struct lyd_node **match_p;
2712 struct lyd_node_inner *parent;
2713
Michal Vaskof03ed032020-03-04 13:31:44 +01002714 LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
Michal Vaskoe444f752020-02-10 12:20:06 +01002715
Michal Vasko62ed12d2020-05-21 10:08:25 +02002716 if (!siblings || (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema))) {
2717 /* no data or schema mismatch */
Michal Vasko9b368d32020-02-14 13:53:31 +01002718 if (match) {
2719 *match = NULL;
2720 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002721 return LY_ENOTFOUND;
2722 }
2723
2724 /* find first sibling */
2725 if (siblings->parent) {
2726 siblings = siblings->parent->child;
2727 } else {
2728 while (siblings->prev->next) {
2729 siblings = siblings->prev;
2730 }
2731 }
2732
2733 parent = (struct lyd_node_inner *)siblings->parent;
2734 if (parent && parent->children_ht) {
2735 assert(target->hash);
2736
2737 /* find by hash */
2738 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
2739 siblings = *match_p;
2740 } else {
2741 /* not found */
2742 siblings = NULL;
2743 }
2744 } else {
2745 /* no children hash table */
2746 for (; siblings; siblings = siblings->next) {
2747 if (!lyd_compare(siblings, target, 0)) {
2748 break;
2749 }
2750 }
2751 }
2752
2753 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002754 if (match) {
2755 *match = NULL;
2756 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002757 return LY_ENOTFOUND;
2758 }
2759
Michal Vasko9b368d32020-02-14 13:53:31 +01002760 if (match) {
2761 *match = (struct lyd_node *)siblings;
2762 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002763 return LY_SUCCESS;
2764}
2765
2766API LY_ERR
2767lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
2768{
2769 struct lyd_node_inner *parent;
2770 struct lyd_node *match;
2771 struct lyd_node **match_p;
2772 struct ly_set *ret;
2773
2774 LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
2775
Michal Vasko62ed12d2020-05-21 10:08:25 +02002776 if (!siblings || (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema))) {
2777 /* no data or schema mismatch */
Michal Vaskoe444f752020-02-10 12:20:06 +01002778 return LY_ENOTFOUND;
2779 }
2780
2781 ret = ly_set_new();
2782 LY_CHECK_ERR_RET(!ret, LOGMEM(target->schema->module->ctx), LY_EMEM);
2783
2784 /* find first sibling */
2785 if (siblings->parent) {
2786 siblings = siblings->parent->child;
2787 } else {
2788 while (siblings->prev->next) {
2789 siblings = siblings->prev;
2790 }
2791 }
2792
2793 parent = (struct lyd_node_inner *)siblings->parent;
2794 if (parent && parent->children_ht) {
2795 assert(target->hash);
2796
2797 /* find by hash */
2798 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
2799 match = *match_p;
2800 } else {
2801 /* not found */
2802 match = NULL;
2803 }
2804 while (match) {
2805 /* add all found nodes into the return set */
2806 if (ly_set_add(ret, match, LY_SET_OPT_USEASLIST) == -1) {
2807 goto error;
2808 }
2809
2810 /* find next instance */
2811 if (lyht_find_next(parent->children_ht, &match, match->hash, (void **)&match_p)) {
2812 match = NULL;
2813 } else {
2814 match = *match_p;
2815 }
2816 }
2817 } else {
2818 /* no children hash table */
2819 for (; siblings; siblings = siblings->next) {
2820 if (!lyd_compare(siblings, target, 0)) {
2821 /* a match */
2822 if (ly_set_add(ret, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
2823 goto error;
2824 }
2825 }
2826 }
2827 }
2828
2829 if (!ret->count) {
2830 ly_set_free(ret, NULL);
2831 return LY_ENOTFOUND;
2832 }
2833
2834 *set = ret;
2835 return LY_SUCCESS;
2836
2837error:
2838 ly_set_free(ret, NULL);
2839 return LY_EMEM;
2840}
2841
Michal Vasko90932a92020-02-12 14:33:03 +01002842static int
2843lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
2844{
2845 struct lysc_node *val1;
2846 struct lyd_node *val2;
2847
2848 val1 = *((struct lysc_node **)val1_p);
2849 val2 = *((struct lyd_node **)val2_p);
2850
2851 assert(val1->nodetype & (LYD_NODE_INNER | LYS_LEAF));
2852
2853 if (val1 == val2->schema) {
2854 /* schema match is enough */
2855 return 1;
2856 } else {
2857 return 0;
2858 }
2859}
2860
2861static LY_ERR
2862lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
2863{
2864 struct lyd_node **match_p;
2865 struct lyd_node_inner *parent;
2866 uint32_t hash;
2867 values_equal_cb ht_cb;
2868
2869 assert(siblings && schema && (schema->nodetype & (LYD_NODE_INNER | LYS_LEAF)));
2870
2871 /* find first sibling */
2872 if (siblings->parent) {
2873 siblings = siblings->parent->child;
2874 } else {
2875 while (siblings->prev->next) {
2876 siblings = siblings->prev;
2877 }
2878 }
2879
2880 parent = (struct lyd_node_inner *)siblings->parent;
2881 if (parent && parent->children_ht) {
2882 /* calculate our hash */
2883 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
2884 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
2885 hash = dict_hash_multi(hash, NULL, 0);
2886
2887 /* use special hash table function */
2888 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
2889
2890 /* find by hash */
2891 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
2892 siblings = *match_p;
2893 } else {
2894 /* not found */
2895 siblings = NULL;
2896 }
2897
2898 /* set the original hash table compare function back */
2899 lyht_set_cb(parent->children_ht, ht_cb);
2900 } else {
2901 /* no children hash table */
2902 for (; siblings; siblings = siblings->next) {
2903 if (siblings->schema == schema) {
2904 /* schema match is enough */
2905 break;
2906 }
2907 }
2908 }
2909
2910 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002911 if (match) {
2912 *match = NULL;
2913 }
Michal Vasko90932a92020-02-12 14:33:03 +01002914 return LY_ENOTFOUND;
2915 }
2916
Michal Vasko9b368d32020-02-14 13:53:31 +01002917 if (match) {
2918 *match = (struct lyd_node *)siblings;
2919 }
Michal Vasko90932a92020-02-12 14:33:03 +01002920 return LY_SUCCESS;
2921}
2922
Michal Vaskoe444f752020-02-10 12:20:06 +01002923API LY_ERR
2924lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
2925 size_t val_len, struct lyd_node **match)
2926{
2927 LY_ERR rc;
2928 struct lyd_node *target = NULL;
2929
2930 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
Michal Vasko62ed12d2020-05-21 10:08:25 +02002931 if ((schema->nodetype == LYS_LIST) && (schema->flags & LYS_KEYLESS)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002932 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
2933 return LY_EINVAL;
2934 } else if ((schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && !key_or_value) {
2935 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - no value/keys for a (leaf-)list (%s()).", __func__);
2936 return LY_EINVAL;
2937 } else if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
2938 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
2939 lys_nodetype2str(schema->nodetype), __func__);
2940 return LY_EINVAL;
2941 }
2942
Michal Vasko62ed12d2020-05-21 10:08:25 +02002943 if (!siblings || (lysc_data_parent(siblings->schema) != lysc_data_parent(schema))) {
2944 /* no data or schema mismatch */
Michal Vasko9b368d32020-02-14 13:53:31 +01002945 if (match) {
2946 *match = NULL;
2947 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002948 return LY_ENOTFOUND;
2949 }
2950
Michal Vaskof03ed032020-03-04 13:31:44 +01002951 if (key_or_value && !val_len) {
2952 val_len = strlen(key_or_value);
2953 }
2954
Michal Vasko90932a92020-02-12 14:33:03 +01002955 /* create data node if needed and find it */
Michal Vaskoe444f752020-02-10 12:20:06 +01002956 switch (schema->nodetype) {
2957 case LYS_CONTAINER:
2958 case LYS_ANYXML:
2959 case LYS_ANYDATA:
2960 case LYS_NOTIF:
Michal Vasko1bf09392020-03-27 12:38:10 +01002961 case LYS_RPC:
Michal Vasko9b368d32020-02-14 13:53:31 +01002962 case LYS_ACTION:
Michal Vaskoe444f752020-02-10 12:20:06 +01002963 case LYS_LEAF:
Michal Vasko004d3152020-06-11 19:59:22 +02002964 /* find it based on schema only, there cannot be more instances */
Michal Vasko90932a92020-02-12 14:33:03 +01002965 rc = lyd_find_sibling_schema(siblings, schema, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01002966 break;
2967 case LYS_LEAFLIST:
2968 /* target used attributes: schema, hash, value */
Michal Vaskocbff3e92020-05-27 12:56:41 +02002969 rc = lyd_create_term(schema, key_or_value, val_len, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &target);
2970 LY_CHECK_RET(rc && (rc != LY_EINCOMPLETE), rc);
2971 rc = LY_SUCCESS;
Michal Vasko90932a92020-02-12 14:33:03 +01002972 /* fallthrough */
Michal Vaskoe444f752020-02-10 12:20:06 +01002973 case LYS_LIST:
Michal Vasko90932a92020-02-12 14:33:03 +01002974 if (schema->nodetype == LYS_LIST) {
2975 /* target used attributes: schema, hash, child (all keys) */
Michal Vasko004d3152020-06-11 19:59:22 +02002976 LY_CHECK_RET(lyd_create_list2(schema, key_or_value, val_len, &target));
Michal Vasko90932a92020-02-12 14:33:03 +01002977 }
2978
2979 /* find it */
2980 rc = lyd_find_sibling_first(siblings, target, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01002981 break;
2982 default:
2983 /* unreachable */
2984 LOGINT(schema->module->ctx);
2985 return LY_EINT;
2986 }
2987
Michal Vaskoe444f752020-02-10 12:20:06 +01002988 lyd_free_tree(target);
2989 return rc;
2990}
Michal Vaskoccc02342020-05-21 10:09:21 +02002991
2992API LY_ERR
2993lyd_find_xpath(const struct lyd_node *ctx_node, const char *xpath, struct ly_set **set)
2994{
2995 LY_ERR ret = LY_SUCCESS;
2996 struct lyxp_set xp_set;
2997 struct lyxp_expr *exp;
2998 uint32_t i;
2999
3000 LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
3001
3002 memset(&xp_set, 0, sizeof xp_set);
3003
3004 /* compile expression */
Michal Vasko004d3152020-06-11 19:59:22 +02003005 exp = lyxp_expr_parse((struct ly_ctx *)LYD_NODE_CTX(ctx_node), xpath, 0, 1);
Michal Vaskoccc02342020-05-21 10:09:21 +02003006 LY_CHECK_ERR_GOTO(!exp, ret = LY_EINVAL, cleanup);
3007
3008 /* evaluate expression */
3009 ret = lyxp_eval(exp, LYD_JSON, ctx_node->schema->module, ctx_node, LYXP_NODE_ELEM, ctx_node, &xp_set, 0);
3010 LY_CHECK_GOTO(ret, cleanup);
3011
3012 /* allocate return set */
3013 *set = ly_set_new();
3014 LY_CHECK_ERR_GOTO(!*set, LOGMEM(LYD_NODE_CTX(ctx_node)); ret = LY_EMEM, cleanup);
3015
3016 /* transform into ly_set */
3017 if (xp_set.type == LYXP_SET_NODE_SET) {
3018 /* allocate memory for all the elements once (even though not all items must be elements but most likely will be) */
3019 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
3020 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(LYD_NODE_CTX(ctx_node)); ret = LY_EMEM, cleanup);
3021 (*set)->size = xp_set.used;
3022
3023 for (i = 0; i < xp_set.used; ++i) {
3024 if (xp_set.val.nodes[i].type == LYXP_NODE_ELEM) {
3025 ly_set_add(*set, xp_set.val.nodes[i].node, LY_SET_OPT_USEASLIST);
3026 }
3027 }
3028 }
3029
3030cleanup:
Michal Vasko0691d522020-05-21 13:21:47 +02003031 lyxp_set_free_content(&xp_set);
Michal Vaskoccc02342020-05-21 10:09:21 +02003032 lyxp_expr_free((struct ly_ctx *)LYD_NODE_CTX(ctx_node), exp);
3033 return ret;
3034}