blob: 0b9b59f30ec2573478ee7688ba6fe168ecef7aea [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file tree_schema.c
3 * @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"
Radek Krejci38d85362019-09-05 16:26:38 +020032#include "plugins_exts_metadata.h"
Michal Vasko90932a92020-02-12 14:33:03 +010033#include "plugins_exts_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020034
Michal Vaskoe444f752020-02-10 12:20:06 +010035struct ly_keys {
36 char *str;
37 struct {
38 const struct lysc_node_leaf *schema;
39 char *value;
Michal Vasko90932a92020-02-12 14:33:03 +010040 struct lyd_value val;
Michal Vaskoe444f752020-02-10 12:20:06 +010041 } *keys;
42 size_t key_count;
43};
44
Radek Krejci576b23f2019-07-12 14:06:32 +020045API void
46lyd_trees_free(const struct lyd_node **trees, int free_data)
47{
48 if (!trees) {
49 return;
50 }
51
52 if (free_data) {
53 unsigned int u;
54 LY_ARRAY_FOR(trees, u) {
55 lyd_free_all((struct lyd_node *)trees[u]);
56 }
57 }
58 LY_ARRAY_FREE(trees);
59}
60
61static const struct lyd_node *
62lyd_trees_getstart(const struct lyd_node *tree)
63{
64 if (!tree) {
65 return NULL;
66 }
67 while (tree->prev->next) {
68 tree = tree->prev;
69 }
70 return tree;
71}
72
73API const struct lyd_node **
74lyd_trees_new(size_t count, const struct lyd_node *tree, ...)
75{
76 LY_ERR ret;
77 const struct lyd_node **trees = NULL;
78 va_list ap;
79
80 LY_CHECK_ARG_RET(NULL, tree, count > 0, NULL);
81
82 va_start(ap, tree);
83
84 LY_ARRAY_CREATE_GOTO(tree->schema->module->ctx, trees, count, ret, error);
85 /* first, mandatory, tree to insert */
86 trees[0] = lyd_trees_getstart(tree);
87 LY_ARRAY_INCREMENT(trees);
88
89 /* variable arguments */
90 for (unsigned int u = 1; u < count; ++u) {
91 trees[u] = lyd_trees_getstart(va_arg(ap, const struct lyd_node *));
92 LY_ARRAY_INCREMENT(trees);
93 }
94
95 va_end(ap);
96 return trees;
97
98error:
99 (void)ret; /* unused */
100 lyd_trees_free(trees, 1);
101 va_end(ap);
102 return NULL;
103}
104
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200105API const struct lyd_node **
106lyd_trees_add(const struct lyd_node **trees, const struct lyd_node *tree)
107{
108 const struct lyd_node **t = NULL;
109
110 LY_CHECK_ARG_RET(NULL, tree, trees, trees);
111
112 LY_ARRAY_NEW_RET(tree->schema->module->ctx, trees, t, NULL);
113 *t = lyd_trees_getstart(tree);
114
115 return trees;
116}
117
Radek Krejci084289f2019-07-09 17:35:30 +0200118LY_ERR
Michal Vasko90932a92020-02-12 14:33:03 +0100119lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second,
Radek Krejci576b23f2019-07-12 14:06:32 +0200120 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200121{
Michal Vasko90932a92020-02-12 14:33:03 +0100122 LY_ERR ret = LY_SUCCESS;
Radek Krejci084289f2019-07-09 17:35:30 +0200123 struct ly_err_item *err = NULL;
124 struct ly_ctx *ctx;
125 struct lysc_type *type;
Radek Krejci3c9758d2019-07-11 16:49:10 +0200126 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
Michal Vasko90932a92020-02-12 14:33:03 +0100127 (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200128 assert(node);
129
130 ctx = node->schema->module->ctx;
Radek Krejci084289f2019-07-09 17:35:30 +0200131
Radek Krejci73dead22019-07-11 16:46:16 +0200132 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci62903c32019-07-15 14:42:05 +0200133 if (!second) {
134 node->value.realtype = type;
135 }
Michal Vasko90932a92020-02-12 14:33:03 +0100136 ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
Radek Krejci73dead22019-07-11 16:46:16 +0200137 trees ? (void*)node : (void*)node->schema, trees,
138 &node->value, NULL, &err);
Michal Vasko90932a92020-02-12 14:33:03 +0100139 if (ret && (ret != LY_EINCOMPLETE)) {
Radek Krejci73dead22019-07-11 16:46:16 +0200140 if (err) {
141 ly_err_print(err);
142 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
143 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200144 }
Radek Krejci73dead22019-07-11 16:46:16 +0200145 goto error;
Michal Vasko90932a92020-02-12 14:33:03 +0100146 } else if (dynamic) {
147 *dynamic = 0;
Radek Krejci084289f2019-07-09 17:35:30 +0200148 }
149
150error:
151 return ret;
152}
153
Michal Vasko90932a92020-02-12 14:33:03 +0100154/* similar to lyd_value_parse except can be used just to store the value, hence does also not support a second call */
155static LY_ERR
156lyd_value_store(struct lyd_value *val, const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
157 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format)
158{
159 LY_ERR ret = LY_SUCCESS;
160 struct ly_err_item *err = NULL;
161 struct ly_ctx *ctx;
162 struct lysc_type *type;
163 int options = LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA | (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0);
164
165 assert(val && schema && (schema->nodetype & LYD_NODE_TERM));
166
167 ctx = schema->module->ctx;
168 type = ((struct lysc_node_leaf *)schema)->type;
169 val->realtype = type;
170 ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format, (void *)schema, NULL,
171 val, NULL, &err);
172 if (ret == LY_EINCOMPLETE) {
173 /* this is fine, we do not need it resolved */
174 ret = LY_SUCCESS;
175 } else if (ret && err) {
176 ly_err_print(err);
177 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
178 ly_err_free(err);
179 }
180 if (!ret && dynamic) {
181 *dynamic = 0;
182 }
183
184 return ret;
185}
186
Radek Krejci38d85362019-09-05 16:26:38 +0200187LY_ERR
Michal Vasko90932a92020-02-12 14:33:03 +0100188lyd_value_parse_attr(struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic, int second,
Radek Krejci38d85362019-09-05 16:26:38 +0200189 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
190{
Michal Vasko90932a92020-02-12 14:33:03 +0100191 LY_ERR ret = LY_SUCCESS;
Radek Krejci38d85362019-09-05 16:26:38 +0200192 struct ly_err_item *err = NULL;
193 struct ly_ctx *ctx;
194 struct lyext_metadata *ant;
195 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
Michal Vasko90932a92020-02-12 14:33:03 +0100196 (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci38d85362019-09-05 16:26:38 +0200197 assert(attr);
198
199 ctx = attr->parent->schema->module->ctx;
200 ant = attr->annotation->data;
201
202 if (!second) {
203 attr->value.realtype = ant->type;
204 }
Michal Vasko90932a92020-02-12 14:33:03 +0100205 ret = ant->type->plugin->store(ctx, ant->type, value, value_len, options, get_prefix, parser, format,
Radek Krejci38d85362019-09-05 16:26:38 +0200206 trees ? (void*)attr->parent : (void*)attr->parent->schema, trees,
207 &attr->value, NULL, &err);
Michal Vasko90932a92020-02-12 14:33:03 +0100208 if (ret && (ret != LY_EINCOMPLETE)) {
Radek Krejci38d85362019-09-05 16:26:38 +0200209 if (err) {
210 ly_err_print(err);
211 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
212 ly_err_free(err);
213 }
214 goto error;
Michal Vasko90932a92020-02-12 14:33:03 +0100215 } else if (dynamic) {
216 *dynamic = 0;
Radek Krejci38d85362019-09-05 16:26:38 +0200217 }
218
219error:
220 return ret;
221}
222
Radek Krejci084289f2019-07-09 17:35:30 +0200223API LY_ERR
224lys_value_validate(struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
225 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format)
226{
227 LY_ERR rc = LY_SUCCESS;
228 struct ly_err_item *err = NULL;
229 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200230
231 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
232
233 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
234 LOGARG(ctx, node);
235 return LY_EINVAL;
236 }
237
238 type = ((struct lysc_node_leaf*)node)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200239 /* just validate, no storing of enything */
240 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, LY_TYPE_OPTS_INCOMPLETE_DATA,
241 get_prefix, get_prefix_data, format, node, NULL, NULL, NULL, &err);
242 if (rc == LY_EINCOMPLETE) {
243 /* actually success since we do not provide the context tree and call validation with
244 * LY_TYPE_OPTS_INCOMPLETE_DATA */
245 rc = LY_SUCCESS;
246 } else if (rc && err) {
247 if (ctx) {
248 /* log only in case the ctx was provided as input parameter */
249 ly_err_print(err);
250 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200251 }
Radek Krejci73dead22019-07-11 16:46:16 +0200252 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200253 }
254
255 return rc;
256}
257
258API LY_ERR
259lyd_value_validate(struct ly_ctx *ctx, const struct lyd_node_term *node, const char *value, size_t value_len,
Radek Krejci576b23f2019-07-12 14:06:32 +0200260 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200261{
262 LY_ERR rc;
263 struct ly_err_item *err = NULL;
264 struct lysc_type *type;
Radek Krejci73dead22019-07-11 16:46:16 +0200265 int options = (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200266
267 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
268
269 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200270 rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
271 get_prefix, get_prefix_data, format, trees ? (void*)node : (void*)node->schema, trees,
272 NULL, NULL, &err);
273 if (rc == LY_EINCOMPLETE) {
274 return rc;
275 } else if (rc) {
276 if (err) {
277 if (ctx) {
278 ly_err_print(err);
279 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200280 }
Radek Krejci73dead22019-07-11 16:46:16 +0200281 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200282 }
Radek Krejci73dead22019-07-11 16:46:16 +0200283 return rc;
Radek Krejci084289f2019-07-09 17:35:30 +0200284 }
285
286 return LY_SUCCESS;
287}
288
289API LY_ERR
290lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
Michal Vasko14654712020-02-06 08:35:21 +0100291 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200292{
293 LY_ERR ret = LY_SUCCESS, rc;
294 struct ly_err_item *err = NULL;
295 struct ly_ctx *ctx;
296 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200297 struct lyd_value data = {0};
Radek Krejci73dead22019-07-11 16:46:16 +0200298 int options = LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200299
300 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
301
302 ctx = node->schema->module->ctx;
303 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200304 rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, get_prefix_data, format, (struct lyd_node*)node,
305 trees, &data, NULL, &err);
306 if (rc == LY_EINCOMPLETE) {
307 ret = rc;
308 /* continue with comparing, just remember what to return if storing is ok */
309 } else if (rc) {
310 /* value to compare is invalid */
311 ret = LY_EINVAL;
312 if (err) {
313 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200314 }
Radek Krejci73dead22019-07-11 16:46:16 +0200315 goto cleanup;
Radek Krejci084289f2019-07-09 17:35:30 +0200316 }
317
318 /* compare data */
Radek Krejci5af04842019-07-12 11:32:07 +0200319 if (type->plugin->compare(&node->value, &data)) {
320 /* do not assign it directly from the compare callback to keep possible LY_EINCOMPLETE from validation */
321 ret = LY_EVALID;
322 }
Radek Krejci084289f2019-07-09 17:35:30 +0200323
324cleanup:
Radek Krejci62903c32019-07-15 14:42:05 +0200325 type->plugin->free(ctx, &data);
Radek Krejci084289f2019-07-09 17:35:30 +0200326
327 return ret;
328}
329
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200330API const char *
331lyd_value2str(const struct lyd_node_term *node, int *dynamic)
332{
333 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, dynamic, NULL);
334
335 return node->value.realtype->plugin->print(&node->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
336}
337
338API const char *
339lyd_attr2str(const struct lyd_attr *attr, int *dynamic)
340{
341 LY_CHECK_ARG_RET(attr ? attr->parent->schema->module->ctx : NULL, attr, dynamic, NULL);
342
343 return attr->value.realtype->plugin->print(&attr->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
344}
345
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200346API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100347lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200348{
Radek Krejcie7b95092019-05-15 11:03:07 +0200349 struct lyd_node *result = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200350#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200351 const char *yang_data_name = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200352#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200353
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200354 LY_CHECK_ARG_RET(ctx, ctx, NULL);
355
Michal Vaskoa3881362020-01-21 15:57:35 +0100356#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200357 if (options & LYD_OPT_RPCREPLY) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200358 /* first item in trees is mandatory - the RPC/action request */
359 LY_CHECK_ARG_RET(ctx, trees, LY_ARRAY_SIZE(trees) >= 1, NULL);
360 if (!trees[0] || trees[0]->parent || !(trees[0]->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
361 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
362 lyd_parse_options_type2str(options));
Radek Krejcie7b95092019-05-15 11:03:07 +0200363 return NULL;
364 }
365 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200366
Radek Krejcie7b95092019-05-15 11:03:07 +0200367 if (options & LYD_OPT_DATA_TEMPLATE) {
368 yang_data_name = va_arg(ap, const char *);
369 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200370#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200371
372 if (!format) {
373 /* TODO try to detect format from the content */
374 }
375
376 switch (format) {
377 case LYD_XML:
Michal Vaskoa3881362020-01-21 15:57:35 +0100378 lyd_parse_xml(ctx, data, options, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200379 break;
380#if 0
381 case LYD_JSON:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200382 lyd_parse_json(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200383 break;
384 case LYD_LYB:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200385 lyd_parse_lyb(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200386 break;
387#endif
388 case LYD_UNKNOWN:
389 LOGINT(ctx);
390 break;
391 }
392
Radek Krejcie7b95092019-05-15 11:03:07 +0200393 return result;
394}
395
396API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100397lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200398{
399 struct lyd_node *result;
400 size_t length;
401 char *addr;
402
403 LY_CHECK_ARG_RET(ctx, ctx, NULL);
404 if (fd < 0) {
405 LOGARG(ctx, fd);
406 return NULL;
407 }
408
409 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
Michal Vaskoa3881362020-01-21 15:57:35 +0100410 result = lyd_parse_mem(ctx, addr ? addr : "", format, options);
Radek Krejcidf3da792019-05-17 10:32:24 +0200411 if (addr) {
412 ly_munmap(addr, length);
413 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200414
415 return result;
416}
417
418API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100419lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200420{
421 int fd;
422 struct lyd_node *result;
423 size_t len;
Radek Krejcie7b95092019-05-15 11:03:07 +0200424
425 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
426
427 fd = open(path, O_RDONLY);
428 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
429
430 if (!format) {
431 /* unknown format - try to detect it from filename's suffix */
432 len = strlen(path);
433
434 /* ignore trailing whitespaces */
435 for (; len > 0 && isspace(path[len - 1]); len--);
436
437 if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
438 format = LYD_XML;
439#if 0
440 } else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
441 format = LYD_JSON;
442 } else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
443 format = LYD_LYB;
444#endif
445 } /* else still unknown, try later to detect it from the content */
446 }
447
Michal Vaskoa3881362020-01-21 15:57:35 +0100448 result = lyd_parse_fd(ctx, fd, format, options);
Radek Krejcie7b95092019-05-15 11:03:07 +0200449 close(fd);
450
451 return result;
452}
Radek Krejci084289f2019-07-09 17:35:30 +0200453
Michal Vasko90932a92020-02-12 14:33:03 +0100454LY_ERR
455lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
456 ly_clb_resolve_prefix get_prefix, void *prefix_data, LYD_FORMAT format, struct lyd_node **node)
457{
458 LY_ERR ret;
459 struct lyd_node_term *term;
460
461 term = calloc(1, sizeof *term);
462 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
463
464 term->schema = schema;
465 term->prev = (struct lyd_node *)term;
466
467 ret = lyd_value_parse(term, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
468 if (ret && (ret != LY_EINCOMPLETE)) {
469 free(term);
470 return ret;
471 }
472
473 *node = (struct lyd_node *)term;
474 return ret;
475}
476
477LY_ERR
478lyd_create_inner(const struct lysc_node *schema, struct lyd_node **node)
479{
480 struct lyd_node_inner *in;
481
482 in = calloc(1, sizeof *in);
483 LY_CHECK_ERR_RET(!in, LOGMEM(schema->module->ctx), LY_EMEM);
484
485 in->schema = schema;
486 in->prev = (struct lyd_node *)in;
487
488 if ((schema->nodetype == LYS_CONTAINER) && !(((struct lysc_node_container *)schema)->flags & LYS_PRESENCE)) {
489 /* non-presence cotnainer, default */
490 in->flags = LYD_DEFAULT;
491 }
492
493 *node = (struct lyd_node *)in;
494 return LY_SUCCESS;
495}
496
497static void
498ly_keys_clean(struct ly_keys *keys)
499{
500 size_t i;
501
502 for (i = 0; i < keys->key_count; ++i) {
503 keys->keys[i].schema->type->plugin->free(keys->keys[i].schema->module->ctx, &keys->keys[i].val);
504 }
505 free(keys->str);
506 free(keys->keys);
507}
508
509static char *
510ly_keys_parse_next(char **next_key, char **key_name)
511{
512 char *ptr, *ptr2, *val, quot;
513
514 ptr = *next_key;
515
516 /* "[" */
517 LY_CHECK_GOTO(ptr[0] != '[', error);
518 ++ptr;
519
520 /* key name */
521 ptr2 = strchr(ptr, '=');
522 LY_CHECK_GOTO(!ptr2, error);
523
524 *key_name = ptr;
525 ptr2[0] = '\0';
526
527 /* \0, was '=' */
528 ptr = ptr2 + 1;
529
530 /* quote */
531 LY_CHECK_GOTO((ptr[0] != '\'') && (ptr[0] != '\"'), error);
532 quot = ptr[0];
533 ++ptr;
534
535 /* value, terminate it */
536 val = ptr;
537 ptr2 = strchr(ptr, quot);
538 LY_CHECK_GOTO(!ptr2, error);
539 ptr2[0] = '\0';
540
541 /* \0, was quote */
542 ptr = ptr2 + 1;
543
544 /* "]" */
545 LY_CHECK_GOTO(ptr[0] != ']', error);
546 ++ptr;
547
548 *next_key = ptr;
549 return val;
550
551error:
552 *next_key = ptr;
553 return NULL;
554}
555
556/* fill keys structure; if store is set, fill also each val */
557static LY_ERR
558ly_keys_parse(const struct lysc_node *list, const char *keys_str, size_t keys_len, int store, struct ly_keys *keys)
559{
560 LY_ERR ret = LY_SUCCESS;
561 char *next_key, *name;
562 const struct lysc_node *key;
563 size_t i;
564
565 assert(list->nodetype == LYS_LIST);
566
567 memset(keys, 0, sizeof *keys);
568
569 keys->str = strndup(keys_str, keys_len ? keys_len : strlen(keys_str));
570 LY_CHECK_ERR_GOTO(!keys->str, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
571
572 next_key = keys->str;
573 while (next_key[0]) {
574 /* new key */
575 keys->keys = ly_realloc(keys->keys, (keys->key_count + 1) * sizeof *keys->keys);
576 LY_CHECK_ERR_GOTO(!keys->keys, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
577
578 /* fill */
579 keys->keys[keys->key_count].value = ly_keys_parse_next(&next_key, &name);
580 if (!keys->keys[keys->key_count].value) {
581 LOGERR(list->module->ctx, LY_EINVAL, "Invalid keys string (at \"%s\").", next_key);
582 ret = LY_EINVAL;
583 goto cleanup;
584 }
585
586 /* find schema node */
587 key = lys_find_child(list, list->module, name, 0, LYS_LEAF, 0);
588 if (!key) {
589 LOGERR(list->module->ctx, LY_EINVAL, "List \"%s\" has no key \"%s\".", list->name, name);
590 ret = LY_EINVAL;
591 goto cleanup;
592 }
593 keys->keys[keys->key_count].schema = (const struct lysc_node_leaf *)key;
594
595 /* check that we do not have it already */
596 for (i = 0; i < keys->key_count; ++i) {
597 if (keys->keys[i].schema == keys->keys[keys->key_count].schema) {
598 LOGERR(list->module->ctx, LY_EINVAL, "Duplicit key \"%s\" value.", name);
599 ret = LY_EINVAL;
600 goto cleanup;
601 }
602 }
603
604 if (store) {
605 /* store the value */
606 ret = lyd_value_store(&keys->keys[keys->key_count].val, key, keys->keys[keys->key_count].value, 0, 0,
607 lydjson_resolve_prefix, NULL, LYD_JSON);
608 LY_CHECK_GOTO(ret, cleanup);
609 }
610
611 /* another valid key */
612 ++keys->key_count;
613 }
614
615cleanup:
616 ly_keys_clean(keys);
617 return ret;
618}
619
620LY_ERR
621lyd_create_list(const struct lysc_node *schema, const char *keys_str, size_t keys_len, struct lyd_node **node)
622{
623 LY_ERR ret = LY_SUCCESS;
624 const struct lysc_node *key_s;
625 struct lyd_node *list = NULL, *key;
626 struct ly_keys keys = {0};
627 size_t i;
628
629 assert((schema->nodetype == LYS_LIST) && !(schema->flags & LYS_KEYLESS));
630
631 /* parse keys */
632 LY_CHECK_GOTO(ret = ly_keys_parse(schema, keys_str, keys_len, 0, &keys), cleanup);
633
634 /* create list */
635 LY_CHECK_GOTO(ret = lyd_create_inner(schema, &list), cleanup);
636
637 /* everything was checked except that all keys are set */
638 i = 0;
639 for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
640 ++i;
641 }
642 if (i != keys.key_count) {
643 LOGERR(schema->module->ctx, LY_EINVAL, "List \"%s\" is missing some keys.", schema->name);
644 ret = LY_EINVAL;
645 goto cleanup;
646 }
647
648 /* create and insert all the keys */
649 for (i = 0; i < keys.key_count; ++i) {
650 LY_CHECK_GOTO(ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value, 0, 0,
651 lydjson_resolve_prefix, NULL, LYD_JSON, &key), cleanup);
652 lyd_insert_node(list, NULL, key);
653 }
654
655 /* success */
656 *node = list;
657 list = NULL;
658
659cleanup:
660 lyd_free_tree(list);
661 ly_keys_clean(&keys);
662 return ret;
663}
664
665LY_ERR
666lyd_create_any(const struct lysc_node *schema, const void *value, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
667{
668 struct lyd_node_any *any;
669
670 any = calloc(1, sizeof *any);
671 LY_CHECK_ERR_RET(!any, LOGMEM(schema->module->ctx), LY_EMEM);
672
673 any->schema = schema;
674 any->prev = (struct lyd_node *)any;
675
676 any->value.xml = value;
677 any->value_type = value_type;
678
679 *node = (struct lyd_node *)any;
680 return LY_SUCCESS;
681}
682
683struct lyd_node *
684lyd_get_prev_key_anchor(const struct lyd_node *first_sibling, const struct lysc_node *new_key)
685{
686 const struct lysc_node *prev_key;
687 struct lyd_node *match = NULL;
688
689 if (!first_sibling) {
690 return NULL;
691 }
692
693 for (prev_key = new_key->prev; !match && prev_key->next; prev_key = prev_key->prev) {
694 lyd_find_sibling_val(first_sibling, prev_key, NULL, 0, &match);
695 }
696
697 return match;
698}
699
700/**
701 * @brief Insert node after a sibling.
702 *
703 * @param[in] sibling Sibling to insert after.
704 * @param[in] node Node to insert.
705 */
706static void
707lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
708{
709 assert(!node->next && (node->prev == node));
710
711 node->next = sibling->next;
712 node->prev = sibling;
713 sibling->next = node;
714 if (node->next) {
715 /* sibling had a succeeding node */
716 node->next->prev = node;
717 } else {
718 /* sibling was last, find first sibling and change its prev */
719 if (sibling->parent) {
720 sibling = sibling->parent->child;
721 } else {
722 for (; sibling->prev->next != node; sibling = sibling->prev);
723 }
724 sibling->prev = node;
725 }
726 node->parent = sibling->parent;
727}
728
729/**
730 * @brief Insert node before a sibling.
731 *
732 * @param[in] sibling Sibling to insert before.
733 * @param[in] node Node to insert.
734 */
735static void
736lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
737{
738 assert(!node->next && (node->prev == node));
739
740 node->next = sibling;
741 /* covers situation of sibling being first */
742 node->prev = sibling->prev;
743 sibling->prev = node;
744 if (node->prev->next) {
745 /* sibling had a preceding node */
746 node->prev->next = node;
747 } else if (sibling->parent) {
748 /* sibling was first and we must also change parent child pointer */
749 sibling->parent->child = node;
750 }
751 node->parent = sibling->parent;
752}
753
754/**
755 * @brief Insert node as the last child of a parent.
756 *
757 * @param[in] parent Parent to insert into.
758 * @param[in] node Node to insert.
759 */
760static void
761lyd_insert_last(struct lyd_node *parent, struct lyd_node *node)
762{
763 struct lyd_node_inner *par;
764
765 assert(!node->next && (node->prev == node));
766 assert(parent->schema->nodetype & LYD_NODE_INNER);
767
768 par = (struct lyd_node_inner *)parent;
769
770 if (!par->child) {
771 par->child = node;
772 } else {
773 node->prev = par->child->prev;
774 par->child->prev->next = node;
775 par->child->prev = node;
776 }
777 node->parent = par;
778}
779
780void
781lyd_insert_node(struct lyd_node *parent, struct lyd_node *first_sibling, struct lyd_node *node)
782{
783 struct lyd_node *key_anchor;
784
785 assert((!parent && first_sibling) || (!first_sibling && parent));
786 assert(node && node->hash);
787
788 if (parent) {
789 if (node->schema->flags & LYS_KEY) {
790 /* it is key and we need to insert it at the correct place */
791 key_anchor = lyd_get_prev_key_anchor(lyd_node_children(parent), node->schema);
792 if (key_anchor) {
793 lyd_insert_after(key_anchor, node);
794 } else if (lyd_node_children(parent)) {
795 lyd_insert_before((struct lyd_node *)lyd_node_children(parent), node);
796 } else {
797 lyd_insert_last(parent, node);
798 }
799 } else {
800 /* last child */
801 lyd_insert_last(parent, node);
802 }
803 } else {
804 /* last sibling */
805 lyd_insert_after(first_sibling->prev, node);
806 }
807
808 /* remove default flags from NP containers */
809 while (parent && (parent->flags & LYD_DEFAULT)) {
810 parent->flags &= ~LYD_DEFAULT;
811 parent = (struct lyd_node *)parent->parent;
812 }
813
814 /* insert into hash table */
815 lyd_insert_hash(node);
816}
817
818LY_ERR
819lyd_create_attr(struct lyd_node *parent, const struct lys_module *mod, const char *name, size_t name_len,
820 const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix get_prefix, void *prefix_data,
821 LYD_FORMAT format, struct lyd_attr **attr)
822{
823 LY_ERR ret;
824 struct lysc_ext_instance *ant = NULL;
825 struct lyd_attr *at, *last;
826 uint32_t v;
827
828 LY_ARRAY_FOR(mod->compiled->exts, v) {
829 if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
830 !ly_strncmp(mod->compiled->exts[v].argument, name, name_len)) {
831 /* we have the annotation definition */
832 ant = &mod->compiled->exts[v];
833 break;
834 }
835 }
836 if (!ant) {
837 /* attribute is not defined as a metadata annotation (RFC 7952) */
838 LOGERR(mod->ctx, LY_EINVAL, "Annotation definition for attribute \"%s:%.*s\" not found.",
839 mod->name, name_len, name);
840 return LY_EINVAL;
841 }
842
843 at = calloc(1, sizeof *at);
844 LY_CHECK_ERR_RET(!at, LOGMEM(mod->ctx), LY_EMEM);
845 at->parent = parent;
846 at->annotation = ant;
847 ret = lyd_value_parse_attr(at, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
848 if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
849 free(at);
850 return ret;
851 }
852 at->name = lydict_insert(mod->ctx, name, name_len);
853
854 /* insert into parent as the last attribute */
855 if (parent->attr) {
856 for (last = parent->attr; last->next; last = last->next);
857 last->next = at;
858 } else {
859 parent->attr = at;
860 }
861
862 /* remove default flags from NP containers */
863 while (parent && (parent->flags & LYD_DEFAULT)) {
864 parent->flags &= ~LYD_DEFAULT;
865 parent = (struct lyd_node *)parent->parent;
866 }
867
868 if (attr) {
869 *attr = at;
870 }
871 return ret;
872}
873
Radek Krejci084289f2019-07-09 17:35:30 +0200874API const struct lyd_node_term *
Radek Krejci576b23f2019-07-12 14:06:32 +0200875lyd_target(struct lyd_value_path *path, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200876{
877 unsigned int u, v, x;
Michal Vaskoe444f752020-02-10 12:20:06 +0100878 const struct lyd_node *parent = NULL, *start_search;
879 struct lyd_node *node = NULL;
Radek Krejci084289f2019-07-09 17:35:30 +0200880 uint64_t pos = 1;
881
882 LY_CHECK_ARG_RET(NULL, path, trees, NULL);
883
884 LY_ARRAY_FOR(path, u) {
885 if (parent) {
886 start_search = lyd_node_children(parent);
887search_inner:
Michal Vaskoe444f752020-02-10 12:20:06 +0100888 lyd_find_sibling_next(start_search, path[u].node->module, path[u].node->name, 0, NULL, 0, &node);
Radek Krejci084289f2019-07-09 17:35:30 +0200889 } else {
890 LY_ARRAY_FOR(trees, v) {
891 start_search = trees[v];
892search_toplevel:
893 /* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
Michal Vaskoe444f752020-02-10 12:20:06 +0100894 lyd_find_sibling_next(start_search, path[u].node->module, path[u].node->name, 0, NULL, 0, &node);
Radek Krejci084289f2019-07-09 17:35:30 +0200895 if (node) {
896 break;
897 }
898 }
899 }
900 if (!node) {
901 return NULL;
902 }
903
904 /* check predicate if any */
905 LY_ARRAY_FOR(path[u].predicates, x) {
906 if (path[u].predicates[x].type == 0) {
907 /* position predicate */
908 if (pos != path[u].predicates[x].position) {
909 pos++;
910 goto search_repeat;
911 }
912 /* done, no more predicates are allowed here */
913 break;
914 } else if (path[u].predicates[x].type == 1) {
915 /* key-predicate */
916 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].predicates[x].key)->type;
Michal Vaskoe444f752020-02-10 12:20:06 +0100917 struct lyd_node *key;
918 lyd_find_sibling_next(lyd_node_children(node), path[u].predicates[x].key->module,
919 path[u].predicates[x].key->name, 0, NULL, 0, &key);
Radek Krejci084289f2019-07-09 17:35:30 +0200920 if (!key) {
921 /* probably error and we shouldn't be here due to previous checks when creating path */
922 goto search_repeat;
923 }
924 if (type->plugin->compare(&((struct lyd_node_term*)key)->value, path[u].predicates[x].value)) {
925 goto search_repeat;
926 }
927 } else if (path[u].predicates[x].type == 2) {
928 /* leaf-list-predicate */
929 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].node)->type;
930 if (type->plugin->compare(&((struct lyd_node_term*)node)->value, path[u].predicates[x].value)) {
931 goto search_repeat;
932 }
933 } else {
934 LOGINT(NULL);
935 }
936 }
937
938 parent = node;
939 }
940
941 return (const struct lyd_node_term*)node;
942
943search_repeat:
944 start_search = node->next;
945 if (parent) {
946 goto search_inner;
947 } else {
948 goto search_toplevel;
949 }
950}
951
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200952API LY_ERR
953lyd_compare(const struct lyd_node *node1, const struct lyd_node *node2, int options)
954{
955 const struct lyd_node *iter1, *iter2;
956 struct lyd_node_term *term1, *term2;
957 struct lyd_node_any *any1, *any2;
958 struct lysc_type *type;
959 size_t len1, len2;
Radek Krejci084289f2019-07-09 17:35:30 +0200960
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200961 if (!node1 || !node2) {
962 if (node1 == node2) {
963 return LY_SUCCESS;
964 } else {
965 return LY_ENOT;
966 }
967 }
968
Michal Vasko14654712020-02-06 08:35:21 +0100969 if (node1->schema->module->ctx != node2->schema->module->ctx || node1->schema != node2->schema) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200970 return LY_ENOT;
971 }
972
973 if (node1->hash != node2->hash) {
974 return LY_ENOT;
975 }
976
977 /* equal hashes do not mean equal nodes, they can be just in collision so the nodes must be checked explicitly */
978
979 switch (node1->schema->nodetype) {
980 case LYS_LEAF:
981 case LYS_LEAFLIST:
982 if (options & LYD_COMPARE_DEFAULTS) {
983 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
984 return LY_ENOT;
985 }
986 }
987
988 term1 = (struct lyd_node_term*)node1;
989 term2 = (struct lyd_node_term*)node2;
990 type = ((struct lysc_node_leaf*)node1->schema)->type;
991
992 return type->plugin->compare(&term1->value, &term2->value);
993 case LYS_CONTAINER:
994 if (options & LYD_COMPARE_DEFAULTS) {
995 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
996 return LY_ENOT;
997 }
998 }
999 if (options & LYD_COMPARE_FULL_RECURSION) {
1000 iter1 = ((struct lyd_node_inner*)node1)->child;
1001 iter2 = ((struct lyd_node_inner*)node2)->child;
1002 goto all_children_compare;
1003 }
1004 return LY_SUCCESS;
1005 case LYS_ACTION:
1006 if (options & LYD_COMPARE_FULL_RECURSION) {
1007 /* TODO action/RPC
1008 goto all_children_compare;
1009 */
1010 }
1011 return LY_SUCCESS;
1012 case LYS_NOTIF:
1013 if (options & LYD_COMPARE_FULL_RECURSION) {
1014 /* TODO Notification
1015 goto all_children_compare;
1016 */
1017 }
1018 return LY_SUCCESS;
1019 case LYS_LIST:
1020 iter1 = ((struct lyd_node_inner*)node1)->child;
1021 iter2 = ((struct lyd_node_inner*)node2)->child;
1022
Radek Krejci0fe9b512019-07-26 17:51:05 +02001023 if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001024 /* lists with keys, their equivalence is based on their keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +02001025 for (struct lysc_node *key = ((struct lysc_node_list*)node1->schema)->child;
1026 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1027 key = key->next) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001028 if (lyd_compare(iter1, iter2, options)) {
1029 return LY_ENOT;
1030 }
1031 iter1 = iter1->next;
1032 iter2 = iter2->next;
1033 }
1034 } else {
1035 /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
1036
1037all_children_compare:
1038 if (!iter1 && !iter2) {
1039 /* no children, nothing to compare */
1040 return LY_SUCCESS;
1041 }
1042
1043 for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
1044 if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
1045 return LY_ENOT;
1046 }
1047 }
1048 if (iter1 || iter2) {
1049 return LY_ENOT;
1050 }
1051 }
1052 return LY_SUCCESS;
1053 case LYS_ANYXML:
1054 case LYS_ANYDATA:
1055 any1 = (struct lyd_node_any*)node1;
1056 any2 = (struct lyd_node_any*)node2;
1057
1058 if (any1->value_type != any2->value_type) {
1059 return LY_ENOT;
1060 }
1061 switch (any1->value_type) {
1062 case LYD_ANYDATA_DATATREE:
1063 iter1 = any1->value.tree;
1064 iter2 = any2->value.tree;
1065 goto all_children_compare;
1066 case LYD_ANYDATA_STRING:
1067 case LYD_ANYDATA_XML:
1068 case LYD_ANYDATA_JSON:
1069 len1 = strlen(any1->value.str);
1070 len2 = strlen(any2->value.str);
1071 if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
1072 return LY_ENOT;
1073 }
1074 return LY_SUCCESS;
1075#if 0 /* TODO LYB format */
1076 case LYD_ANYDATA_LYB:
1077 int len1 = lyd_lyb_data_length(any1->value.mem);
1078 int len2 = lyd_lyb_data_length(any2->value.mem);
1079 if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
1080 return LY_ENOT;
1081 }
1082 return LY_SUCCESS;
1083#endif
1084 }
1085 }
1086
1087 LOGINT(node1->schema->module->ctx);
1088 return LY_EINT;
1089}
Radek Krejci22ebdba2019-07-25 13:59:43 +02001090
1091/**
1092 * @brief Duplicates just a single node and interconnect it into a @p parent (if present) and after the @p prev
1093 * sibling (if present).
1094 *
1095 * Ignores LYD_DUP_WITH_PARENTS and LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
1096 */
1097static struct lyd_node *
1098lyd_dup_recursive(const struct lyd_node *node, struct lyd_node_inner *parent, struct lyd_node *prev, int options)
1099{
1100 struct ly_ctx *ctx;
1101 struct lyd_node *dup = NULL;
1102
1103 LY_CHECK_ARG_RET(NULL, node, NULL);
1104 ctx = node->schema->module->ctx;
1105
1106 switch (node->schema->nodetype) {
1107 case LYS_ACTION:
1108 case LYS_NOTIF:
1109 case LYS_CONTAINER:
1110 case LYS_LIST:
1111 dup = calloc(1, sizeof(struct lyd_node_inner));
1112 break;
1113 case LYS_LEAF:
1114 case LYS_LEAFLIST:
1115 dup = calloc(1, sizeof(struct lyd_node_term));
1116 break;
1117 case LYS_ANYDATA:
1118 case LYS_ANYXML:
1119 dup = calloc(1, sizeof(struct lyd_node_any));
1120 break;
1121 default:
1122 LOGINT(ctx);
1123 goto error;
1124 }
1125
1126 /* TODO implement LYD_DUP_WITH_WHEN */
1127 dup->flags = node->flags;
1128 dup->schema = node->schema;
1129
1130 /* interconnect the node at the end */
1131 dup->parent = parent;
1132 if (prev) {
1133 dup->prev = prev;
1134 prev->next = dup;
1135 } else {
1136 dup->prev = dup;
1137 if (parent) {
1138 parent->child = dup;
1139 }
1140 }
1141 if (parent) {
1142 parent->child->prev = dup;
1143 } else if (prev) {
1144 struct lyd_node *first;
1145 for (first = prev; first->prev != prev; first = first->prev);
1146 first->prev = dup;
1147 }
1148
1149 /* TODO duplicate attributes, implement LYD_DUP_NO_ATTR */
1150
1151 /* nodetype-specific work */
1152 if (dup->schema->nodetype & LYD_NODE_TERM) {
1153 struct lyd_node_term *term = (struct lyd_node_term*)dup;
1154 struct lyd_node_term *orig = (struct lyd_node_term*)node;
1155
1156 term->hash = orig->hash;
1157 term->value.realtype = orig->value.realtype;
1158 LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(ctx, &orig->value, &term->value),
1159 LOGERR(ctx, LY_EINT, "Value duplication failed."), error);
1160 } else if (dup->schema->nodetype & LYD_NODE_INNER) {
1161 struct lyd_node_inner *inner = (struct lyd_node_inner*)dup;
1162 struct lyd_node_inner *orig = (struct lyd_node_inner*)node;
1163 struct lyd_node *child, *last = NULL;
1164
1165 if (options & LYD_DUP_RECURSIVE) {
1166 /* duplicate all the children */
1167 LY_LIST_FOR(orig->child, child) {
1168 last = lyd_dup_recursive(child, inner, last, options);
1169 LY_CHECK_GOTO(!last, error);
1170 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02001171 } else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001172 /* always duplicate keys of a list */
Radek Krejci22ebdba2019-07-25 13:59:43 +02001173 child = orig->child;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001174 for (struct lysc_node *key = ((struct lysc_node_list*)dup->schema)->child;
1175 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1176 key = key->next) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001177 if (!child) {
1178 /* possibly not keys are present in filtered tree */
1179 break;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001180 } else if (child->schema != key) {
1181 /* possibly not all keys are present in filtered tree,
1182 * but there can be also some non-key nodes */
1183 continue;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001184 }
1185 last = lyd_dup_recursive(child, inner, last, options);
1186 child = child->next;
1187 }
1188 }
1189 lyd_hash(dup);
1190 } else if (dup->schema->nodetype & LYD_NODE_ANY) {
1191 struct lyd_node_any *any = (struct lyd_node_any*)dup;
1192 struct lyd_node_any *orig = (struct lyd_node_any*)node;
1193
1194 any->hash = orig->hash;
1195 any->value_type = orig->value_type;
1196 switch (any->value_type) {
1197 case LYD_ANYDATA_DATATREE:
1198 if (orig->value.tree) {
1199 any->value.tree = lyd_dup(orig->value.tree, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_SIBLINGS);
1200 LY_CHECK_GOTO(!any->value.tree, error);
1201 }
1202 break;
1203 case LYD_ANYDATA_STRING:
1204 case LYD_ANYDATA_XML:
1205 case LYD_ANYDATA_JSON:
1206 if (orig->value.str) {
1207 any->value.str = lydict_insert(ctx, orig->value.str, strlen(orig->value.str));
1208 }
1209 break;
1210 }
1211 }
1212
1213 lyd_insert_hash(dup);
1214 return dup;
1215
1216error:
1217 if (!parent && !prev) {
1218 lyd_free_tree(dup);
1219 }
1220 return NULL;
1221}
1222
1223API struct lyd_node *
1224lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
1225{
1226 struct ly_ctx *ctx;
1227 const struct lyd_node *orig; /* original node to be duplicated */
1228 struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
1229 struct lyd_node *last = NULL; /* the last sibling of the duplicated nodes */
1230 struct lyd_node *top = NULL; /* the most higher created node */
1231 struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
1232 int keyless_parent_list = 0;
1233
1234 LY_CHECK_ARG_RET(NULL, node, NULL);
1235 ctx = node->schema->module->ctx;
1236
1237 if (options & LYD_DUP_WITH_PARENTS) {
1238 struct lyd_node_inner *orig_parent, *iter;
1239 int repeat = 1;
1240 for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
1241 if (parent && parent->schema == orig_parent->schema) {
1242 /* stop creating parents, connect what we have into the provided parent */
1243 iter = parent;
1244 repeat = 0;
1245 /* get know if there is a keyless list which we will have to rehash */
1246 for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02001247 if (piter->schema->nodetype == LYS_LIST && (piter->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001248 keyless_parent_list = 1;
1249 break;
1250 }
1251 }
1252 } else {
1253 iter = (struct lyd_node_inner*)lyd_dup_recursive((struct lyd_node*)orig_parent, NULL, NULL, 0);
1254 LY_CHECK_GOTO(!iter, error);
1255 }
1256 if (!local_parent) {
1257 local_parent = iter;
1258 }
1259 if (iter->child) {
1260 /* 1) list - add after keys
1261 * 2) provided parent with some children */
1262 iter->child->prev->next = top;
1263 if (top) {
1264 top->prev = iter->child->prev;
1265 iter->child->prev = top;
1266 }
1267 } else {
1268 iter->child = top;
1269 if (iter->schema->nodetype == LYS_LIST) {
1270 /* keyless list - we will need to rehash it since we are going to add nodes into it */
1271 keyless_parent_list = 1;
1272 }
1273 }
1274 if (top) {
1275 top->parent = iter;
1276 }
1277 top = (struct lyd_node*)iter;
1278 }
1279 if (repeat && parent) {
1280 /* given parent and created parents chain actually do not interconnect */
1281 LOGERR(ctx, LY_EINVAL, "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
1282 goto error;
1283 }
1284 } else {
1285 local_parent = parent;
1286 }
1287
1288 if (local_parent && local_parent->child) {
1289 last = local_parent->child->prev;
1290 }
1291
1292 LY_LIST_FOR(node, orig) {
1293 last = lyd_dup_recursive(orig, local_parent, last, options);
1294 LY_CHECK_GOTO(!last, error);
1295 if (!first) {
1296 first = last;
1297 }
1298
1299 if (!(options & LYD_DUP_WITH_SIBLINGS)) {
1300 break;
1301 }
1302 }
1303 if (keyless_parent_list) {
1304 /* rehash */
1305 for (; local_parent; local_parent = local_parent->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02001306 if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001307 lyd_hash((struct lyd_node*)local_parent);
1308 }
1309 }
1310 }
1311 return first;
1312
1313error:
1314 if (top) {
1315 lyd_free_tree(top);
1316 } else {
1317 lyd_free_withsiblings(first);
1318 }
1319 return NULL;
1320}
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001321
1322static LY_ERR
1323lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
1324{
Michal Vasko14654712020-02-06 08:35:21 +01001325 /* ending \0 */
1326 ++reqlen;
1327
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001328 if (reqlen > *buflen) {
1329 if (is_static) {
1330 return LY_EINCOMPLETE;
1331 }
1332
1333 *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
1334 if (!*buffer) {
1335 return LY_EMEM;
1336 }
1337
1338 *buflen = reqlen;
1339 }
1340
1341 return LY_SUCCESS;
1342}
1343
1344/**
1345 * @brief Append all list key predicates to path.
1346 *
1347 * @param[in] node Node with keys to print.
1348 * @param[in,out] buffer Buffer to print to.
1349 * @param[in,out] buflen Current buffer length.
1350 * @param[in,out] bufused Current number of characters used in @p buffer.
1351 * @param[in] is_static Whether buffer is static or can be reallocated.
1352 * @return LY_ERR
1353 */
1354static LY_ERR
1355lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
1356{
1357 const struct lyd_node *key;
1358 int dynamic = 0;
1359 size_t len;
1360 const char *val;
1361 char quot;
1362 LY_ERR rc;
1363
Michal Vasko14654712020-02-06 08:35:21 +01001364 for (key = lyd_node_children(node); key && (key->schema->flags & LYS_KEY); key = key->next) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001365 val = lyd_value2str((struct lyd_node_term *)key, &dynamic);
1366 len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
1367 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1368 if (rc != LY_SUCCESS) {
1369 if (dynamic) {
1370 free((char *)val);
1371 }
1372 return rc;
1373 }
1374
1375 quot = '\'';
1376 if (strchr(val, '\'')) {
1377 quot = '"';
1378 }
1379 *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
1380
1381 if (dynamic) {
1382 free((char *)val);
1383 }
1384 }
1385
1386 return LY_SUCCESS;
1387}
1388
1389/**
1390 * @brief Append leaf-list value predicate to path.
1391 *
1392 * @param[in] node Node to print.
1393 * @param[in,out] buffer Buffer to print to.
1394 * @param[in,out] buflen Current buffer length.
1395 * @param[in,out] bufused Current number of characters used in @p buffer.
1396 * @param[in] is_static Whether buffer is static or can be reallocated.
1397 * @return LY_ERR
1398 */
1399static LY_ERR
1400lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
1401{
1402 int dynamic = 0;
1403 size_t len;
1404 const char *val;
1405 char quot;
1406 LY_ERR rc;
1407
1408 val = lyd_value2str((struct lyd_node_term *)node, &dynamic);
1409 len = 4 + strlen(val) + 2;
1410 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1411 if (rc != LY_SUCCESS) {
1412 goto cleanup;
1413 }
1414
1415 quot = '\'';
1416 if (strchr(val, '\'')) {
1417 quot = '"';
1418 }
1419 *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
1420
1421cleanup:
1422 if (dynamic) {
1423 free((char *)val);
1424 }
1425 return rc;
1426}
1427
1428/**
1429 * @brief Append node position (relative to its other instances) predicate to path.
1430 *
1431 * @param[in] node Node to print.
1432 * @param[in,out] buffer Buffer to print to.
1433 * @param[in,out] buflen Current buffer length.
1434 * @param[in,out] bufused Current number of characters used in @p buffer.
1435 * @param[in] is_static Whether buffer is static or can be reallocated.
1436 * @return LY_ERR
1437 */
1438static LY_ERR
1439lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
1440{
1441 const struct lyd_node *first, *iter;
1442 size_t len;
1443 int pos;
1444 char *val = NULL;
1445 LY_ERR rc;
1446
1447 if (node->parent) {
1448 first = node->parent->child;
1449 } else {
1450 for (first = node; node->prev->next; node = node->prev);
1451 }
1452 pos = 1;
1453 for (iter = first; iter != node; iter = iter->next) {
1454 if (iter->schema == node->schema) {
1455 ++pos;
1456 }
1457 }
1458 if (asprintf(&val, "%d", pos) == -1) {
1459 return LY_EMEM;
1460 }
1461
1462 len = 1 + strlen(val) + 1;
1463 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1464 if (rc != LY_SUCCESS) {
1465 goto cleanup;
1466 }
1467
1468 *bufused += sprintf(*buffer + *bufused, "[%s]", val);
1469
1470cleanup:
1471 free(val);
1472 return rc;
1473}
1474
1475API char *
1476lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
1477{
Michal Vasko14654712020-02-06 08:35:21 +01001478 int is_static = 0, i, depth;
1479 size_t bufused = 0, len;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001480 const struct lyd_node *iter;
1481 const struct lys_module *mod;
1482 LY_ERR rc;
1483
1484 LY_CHECK_ARG_RET(NULL, node, NULL);
1485 if (buffer) {
1486 LY_CHECK_ARG_RET(node->schema->module->ctx, buflen > 1, NULL);
1487 is_static = 1;
Michal Vasko14654712020-02-06 08:35:21 +01001488 } else {
1489 buflen = 0;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001490 }
1491
1492 switch (pathtype) {
Michal Vasko14654712020-02-06 08:35:21 +01001493 case LYD_PATH_LOG:
1494 depth = 1;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001495 for (iter = node; iter->parent; iter = (const struct lyd_node *)iter->parent) {
1496 ++depth;
1497 }
1498
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001499 goto iter_print;
Michal Vasko14654712020-02-06 08:35:21 +01001500 while (depth) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001501 /* find the right node */
Michal Vasko14654712020-02-06 08:35:21 +01001502 for (iter = node, i = 1; i < depth; iter = (const struct lyd_node *)iter->parent, ++i);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001503iter_print:
1504 /* print prefix and name */
1505 mod = NULL;
1506 if (!iter->parent || (iter->schema->module != iter->parent->schema->module)) {
1507 mod = iter->schema->module;
1508 }
1509
1510 /* realloc string */
1511 len = 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(iter->schema->name);
1512 rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
1513 if (rc != LY_SUCCESS) {
1514 break;
1515 }
1516
1517 /* print next node */
1518 bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", iter->schema->name);
1519
1520 switch (iter->schema->nodetype) {
1521 case LYS_LIST:
1522 if (iter->schema->flags & LYS_KEYLESS) {
1523 /* print its position */
1524 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
1525 } else {
1526 /* print all list keys in predicates */
1527 rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
1528 }
1529 break;
1530 case LYS_LEAFLIST:
1531 if (iter->schema->flags & LYS_CONFIG_W) {
1532 /* print leaf-list value */
1533 rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
1534 } else {
1535 /* print its position */
1536 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
1537 }
1538 break;
1539 default:
1540 /* nothing to print more */
1541 rc = LY_SUCCESS;
1542 break;
1543 }
1544 if (rc != LY_SUCCESS) {
1545 break;
1546 }
1547
Michal Vasko14654712020-02-06 08:35:21 +01001548 --depth;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001549 }
1550 break;
1551 }
1552
1553 return buffer;
1554}
Michal Vaskoe444f752020-02-10 12:20:06 +01001555
1556API struct ly_set *
1557lyd_find_instance(const struct lyd_node *sibling, const struct lysc_node *schema)
1558{
1559 struct ly_set *ret, *ret_aux, *spath;
1560 const struct lysc_node *siter, *sparent;
1561 const struct lyd_node *iter;
1562 unsigned int i, j;
1563
1564 LY_CHECK_ARG_RET(NULL, sibling, schema, NULL);
1565 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1566 LOGARG(schema->module->ctx, schema);
1567 return NULL;
1568 }
1569
1570 ret = ly_set_new();
1571 spath = ly_set_new();
1572 LY_CHECK_ERR_GOTO(!ret || !spath, LOGMEM(schema->module->ctx), error);
1573
1574 /* build schema path until sibling parent */
1575 sparent = sibling->parent ? sibling->parent->schema : NULL;
1576 for (siter = schema; siter && (siter != sparent); siter = siter->parent) {
1577 if (siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC | LYS_ACTION)) {
1578 /* standard data node */
1579 ly_set_add(spath, (void *)siter, LY_SET_OPT_USEASLIST);
1580
1581 } /* else skip the rest node types */
1582 }
1583 /* no valid path */
1584 LY_CHECK_GOTO(!spath->count, error);
1585
1586 /* start searching */
1587 LY_LIST_FOR(sibling, iter) {
1588 if (iter->schema == spath->objs[spath->count - 1]) {
1589 ly_set_add(ret, (void *)iter, LY_SET_OPT_USEASLIST);
1590 }
1591 }
1592 for (i = spath->count - 1; i; i--) {
1593 if (!ret->count) {
1594 /* nothing found */
1595 break;
1596 }
1597
1598 ret_aux = ly_set_new();
1599 LY_CHECK_ERR_GOTO(!ret_aux, LOGMEM(schema->module->ctx), error);
1600 for (j = 0; j < ret->count; j++) {
1601 LY_LIST_FOR(lyd_node_children(ret->objs[j]), iter) {
1602 if (iter->schema == spath->objs[i - 1]) {
1603 ly_set_add(ret_aux, (void *)iter, LY_SET_OPT_USEASLIST);
1604 }
1605 }
1606 }
1607 ly_set_free(ret, NULL);
1608 ret = ret_aux;
1609 }
1610
1611 ly_set_free(spath, NULL);
1612 return ret;
1613
1614error:
1615 ly_set_free(ret, NULL);
1616 ly_set_free(spath, NULL);
1617
1618 return NULL;
1619}
1620
Michal Vaskoe444f752020-02-10 12:20:06 +01001621API LY_ERR
1622lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name, size_t name_len,
1623 const char *key_or_value, size_t val_len, struct lyd_node **match)
1624{
1625 LY_ERR rc;
1626 const struct lyd_node *node = NULL;
1627 struct lyd_node_term *term;
1628 const struct lysc_node *schema;
1629 struct ly_keys keys = {0};
Michal Vasko90932a92020-02-12 14:33:03 +01001630 struct lyd_value val = {0};
Michal Vaskoe444f752020-02-10 12:20:06 +01001631 size_t i;
Michal Vaskoe444f752020-02-10 12:20:06 +01001632
1633 LY_CHECK_ARG_RET(NULL, module, name, LY_EINVAL);
1634
1635 if (!first) {
1636 /* no data */
1637 *match = NULL;
1638 return LY_ENOTFOUND;
1639 }
1640
1641 /* find schema */
1642 schema = lys_find_child(first->parent ? first->parent->schema : NULL, module, name, name_len, 0, 0);
1643 if (!schema) {
1644 LOGERR(module->ctx, LY_EINVAL, "Schema node not found.");
1645 return LY_EINVAL;
1646 }
1647
1648 if (key_or_value && !val_len) {
1649 val_len = strlen(key_or_value);
1650 }
1651
1652 if (key_or_value && (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko90932a92020-02-12 14:33:03 +01001653 /* store the value */
1654 LY_CHECK_GOTO(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 +01001655 } else if (key_or_value && (schema->nodetype == LYS_LIST)) {
1656 /* parse keys into canonical values */
1657 LY_CHECK_GOTO(rc = ly_keys_parse(schema, key_or_value, val_len, 1, &keys), cleanup);
1658 }
1659
1660 /* find first matching value */
1661 LY_LIST_FOR(first, node) {
1662 if (node->schema != schema) {
1663 continue;
1664 }
1665
1666 if ((schema->nodetype == LYS_LIST) && keys.str) {
1667 /* compare all set keys */
1668 for (i = 0; i < keys.key_count; ++i) {
1669 /* find key */
1670 rc = lyd_find_sibling_val(lyd_node_children(node), (struct lysc_node *)keys.keys[i].schema, NULL, 0,
1671 (struct lyd_node **)&term);
1672 if (rc == LY_ENOTFOUND) {
1673 /* all keys must always exist */
1674 LOGINT_RET(module->ctx);
1675 }
1676 LY_CHECK_GOTO(rc, cleanup);
1677
1678 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01001679 if (!term->value.realtype->plugin->compare(&term->value, &keys.keys[i].val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01001680 break;
1681 }
1682 }
1683
1684 if (i < keys.key_count) {
1685 /* not a match */
1686 continue;
1687 }
Michal Vasko90932a92020-02-12 14:33:03 +01001688 } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && val.realtype) {
Michal Vaskoe444f752020-02-10 12:20:06 +01001689 term = (struct lyd_node_term *)node;
1690
1691 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01001692 if (!term->value.realtype->plugin->compare(&term->value, &val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01001693 /* not a match */
1694 continue;
1695 }
1696 }
1697
1698 /* all criteria passed */
1699 break;
1700 }
1701
1702 if (!node) {
1703 rc = LY_ENOTFOUND;
1704 *match = NULL;
1705 goto cleanup;
1706 }
1707
1708 /* success */
1709 *match = (struct lyd_node *)node;
1710 rc = LY_SUCCESS;
1711
1712cleanup:
1713 ly_keys_clean(&keys);
Michal Vasko90932a92020-02-12 14:33:03 +01001714 if (val.realtype) {
1715 val.realtype->plugin->free(module->ctx, &val);
1716 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001717 return rc;
1718}
1719
1720API LY_ERR
1721lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
1722{
1723 struct lyd_node **match_p;
1724 struct lyd_node_inner *parent;
1725
1726 LY_CHECK_ARG_RET(NULL, target, match, LY_EINVAL);
1727
1728 if (!siblings) {
1729 /* no data */
1730 *match = NULL;
1731 return LY_ENOTFOUND;
1732 }
1733
1734 /* find first sibling */
1735 if (siblings->parent) {
1736 siblings = siblings->parent->child;
1737 } else {
1738 while (siblings->prev->next) {
1739 siblings = siblings->prev;
1740 }
1741 }
1742
1743 parent = (struct lyd_node_inner *)siblings->parent;
1744 if (parent && parent->children_ht) {
1745 assert(target->hash);
1746
1747 /* find by hash */
1748 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
1749 siblings = *match_p;
1750 } else {
1751 /* not found */
1752 siblings = NULL;
1753 }
1754 } else {
1755 /* no children hash table */
1756 for (; siblings; siblings = siblings->next) {
1757 if (!lyd_compare(siblings, target, 0)) {
1758 break;
1759 }
1760 }
1761 }
1762
1763 if (!siblings) {
1764 *match = NULL;
1765 return LY_ENOTFOUND;
1766 }
1767
1768 *match = (struct lyd_node *)siblings;
1769 return LY_SUCCESS;
1770}
1771
1772API LY_ERR
1773lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
1774{
1775 struct lyd_node_inner *parent;
1776 struct lyd_node *match;
1777 struct lyd_node **match_p;
1778 struct ly_set *ret;
1779
1780 LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
1781
1782 if (!siblings) {
1783 /* no data */
1784 return LY_ENOTFOUND;
1785 }
1786
1787 ret = ly_set_new();
1788 LY_CHECK_ERR_RET(!ret, LOGMEM(target->schema->module->ctx), LY_EMEM);
1789
1790 /* find first sibling */
1791 if (siblings->parent) {
1792 siblings = siblings->parent->child;
1793 } else {
1794 while (siblings->prev->next) {
1795 siblings = siblings->prev;
1796 }
1797 }
1798
1799 parent = (struct lyd_node_inner *)siblings->parent;
1800 if (parent && parent->children_ht) {
1801 assert(target->hash);
1802
1803 /* find by hash */
1804 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
1805 match = *match_p;
1806 } else {
1807 /* not found */
1808 match = NULL;
1809 }
1810 while (match) {
1811 /* add all found nodes into the return set */
1812 if (ly_set_add(ret, match, LY_SET_OPT_USEASLIST) == -1) {
1813 goto error;
1814 }
1815
1816 /* find next instance */
1817 if (lyht_find_next(parent->children_ht, &match, match->hash, (void **)&match_p)) {
1818 match = NULL;
1819 } else {
1820 match = *match_p;
1821 }
1822 }
1823 } else {
1824 /* no children hash table */
1825 for (; siblings; siblings = siblings->next) {
1826 if (!lyd_compare(siblings, target, 0)) {
1827 /* a match */
1828 if (ly_set_add(ret, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
1829 goto error;
1830 }
1831 }
1832 }
1833 }
1834
1835 if (!ret->count) {
1836 ly_set_free(ret, NULL);
1837 return LY_ENOTFOUND;
1838 }
1839
1840 *set = ret;
1841 return LY_SUCCESS;
1842
1843error:
1844 ly_set_free(ret, NULL);
1845 return LY_EMEM;
1846}
1847
Michal Vasko90932a92020-02-12 14:33:03 +01001848static int
1849lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
1850{
1851 struct lysc_node *val1;
1852 struct lyd_node *val2;
1853
1854 val1 = *((struct lysc_node **)val1_p);
1855 val2 = *((struct lyd_node **)val2_p);
1856
1857 assert(val1->nodetype & (LYD_NODE_INNER | LYS_LEAF));
1858
1859 if (val1 == val2->schema) {
1860 /* schema match is enough */
1861 return 1;
1862 } else {
1863 return 0;
1864 }
1865}
1866
1867static LY_ERR
1868lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
1869{
1870 struct lyd_node **match_p;
1871 struct lyd_node_inner *parent;
1872 uint32_t hash;
1873 values_equal_cb ht_cb;
1874
1875 assert(siblings && schema && (schema->nodetype & (LYD_NODE_INNER | LYS_LEAF)));
1876
1877 /* find first sibling */
1878 if (siblings->parent) {
1879 siblings = siblings->parent->child;
1880 } else {
1881 while (siblings->prev->next) {
1882 siblings = siblings->prev;
1883 }
1884 }
1885
1886 parent = (struct lyd_node_inner *)siblings->parent;
1887 if (parent && parent->children_ht) {
1888 /* calculate our hash */
1889 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
1890 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
1891 hash = dict_hash_multi(hash, NULL, 0);
1892
1893 /* use special hash table function */
1894 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
1895
1896 /* find by hash */
1897 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
1898 siblings = *match_p;
1899 } else {
1900 /* not found */
1901 siblings = NULL;
1902 }
1903
1904 /* set the original hash table compare function back */
1905 lyht_set_cb(parent->children_ht, ht_cb);
1906 } else {
1907 /* no children hash table */
1908 for (; siblings; siblings = siblings->next) {
1909 if (siblings->schema == schema) {
1910 /* schema match is enough */
1911 break;
1912 }
1913 }
1914 }
1915
1916 if (!siblings) {
1917 *match = NULL;
1918 return LY_ENOTFOUND;
1919 }
1920
1921 *match = (struct lyd_node *)siblings;
1922 return LY_SUCCESS;
1923}
1924
Michal Vaskoe444f752020-02-10 12:20:06 +01001925API LY_ERR
1926lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
1927 size_t val_len, struct lyd_node **match)
1928{
1929 LY_ERR rc;
1930 struct lyd_node *target = NULL;
1931
1932 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
1933 if ((schema->nodetype == LYS_LIST) && schema->flags & LYS_KEYLESS) {
1934 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
1935 return LY_EINVAL;
1936 } else if ((schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && !key_or_value) {
1937 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - no value/keys for a (leaf-)list (%s()).", __func__);
1938 return LY_EINVAL;
1939 } else if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1940 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
1941 lys_nodetype2str(schema->nodetype), __func__);
1942 return LY_EINVAL;
1943 }
1944
1945 if (!siblings) {
1946 /* no data */
1947 *match = NULL;
1948 return LY_ENOTFOUND;
1949 }
1950
Michal Vasko90932a92020-02-12 14:33:03 +01001951 /* create data node if needed and find it */
Michal Vaskoe444f752020-02-10 12:20:06 +01001952 switch (schema->nodetype) {
1953 case LYS_CONTAINER:
1954 case LYS_ANYXML:
1955 case LYS_ANYDATA:
1956 case LYS_NOTIF:
1957 case LYS_RPC:
Michal Vaskoe444f752020-02-10 12:20:06 +01001958 case LYS_LEAF:
Michal Vasko90932a92020-02-12 14:33:03 +01001959 /* find it based on schema only */
1960 rc = lyd_find_sibling_schema(siblings, schema, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01001961 break;
1962 case LYS_LEAFLIST:
1963 /* target used attributes: schema, hash, value */
Michal Vasko90932a92020-02-12 14:33:03 +01001964 LY_CHECK_RET(lyd_create_term(schema, key_or_value, val_len, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &target));
1965 lyd_hash(target);
1966 /* fallthrough */
Michal Vaskoe444f752020-02-10 12:20:06 +01001967 case LYS_LIST:
Michal Vasko90932a92020-02-12 14:33:03 +01001968 if (schema->nodetype == LYS_LIST) {
1969 /* target used attributes: schema, hash, child (all keys) */
1970 LY_CHECK_RET(lyd_create_list(schema, key_or_value, val_len, &target));
1971 lyd_hash(target);
1972 }
1973
1974 /* find it */
1975 rc = lyd_find_sibling_first(siblings, target, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01001976 break;
1977 default:
1978 /* unreachable */
1979 LOGINT(schema->module->ctx);
1980 return LY_EINT;
1981 }
1982
Michal Vaskoe444f752020-02-10 12:20:06 +01001983 lyd_free_tree(target);
1984 return rc;
1985}