blob: 3841c3acb36de5e08178bf1e905b3c42048a9705 [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
15#include "common.h"
16
Radek Krejci084289f2019-07-09 17:35:30 +020017#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020018#include <ctype.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <stdarg.h>
22#include <stdint.h>
23#include <string.h>
24#include <unistd.h>
25
26#include "log.h"
27#include "tree.h"
28#include "tree_data.h"
29#include "tree_data_internal.h"
Michal Vasko90932a92020-02-12 14:33:03 +010030#include "hash_table.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031#include "tree_schema.h"
Michal Vasko52927e22020-03-16 17:26:14 +010032#include "xml.h"
Radek Krejci38d85362019-09-05 16:26:38 +020033#include "plugins_exts_metadata.h"
Michal Vasko90932a92020-02-12 14:33:03 +010034#include "plugins_exts_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020035
Michal Vaskoe444f752020-02-10 12:20:06 +010036struct ly_keys {
37 char *str;
38 struct {
39 const struct lysc_node_leaf *schema;
40 char *value;
Michal Vasko90932a92020-02-12 14:33:03 +010041 struct lyd_value val;
Michal Vaskoe444f752020-02-10 12:20:06 +010042 } *keys;
43 size_t key_count;
44};
45
Radek Krejci084289f2019-07-09 17:35:30 +020046LY_ERR
Michal Vasko90932a92020-02-12 14:33:03 +010047lyd_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 +010048 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +020049{
Michal Vasko90932a92020-02-12 14:33:03 +010050 LY_ERR ret = LY_SUCCESS;
Radek Krejci084289f2019-07-09 17:35:30 +020051 struct ly_err_item *err = NULL;
52 struct ly_ctx *ctx;
53 struct lysc_type *type;
Radek Krejci3c9758d2019-07-11 16:49:10 +020054 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
Michal Vaskof03ed032020-03-04 13:31:44 +010055 (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +020056 assert(node);
57
58 ctx = node->schema->module->ctx;
Radek Krejci084289f2019-07-09 17:35:30 +020059
Radek Krejci73dead22019-07-11 16:46:16 +020060 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci62903c32019-07-15 14:42:05 +020061 if (!second) {
62 node->value.realtype = type;
63 }
Michal Vasko90932a92020-02-12 14:33:03 +010064 ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
Michal Vaskof03ed032020-03-04 13:31:44 +010065 tree ? (void *)node : (void *)node->schema, tree,
Radek Krejci73dead22019-07-11 16:46:16 +020066 &node->value, NULL, &err);
Michal Vasko90932a92020-02-12 14:33:03 +010067 if (ret && (ret != LY_EINCOMPLETE)) {
Radek Krejci73dead22019-07-11 16:46:16 +020068 if (err) {
Michal Vaskofea12c62020-03-30 11:00:15 +020069 LOGVAL(ctx, LY_VLOG_LYD, node, err->vecode, err->msg);
Radek Krejci73dead22019-07-11 16:46:16 +020070 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +020071 }
Radek Krejci73dead22019-07-11 16:46:16 +020072 goto error;
Michal Vasko90932a92020-02-12 14:33:03 +010073 } else if (dynamic) {
74 *dynamic = 0;
Radek Krejci084289f2019-07-09 17:35:30 +020075 }
76
77error:
78 return ret;
79}
80
Michal Vasko90932a92020-02-12 14:33:03 +010081/* similar to lyd_value_parse except can be used just to store the value, hence does also not support a second call */
82static LY_ERR
83lyd_value_store(struct lyd_value *val, const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
84 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format)
85{
86 LY_ERR ret = LY_SUCCESS;
87 struct ly_err_item *err = NULL;
88 struct ly_ctx *ctx;
89 struct lysc_type *type;
90 int options = LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA | (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0);
91
92 assert(val && schema && (schema->nodetype & LYD_NODE_TERM));
93
94 ctx = schema->module->ctx;
95 type = ((struct lysc_node_leaf *)schema)->type;
96 val->realtype = type;
97 ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format, (void *)schema, NULL,
98 val, NULL, &err);
99 if (ret == LY_EINCOMPLETE) {
100 /* this is fine, we do not need it resolved */
101 ret = LY_SUCCESS;
102 } else if (ret && err) {
103 ly_err_print(err);
104 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
105 ly_err_free(err);
106 }
107 if (!ret && dynamic) {
108 *dynamic = 0;
109 }
110
111 return ret;
112}
113
Radek Krejci38d85362019-09-05 16:26:38 +0200114LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100115lyd_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 +0100116 int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
Michal Vaskof03ed032020-03-04 13:31:44 +0100117 const struct lysc_node *ctx_snode, const struct lyd_node *tree)
Radek Krejci38d85362019-09-05 16:26:38 +0200118{
Michal Vasko90932a92020-02-12 14:33:03 +0100119 LY_ERR ret = LY_SUCCESS;
Radek Krejci38d85362019-09-05 16:26:38 +0200120 struct ly_err_item *err = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200121 struct lyext_metadata *ant;
122 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
Michal Vaskof03ed032020-03-04 13:31:44 +0100123 (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci38d85362019-09-05 16:26:38 +0200124
Michal Vasko9f96a052020-03-10 09:41:45 +0100125 assert(ctx && meta && ((tree && meta->parent) || ctx_snode));
Michal Vasko8d544252020-03-02 10:19:52 +0100126
Michal Vasko9f96a052020-03-10 09:41:45 +0100127 ant = meta->annotation->data;
Radek Krejci38d85362019-09-05 16:26:38 +0200128
129 if (!second) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100130 meta->value.realtype = ant->type;
Radek Krejci38d85362019-09-05 16:26:38 +0200131 }
Michal Vasko90932a92020-02-12 14:33:03 +0100132 ret = ant->type->plugin->store(ctx, ant->type, value, value_len, options, get_prefix, parser, format,
Michal Vasko9f96a052020-03-10 09:41:45 +0100133 tree ? (void *)meta->parent : (void *)ctx_snode, tree, &meta->value, NULL, &err);
Michal Vasko90932a92020-02-12 14:33:03 +0100134 if (ret && (ret != LY_EINCOMPLETE)) {
Radek Krejci38d85362019-09-05 16:26:38 +0200135 if (err) {
136 ly_err_print(err);
137 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
138 ly_err_free(err);
139 }
140 goto error;
Michal Vasko90932a92020-02-12 14:33:03 +0100141 } else if (dynamic) {
142 *dynamic = 0;
Radek Krejci38d85362019-09-05 16:26:38 +0200143 }
144
145error:
146 return ret;
147}
148
Radek Krejci084289f2019-07-09 17:35:30 +0200149API LY_ERR
Michal Vasko44685da2020-03-17 15:38:06 +0100150lys_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 +0200151 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format)
152{
153 LY_ERR rc = LY_SUCCESS;
154 struct ly_err_item *err = NULL;
155 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200156
157 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
158
159 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
160 LOGARG(ctx, node);
161 return LY_EINVAL;
162 }
163
164 type = ((struct lysc_node_leaf*)node)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200165 /* just validate, no storing of enything */
166 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, LY_TYPE_OPTS_INCOMPLETE_DATA,
167 get_prefix, get_prefix_data, format, node, NULL, NULL, NULL, &err);
168 if (rc == LY_EINCOMPLETE) {
169 /* actually success since we do not provide the context tree and call validation with
170 * LY_TYPE_OPTS_INCOMPLETE_DATA */
171 rc = LY_SUCCESS;
172 } else if (rc && err) {
173 if (ctx) {
174 /* log only in case the ctx was provided as input parameter */
175 ly_err_print(err);
176 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200177 }
Radek Krejci73dead22019-07-11 16:46:16 +0200178 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200179 }
180
181 return rc;
182}
183
184API LY_ERR
Michal Vasko44685da2020-03-17 15:38:06 +0100185lyd_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 +0100186 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 +0200187{
188 LY_ERR rc;
189 struct ly_err_item *err = NULL;
190 struct lysc_type *type;
Michal Vaskof03ed032020-03-04 13:31:44 +0100191 int options = (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200192
193 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
194
195 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200196 rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
Michal Vaskof03ed032020-03-04 13:31:44 +0100197 get_prefix, get_prefix_data, format, tree ? (void*)node : (void*)node->schema, tree,
Radek Krejci73dead22019-07-11 16:46:16 +0200198 NULL, NULL, &err);
199 if (rc == LY_EINCOMPLETE) {
200 return rc;
201 } else if (rc) {
202 if (err) {
203 if (ctx) {
204 ly_err_print(err);
205 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200206 }
Radek Krejci73dead22019-07-11 16:46:16 +0200207 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200208 }
Radek Krejci73dead22019-07-11 16:46:16 +0200209 return rc;
Radek Krejci084289f2019-07-09 17:35:30 +0200210 }
211
212 return LY_SUCCESS;
213}
214
215API LY_ERR
216lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
Michal Vaskof03ed032020-03-04 13:31:44 +0100217 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 +0200218{
219 LY_ERR ret = LY_SUCCESS, rc;
220 struct ly_err_item *err = NULL;
221 struct ly_ctx *ctx;
222 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200223 struct lyd_value data = {0};
Michal Vaskof03ed032020-03-04 13:31:44 +0100224 int options = LY_TYPE_OPTS_STORE | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200225
226 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
227
228 ctx = node->schema->module->ctx;
229 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200230 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 +0100231 tree, &data, NULL, &err);
Radek Krejci73dead22019-07-11 16:46:16 +0200232 if (rc == LY_EINCOMPLETE) {
233 ret = rc;
234 /* continue with comparing, just remember what to return if storing is ok */
235 } else if (rc) {
236 /* value to compare is invalid */
237 ret = LY_EINVAL;
238 if (err) {
239 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200240 }
Radek Krejci73dead22019-07-11 16:46:16 +0200241 goto cleanup;
Radek Krejci084289f2019-07-09 17:35:30 +0200242 }
243
244 /* compare data */
Radek Krejci5af04842019-07-12 11:32:07 +0200245 if (type->plugin->compare(&node->value, &data)) {
246 /* do not assign it directly from the compare callback to keep possible LY_EINCOMPLETE from validation */
247 ret = LY_EVALID;
248 }
Radek Krejci084289f2019-07-09 17:35:30 +0200249
250cleanup:
Radek Krejci62903c32019-07-15 14:42:05 +0200251 type->plugin->free(ctx, &data);
Radek Krejci084289f2019-07-09 17:35:30 +0200252
253 return ret;
254}
255
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200256API const char *
257lyd_value2str(const struct lyd_node_term *node, int *dynamic)
258{
259 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, dynamic, NULL);
260
261 return node->value.realtype->plugin->print(&node->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
262}
263
264API const char *
Michal Vasko9f96a052020-03-10 09:41:45 +0100265lyd_meta2str(const struct lyd_meta *meta, int *dynamic)
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200266{
Michal Vasko9f96a052020-03-10 09:41:45 +0100267 LY_CHECK_ARG_RET(meta ? meta->parent->schema->module->ctx : NULL, meta, dynamic, NULL);
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200268
Michal Vasko9f96a052020-03-10 09:41:45 +0100269 return meta->value.realtype->plugin->print(&meta->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200270}
271
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200272API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100273lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200274{
Radek Krejcie7b95092019-05-15 11:03:07 +0200275 struct lyd_node *result = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200276#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200277 const char *yang_data_name = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200278#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200279
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200280 LY_CHECK_ARG_RET(ctx, ctx, NULL);
281
Michal Vasko5b37a352020-03-06 13:38:33 +0100282 if ((options & LYD_OPT_PARSE_ONLY) && (options & LYD_VALOPT_MASK)) {
283 LOGERR(ctx, LY_EINVAL, "Passing validation flags with LYD_OPT_PARSE_ONLY is not allowed.");
284 return NULL;
285 }
286
Michal Vaskoa3881362020-01-21 15:57:35 +0100287#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200288 if (options & LYD_OPT_RPCREPLY) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200289 /* first item in trees is mandatory - the RPC/action request */
290 LY_CHECK_ARG_RET(ctx, trees, LY_ARRAY_SIZE(trees) >= 1, NULL);
291 if (!trees[0] || trees[0]->parent || !(trees[0]->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
292 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
293 lyd_parse_options_type2str(options));
Radek Krejcie7b95092019-05-15 11:03:07 +0200294 return NULL;
295 }
296 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200297
Radek Krejcie7b95092019-05-15 11:03:07 +0200298 if (options & LYD_OPT_DATA_TEMPLATE) {
299 yang_data_name = va_arg(ap, const char *);
300 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200301#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200302
303 if (!format) {
304 /* TODO try to detect format from the content */
305 }
306
307 switch (format) {
308 case LYD_XML:
Michal Vasko9f96a052020-03-10 09:41:45 +0100309 lyd_parse_xml_data(ctx, data, options, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200310 break;
311#if 0
312 case LYD_JSON:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200313 lyd_parse_json(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200314 break;
315 case LYD_LYB:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200316 lyd_parse_lyb(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200317 break;
318#endif
Michal Vasko52927e22020-03-16 17:26:14 +0100319 case LYD_SCHEMA:
Radek Krejcie7b95092019-05-15 11:03:07 +0200320 LOGINT(ctx);
321 break;
322 }
323
Radek Krejcie7b95092019-05-15 11:03:07 +0200324 return result;
325}
326
327API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100328lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200329{
330 struct lyd_node *result;
331 size_t length;
332 char *addr;
333
334 LY_CHECK_ARG_RET(ctx, ctx, NULL);
335 if (fd < 0) {
336 LOGARG(ctx, fd);
337 return NULL;
338 }
339
340 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
Michal Vaskoa3881362020-01-21 15:57:35 +0100341 result = lyd_parse_mem(ctx, addr ? addr : "", format, options);
Radek Krejcidf3da792019-05-17 10:32:24 +0200342 if (addr) {
343 ly_munmap(addr, length);
344 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200345
346 return result;
347}
348
349API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100350lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200351{
352 int fd;
353 struct lyd_node *result;
354 size_t len;
Radek Krejcie7b95092019-05-15 11:03:07 +0200355
356 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
357
358 fd = open(path, O_RDONLY);
359 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
360
361 if (!format) {
362 /* unknown format - try to detect it from filename's suffix */
363 len = strlen(path);
364
365 /* ignore trailing whitespaces */
366 for (; len > 0 && isspace(path[len - 1]); len--);
367
368 if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
369 format = LYD_XML;
370#if 0
371 } else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
372 format = LYD_JSON;
373 } else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
374 format = LYD_LYB;
375#endif
376 } /* else still unknown, try later to detect it from the content */
377 }
378
Michal Vaskoa3881362020-01-21 15:57:35 +0100379 result = lyd_parse_fd(ctx, fd, format, options);
Radek Krejcie7b95092019-05-15 11:03:07 +0200380 close(fd);
381
382 return result;
383}
Radek Krejci084289f2019-07-09 17:35:30 +0200384
Michal Vasko90932a92020-02-12 14:33:03 +0100385LY_ERR
386lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
387 ly_clb_resolve_prefix get_prefix, void *prefix_data, LYD_FORMAT format, struct lyd_node **node)
388{
389 LY_ERR ret;
390 struct lyd_node_term *term;
391
Michal Vasko9b368d32020-02-14 13:53:31 +0100392 assert(schema->nodetype & LYD_NODE_TERM);
393
Michal Vasko90932a92020-02-12 14:33:03 +0100394 term = calloc(1, sizeof *term);
395 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
396
397 term->schema = schema;
398 term->prev = (struct lyd_node *)term;
Michal Vasko9b368d32020-02-14 13:53:31 +0100399 term->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100400
401 ret = lyd_value_parse(term, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
402 if (ret && (ret != LY_EINCOMPLETE)) {
403 free(term);
404 return ret;
405 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100406 lyd_hash((struct lyd_node *)term);
407
408 *node = (struct lyd_node *)term;
409 return ret;
410}
411
412LY_ERR
413lyd_create_term2(const struct lysc_node *schema, const struct lyd_value *val, struct lyd_node **node)
414{
415 LY_ERR ret;
416 struct lyd_node_term *term;
417 struct lysc_type *type;
418
419 assert(schema->nodetype & LYD_NODE_TERM);
420
421 term = calloc(1, sizeof *term);
422 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
423
424 term->schema = schema;
425 term->prev = (struct lyd_node *)term;
426 term->flags = LYD_NEW;
427
428 type = ((struct lysc_node_leaf *)schema)->type;
429 ret = type->plugin->duplicate(schema->module->ctx, val, &term->value);
430 if (ret) {
431 LOGERR(schema->module->ctx, ret, "Value duplication failed.");
432 free(term);
433 return ret;
434 }
435 lyd_hash((struct lyd_node *)term);
Michal Vasko90932a92020-02-12 14:33:03 +0100436
437 *node = (struct lyd_node *)term;
438 return ret;
439}
440
441LY_ERR
442lyd_create_inner(const struct lysc_node *schema, struct lyd_node **node)
443{
444 struct lyd_node_inner *in;
445
Michal Vasko9b368d32020-02-14 13:53:31 +0100446 assert(schema->nodetype & LYD_NODE_INNER);
447
Michal Vasko90932a92020-02-12 14:33:03 +0100448 in = calloc(1, sizeof *in);
449 LY_CHECK_ERR_RET(!in, LOGMEM(schema->module->ctx), LY_EMEM);
450
451 in->schema = schema;
452 in->prev = (struct lyd_node *)in;
Michal Vasko9b368d32020-02-14 13:53:31 +0100453 in->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100454
Michal Vasko9b368d32020-02-14 13:53:31 +0100455 /* do not hash list with keys, we need them for the hash */
456 if ((schema->nodetype != LYS_LIST) || (schema->flags & LYS_KEYLESS)) {
457 lyd_hash((struct lyd_node *)in);
458 }
Michal Vasko90932a92020-02-12 14:33:03 +0100459
460 *node = (struct lyd_node *)in;
461 return LY_SUCCESS;
462}
463
464static void
465ly_keys_clean(struct ly_keys *keys)
466{
467 size_t i;
468
469 for (i = 0; i < keys->key_count; ++i) {
470 keys->keys[i].schema->type->plugin->free(keys->keys[i].schema->module->ctx, &keys->keys[i].val);
471 }
472 free(keys->str);
473 free(keys->keys);
474}
475
476static char *
477ly_keys_parse_next(char **next_key, char **key_name)
478{
479 char *ptr, *ptr2, *val, quot;
480
481 ptr = *next_key;
482
483 /* "[" */
484 LY_CHECK_GOTO(ptr[0] != '[', error);
485 ++ptr;
486
487 /* key name */
488 ptr2 = strchr(ptr, '=');
489 LY_CHECK_GOTO(!ptr2, error);
490
491 *key_name = ptr;
492 ptr2[0] = '\0';
493
494 /* \0, was '=' */
495 ptr = ptr2 + 1;
496
497 /* quote */
498 LY_CHECK_GOTO((ptr[0] != '\'') && (ptr[0] != '\"'), error);
499 quot = ptr[0];
500 ++ptr;
501
502 /* value, terminate it */
503 val = ptr;
504 ptr2 = strchr(ptr, quot);
505 LY_CHECK_GOTO(!ptr2, error);
506 ptr2[0] = '\0';
507
508 /* \0, was quote */
509 ptr = ptr2 + 1;
510
511 /* "]" */
512 LY_CHECK_GOTO(ptr[0] != ']', error);
513 ++ptr;
514
515 *next_key = ptr;
516 return val;
517
518error:
519 *next_key = ptr;
520 return NULL;
521}
522
523/* fill keys structure; if store is set, fill also each val */
524static LY_ERR
525ly_keys_parse(const struct lysc_node *list, const char *keys_str, size_t keys_len, int store, struct ly_keys *keys)
526{
527 LY_ERR ret = LY_SUCCESS;
528 char *next_key, *name;
529 const struct lysc_node *key;
530 size_t i;
531
532 assert(list->nodetype == LYS_LIST);
533
534 memset(keys, 0, sizeof *keys);
535
Michal Vaskof03ed032020-03-04 13:31:44 +0100536 if (!keys_str) {
537 /* nothing to parse */
538 return LY_SUCCESS;
539 }
540
541 keys->str = strndup(keys_str, keys_len);
Michal Vasko90932a92020-02-12 14:33:03 +0100542 LY_CHECK_ERR_GOTO(!keys->str, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
543
544 next_key = keys->str;
545 while (next_key[0]) {
546 /* new key */
547 keys->keys = ly_realloc(keys->keys, (keys->key_count + 1) * sizeof *keys->keys);
548 LY_CHECK_ERR_GOTO(!keys->keys, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
549
550 /* fill */
551 keys->keys[keys->key_count].value = ly_keys_parse_next(&next_key, &name);
552 if (!keys->keys[keys->key_count].value) {
553 LOGERR(list->module->ctx, LY_EINVAL, "Invalid keys string (at \"%s\").", next_key);
554 ret = LY_EINVAL;
555 goto cleanup;
556 }
557
558 /* find schema node */
559 key = lys_find_child(list, list->module, name, 0, LYS_LEAF, 0);
560 if (!key) {
561 LOGERR(list->module->ctx, LY_EINVAL, "List \"%s\" has no key \"%s\".", list->name, name);
562 ret = LY_EINVAL;
563 goto cleanup;
564 }
565 keys->keys[keys->key_count].schema = (const struct lysc_node_leaf *)key;
566
567 /* check that we do not have it already */
568 for (i = 0; i < keys->key_count; ++i) {
569 if (keys->keys[i].schema == keys->keys[keys->key_count].schema) {
570 LOGERR(list->module->ctx, LY_EINVAL, "Duplicit key \"%s\" value.", name);
571 ret = LY_EINVAL;
572 goto cleanup;
573 }
574 }
575
576 if (store) {
577 /* store the value */
578 ret = lyd_value_store(&keys->keys[keys->key_count].val, key, keys->keys[keys->key_count].value, 0, 0,
579 lydjson_resolve_prefix, NULL, LYD_JSON);
580 LY_CHECK_GOTO(ret, cleanup);
581 }
582
583 /* another valid key */
584 ++keys->key_count;
585 }
586
587cleanup:
588 ly_keys_clean(keys);
589 return ret;
590}
591
592LY_ERR
593lyd_create_list(const struct lysc_node *schema, const char *keys_str, size_t keys_len, struct lyd_node **node)
594{
595 LY_ERR ret = LY_SUCCESS;
596 const struct lysc_node *key_s;
597 struct lyd_node *list = NULL, *key;
598 struct ly_keys keys = {0};
599 size_t i;
600
601 assert((schema->nodetype == LYS_LIST) && !(schema->flags & LYS_KEYLESS));
602
603 /* parse keys */
604 LY_CHECK_GOTO(ret = ly_keys_parse(schema, keys_str, keys_len, 0, &keys), cleanup);
605
606 /* create list */
607 LY_CHECK_GOTO(ret = lyd_create_inner(schema, &list), cleanup);
608
609 /* everything was checked except that all keys are set */
610 i = 0;
611 for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
612 ++i;
613 }
614 if (i != keys.key_count) {
615 LOGERR(schema->module->ctx, LY_EINVAL, "List \"%s\" is missing some keys.", schema->name);
616 ret = LY_EINVAL;
617 goto cleanup;
618 }
619
620 /* create and insert all the keys */
621 for (i = 0; i < keys.key_count; ++i) {
Michal Vaskof03ed032020-03-04 13:31:44 +0100622 LY_CHECK_GOTO(ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value,
623 strlen(keys.keys[i].value), NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key), cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100624 lyd_insert_node(list, NULL, key);
625 }
626
Michal Vasko9b368d32020-02-14 13:53:31 +0100627 /* hash having all the keys */
628 lyd_hash(list);
629
Michal Vasko90932a92020-02-12 14:33:03 +0100630 /* success */
631 *node = list;
632 list = NULL;
633
634cleanup:
635 lyd_free_tree(list);
636 ly_keys_clean(&keys);
637 return ret;
638}
639
640LY_ERR
641lyd_create_any(const struct lysc_node *schema, const void *value, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
642{
643 struct lyd_node_any *any;
644
Michal Vasko9b368d32020-02-14 13:53:31 +0100645 assert(schema->nodetype & LYD_NODE_ANY);
646
Michal Vasko90932a92020-02-12 14:33:03 +0100647 any = calloc(1, sizeof *any);
648 LY_CHECK_ERR_RET(!any, LOGMEM(schema->module->ctx), LY_EMEM);
649
650 any->schema = schema;
651 any->prev = (struct lyd_node *)any;
Michal Vasko9b368d32020-02-14 13:53:31 +0100652 any->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100653
654 any->value.xml = value;
655 any->value_type = value_type;
Michal Vasko9b368d32020-02-14 13:53:31 +0100656 lyd_hash((struct lyd_node *)any);
Michal Vasko90932a92020-02-12 14:33:03 +0100657
658 *node = (struct lyd_node *)any;
659 return LY_SUCCESS;
660}
661
Michal Vasko52927e22020-03-16 17:26:14 +0100662LY_ERR
663lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *value, size_t value_len,
664 int *dynamic, LYD_FORMAT format, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
665 const char *ns, struct lyd_node **node)
666{
667 struct lyd_node_opaq *opaq;
668
669 assert(ctx && name && name_len && ns);
670
671 if (!value_len) {
672 value = "";
673 }
674
675 opaq = calloc(1, sizeof *opaq);
676 LY_CHECK_ERR_RET(!opaq, LOGMEM(ctx), LY_EMEM);
677
678 opaq->prev = (struct lyd_node *)opaq;
679
680 opaq->name = lydict_insert(ctx, name, name_len);
681 opaq->format = format;
682 if (pref_len) {
683 opaq->prefix.pref = lydict_insert(ctx, prefix, pref_len);
684 }
685 opaq->prefix.ns = lydict_insert(ctx, ns, 0);
686 opaq->val_prefs = val_prefs;
687 if (dynamic && *dynamic) {
688 opaq->value = lydict_insert_zc(ctx, (char *)value);
689 *dynamic = 0;
690 } else {
691 opaq->value = lydict_insert(ctx, value, value_len);
692 }
693 opaq->ctx = ctx;
694
695 *node = (struct lyd_node *)opaq;
696 return LY_SUCCESS;
697}
698
Michal Vasko013a8182020-03-03 10:46:53 +0100699API struct lyd_node *
700lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name)
701{
702 struct lyd_node *ret = NULL;
703 const struct lysc_node *schema;
704 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
705
706 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
707
Michal Vaskof03ed032020-03-04 13:31:44 +0100708 if (!module) {
709 module = parent->schema->module;
710 }
711
Michal Vasko1bf09392020-03-27 12:38:10 +0100712 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_CONTAINER | LYS_NOTIF | LYS_RPC | LYS_ACTION, 0);
Michal Vasko013a8182020-03-03 10:46:53 +0100713 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Inner node \"%s\" not found.", name), NULL);
714
715 if (!lyd_create_inner(schema, &ret) && parent) {
716 lyd_insert_node(parent, NULL, ret);
717 }
718 return ret;
719}
720
721API struct lyd_node *
722lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, ...)
723{
724 struct lyd_node *ret = NULL, *key;
725 const struct lysc_node *schema, *key_s;
726 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
727 va_list ap;
728 const char *key_val;
729 LY_ERR rc = LY_SUCCESS;
730
731 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
732
Michal Vaskof03ed032020-03-04 13:31:44 +0100733 if (!module) {
734 module = parent->schema->module;
735 }
736
Michal Vasko013a8182020-03-03 10:46:53 +0100737 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
738 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
739
740 /* create list inner node */
741 LY_CHECK_RET(lyd_create_inner(schema, &ret), NULL);
742
743 va_start(ap, name);
744
745 /* create and insert all the keys */
746 for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
747 key_val = va_arg(ap, const char *);
748
Michal Vaskof03ed032020-03-04 13:31:44 +0100749 rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key);
750 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko013a8182020-03-03 10:46:53 +0100751 lyd_insert_node(ret, NULL, key);
752 }
753
754 /* hash having all the keys */
755 lyd_hash(ret);
756
757 if (parent) {
758 lyd_insert_node(parent, NULL, ret);
759 }
760
761cleanup:
762 if (rc) {
763 lyd_free_tree(ret);
764 ret = NULL;
765 }
766 va_end(ap);
767 return ret;
768}
769
770API struct lyd_node *
771lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys)
772{
773 struct lyd_node *ret = NULL;
774 const struct lysc_node *schema;
775 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
776
777 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
778
Michal Vaskof03ed032020-03-04 13:31:44 +0100779 if (!module) {
780 module = parent->schema->module;
781 }
782
Michal Vasko013a8182020-03-03 10:46:53 +0100783 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
784 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
785
Michal Vaskof03ed032020-03-04 13:31:44 +0100786 if (!lyd_create_list(schema, keys, keys ? strlen(keys) : 0, &ret) && parent) {
Michal Vasko013a8182020-03-03 10:46:53 +0100787 lyd_insert_node(parent, NULL, ret);
788 }
789 return ret;
790}
791
792API struct lyd_node *
793lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
794{
795 struct lyd_node *ret = NULL;
796 const struct lysc_node *schema;
797 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
798
799 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
800
Michal Vaskof03ed032020-03-04 13:31:44 +0100801 if (!module) {
802 module = parent->schema->module;
803 }
804
Michal Vasko013a8182020-03-03 10:46:53 +0100805 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, 0);
806 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), NULL);
807
Michal Vaskof03ed032020-03-04 13:31:44 +0100808 if (!lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &ret)
809 && parent) {
Michal Vasko013a8182020-03-03 10:46:53 +0100810 lyd_insert_node(parent, NULL, ret);
811 }
812 return ret;
813}
814
815API struct lyd_node *
816lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
817 LYD_ANYDATA_VALUETYPE value_type)
818{
819 struct lyd_node *ret = NULL;
820 const struct lysc_node *schema;
821 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
822
823 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
824
Michal Vaskof03ed032020-03-04 13:31:44 +0100825 if (!module) {
826 module = parent->schema->module;
827 }
828
Michal Vasko013a8182020-03-03 10:46:53 +0100829 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, 0);
830 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Any node \"%s\" not found.", name), NULL);
831
832 if (!lyd_create_any(schema, value, value_type, &ret) && parent) {
833 lyd_insert_node(parent, NULL, ret);
834 }
835 return ret;
836}
837
Michal Vasko90932a92020-02-12 14:33:03 +0100838struct lyd_node *
839lyd_get_prev_key_anchor(const struct lyd_node *first_sibling, const struct lysc_node *new_key)
840{
841 const struct lysc_node *prev_key;
842 struct lyd_node *match = NULL;
843
844 if (!first_sibling) {
845 return NULL;
846 }
847
848 for (prev_key = new_key->prev; !match && prev_key->next; prev_key = prev_key->prev) {
849 lyd_find_sibling_val(first_sibling, prev_key, NULL, 0, &match);
850 }
851
852 return match;
853}
854
855/**
856 * @brief Insert node after a sibling.
857 *
Michal Vasko9f96a052020-03-10 09:41:45 +0100858 * Handles inserting into NP containers and key-less lists.
859 *
Michal Vasko90932a92020-02-12 14:33:03 +0100860 * @param[in] sibling Sibling to insert after.
861 * @param[in] node Node to insert.
862 */
863static void
Michal Vaskof03ed032020-03-04 13:31:44 +0100864lyd_insert_after_node(struct lyd_node *sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100865{
Michal Vasko0249f7c2020-03-05 16:36:40 +0100866 struct lyd_node_inner *par;
867
Michal Vasko90932a92020-02-12 14:33:03 +0100868 assert(!node->next && (node->prev == node));
869
870 node->next = sibling->next;
871 node->prev = sibling;
872 sibling->next = node;
873 if (node->next) {
874 /* sibling had a succeeding node */
875 node->next->prev = node;
876 } else {
877 /* sibling was last, find first sibling and change its prev */
878 if (sibling->parent) {
879 sibling = sibling->parent->child;
880 } else {
881 for (; sibling->prev->next != node; sibling = sibling->prev);
882 }
883 sibling->prev = node;
884 }
885 node->parent = sibling->parent;
Michal Vasko0249f7c2020-03-05 16:36:40 +0100886
Michal Vasko9f96a052020-03-10 09:41:45 +0100887 for (par = node->parent; par; par = par->parent) {
888 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
889 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +0100890 par->flags &= ~LYD_DEFAULT;
891 }
Michal Vasko9f96a052020-03-10 09:41:45 +0100892 if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
893 /* rehash key-less list */
894 lyd_hash((struct lyd_node *)par);
895 }
Michal Vasko0249f7c2020-03-05 16:36:40 +0100896 }
897
898 /* insert into hash table */
899 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +0100900}
901
902/**
903 * @brief Insert node before a sibling.
904 *
Michal Vasko9f96a052020-03-10 09:41:45 +0100905 * Handles inserting into NP containers and key-less lists.
906 *
Michal Vasko90932a92020-02-12 14:33:03 +0100907 * @param[in] sibling Sibling to insert before.
908 * @param[in] node Node to insert.
909 */
910static void
Michal Vaskof03ed032020-03-04 13:31:44 +0100911lyd_insert_before_node(struct lyd_node *sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100912{
Michal Vasko0249f7c2020-03-05 16:36:40 +0100913 struct lyd_node_inner *par;
914
Michal Vasko90932a92020-02-12 14:33:03 +0100915 assert(!node->next && (node->prev == node));
916
917 node->next = sibling;
918 /* covers situation of sibling being first */
919 node->prev = sibling->prev;
920 sibling->prev = node;
921 if (node->prev->next) {
922 /* sibling had a preceding node */
923 node->prev->next = node;
924 } else if (sibling->parent) {
925 /* sibling was first and we must also change parent child pointer */
926 sibling->parent->child = node;
927 }
928 node->parent = sibling->parent;
Michal Vasko0249f7c2020-03-05 16:36:40 +0100929
Michal Vasko9f96a052020-03-10 09:41:45 +0100930 for (par = node->parent; par; par = par->parent) {
931 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
932 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +0100933 par->flags &= ~LYD_DEFAULT;
934 }
Michal Vasko9f96a052020-03-10 09:41:45 +0100935 if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
936 /* rehash key-less list */
937 lyd_hash((struct lyd_node *)par);
938 }
Michal Vasko0249f7c2020-03-05 16:36:40 +0100939 }
940
941 /* insert into hash table */
942 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +0100943}
944
945/**
946 * @brief Insert node as the last child of a parent.
947 *
Michal Vasko9f96a052020-03-10 09:41:45 +0100948 * Handles inserting into NP containers and key-less lists.
949 *
Michal Vasko90932a92020-02-12 14:33:03 +0100950 * @param[in] parent Parent to insert into.
951 * @param[in] node Node to insert.
952 */
953static void
Michal Vaskof03ed032020-03-04 13:31:44 +0100954lyd_insert_last_node(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100955{
956 struct lyd_node_inner *par;
957
Michal Vasko0249f7c2020-03-05 16:36:40 +0100958 assert(parent && !node->next && (node->prev == node));
Michal Vasko52927e22020-03-16 17:26:14 +0100959 assert(!parent->schema || (parent->schema->nodetype & LYD_NODE_INNER));
Michal Vasko90932a92020-02-12 14:33:03 +0100960
961 par = (struct lyd_node_inner *)parent;
962
963 if (!par->child) {
964 par->child = node;
965 } else {
966 node->prev = par->child->prev;
967 par->child->prev->next = node;
968 par->child->prev = node;
969 }
970 node->parent = par;
Michal Vasko0249f7c2020-03-05 16:36:40 +0100971
Michal Vasko9f96a052020-03-10 09:41:45 +0100972 for (; par; par = par->parent) {
973 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
974 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +0100975 par->flags &= ~LYD_DEFAULT;
976 }
Michal Vasko52927e22020-03-16 17:26:14 +0100977 if (par->schema && (par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100978 /* rehash key-less list */
979 lyd_hash((struct lyd_node *)par);
980 }
Michal Vasko0249f7c2020-03-05 16:36:40 +0100981 }
982
983 /* insert into hash table */
984 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +0100985}
986
987void
Michal Vasko9b368d32020-02-14 13:53:31 +0100988lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100989{
Michal Vasko9b368d32020-02-14 13:53:31 +0100990 struct lyd_node *anchor;
Michal Vasko9f96a052020-03-10 09:41:45 +0100991 const struct lysc_node *skey = NULL;
992 int has_keys;
Michal Vasko90932a92020-02-12 14:33:03 +0100993
Michal Vasko52927e22020-03-16 17:26:14 +0100994 assert((parent || first_sibling) && node && (node->hash || !node->schema));
Michal Vasko9b368d32020-02-14 13:53:31 +0100995
996 if (!parent && first_sibling && (*first_sibling) && (*first_sibling)->parent) {
997 parent = (struct lyd_node *)(*first_sibling)->parent;
998 }
Michal Vasko90932a92020-02-12 14:33:03 +0100999
1000 if (parent) {
Michal Vasko52927e22020-03-16 17:26:14 +01001001 if (node->schema && (node->schema->flags & LYS_KEY)) {
Michal Vasko90932a92020-02-12 14:33:03 +01001002 /* it is key and we need to insert it at the correct place */
Michal Vasko9b368d32020-02-14 13:53:31 +01001003 anchor = lyd_get_prev_key_anchor(lyd_node_children(parent), node->schema);
1004 if (anchor) {
Michal Vaskof03ed032020-03-04 13:31:44 +01001005 lyd_insert_after_node(anchor, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001006 } else if (lyd_node_children(parent)) {
Radek Krejcidae0ee82020-05-06 16:53:24 +02001007 lyd_insert_before_node(lyd_node_children(parent), node);
Michal Vasko90932a92020-02-12 14:33:03 +01001008 } else {
Michal Vaskof03ed032020-03-04 13:31:44 +01001009 lyd_insert_last_node(parent, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001010 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001011
1012 /* hash list if all its keys were added */
1013 assert(parent->schema->nodetype == LYS_LIST);
Radek Krejcidae0ee82020-05-06 16:53:24 +02001014 anchor = lyd_node_children(parent);
Michal Vasko9f96a052020-03-10 09:41:45 +01001015 has_keys = 1;
1016 while ((skey = lys_getnext(skey, parent->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
1017 if (!anchor || (anchor->schema != skey)) {
1018 /* key missing */
1019 has_keys = 0;
1020 break;
1021 }
1022
1023 anchor = anchor->next;
1024 }
1025 if (has_keys) {
1026 lyd_hash(parent);
1027 }
1028
Michal Vasko90932a92020-02-12 14:33:03 +01001029 } else {
1030 /* last child */
Michal Vaskof03ed032020-03-04 13:31:44 +01001031 lyd_insert_last_node(parent, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001032 }
Michal Vasko9b368d32020-02-14 13:53:31 +01001033 } else if (*first_sibling) {
Michal Vaskob1b5c262020-03-05 14:29:47 +01001034 /* top-level siblings */
Michal Vasko9b368d32020-02-14 13:53:31 +01001035 anchor = (*first_sibling)->prev;
Michal Vaskoc193ce92020-03-06 11:04:48 +01001036 while (anchor->prev->next && (lyd_owner_module(anchor) != lyd_owner_module(node))) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001037 anchor = anchor->prev;
1038 }
1039
Michal Vaskoc193ce92020-03-06 11:04:48 +01001040 if (lyd_owner_module(anchor) == lyd_owner_module(node)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +01001041 /* insert after last sibling from this module */
1042 lyd_insert_after_node(anchor, node);
1043 } else {
1044 /* no data from this module, insert at the last position */
1045 lyd_insert_after_node((*first_sibling)->prev, node);
1046 }
Michal Vasko90932a92020-02-12 14:33:03 +01001047 } else {
Michal Vasko9b368d32020-02-14 13:53:31 +01001048 /* the only sibling */
1049 *first_sibling = node;
Michal Vasko90932a92020-02-12 14:33:03 +01001050 }
Michal Vasko90932a92020-02-12 14:33:03 +01001051}
1052
Michal Vaskof03ed032020-03-04 13:31:44 +01001053static LY_ERR
1054lyd_insert_check_schema(const struct lysc_node *parent, const struct lysc_node *schema)
1055{
1056 const struct lysc_node *par2;
1057
1058 assert(schema);
1059
1060 /* adjust parent first */
1061 while (parent && (parent->nodetype & (LYS_CASE | LYS_CHOICE))) {
1062 parent = parent->parent;
1063 }
1064
1065 /* find schema parent */
1066 for (par2 = schema->parent; par2 && (par2->nodetype & (LYS_CASE | LYS_CHOICE)); par2 = par2->parent);
1067
1068 if (parent) {
1069 /* inner node */
1070 if (par2 != parent) {
1071 LOGERR(parent->module->ctx, LY_EINVAL, "Cannot insert, parent of \"%s\" is not \"%s\".", schema->name, parent->name);
1072 return LY_EINVAL;
1073 }
1074 } else {
1075 /* top-level node */
1076 if (par2) {
1077 LOGERR(parent->module->ctx, LY_EINVAL, "Cannot insert, node \"%s\" is not top-level.", schema->name);
1078 return LY_EINVAL;
1079 }
1080 }
1081
1082 return LY_SUCCESS;
1083}
1084
1085API LY_ERR
1086lyd_insert(struct lyd_node *parent, struct lyd_node *node)
1087{
1088 struct lyd_node *iter;
1089
1090 LY_CHECK_ARG_RET(NULL, parent, node, !(parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
1091
1092 LY_CHECK_RET(lyd_insert_check_schema(parent->schema, node->schema));
1093
1094 if (node->schema->flags & LYS_KEY) {
1095 LOGERR(parent->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1096 return LY_EINVAL;
1097 }
1098
1099 if (node->parent || node->prev->next) {
1100 lyd_unlink_tree(node);
1101 }
1102
1103 while (node) {
1104 iter = node->next;
1105 lyd_unlink_tree(node);
1106 lyd_insert_node(parent, NULL, node);
1107 node = iter;
1108 }
1109 return LY_SUCCESS;
1110}
1111
1112API LY_ERR
Michal Vaskob1b5c262020-03-05 14:29:47 +01001113lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node)
1114{
1115 struct lyd_node *iter;
1116
1117 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1118
1119 LY_CHECK_RET(lyd_insert_check_schema(sibling->schema->parent, node->schema));
1120
1121 if (node->schema->flags & LYS_KEY) {
1122 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1123 return LY_EINVAL;
1124 }
1125
1126 if (node->parent || node->prev->next) {
1127 lyd_unlink_tree(node);
1128 }
1129
1130 while (node) {
1131 iter = node->next;
1132 lyd_unlink_tree(node);
1133 lyd_insert_node(NULL, &sibling, node);
1134 node = iter;
1135 }
1136 return LY_SUCCESS;
1137}
1138
Michal Vasko0249f7c2020-03-05 16:36:40 +01001139static LY_ERR
1140lyd_insert_after_check_place(struct lyd_node *anchor, struct lyd_node *sibling, struct lyd_node *node)
1141{
1142 if (sibling->parent) {
1143 /* nested, we do not care for the order */
1144 return LY_SUCCESS;
1145 }
1146
1147 if (anchor) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001148 if (anchor->next && (lyd_owner_module(anchor) == lyd_owner_module(anchor->next))
1149 && (lyd_owner_module(node) != lyd_owner_module(anchor))) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001150 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 +01001151 lyd_owner_module(node)->name, lyd_owner_module(anchor)->name);
Michal Vasko0249f7c2020-03-05 16:36:40 +01001152 return LY_EINVAL;
1153 }
1154
Michal Vaskoc193ce92020-03-06 11:04:48 +01001155 if ((lyd_owner_module(node) == lyd_owner_module(anchor))
1156 || (anchor->next && (lyd_owner_module(node) == lyd_owner_module(anchor->next)))) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001157 /* inserting before/after its module data */
1158 return LY_SUCCESS;
1159 }
1160 }
1161
1162 /* find first sibling */
1163 while (sibling->prev->next) {
1164 sibling = sibling->prev;
1165 }
1166
1167 if (!anchor) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001168 if (lyd_owner_module(node) == lyd_owner_module(sibling)) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001169 /* inserting before its module data */
1170 return LY_SUCCESS;
1171 }
1172 }
1173
1174 /* check there are no data of this module */
1175 LY_LIST_FOR(sibling, sibling) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001176 if (lyd_owner_module(node) == lyd_owner_module(sibling)) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001177 /* some data of this module found */
1178 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Top-level data of module \"%s\" already exist,"
Michal Vaskoc193ce92020-03-06 11:04:48 +01001179 " they must be directly connected.", lyd_owner_module(node)->name);
Michal Vasko0249f7c2020-03-05 16:36:40 +01001180 return LY_EINVAL;
1181 }
1182 }
1183
1184 return LY_SUCCESS;
1185}
1186
Michal Vaskob1b5c262020-03-05 14:29:47 +01001187API LY_ERR
Michal Vaskof03ed032020-03-04 13:31:44 +01001188lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
1189{
1190 struct lyd_node *iter;
1191
1192 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1193
1194 LY_CHECK_RET(lyd_insert_check_schema(sibling->schema->parent, node->schema));
1195
1196 if (node->schema->flags & LYS_KEY) {
1197 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1198 return LY_EINVAL;
1199 } else if (sibling->schema->flags & LYS_KEY) {
1200 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert into keys.");
1201 return LY_EINVAL;
1202 }
1203
Michal Vasko0249f7c2020-03-05 16:36:40 +01001204 LY_CHECK_RET(lyd_insert_after_check_place(sibling->prev->next ? sibling->prev : NULL, sibling, node));
1205
Michal Vaskof03ed032020-03-04 13:31:44 +01001206 if (node->parent || node->prev->next) {
1207 lyd_unlink_tree(node);
1208 }
1209
1210 /* insert in reverse order to get the original order */
1211 node = node->prev;
1212 while (node) {
1213 iter = node->prev;
1214 lyd_unlink_tree(node);
1215
1216 lyd_insert_before_node(sibling, node);
1217 /* move the anchor accordingly */
1218 sibling = node;
1219
1220 node = (iter == node) ? NULL : iter;
1221 }
1222 return LY_SUCCESS;
1223}
1224
1225API LY_ERR
1226lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
1227{
1228 struct lyd_node *iter;
1229
1230 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1231
1232 LY_CHECK_RET(lyd_insert_check_schema(sibling->schema->parent, node->schema));
1233
1234 if (node->schema->flags & LYS_KEY) {
1235 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1236 return LY_EINVAL;
1237 } else if (sibling->next && (sibling->next->schema->flags & LYS_KEY)) {
1238 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert into keys.");
1239 return LY_EINVAL;
1240 }
1241
Michal Vasko0249f7c2020-03-05 16:36:40 +01001242 LY_CHECK_RET(lyd_insert_after_check_place(sibling, sibling, node));
1243
Michal Vaskof03ed032020-03-04 13:31:44 +01001244 if (node->parent || node->prev->next) {
1245 lyd_unlink_tree(node);
1246 }
1247
1248 while (node) {
1249 iter = node->next;
1250 lyd_unlink_tree(node);
1251
1252 lyd_insert_after_node(sibling, node);
1253 /* move the anchor accordingly */
1254 sibling = node;
1255
1256 node = iter;
1257 }
1258 return LY_SUCCESS;
1259}
1260
1261API void
1262lyd_unlink_tree(struct lyd_node *node)
1263{
1264 struct lyd_node *iter;
1265
1266 if (!node) {
1267 return;
1268 }
1269
1270 /* unlink from siblings */
1271 if (node->prev->next) {
1272 node->prev->next = node->next;
1273 }
1274 if (node->next) {
1275 node->next->prev = node->prev;
1276 } else {
1277 /* unlinking the last node */
1278 if (node->parent) {
1279 iter = node->parent->child;
1280 } else {
1281 iter = node->prev;
1282 while (iter->prev != node) {
1283 iter = iter->prev;
1284 }
1285 }
1286 /* update the "last" pointer from the first node */
1287 iter->prev = node->prev;
1288 }
1289
1290 /* unlink from parent */
1291 if (node->parent) {
1292 if (node->parent->child == node) {
1293 /* the node is the first child */
1294 node->parent->child = node->next;
1295 }
1296
1297 lyd_unlink_hash(node);
1298
1299 /* check for keyless list and update its hash */
1300 for (iter = (struct lyd_node *)node->parent; iter; iter = (struct lyd_node *)iter->parent) {
Michal Vasko413c7f22020-05-05 12:34:06 +02001301 if (iter->schema && (iter->schema->flags & LYS_KEYLESS)) {
Michal Vaskof03ed032020-03-04 13:31:44 +01001302 lyd_hash(iter);
1303 }
1304 }
1305
1306 node->parent = NULL;
1307 }
1308
1309 node->next = NULL;
1310 node->prev = node;
1311}
1312
Michal Vasko90932a92020-02-12 14:33:03 +01001313LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +01001314lyd_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 +01001315 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 +01001316 void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode)
Michal Vasko90932a92020-02-12 14:33:03 +01001317{
1318 LY_ERR ret;
1319 struct lysc_ext_instance *ant = NULL;
Michal Vasko9f96a052020-03-10 09:41:45 +01001320 struct lyd_meta *mt, *last;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001321 LY_ARRAY_SIZE_TYPE u;
Michal Vasko90932a92020-02-12 14:33:03 +01001322
Michal Vasko9f96a052020-03-10 09:41:45 +01001323 assert((parent || meta) && mod);
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001324
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001325 LY_ARRAY_FOR(mod->compiled->exts, u) {
1326 if (mod->compiled->exts[u].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
1327 !ly_strncmp(mod->compiled->exts[u].argument, name, name_len)) {
Michal Vasko90932a92020-02-12 14:33:03 +01001328 /* we have the annotation definition */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001329 ant = &mod->compiled->exts[u];
Michal Vasko90932a92020-02-12 14:33:03 +01001330 break;
1331 }
1332 }
1333 if (!ant) {
1334 /* attribute is not defined as a metadata annotation (RFC 7952) */
1335 LOGERR(mod->ctx, LY_EINVAL, "Annotation definition for attribute \"%s:%.*s\" not found.",
1336 mod->name, name_len, name);
1337 return LY_EINVAL;
1338 }
1339
Michal Vasko9f96a052020-03-10 09:41:45 +01001340 mt = calloc(1, sizeof *mt);
1341 LY_CHECK_ERR_RET(!mt, LOGMEM(mod->ctx), LY_EMEM);
1342 mt->parent = parent;
1343 mt->annotation = ant;
Michal Vasko52927e22020-03-16 17:26:14 +01001344 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 +01001345 if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001346 free(mt);
Michal Vasko90932a92020-02-12 14:33:03 +01001347 return ret;
1348 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001349 mt->name = lydict_insert(mod->ctx, name, name_len);
Michal Vasko90932a92020-02-12 14:33:03 +01001350
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001351 /* insert as the last attribute */
1352 if (parent) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001353 if (parent->meta) {
1354 for (last = parent->meta; last->next; last = last->next);
1355 last->next = mt;
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001356 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01001357 parent->meta = mt;
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001358 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001359 } else if (*meta) {
1360 for (last = *meta; last->next; last = last->next);
1361 last->next = mt;
Michal Vasko90932a92020-02-12 14:33:03 +01001362 }
1363
1364 /* remove default flags from NP containers */
1365 while (parent && (parent->flags & LYD_DEFAULT)) {
1366 parent->flags &= ~LYD_DEFAULT;
1367 parent = (struct lyd_node *)parent->parent;
1368 }
1369
Michal Vasko9f96a052020-03-10 09:41:45 +01001370 if (meta) {
1371 *meta = mt;
Michal Vasko90932a92020-02-12 14:33:03 +01001372 }
1373 return ret;
1374}
1375
Michal Vasko52927e22020-03-16 17:26:14 +01001376LY_ERR
1377ly_create_attr(struct lyd_node *parent, struct ly_attr **attr, const struct ly_ctx *ctx, const char *name,
1378 size_t name_len, const char *value, size_t value_len, int *dynamic, LYD_FORMAT format,
1379 struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *ns)
1380{
1381 struct ly_attr *at, *last;
1382 struct lyd_node_opaq *opaq;
1383
1384 assert(ctx && (parent || attr) && (!parent || !parent->schema));
1385 assert(name && name_len);
1386 assert((prefix_len && ns) || (!prefix_len && !ns));
1387
1388 if (!value_len) {
1389 value = "";
1390 }
1391
1392 at = calloc(1, sizeof *at);
1393 LY_CHECK_ERR_RET(!at, LOGMEM(ctx), LY_EMEM);
1394 at->parent = (struct lyd_node_opaq *)parent;
1395 at->name = lydict_insert(ctx, name, name_len);
1396 if (dynamic && *dynamic) {
1397 at->value = lydict_insert_zc(ctx, (char *)value);
1398 *dynamic = 0;
1399 } else {
1400 at->value = lydict_insert(ctx, value, value_len);
1401 }
1402
1403 at->format = format;
1404 at->val_prefs = val_prefs;
1405 if (ns) {
1406 at->prefix.pref = lydict_insert(ctx, prefix, prefix_len);
1407 at->prefix.ns = lydict_insert(ctx, ns, 0);
1408 }
1409
1410 /* insert as the last attribute */
1411 if (parent) {
1412 opaq = (struct lyd_node_opaq *)parent;
1413 if (opaq->attr) {
1414 for (last = opaq->attr; last->next; last = last->next);
1415 last->next = at;
1416 } else {
1417 opaq->attr = at;
1418 }
1419 } else if (*attr) {
1420 for (last = *attr; last->next; last = last->next);
1421 last->next = at;
1422 }
1423
1424 if (attr) {
1425 *attr = at;
1426 }
1427 return LY_SUCCESS;
1428}
1429
Radek Krejci084289f2019-07-09 17:35:30 +02001430API const struct lyd_node_term *
Michal Vaskof03ed032020-03-04 13:31:44 +01001431lyd_target(struct lyd_value_path *path, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +02001432{
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001433 LY_ARRAY_SIZE_TYPE u, v;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001434 const struct lyd_node *start_sibling;
Michal Vaskoe444f752020-02-10 12:20:06 +01001435 struct lyd_node *node = NULL;
Radek Krejci084289f2019-07-09 17:35:30 +02001436 uint64_t pos = 1;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001437 int match;
Radek Krejci084289f2019-07-09 17:35:30 +02001438
Michal Vaskof03ed032020-03-04 13:31:44 +01001439 LY_CHECK_ARG_RET(NULL, path, tree, NULL);
Radek Krejci084289f2019-07-09 17:35:30 +02001440
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001441 /* first iteration */
1442 start_sibling = tree;
1443 u = 0;
1444 while (u < LY_ARRAY_SIZE(path)) {
1445 /* find next node instance */
Michal Vasko84c9f1b2020-05-14 12:08:11 +02001446 if (start_sibling && !start_sibling->prev->next && !(path[u].node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
1447 /* starting from the beginning using hashes */
1448 lyd_find_sibling_val(start_sibling, path[u].node, NULL, 0, &node);
1449 } else {
1450 /* next matching sibling */
1451 lyd_find_sibling_next2(start_sibling, path[u].node, NULL, 0, &node);
1452 }
Radek Krejci084289f2019-07-09 17:35:30 +02001453 if (!node) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001454 break;
Radek Krejci084289f2019-07-09 17:35:30 +02001455 }
1456
1457 /* check predicate if any */
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001458 match = 1;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001459 LY_ARRAY_FOR(path[u].predicates, v) {
1460 if (path[u].predicates[v].type == 0) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001461 assert(LY_ARRAY_SIZE(path[u].predicates) == 1);
Radek Krejci084289f2019-07-09 17:35:30 +02001462 /* position predicate */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001463 if (pos != path[u].predicates[v].position) {
Radek Krejci084289f2019-07-09 17:35:30 +02001464 pos++;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001465 match = 0;
Radek Krejci084289f2019-07-09 17:35:30 +02001466 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001467 } else if (path[u].predicates[v].type == 1) {
Radek Krejci084289f2019-07-09 17:35:30 +02001468 /* key-predicate */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001469 struct lysc_type *type = ((struct lysc_node_leaf *)path[u].predicates[v].key)->type;
Michal Vaskoe444f752020-02-10 12:20:06 +01001470 struct lyd_node *key;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001471
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001472 lyd_find_sibling_val(lyd_node_children(node), path[u].predicates[v].key, NULL, 0, &key);
Radek Krejci084289f2019-07-09 17:35:30 +02001473 if (!key) {
1474 /* probably error and we shouldn't be here due to previous checks when creating path */
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001475 match = 0;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001476 } else if (type->plugin->compare(&((struct lyd_node_term *)key)->value, path[u].predicates[v].value)) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001477 match = 0;
Radek Krejci084289f2019-07-09 17:35:30 +02001478 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001479 } else if (path[u].predicates[v].type == 2) {
Radek Krejci084289f2019-07-09 17:35:30 +02001480 /* leaf-list-predicate */
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001481 struct lysc_type *type = ((struct lysc_node_leaf *)path[u].node)->type;
1482
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001483 if (type->plugin->compare(&((struct lyd_node_term *)node)->value, path[u].predicates[v].value)) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001484 match = 0;
Radek Krejci084289f2019-07-09 17:35:30 +02001485 }
1486 } else {
1487 LOGINT(NULL);
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001488 return NULL;
1489 }
1490
1491 if (!match) {
1492 /* useless to check more predicates */
1493 break;
Radek Krejci084289f2019-07-09 17:35:30 +02001494 }
1495 }
1496
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001497 if (!match) {
1498 /* try to match next sibling */
1499 start_sibling = node->next;
1500 } else {
1501 /* matched, move to the next path segment */
1502 ++u;
1503 start_sibling = lyd_node_children(node);
1504 pos = 1;
1505 }
Radek Krejci084289f2019-07-09 17:35:30 +02001506 }
1507
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001508 return (const struct lyd_node_term *)node;
Radek Krejci084289f2019-07-09 17:35:30 +02001509}
1510
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001511API LY_ERR
1512lyd_compare(const struct lyd_node *node1, const struct lyd_node *node2, int options)
1513{
1514 const struct lyd_node *iter1, *iter2;
1515 struct lyd_node_term *term1, *term2;
1516 struct lyd_node_any *any1, *any2;
Michal Vasko52927e22020-03-16 17:26:14 +01001517 struct lyd_node_opaq *opaq1, *opaq2;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001518 struct lysc_type *type;
1519 size_t len1, len2;
Radek Krejci084289f2019-07-09 17:35:30 +02001520
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001521 if (!node1 || !node2) {
1522 if (node1 == node2) {
1523 return LY_SUCCESS;
1524 } else {
1525 return LY_ENOT;
1526 }
1527 }
1528
Michal Vasko52927e22020-03-16 17:26:14 +01001529 if ((LYD_NODE_CTX(node1) != LYD_NODE_CTX(node2)) || (node1->schema != node2->schema)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001530 return LY_ENOT;
1531 }
1532
1533 if (node1->hash != node2->hash) {
1534 return LY_ENOT;
1535 }
Michal Vasko52927e22020-03-16 17:26:14 +01001536 /* 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 +02001537
Michal Vasko52927e22020-03-16 17:26:14 +01001538 if (!node1->schema) {
1539 opaq1 = (struct lyd_node_opaq *)node1;
1540 opaq2 = (struct lyd_node_opaq *)node2;
1541 if ((opaq1->name != opaq2->name) || (opaq1->prefix.ns != opaq2->prefix.ns) || (opaq1->format != opaq2->format)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001542 return LY_ENOT;
1543 }
Michal Vasko52927e22020-03-16 17:26:14 +01001544 switch (opaq1->format) {
1545 case LYD_XML:
1546 if (lyxml_value_compare(opaq1->value, opaq1->val_prefs, opaq2->value, opaq2->val_prefs)) {
1547 return LY_ENOT;
1548 }
1549 break;
1550 case LYD_SCHEMA:
1551 /* not allowed */
1552 LOGINT(LYD_NODE_CTX(node1));
1553 return LY_EINT;
1554 }
1555 if (options & LYD_COMPARE_FULL_RECURSION) {
1556 iter1 = opaq1->child;
1557 iter2 = opaq2->child;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001558 goto all_children_compare;
Michal Vasko52927e22020-03-16 17:26:14 +01001559 }
1560 return LY_SUCCESS;
1561 } else {
1562 switch (node1->schema->nodetype) {
1563 case LYS_LEAF:
1564 case LYS_LEAFLIST:
1565 if (options & LYD_COMPARE_DEFAULTS) {
1566 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1567 return LY_ENOT;
1568 }
1569 }
1570
1571 term1 = (struct lyd_node_term*)node1;
1572 term2 = (struct lyd_node_term*)node2;
1573 type = ((struct lysc_node_leaf*)node1->schema)->type;
1574
1575 return type->plugin->compare(&term1->value, &term2->value);
1576 case LYS_CONTAINER:
1577 if (options & LYD_COMPARE_DEFAULTS) {
1578 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1579 return LY_ENOT;
1580 }
1581 }
1582 if (options & LYD_COMPARE_FULL_RECURSION) {
1583 iter1 = ((struct lyd_node_inner*)node1)->child;
1584 iter2 = ((struct lyd_node_inner*)node2)->child;
1585 goto all_children_compare;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001586 }
1587 return LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +01001588 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +01001589 case LYS_ACTION:
1590 if (options & LYD_COMPARE_FULL_RECURSION) {
1591 /* TODO action/RPC
1592 goto all_children_compare;
1593 */
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001594 }
1595 return LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +01001596 case LYS_NOTIF:
1597 if (options & LYD_COMPARE_FULL_RECURSION) {
1598 /* TODO Notification
1599 goto all_children_compare;
1600 */
1601 }
1602 return LY_SUCCESS;
1603 case LYS_LIST:
1604 iter1 = ((struct lyd_node_inner*)node1)->child;
1605 iter2 = ((struct lyd_node_inner*)node2)->child;
1606
1607 if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
1608 /* lists with keys, their equivalence is based on their keys */
1609 for (struct lysc_node *key = ((struct lysc_node_list*)node1->schema)->child;
1610 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1611 key = key->next) {
1612 if (lyd_compare(iter1, iter2, options)) {
1613 return LY_ENOT;
1614 }
1615 iter1 = iter1->next;
1616 iter2 = iter2->next;
1617 }
1618 } else {
1619 /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
1620
1621 all_children_compare:
1622 if (!iter1 && !iter2) {
1623 /* no children, nothing to compare */
1624 return LY_SUCCESS;
1625 }
1626
1627 for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
1628 if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
1629 return LY_ENOT;
1630 }
1631 }
1632 if (iter1 || iter2) {
1633 return LY_ENOT;
1634 }
1635 }
1636 return LY_SUCCESS;
1637 case LYS_ANYXML:
1638 case LYS_ANYDATA:
1639 any1 = (struct lyd_node_any*)node1;
1640 any2 = (struct lyd_node_any*)node2;
1641
1642 if (any1->value_type != any2->value_type) {
1643 return LY_ENOT;
1644 }
1645 switch (any1->value_type) {
1646 case LYD_ANYDATA_DATATREE:
1647 iter1 = any1->value.tree;
1648 iter2 = any2->value.tree;
1649 goto all_children_compare;
1650 case LYD_ANYDATA_STRING:
1651 case LYD_ANYDATA_XML:
1652 case LYD_ANYDATA_JSON:
1653 len1 = strlen(any1->value.str);
1654 len2 = strlen(any2->value.str);
1655 if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
1656 return LY_ENOT;
1657 }
1658 return LY_SUCCESS;
1659 #if 0 /* TODO LYB format */
1660 case LYD_ANYDATA_LYB:
1661 int len1 = lyd_lyb_data_length(any1->value.mem);
1662 int len2 = lyd_lyb_data_length(any2->value.mem);
1663 if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
1664 return LY_ENOT;
1665 }
1666 return LY_SUCCESS;
1667 #endif
1668 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001669 }
1670 }
1671
Michal Vasko52927e22020-03-16 17:26:14 +01001672 LOGINT(LYD_NODE_CTX(node1));
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001673 return LY_EINT;
1674}
Radek Krejci22ebdba2019-07-25 13:59:43 +02001675
1676/**
Michal Vasko52927e22020-03-16 17:26:14 +01001677 * @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 +02001678 *
1679 * 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 +02001680 *
1681 * @param[in] node Original node to duplicate
1682 * @param[in] parent Parent to insert into, NULL for top-level sibling.
1683 * @param[in,out] first First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
1684 * @param[in] options Bitmask of options flags, see @ref dupoptions.
1685 * @param[out] dup_p Pointer where the created duplicated node is placed (besides connecting it int @p parent / @p first sibling).
1686 * @return LY_ERR value
Radek Krejci22ebdba2019-07-25 13:59:43 +02001687 */
Michal Vasko52927e22020-03-16 17:26:14 +01001688static LY_ERR
1689lyd_dup_recursive(const struct lyd_node *node, struct lyd_node *parent, struct lyd_node **first, int options,
1690 struct lyd_node **dup_p)
Radek Krejci22ebdba2019-07-25 13:59:43 +02001691{
Michal Vasko52927e22020-03-16 17:26:14 +01001692 LY_ERR ret;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001693 struct lyd_node *dup = NULL;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001694 LY_ARRAY_SIZE_TYPE u;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001695
Michal Vasko52927e22020-03-16 17:26:14 +01001696 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001697
Michal Vasko52927e22020-03-16 17:26:14 +01001698 if (!node->schema) {
1699 dup = calloc(1, sizeof(struct lyd_node_opaq));
1700 } else {
1701 switch (node->schema->nodetype) {
Michal Vasko1bf09392020-03-27 12:38:10 +01001702 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +01001703 case LYS_ACTION:
1704 case LYS_NOTIF:
1705 case LYS_CONTAINER:
1706 case LYS_LIST:
1707 dup = calloc(1, sizeof(struct lyd_node_inner));
1708 break;
1709 case LYS_LEAF:
1710 case LYS_LEAFLIST:
1711 dup = calloc(1, sizeof(struct lyd_node_term));
1712 break;
1713 case LYS_ANYDATA:
1714 case LYS_ANYXML:
1715 dup = calloc(1, sizeof(struct lyd_node_any));
1716 break;
1717 default:
1718 LOGINT(LYD_NODE_CTX(node));
1719 ret = LY_EINT;
1720 goto error;
1721 }
Radek Krejci22ebdba2019-07-25 13:59:43 +02001722 }
Michal Vasko52927e22020-03-16 17:26:14 +01001723 LY_CHECK_ERR_GOTO(!dup, LOGMEM(LYD_NODE_CTX(node)); ret = LY_EMEM, error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001724
1725 /* TODO implement LYD_DUP_WITH_WHEN */
1726 dup->flags = node->flags;
1727 dup->schema = node->schema;
Michal Vasko52927e22020-03-16 17:26:14 +01001728 dup->prev = dup;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001729
1730 /* TODO duplicate attributes, implement LYD_DUP_NO_ATTR */
1731
1732 /* nodetype-specific work */
Michal Vasko52927e22020-03-16 17:26:14 +01001733 if (!dup->schema) {
1734 struct lyd_node_opaq *opaq = (struct lyd_node_opaq *)dup;
1735 struct lyd_node_opaq *orig = (struct lyd_node_opaq *)node;
1736 struct lyd_node *child;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001737
1738 if (options & LYD_DUP_RECURSIVE) {
1739 /* duplicate all the children */
1740 LY_LIST_FOR(orig->child, child) {
Michal Vasko52927e22020-03-16 17:26:14 +01001741 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
1742 }
1743 }
1744 opaq->name = lydict_insert(LYD_NODE_CTX(node), orig->name, 0);
1745 opaq->format = orig->format;
1746 if (orig->prefix.pref) {
1747 opaq->prefix.pref = lydict_insert(LYD_NODE_CTX(node), orig->prefix.pref, 0);
1748 }
1749 if (orig->prefix.ns) {
1750 opaq->prefix.ns = lydict_insert(LYD_NODE_CTX(node), orig->prefix.ns, 0);
1751 }
1752 if (orig->val_prefs) {
1753 LY_ARRAY_CREATE_GOTO(LYD_NODE_CTX(node), opaq->val_prefs, LY_ARRAY_SIZE(orig->val_prefs), ret, error);
1754 LY_ARRAY_FOR(orig->val_prefs, u) {
1755 opaq->val_prefs[u].pref = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].pref, 0);
1756 opaq->val_prefs[u].ns = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].ns, 0);
1757 LY_ARRAY_INCREMENT(opaq->val_prefs);
1758 }
1759 }
1760 opaq->value = lydict_insert(LYD_NODE_CTX(node), orig->value, 0);
1761 opaq->ctx = orig->ctx;
1762 } else if (dup->schema->nodetype & LYD_NODE_TERM) {
1763 struct lyd_node_term *term = (struct lyd_node_term *)dup;
1764 struct lyd_node_term *orig = (struct lyd_node_term *)node;
1765
1766 term->hash = orig->hash;
1767 term->value.realtype = orig->value.realtype;
1768 LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &orig->value, &term->value),
1769 LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."); ret = LY_EINT, error);
1770 } else if (dup->schema->nodetype & LYD_NODE_INNER) {
1771 struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
1772 struct lyd_node *child;
1773
1774 if (options & LYD_DUP_RECURSIVE) {
1775 /* duplicate all the children */
1776 LY_LIST_FOR(orig->child, child) {
1777 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001778 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02001779 } else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001780 /* always duplicate keys of a list */
Radek Krejci22ebdba2019-07-25 13:59:43 +02001781 child = orig->child;
Michal Vasko52927e22020-03-16 17:26:14 +01001782 for (struct lysc_node *key = ((struct lysc_node_list *)dup->schema)->child;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001783 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1784 key = key->next) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001785 if (!child) {
1786 /* possibly not keys are present in filtered tree */
1787 break;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001788 } else if (child->schema != key) {
1789 /* possibly not all keys are present in filtered tree,
1790 * but there can be also some non-key nodes */
1791 continue;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001792 }
Michal Vasko52927e22020-03-16 17:26:14 +01001793 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001794 child = child->next;
1795 }
1796 }
1797 lyd_hash(dup);
1798 } else if (dup->schema->nodetype & LYD_NODE_ANY) {
Michal Vasko52927e22020-03-16 17:26:14 +01001799 struct lyd_node_any *any = (struct lyd_node_any *)dup;
1800 struct lyd_node_any *orig = (struct lyd_node_any *)node;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001801
1802 any->hash = orig->hash;
1803 any->value_type = orig->value_type;
1804 switch (any->value_type) {
1805 case LYD_ANYDATA_DATATREE:
1806 if (orig->value.tree) {
1807 any->value.tree = lyd_dup(orig->value.tree, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_SIBLINGS);
Radek Krejci25dc3432020-05-15 14:42:12 +02001808 if (!any->value.tree) {
1809 /* get the last error's error code recorded by lyd_dup */
1810 struct ly_err_item *ei = ly_err_first(LYD_NODE_CTX(node));
1811 ret = ei ? ei->prev->no : LY_EOTHER;
1812 goto error;
1813 }
1814 LY_CHECK_ERR_GOTO(!any->value.tree, ret = 0 ,error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001815 }
1816 break;
1817 case LYD_ANYDATA_STRING:
1818 case LYD_ANYDATA_XML:
1819 case LYD_ANYDATA_JSON:
1820 if (orig->value.str) {
Michal Vasko52927e22020-03-16 17:26:14 +01001821 any->value.str = lydict_insert(LYD_NODE_CTX(node), orig->value.str, strlen(orig->value.str));
Radek Krejci22ebdba2019-07-25 13:59:43 +02001822 }
1823 break;
1824 }
1825 }
1826
Michal Vasko52927e22020-03-16 17:26:14 +01001827 /* insert */
1828 lyd_insert_node(parent, first, dup);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001829 lyd_insert_hash(dup);
Michal Vasko52927e22020-03-16 17:26:14 +01001830
1831 if (dup_p) {
1832 *dup_p = dup;
1833 }
1834 return LY_SUCCESS;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001835
1836error:
Michal Vasko52927e22020-03-16 17:26:14 +01001837 lyd_free_tree(dup);
1838 return ret;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001839}
1840
1841API struct lyd_node *
1842lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
1843{
1844 struct ly_ctx *ctx;
1845 const struct lyd_node *orig; /* original node to be duplicated */
1846 struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
Radek Krejci22ebdba2019-07-25 13:59:43 +02001847 struct lyd_node *top = NULL; /* the most higher created node */
1848 struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
1849 int keyless_parent_list = 0;
1850
1851 LY_CHECK_ARG_RET(NULL, node, NULL);
1852 ctx = node->schema->module->ctx;
1853
1854 if (options & LYD_DUP_WITH_PARENTS) {
1855 struct lyd_node_inner *orig_parent, *iter;
1856 int repeat = 1;
1857 for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
1858 if (parent && parent->schema == orig_parent->schema) {
1859 /* stop creating parents, connect what we have into the provided parent */
1860 iter = parent;
1861 repeat = 0;
1862 /* get know if there is a keyless list which we will have to rehash */
1863 for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02001864 if (piter->schema->nodetype == LYS_LIST && (piter->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001865 keyless_parent_list = 1;
1866 break;
1867 }
1868 }
1869 } else {
Michal Vasko52927e22020-03-16 17:26:14 +01001870 iter = NULL;
1871 LY_CHECK_GOTO(lyd_dup_recursive((struct lyd_node *)orig_parent, NULL, (struct lyd_node **)&iter, 0,
1872 (struct lyd_node **)&iter), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001873 }
1874 if (!local_parent) {
1875 local_parent = iter;
1876 }
1877 if (iter->child) {
1878 /* 1) list - add after keys
1879 * 2) provided parent with some children */
1880 iter->child->prev->next = top;
1881 if (top) {
1882 top->prev = iter->child->prev;
1883 iter->child->prev = top;
1884 }
1885 } else {
1886 iter->child = top;
1887 if (iter->schema->nodetype == LYS_LIST) {
1888 /* keyless list - we will need to rehash it since we are going to add nodes into it */
1889 keyless_parent_list = 1;
1890 }
1891 }
1892 if (top) {
1893 top->parent = iter;
1894 }
1895 top = (struct lyd_node*)iter;
1896 }
1897 if (repeat && parent) {
1898 /* given parent and created parents chain actually do not interconnect */
1899 LOGERR(ctx, LY_EINVAL, "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
1900 goto error;
1901 }
1902 } else {
1903 local_parent = parent;
1904 }
1905
Radek Krejci22ebdba2019-07-25 13:59:43 +02001906 LY_LIST_FOR(node, orig) {
Michal Vasko52927e22020-03-16 17:26:14 +01001907 /* if there is no local parent, it will be inserted into first */
1908 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 +02001909 if (!(options & LYD_DUP_WITH_SIBLINGS)) {
1910 break;
1911 }
1912 }
1913 if (keyless_parent_list) {
1914 /* rehash */
1915 for (; local_parent; local_parent = local_parent->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02001916 if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001917 lyd_hash((struct lyd_node*)local_parent);
1918 }
1919 }
1920 }
1921 return first;
1922
1923error:
1924 if (top) {
1925 lyd_free_tree(top);
1926 } else {
Michal Vaskof03ed032020-03-04 13:31:44 +01001927 lyd_free_siblings(first);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001928 }
1929 return NULL;
1930}
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001931
1932static LY_ERR
1933lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
1934{
Michal Vasko14654712020-02-06 08:35:21 +01001935 /* ending \0 */
1936 ++reqlen;
1937
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001938 if (reqlen > *buflen) {
1939 if (is_static) {
1940 return LY_EINCOMPLETE;
1941 }
1942
1943 *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
1944 if (!*buffer) {
1945 return LY_EMEM;
1946 }
1947
1948 *buflen = reqlen;
1949 }
1950
1951 return LY_SUCCESS;
1952}
1953
1954/**
1955 * @brief Append all list key predicates to path.
1956 *
1957 * @param[in] node Node with keys to print.
1958 * @param[in,out] buffer Buffer to print to.
1959 * @param[in,out] buflen Current buffer length.
1960 * @param[in,out] bufused Current number of characters used in @p buffer.
1961 * @param[in] is_static Whether buffer is static or can be reallocated.
1962 * @return LY_ERR
1963 */
1964static LY_ERR
1965lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
1966{
1967 const struct lyd_node *key;
1968 int dynamic = 0;
1969 size_t len;
1970 const char *val;
1971 char quot;
1972 LY_ERR rc;
1973
Michal Vasko14654712020-02-06 08:35:21 +01001974 for (key = lyd_node_children(node); key && (key->schema->flags & LYS_KEY); key = key->next) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001975 val = lyd_value2str((struct lyd_node_term *)key, &dynamic);
1976 len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
1977 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1978 if (rc != LY_SUCCESS) {
1979 if (dynamic) {
1980 free((char *)val);
1981 }
1982 return rc;
1983 }
1984
1985 quot = '\'';
1986 if (strchr(val, '\'')) {
1987 quot = '"';
1988 }
1989 *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
1990
1991 if (dynamic) {
1992 free((char *)val);
1993 }
1994 }
1995
1996 return LY_SUCCESS;
1997}
1998
1999/**
2000 * @brief Append leaf-list value predicate to path.
2001 *
2002 * @param[in] node Node to print.
2003 * @param[in,out] buffer Buffer to print to.
2004 * @param[in,out] buflen Current buffer length.
2005 * @param[in,out] bufused Current number of characters used in @p buffer.
2006 * @param[in] is_static Whether buffer is static or can be reallocated.
2007 * @return LY_ERR
2008 */
2009static LY_ERR
2010lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2011{
2012 int dynamic = 0;
2013 size_t len;
2014 const char *val;
2015 char quot;
2016 LY_ERR rc;
2017
2018 val = lyd_value2str((struct lyd_node_term *)node, &dynamic);
2019 len = 4 + strlen(val) + 2;
2020 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2021 if (rc != LY_SUCCESS) {
2022 goto cleanup;
2023 }
2024
2025 quot = '\'';
2026 if (strchr(val, '\'')) {
2027 quot = '"';
2028 }
2029 *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
2030
2031cleanup:
2032 if (dynamic) {
2033 free((char *)val);
2034 }
2035 return rc;
2036}
2037
2038/**
2039 * @brief Append node position (relative to its other instances) predicate to path.
2040 *
2041 * @param[in] node Node to print.
2042 * @param[in,out] buffer Buffer to print to.
2043 * @param[in,out] buflen Current buffer length.
2044 * @param[in,out] bufused Current number of characters used in @p buffer.
2045 * @param[in] is_static Whether buffer is static or can be reallocated.
2046 * @return LY_ERR
2047 */
2048static LY_ERR
2049lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2050{
2051 const struct lyd_node *first, *iter;
2052 size_t len;
2053 int pos;
2054 char *val = NULL;
2055 LY_ERR rc;
2056
2057 if (node->parent) {
2058 first = node->parent->child;
2059 } else {
2060 for (first = node; node->prev->next; node = node->prev);
2061 }
2062 pos = 1;
2063 for (iter = first; iter != node; iter = iter->next) {
2064 if (iter->schema == node->schema) {
2065 ++pos;
2066 }
2067 }
2068 if (asprintf(&val, "%d", pos) == -1) {
2069 return LY_EMEM;
2070 }
2071
2072 len = 1 + strlen(val) + 1;
2073 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2074 if (rc != LY_SUCCESS) {
2075 goto cleanup;
2076 }
2077
2078 *bufused += sprintf(*buffer + *bufused, "[%s]", val);
2079
2080cleanup:
2081 free(val);
2082 return rc;
2083}
2084
2085API char *
2086lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
2087{
Michal Vasko14654712020-02-06 08:35:21 +01002088 int is_static = 0, i, depth;
2089 size_t bufused = 0, len;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002090 const struct lyd_node *iter;
2091 const struct lys_module *mod;
2092 LY_ERR rc;
2093
2094 LY_CHECK_ARG_RET(NULL, node, NULL);
2095 if (buffer) {
2096 LY_CHECK_ARG_RET(node->schema->module->ctx, buflen > 1, NULL);
2097 is_static = 1;
Michal Vasko14654712020-02-06 08:35:21 +01002098 } else {
2099 buflen = 0;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002100 }
2101
2102 switch (pathtype) {
Michal Vasko14654712020-02-06 08:35:21 +01002103 case LYD_PATH_LOG:
2104 depth = 1;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002105 for (iter = node; iter->parent; iter = (const struct lyd_node *)iter->parent) {
2106 ++depth;
2107 }
2108
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002109 goto iter_print;
Michal Vasko14654712020-02-06 08:35:21 +01002110 while (depth) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002111 /* find the right node */
Michal Vasko14654712020-02-06 08:35:21 +01002112 for (iter = node, i = 1; i < depth; iter = (const struct lyd_node *)iter->parent, ++i);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002113iter_print:
2114 /* print prefix and name */
2115 mod = NULL;
2116 if (!iter->parent || (iter->schema->module != iter->parent->schema->module)) {
2117 mod = iter->schema->module;
2118 }
2119
2120 /* realloc string */
2121 len = 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(iter->schema->name);
2122 rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
2123 if (rc != LY_SUCCESS) {
2124 break;
2125 }
2126
2127 /* print next node */
2128 bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", iter->schema->name);
2129
2130 switch (iter->schema->nodetype) {
2131 case LYS_LIST:
2132 if (iter->schema->flags & LYS_KEYLESS) {
2133 /* print its position */
2134 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
2135 } else {
2136 /* print all list keys in predicates */
2137 rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
2138 }
2139 break;
2140 case LYS_LEAFLIST:
2141 if (iter->schema->flags & LYS_CONFIG_W) {
2142 /* print leaf-list value */
2143 rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
2144 } else {
2145 /* print its position */
2146 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
2147 }
2148 break;
2149 default:
2150 /* nothing to print more */
2151 rc = LY_SUCCESS;
2152 break;
2153 }
2154 if (rc != LY_SUCCESS) {
2155 break;
2156 }
2157
Michal Vasko14654712020-02-06 08:35:21 +01002158 --depth;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002159 }
2160 break;
2161 }
2162
2163 return buffer;
2164}
Michal Vaskoe444f752020-02-10 12:20:06 +01002165
Michal Vasko9b368d32020-02-14 13:53:31 +01002166LY_ERR
2167lyd_find_sibling_next2(const struct lyd_node *first, const struct lysc_node *schema, const char *key_or_value,
2168 size_t val_len, struct lyd_node **match)
Michal Vaskoe444f752020-02-10 12:20:06 +01002169{
2170 LY_ERR rc;
2171 const struct lyd_node *node = NULL;
2172 struct lyd_node_term *term;
Michal Vaskoe444f752020-02-10 12:20:06 +01002173 struct ly_keys keys = {0};
Michal Vasko90932a92020-02-12 14:33:03 +01002174 struct lyd_value val = {0};
Michal Vaskoe444f752020-02-10 12:20:06 +01002175 size_t i;
Michal Vaskoe444f752020-02-10 12:20:06 +01002176
Michal Vasko9b368d32020-02-14 13:53:31 +01002177 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
Michal Vaskoe444f752020-02-10 12:20:06 +01002178
2179 if (!first) {
2180 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01002181 if (match) {
2182 *match = NULL;
2183 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002184 return LY_ENOTFOUND;
2185 }
2186
Michal Vaskoe444f752020-02-10 12:20:06 +01002187 if (key_or_value && !val_len) {
2188 val_len = strlen(key_or_value);
2189 }
2190
2191 if (key_or_value && (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko90932a92020-02-12 14:33:03 +01002192 /* store the value */
Michal Vasko9b368d32020-02-14 13:53:31 +01002193 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 +01002194 } else if (key_or_value && (schema->nodetype == LYS_LIST)) {
2195 /* parse keys into canonical values */
2196 LY_CHECK_GOTO(rc = ly_keys_parse(schema, key_or_value, val_len, 1, &keys), cleanup);
2197 }
2198
2199 /* find first matching value */
2200 LY_LIST_FOR(first, node) {
2201 if (node->schema != schema) {
2202 continue;
2203 }
2204
2205 if ((schema->nodetype == LYS_LIST) && keys.str) {
2206 /* compare all set keys */
2207 for (i = 0; i < keys.key_count; ++i) {
2208 /* find key */
2209 rc = lyd_find_sibling_val(lyd_node_children(node), (struct lysc_node *)keys.keys[i].schema, NULL, 0,
2210 (struct lyd_node **)&term);
2211 if (rc == LY_ENOTFOUND) {
2212 /* all keys must always exist */
Michal Vasko9b368d32020-02-14 13:53:31 +01002213 LOGINT_RET(schema->module->ctx);
Michal Vaskoe444f752020-02-10 12:20:06 +01002214 }
2215 LY_CHECK_GOTO(rc, cleanup);
2216
2217 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01002218 if (!term->value.realtype->plugin->compare(&term->value, &keys.keys[i].val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002219 break;
2220 }
2221 }
2222
2223 if (i < keys.key_count) {
2224 /* not a match */
2225 continue;
2226 }
Michal Vasko90932a92020-02-12 14:33:03 +01002227 } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && val.realtype) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002228 term = (struct lyd_node_term *)node;
2229
2230 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01002231 if (!term->value.realtype->plugin->compare(&term->value, &val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002232 /* not a match */
2233 continue;
2234 }
2235 }
2236
2237 /* all criteria passed */
2238 break;
2239 }
2240
2241 if (!node) {
2242 rc = LY_ENOTFOUND;
Michal Vasko9b368d32020-02-14 13:53:31 +01002243 if (match) {
2244 *match = NULL;
2245 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002246 goto cleanup;
2247 }
2248
2249 /* success */
Michal Vasko9b368d32020-02-14 13:53:31 +01002250 if (match) {
2251 *match = (struct lyd_node *)node;
2252 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002253 rc = LY_SUCCESS;
2254
2255cleanup:
2256 ly_keys_clean(&keys);
Michal Vasko90932a92020-02-12 14:33:03 +01002257 if (val.realtype) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002258 val.realtype->plugin->free(schema->module->ctx, &val);
Michal Vasko90932a92020-02-12 14:33:03 +01002259 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002260 return rc;
2261}
2262
2263API LY_ERR
Michal Vasko9b368d32020-02-14 13:53:31 +01002264lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name, size_t name_len,
2265 const char *key_or_value, size_t val_len, struct lyd_node **match)
2266{
2267 const struct lysc_node *schema;
2268
2269 LY_CHECK_ARG_RET(NULL, module, name, match, LY_EINVAL);
2270
2271 if (!first) {
2272 /* no data */
2273 *match = NULL;
2274 return LY_ENOTFOUND;
2275 }
2276
2277 /* find schema */
2278 schema = lys_find_child(first->parent ? first->parent->schema : NULL, module, name, name_len, 0, 0);
2279 if (!schema) {
2280 LOGERR(module->ctx, LY_EINVAL, "Schema node not found.");
2281 return LY_EINVAL;
2282 }
2283
2284 return lyd_find_sibling_next2(first, schema, key_or_value, val_len, match);
2285}
2286
2287API LY_ERR
Michal Vaskoe444f752020-02-10 12:20:06 +01002288lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
2289{
2290 struct lyd_node **match_p;
2291 struct lyd_node_inner *parent;
2292
Michal Vaskof03ed032020-03-04 13:31:44 +01002293 LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
Michal Vaskoe444f752020-02-10 12:20:06 +01002294
2295 if (!siblings) {
2296 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01002297 if (match) {
2298 *match = NULL;
2299 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002300 return LY_ENOTFOUND;
2301 }
2302
2303 /* find first sibling */
2304 if (siblings->parent) {
2305 siblings = siblings->parent->child;
2306 } else {
2307 while (siblings->prev->next) {
2308 siblings = siblings->prev;
2309 }
2310 }
2311
2312 parent = (struct lyd_node_inner *)siblings->parent;
2313 if (parent && parent->children_ht) {
2314 assert(target->hash);
2315
2316 /* find by hash */
2317 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
2318 siblings = *match_p;
2319 } else {
2320 /* not found */
2321 siblings = NULL;
2322 }
2323 } else {
2324 /* no children hash table */
2325 for (; siblings; siblings = siblings->next) {
2326 if (!lyd_compare(siblings, target, 0)) {
2327 break;
2328 }
2329 }
2330 }
2331
2332 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002333 if (match) {
2334 *match = NULL;
2335 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002336 return LY_ENOTFOUND;
2337 }
2338
Michal Vasko9b368d32020-02-14 13:53:31 +01002339 if (match) {
2340 *match = (struct lyd_node *)siblings;
2341 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002342 return LY_SUCCESS;
2343}
2344
2345API LY_ERR
2346lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
2347{
2348 struct lyd_node_inner *parent;
2349 struct lyd_node *match;
2350 struct lyd_node **match_p;
2351 struct ly_set *ret;
2352
2353 LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
2354
2355 if (!siblings) {
2356 /* no data */
2357 return LY_ENOTFOUND;
2358 }
2359
2360 ret = ly_set_new();
2361 LY_CHECK_ERR_RET(!ret, LOGMEM(target->schema->module->ctx), LY_EMEM);
2362
2363 /* find first sibling */
2364 if (siblings->parent) {
2365 siblings = siblings->parent->child;
2366 } else {
2367 while (siblings->prev->next) {
2368 siblings = siblings->prev;
2369 }
2370 }
2371
2372 parent = (struct lyd_node_inner *)siblings->parent;
2373 if (parent && parent->children_ht) {
2374 assert(target->hash);
2375
2376 /* find by hash */
2377 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
2378 match = *match_p;
2379 } else {
2380 /* not found */
2381 match = NULL;
2382 }
2383 while (match) {
2384 /* add all found nodes into the return set */
2385 if (ly_set_add(ret, match, LY_SET_OPT_USEASLIST) == -1) {
2386 goto error;
2387 }
2388
2389 /* find next instance */
2390 if (lyht_find_next(parent->children_ht, &match, match->hash, (void **)&match_p)) {
2391 match = NULL;
2392 } else {
2393 match = *match_p;
2394 }
2395 }
2396 } else {
2397 /* no children hash table */
2398 for (; siblings; siblings = siblings->next) {
2399 if (!lyd_compare(siblings, target, 0)) {
2400 /* a match */
2401 if (ly_set_add(ret, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
2402 goto error;
2403 }
2404 }
2405 }
2406 }
2407
2408 if (!ret->count) {
2409 ly_set_free(ret, NULL);
2410 return LY_ENOTFOUND;
2411 }
2412
2413 *set = ret;
2414 return LY_SUCCESS;
2415
2416error:
2417 ly_set_free(ret, NULL);
2418 return LY_EMEM;
2419}
2420
Michal Vasko90932a92020-02-12 14:33:03 +01002421static int
2422lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
2423{
2424 struct lysc_node *val1;
2425 struct lyd_node *val2;
2426
2427 val1 = *((struct lysc_node **)val1_p);
2428 val2 = *((struct lyd_node **)val2_p);
2429
2430 assert(val1->nodetype & (LYD_NODE_INNER | LYS_LEAF));
2431
2432 if (val1 == val2->schema) {
2433 /* schema match is enough */
2434 return 1;
2435 } else {
2436 return 0;
2437 }
2438}
2439
2440static LY_ERR
2441lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
2442{
2443 struct lyd_node **match_p;
2444 struct lyd_node_inner *parent;
2445 uint32_t hash;
2446 values_equal_cb ht_cb;
2447
2448 assert(siblings && schema && (schema->nodetype & (LYD_NODE_INNER | LYS_LEAF)));
2449
2450 /* find first sibling */
2451 if (siblings->parent) {
2452 siblings = siblings->parent->child;
2453 } else {
2454 while (siblings->prev->next) {
2455 siblings = siblings->prev;
2456 }
2457 }
2458
2459 parent = (struct lyd_node_inner *)siblings->parent;
2460 if (parent && parent->children_ht) {
2461 /* calculate our hash */
2462 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
2463 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
2464 hash = dict_hash_multi(hash, NULL, 0);
2465
2466 /* use special hash table function */
2467 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
2468
2469 /* find by hash */
2470 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
2471 siblings = *match_p;
2472 } else {
2473 /* not found */
2474 siblings = NULL;
2475 }
2476
2477 /* set the original hash table compare function back */
2478 lyht_set_cb(parent->children_ht, ht_cb);
2479 } else {
2480 /* no children hash table */
2481 for (; siblings; siblings = siblings->next) {
2482 if (siblings->schema == schema) {
2483 /* schema match is enough */
2484 break;
2485 }
2486 }
2487 }
2488
2489 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002490 if (match) {
2491 *match = NULL;
2492 }
Michal Vasko90932a92020-02-12 14:33:03 +01002493 return LY_ENOTFOUND;
2494 }
2495
Michal Vasko9b368d32020-02-14 13:53:31 +01002496 if (match) {
2497 *match = (struct lyd_node *)siblings;
2498 }
Michal Vasko90932a92020-02-12 14:33:03 +01002499 return LY_SUCCESS;
2500}
2501
Michal Vaskoe444f752020-02-10 12:20:06 +01002502API LY_ERR
2503lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
2504 size_t val_len, struct lyd_node **match)
2505{
2506 LY_ERR rc;
2507 struct lyd_node *target = NULL;
2508
2509 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
2510 if ((schema->nodetype == LYS_LIST) && schema->flags & LYS_KEYLESS) {
2511 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
2512 return LY_EINVAL;
2513 } else if ((schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && !key_or_value) {
2514 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - no value/keys for a (leaf-)list (%s()).", __func__);
2515 return LY_EINVAL;
2516 } else if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
2517 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
2518 lys_nodetype2str(schema->nodetype), __func__);
2519 return LY_EINVAL;
2520 }
2521
2522 if (!siblings) {
2523 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01002524 if (match) {
2525 *match = NULL;
2526 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002527 return LY_ENOTFOUND;
2528 }
2529
Michal Vaskof03ed032020-03-04 13:31:44 +01002530 if (key_or_value && !val_len) {
2531 val_len = strlen(key_or_value);
2532 }
2533
Michal Vasko90932a92020-02-12 14:33:03 +01002534 /* create data node if needed and find it */
Michal Vaskoe444f752020-02-10 12:20:06 +01002535 switch (schema->nodetype) {
2536 case LYS_CONTAINER:
2537 case LYS_ANYXML:
2538 case LYS_ANYDATA:
2539 case LYS_NOTIF:
Michal Vasko1bf09392020-03-27 12:38:10 +01002540 case LYS_RPC:
Michal Vasko9b368d32020-02-14 13:53:31 +01002541 case LYS_ACTION:
Michal Vaskoe444f752020-02-10 12:20:06 +01002542 case LYS_LEAF:
Michal Vasko90932a92020-02-12 14:33:03 +01002543 /* find it based on schema only */
2544 rc = lyd_find_sibling_schema(siblings, schema, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01002545 break;
2546 case LYS_LEAFLIST:
2547 /* target used attributes: schema, hash, value */
Michal Vasko90932a92020-02-12 14:33:03 +01002548 LY_CHECK_RET(lyd_create_term(schema, key_or_value, val_len, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &target));
Michal Vasko90932a92020-02-12 14:33:03 +01002549 /* fallthrough */
Michal Vaskoe444f752020-02-10 12:20:06 +01002550 case LYS_LIST:
Michal Vasko90932a92020-02-12 14:33:03 +01002551 if (schema->nodetype == LYS_LIST) {
2552 /* target used attributes: schema, hash, child (all keys) */
2553 LY_CHECK_RET(lyd_create_list(schema, key_or_value, val_len, &target));
Michal Vasko90932a92020-02-12 14:33:03 +01002554 }
2555
2556 /* find it */
2557 rc = lyd_find_sibling_first(siblings, target, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01002558 break;
2559 default:
2560 /* unreachable */
2561 LOGINT(schema->module->ctx);
2562 return LY_EINT;
2563 }
2564
Michal Vaskoe444f752020-02-10 12:20:06 +01002565 lyd_free_tree(target);
2566 return rc;
2567}