blob: f3c049f19f826f806386dcbfd45d6365e1d96f4a [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
Michal Vasko9b368d32020-02-14 13:53:31 +0100461 assert(schema->nodetype & LYD_NODE_TERM);
462
Michal Vasko90932a92020-02-12 14:33:03 +0100463 term = calloc(1, sizeof *term);
464 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
465
466 term->schema = schema;
467 term->prev = (struct lyd_node *)term;
Michal Vasko9b368d32020-02-14 13:53:31 +0100468 term->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100469
470 ret = lyd_value_parse(term, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
471 if (ret && (ret != LY_EINCOMPLETE)) {
472 free(term);
473 return ret;
474 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100475 lyd_hash((struct lyd_node *)term);
476
477 *node = (struct lyd_node *)term;
478 return ret;
479}
480
481LY_ERR
482lyd_create_term2(const struct lysc_node *schema, const struct lyd_value *val, struct lyd_node **node)
483{
484 LY_ERR ret;
485 struct lyd_node_term *term;
486 struct lysc_type *type;
487
488 assert(schema->nodetype & LYD_NODE_TERM);
489
490 term = calloc(1, sizeof *term);
491 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
492
493 term->schema = schema;
494 term->prev = (struct lyd_node *)term;
495 term->flags = LYD_NEW;
496
497 type = ((struct lysc_node_leaf *)schema)->type;
498 ret = type->plugin->duplicate(schema->module->ctx, val, &term->value);
499 if (ret) {
500 LOGERR(schema->module->ctx, ret, "Value duplication failed.");
501 free(term);
502 return ret;
503 }
504 lyd_hash((struct lyd_node *)term);
Michal Vasko90932a92020-02-12 14:33:03 +0100505
506 *node = (struct lyd_node *)term;
507 return ret;
508}
509
510LY_ERR
511lyd_create_inner(const struct lysc_node *schema, struct lyd_node **node)
512{
513 struct lyd_node_inner *in;
514
Michal Vasko9b368d32020-02-14 13:53:31 +0100515 assert(schema->nodetype & LYD_NODE_INNER);
516
Michal Vasko90932a92020-02-12 14:33:03 +0100517 in = calloc(1, sizeof *in);
518 LY_CHECK_ERR_RET(!in, LOGMEM(schema->module->ctx), LY_EMEM);
519
520 in->schema = schema;
521 in->prev = (struct lyd_node *)in;
Michal Vasko9b368d32020-02-14 13:53:31 +0100522 in->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100523
Michal Vasko9b368d32020-02-14 13:53:31 +0100524 /* do not hash list with keys, we need them for the hash */
525 if ((schema->nodetype != LYS_LIST) || (schema->flags & LYS_KEYLESS)) {
526 lyd_hash((struct lyd_node *)in);
527 }
528 if ((schema->nodetype == LYS_CONTAINER) && !(schema->flags & LYS_PRESENCE)) {
529 /* NP cotnainer always a default */
530 in->flags |= LYD_DEFAULT;
Michal Vasko90932a92020-02-12 14:33:03 +0100531 }
532
533 *node = (struct lyd_node *)in;
534 return LY_SUCCESS;
535}
536
537static void
538ly_keys_clean(struct ly_keys *keys)
539{
540 size_t i;
541
542 for (i = 0; i < keys->key_count; ++i) {
543 keys->keys[i].schema->type->plugin->free(keys->keys[i].schema->module->ctx, &keys->keys[i].val);
544 }
545 free(keys->str);
546 free(keys->keys);
547}
548
549static char *
550ly_keys_parse_next(char **next_key, char **key_name)
551{
552 char *ptr, *ptr2, *val, quot;
553
554 ptr = *next_key;
555
556 /* "[" */
557 LY_CHECK_GOTO(ptr[0] != '[', error);
558 ++ptr;
559
560 /* key name */
561 ptr2 = strchr(ptr, '=');
562 LY_CHECK_GOTO(!ptr2, error);
563
564 *key_name = ptr;
565 ptr2[0] = '\0';
566
567 /* \0, was '=' */
568 ptr = ptr2 + 1;
569
570 /* quote */
571 LY_CHECK_GOTO((ptr[0] != '\'') && (ptr[0] != '\"'), error);
572 quot = ptr[0];
573 ++ptr;
574
575 /* value, terminate it */
576 val = ptr;
577 ptr2 = strchr(ptr, quot);
578 LY_CHECK_GOTO(!ptr2, error);
579 ptr2[0] = '\0';
580
581 /* \0, was quote */
582 ptr = ptr2 + 1;
583
584 /* "]" */
585 LY_CHECK_GOTO(ptr[0] != ']', error);
586 ++ptr;
587
588 *next_key = ptr;
589 return val;
590
591error:
592 *next_key = ptr;
593 return NULL;
594}
595
596/* fill keys structure; if store is set, fill also each val */
597static LY_ERR
598ly_keys_parse(const struct lysc_node *list, const char *keys_str, size_t keys_len, int store, struct ly_keys *keys)
599{
600 LY_ERR ret = LY_SUCCESS;
601 char *next_key, *name;
602 const struct lysc_node *key;
603 size_t i;
604
605 assert(list->nodetype == LYS_LIST);
606
607 memset(keys, 0, sizeof *keys);
608
609 keys->str = strndup(keys_str, keys_len ? keys_len : strlen(keys_str));
610 LY_CHECK_ERR_GOTO(!keys->str, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
611
612 next_key = keys->str;
613 while (next_key[0]) {
614 /* new key */
615 keys->keys = ly_realloc(keys->keys, (keys->key_count + 1) * sizeof *keys->keys);
616 LY_CHECK_ERR_GOTO(!keys->keys, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
617
618 /* fill */
619 keys->keys[keys->key_count].value = ly_keys_parse_next(&next_key, &name);
620 if (!keys->keys[keys->key_count].value) {
621 LOGERR(list->module->ctx, LY_EINVAL, "Invalid keys string (at \"%s\").", next_key);
622 ret = LY_EINVAL;
623 goto cleanup;
624 }
625
626 /* find schema node */
627 key = lys_find_child(list, list->module, name, 0, LYS_LEAF, 0);
628 if (!key) {
629 LOGERR(list->module->ctx, LY_EINVAL, "List \"%s\" has no key \"%s\".", list->name, name);
630 ret = LY_EINVAL;
631 goto cleanup;
632 }
633 keys->keys[keys->key_count].schema = (const struct lysc_node_leaf *)key;
634
635 /* check that we do not have it already */
636 for (i = 0; i < keys->key_count; ++i) {
637 if (keys->keys[i].schema == keys->keys[keys->key_count].schema) {
638 LOGERR(list->module->ctx, LY_EINVAL, "Duplicit key \"%s\" value.", name);
639 ret = LY_EINVAL;
640 goto cleanup;
641 }
642 }
643
644 if (store) {
645 /* store the value */
646 ret = lyd_value_store(&keys->keys[keys->key_count].val, key, keys->keys[keys->key_count].value, 0, 0,
647 lydjson_resolve_prefix, NULL, LYD_JSON);
648 LY_CHECK_GOTO(ret, cleanup);
649 }
650
651 /* another valid key */
652 ++keys->key_count;
653 }
654
655cleanup:
656 ly_keys_clean(keys);
657 return ret;
658}
659
660LY_ERR
661lyd_create_list(const struct lysc_node *schema, const char *keys_str, size_t keys_len, struct lyd_node **node)
662{
663 LY_ERR ret = LY_SUCCESS;
664 const struct lysc_node *key_s;
665 struct lyd_node *list = NULL, *key;
666 struct ly_keys keys = {0};
667 size_t i;
668
669 assert((schema->nodetype == LYS_LIST) && !(schema->flags & LYS_KEYLESS));
670
671 /* parse keys */
672 LY_CHECK_GOTO(ret = ly_keys_parse(schema, keys_str, keys_len, 0, &keys), cleanup);
673
674 /* create list */
675 LY_CHECK_GOTO(ret = lyd_create_inner(schema, &list), cleanup);
676
677 /* everything was checked except that all keys are set */
678 i = 0;
679 for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
680 ++i;
681 }
682 if (i != keys.key_count) {
683 LOGERR(schema->module->ctx, LY_EINVAL, "List \"%s\" is missing some keys.", schema->name);
684 ret = LY_EINVAL;
685 goto cleanup;
686 }
687
688 /* create and insert all the keys */
689 for (i = 0; i < keys.key_count; ++i) {
690 LY_CHECK_GOTO(ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value, 0, 0,
691 lydjson_resolve_prefix, NULL, LYD_JSON, &key), cleanup);
692 lyd_insert_node(list, NULL, key);
693 }
694
Michal Vasko9b368d32020-02-14 13:53:31 +0100695 /* hash having all the keys */
696 lyd_hash(list);
697
Michal Vasko90932a92020-02-12 14:33:03 +0100698 /* success */
699 *node = list;
700 list = NULL;
701
702cleanup:
703 lyd_free_tree(list);
704 ly_keys_clean(&keys);
705 return ret;
706}
707
708LY_ERR
709lyd_create_any(const struct lysc_node *schema, const void *value, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
710{
711 struct lyd_node_any *any;
712
Michal Vasko9b368d32020-02-14 13:53:31 +0100713 assert(schema->nodetype & LYD_NODE_ANY);
714
Michal Vasko90932a92020-02-12 14:33:03 +0100715 any = calloc(1, sizeof *any);
716 LY_CHECK_ERR_RET(!any, LOGMEM(schema->module->ctx), LY_EMEM);
717
718 any->schema = schema;
719 any->prev = (struct lyd_node *)any;
Michal Vasko9b368d32020-02-14 13:53:31 +0100720 any->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100721
722 any->value.xml = value;
723 any->value_type = value_type;
Michal Vasko9b368d32020-02-14 13:53:31 +0100724 lyd_hash((struct lyd_node *)any);
Michal Vasko90932a92020-02-12 14:33:03 +0100725
726 *node = (struct lyd_node *)any;
727 return LY_SUCCESS;
728}
729
730struct lyd_node *
731lyd_get_prev_key_anchor(const struct lyd_node *first_sibling, const struct lysc_node *new_key)
732{
733 const struct lysc_node *prev_key;
734 struct lyd_node *match = NULL;
735
736 if (!first_sibling) {
737 return NULL;
738 }
739
740 for (prev_key = new_key->prev; !match && prev_key->next; prev_key = prev_key->prev) {
741 lyd_find_sibling_val(first_sibling, prev_key, NULL, 0, &match);
742 }
743
744 return match;
745}
746
747/**
748 * @brief Insert node after a sibling.
749 *
750 * @param[in] sibling Sibling to insert after.
751 * @param[in] node Node to insert.
752 */
753static void
754lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
755{
756 assert(!node->next && (node->prev == node));
757
758 node->next = sibling->next;
759 node->prev = sibling;
760 sibling->next = node;
761 if (node->next) {
762 /* sibling had a succeeding node */
763 node->next->prev = node;
764 } else {
765 /* sibling was last, find first sibling and change its prev */
766 if (sibling->parent) {
767 sibling = sibling->parent->child;
768 } else {
769 for (; sibling->prev->next != node; sibling = sibling->prev);
770 }
771 sibling->prev = node;
772 }
773 node->parent = sibling->parent;
774}
775
776/**
777 * @brief Insert node before a sibling.
778 *
779 * @param[in] sibling Sibling to insert before.
780 * @param[in] node Node to insert.
781 */
782static void
783lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
784{
785 assert(!node->next && (node->prev == node));
786
787 node->next = sibling;
788 /* covers situation of sibling being first */
789 node->prev = sibling->prev;
790 sibling->prev = node;
791 if (node->prev->next) {
792 /* sibling had a preceding node */
793 node->prev->next = node;
794 } else if (sibling->parent) {
795 /* sibling was first and we must also change parent child pointer */
796 sibling->parent->child = node;
797 }
798 node->parent = sibling->parent;
799}
800
801/**
802 * @brief Insert node as the last child of a parent.
803 *
804 * @param[in] parent Parent to insert into.
805 * @param[in] node Node to insert.
806 */
807static void
808lyd_insert_last(struct lyd_node *parent, struct lyd_node *node)
809{
810 struct lyd_node_inner *par;
811
812 assert(!node->next && (node->prev == node));
813 assert(parent->schema->nodetype & LYD_NODE_INNER);
814
815 par = (struct lyd_node_inner *)parent;
816
817 if (!par->child) {
818 par->child = node;
819 } else {
820 node->prev = par->child->prev;
821 par->child->prev->next = node;
822 par->child->prev = node;
823 }
824 node->parent = par;
825}
826
827void
Michal Vasko9b368d32020-02-14 13:53:31 +0100828lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100829{
Michal Vasko9b368d32020-02-14 13:53:31 +0100830 struct lyd_node *anchor;
Michal Vasko90932a92020-02-12 14:33:03 +0100831
Michal Vasko9b368d32020-02-14 13:53:31 +0100832 assert((parent || first_sibling) && node && node->hash);
833
834 if (!parent && first_sibling && (*first_sibling) && (*first_sibling)->parent) {
835 parent = (struct lyd_node *)(*first_sibling)->parent;
836 }
Michal Vasko90932a92020-02-12 14:33:03 +0100837
838 if (parent) {
839 if (node->schema->flags & LYS_KEY) {
840 /* it is key and we need to insert it at the correct place */
Michal Vasko9b368d32020-02-14 13:53:31 +0100841 anchor = lyd_get_prev_key_anchor(lyd_node_children(parent), node->schema);
842 if (anchor) {
843 lyd_insert_after(anchor, node);
Michal Vasko90932a92020-02-12 14:33:03 +0100844 } else if (lyd_node_children(parent)) {
845 lyd_insert_before((struct lyd_node *)lyd_node_children(parent), node);
846 } else {
847 lyd_insert_last(parent, node);
848 }
849 } else {
850 /* last child */
851 lyd_insert_last(parent, node);
852 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100853 } else if (*first_sibling) {
854 /* top-level siblings, find the last one from this module, or simply the last */
855 anchor = (*first_sibling)->prev;
856 while (anchor->prev->next && (lyd_top_node_module(anchor) != lyd_top_node_module(node))) {
857 anchor = anchor->prev;
858 }
859
860 /* insert */
861 lyd_insert_after(anchor, node);
Michal Vasko90932a92020-02-12 14:33:03 +0100862 } else {
Michal Vasko9b368d32020-02-14 13:53:31 +0100863 /* the only sibling */
864 *first_sibling = node;
Michal Vasko90932a92020-02-12 14:33:03 +0100865 }
866
Michal Vasko9b368d32020-02-14 13:53:31 +0100867 if (!(node->flags & LYD_DEFAULT)) {
868 /* remove default flags from NP containers */
869 while (parent && (parent->flags & LYD_DEFAULT)) {
870 parent->flags &= ~LYD_DEFAULT;
871 parent = (struct lyd_node *)parent->parent;
872 }
Michal Vasko90932a92020-02-12 14:33:03 +0100873 }
874
875 /* insert into hash table */
876 lyd_insert_hash(node);
877}
878
879LY_ERR
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100880lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct lys_module *mod, const char *name,
881 size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix get_prefix,
882 void *prefix_data, LYD_FORMAT format)
Michal Vasko90932a92020-02-12 14:33:03 +0100883{
884 LY_ERR ret;
885 struct lysc_ext_instance *ant = NULL;
886 struct lyd_attr *at, *last;
887 uint32_t v;
888
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100889 assert(parent || attr);
890
Michal Vasko90932a92020-02-12 14:33:03 +0100891 LY_ARRAY_FOR(mod->compiled->exts, v) {
892 if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
893 !ly_strncmp(mod->compiled->exts[v].argument, name, name_len)) {
894 /* we have the annotation definition */
895 ant = &mod->compiled->exts[v];
896 break;
897 }
898 }
899 if (!ant) {
900 /* attribute is not defined as a metadata annotation (RFC 7952) */
901 LOGERR(mod->ctx, LY_EINVAL, "Annotation definition for attribute \"%s:%.*s\" not found.",
902 mod->name, name_len, name);
903 return LY_EINVAL;
904 }
905
906 at = calloc(1, sizeof *at);
907 LY_CHECK_ERR_RET(!at, LOGMEM(mod->ctx), LY_EMEM);
908 at->parent = parent;
909 at->annotation = ant;
910 ret = lyd_value_parse_attr(at, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
911 if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
912 free(at);
913 return ret;
914 }
915 at->name = lydict_insert(mod->ctx, name, name_len);
916
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100917 /* insert as the last attribute */
918 if (parent) {
919 if (parent->attr) {
920 for (last = parent->attr; last->next; last = last->next);
921 last->next = at;
922 } else {
923 parent->attr = at;
924 }
925 } else if (*attr) {
926 for (last = *attr; last->next; last = last->next);
Michal Vasko90932a92020-02-12 14:33:03 +0100927 last->next = at;
Michal Vasko90932a92020-02-12 14:33:03 +0100928 }
929
930 /* remove default flags from NP containers */
931 while (parent && (parent->flags & LYD_DEFAULT)) {
932 parent->flags &= ~LYD_DEFAULT;
933 parent = (struct lyd_node *)parent->parent;
934 }
935
936 if (attr) {
937 *attr = at;
938 }
939 return ret;
940}
941
Radek Krejci084289f2019-07-09 17:35:30 +0200942API const struct lyd_node_term *
Radek Krejci576b23f2019-07-12 14:06:32 +0200943lyd_target(struct lyd_value_path *path, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200944{
945 unsigned int u, v, x;
Michal Vaskoe444f752020-02-10 12:20:06 +0100946 const struct lyd_node *parent = NULL, *start_search;
947 struct lyd_node *node = NULL;
Radek Krejci084289f2019-07-09 17:35:30 +0200948 uint64_t pos = 1;
949
950 LY_CHECK_ARG_RET(NULL, path, trees, NULL);
951
952 LY_ARRAY_FOR(path, u) {
953 if (parent) {
954 start_search = lyd_node_children(parent);
955search_inner:
Michal Vaskoe444f752020-02-10 12:20:06 +0100956 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 +0200957 } else {
958 LY_ARRAY_FOR(trees, v) {
959 start_search = trees[v];
960search_toplevel:
961 /* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
Michal Vaskoe444f752020-02-10 12:20:06 +0100962 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 +0200963 if (node) {
964 break;
965 }
966 }
967 }
968 if (!node) {
969 return NULL;
970 }
971
972 /* check predicate if any */
973 LY_ARRAY_FOR(path[u].predicates, x) {
974 if (path[u].predicates[x].type == 0) {
975 /* position predicate */
976 if (pos != path[u].predicates[x].position) {
977 pos++;
978 goto search_repeat;
979 }
980 /* done, no more predicates are allowed here */
981 break;
982 } else if (path[u].predicates[x].type == 1) {
983 /* key-predicate */
984 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].predicates[x].key)->type;
Michal Vaskoe444f752020-02-10 12:20:06 +0100985 struct lyd_node *key;
986 lyd_find_sibling_next(lyd_node_children(node), path[u].predicates[x].key->module,
987 path[u].predicates[x].key->name, 0, NULL, 0, &key);
Radek Krejci084289f2019-07-09 17:35:30 +0200988 if (!key) {
989 /* probably error and we shouldn't be here due to previous checks when creating path */
990 goto search_repeat;
991 }
992 if (type->plugin->compare(&((struct lyd_node_term*)key)->value, path[u].predicates[x].value)) {
993 goto search_repeat;
994 }
995 } else if (path[u].predicates[x].type == 2) {
996 /* leaf-list-predicate */
997 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].node)->type;
998 if (type->plugin->compare(&((struct lyd_node_term*)node)->value, path[u].predicates[x].value)) {
999 goto search_repeat;
1000 }
1001 } else {
1002 LOGINT(NULL);
1003 }
1004 }
1005
1006 parent = node;
1007 }
1008
1009 return (const struct lyd_node_term*)node;
1010
1011search_repeat:
1012 start_search = node->next;
1013 if (parent) {
1014 goto search_inner;
1015 } else {
1016 goto search_toplevel;
1017 }
1018}
1019
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001020API LY_ERR
1021lyd_compare(const struct lyd_node *node1, const struct lyd_node *node2, int options)
1022{
1023 const struct lyd_node *iter1, *iter2;
1024 struct lyd_node_term *term1, *term2;
1025 struct lyd_node_any *any1, *any2;
1026 struct lysc_type *type;
1027 size_t len1, len2;
Radek Krejci084289f2019-07-09 17:35:30 +02001028
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001029 if (!node1 || !node2) {
1030 if (node1 == node2) {
1031 return LY_SUCCESS;
1032 } else {
1033 return LY_ENOT;
1034 }
1035 }
1036
Michal Vasko14654712020-02-06 08:35:21 +01001037 if (node1->schema->module->ctx != node2->schema->module->ctx || node1->schema != node2->schema) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001038 return LY_ENOT;
1039 }
1040
1041 if (node1->hash != node2->hash) {
1042 return LY_ENOT;
1043 }
1044
1045 /* equal hashes do not mean equal nodes, they can be just in collision so the nodes must be checked explicitly */
1046
1047 switch (node1->schema->nodetype) {
1048 case LYS_LEAF:
1049 case LYS_LEAFLIST:
1050 if (options & LYD_COMPARE_DEFAULTS) {
1051 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1052 return LY_ENOT;
1053 }
1054 }
1055
1056 term1 = (struct lyd_node_term*)node1;
1057 term2 = (struct lyd_node_term*)node2;
1058 type = ((struct lysc_node_leaf*)node1->schema)->type;
1059
1060 return type->plugin->compare(&term1->value, &term2->value);
1061 case LYS_CONTAINER:
1062 if (options & LYD_COMPARE_DEFAULTS) {
1063 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1064 return LY_ENOT;
1065 }
1066 }
1067 if (options & LYD_COMPARE_FULL_RECURSION) {
1068 iter1 = ((struct lyd_node_inner*)node1)->child;
1069 iter2 = ((struct lyd_node_inner*)node2)->child;
1070 goto all_children_compare;
1071 }
1072 return LY_SUCCESS;
1073 case LYS_ACTION:
1074 if (options & LYD_COMPARE_FULL_RECURSION) {
1075 /* TODO action/RPC
1076 goto all_children_compare;
1077 */
1078 }
1079 return LY_SUCCESS;
1080 case LYS_NOTIF:
1081 if (options & LYD_COMPARE_FULL_RECURSION) {
1082 /* TODO Notification
1083 goto all_children_compare;
1084 */
1085 }
1086 return LY_SUCCESS;
1087 case LYS_LIST:
1088 iter1 = ((struct lyd_node_inner*)node1)->child;
1089 iter2 = ((struct lyd_node_inner*)node2)->child;
1090
Radek Krejci0fe9b512019-07-26 17:51:05 +02001091 if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001092 /* lists with keys, their equivalence is based on their keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +02001093 for (struct lysc_node *key = ((struct lysc_node_list*)node1->schema)->child;
1094 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1095 key = key->next) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001096 if (lyd_compare(iter1, iter2, options)) {
1097 return LY_ENOT;
1098 }
1099 iter1 = iter1->next;
1100 iter2 = iter2->next;
1101 }
1102 } else {
1103 /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
1104
1105all_children_compare:
1106 if (!iter1 && !iter2) {
1107 /* no children, nothing to compare */
1108 return LY_SUCCESS;
1109 }
1110
1111 for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
1112 if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
1113 return LY_ENOT;
1114 }
1115 }
1116 if (iter1 || iter2) {
1117 return LY_ENOT;
1118 }
1119 }
1120 return LY_SUCCESS;
1121 case LYS_ANYXML:
1122 case LYS_ANYDATA:
1123 any1 = (struct lyd_node_any*)node1;
1124 any2 = (struct lyd_node_any*)node2;
1125
1126 if (any1->value_type != any2->value_type) {
1127 return LY_ENOT;
1128 }
1129 switch (any1->value_type) {
1130 case LYD_ANYDATA_DATATREE:
1131 iter1 = any1->value.tree;
1132 iter2 = any2->value.tree;
1133 goto all_children_compare;
1134 case LYD_ANYDATA_STRING:
1135 case LYD_ANYDATA_XML:
1136 case LYD_ANYDATA_JSON:
1137 len1 = strlen(any1->value.str);
1138 len2 = strlen(any2->value.str);
1139 if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
1140 return LY_ENOT;
1141 }
1142 return LY_SUCCESS;
1143#if 0 /* TODO LYB format */
1144 case LYD_ANYDATA_LYB:
1145 int len1 = lyd_lyb_data_length(any1->value.mem);
1146 int len2 = lyd_lyb_data_length(any2->value.mem);
1147 if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
1148 return LY_ENOT;
1149 }
1150 return LY_SUCCESS;
1151#endif
1152 }
1153 }
1154
1155 LOGINT(node1->schema->module->ctx);
1156 return LY_EINT;
1157}
Radek Krejci22ebdba2019-07-25 13:59:43 +02001158
1159/**
1160 * @brief Duplicates just a single node and interconnect it into a @p parent (if present) and after the @p prev
1161 * sibling (if present).
1162 *
1163 * Ignores LYD_DUP_WITH_PARENTS and LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
1164 */
1165static struct lyd_node *
1166lyd_dup_recursive(const struct lyd_node *node, struct lyd_node_inner *parent, struct lyd_node *prev, int options)
1167{
1168 struct ly_ctx *ctx;
1169 struct lyd_node *dup = NULL;
1170
1171 LY_CHECK_ARG_RET(NULL, node, NULL);
1172 ctx = node->schema->module->ctx;
1173
1174 switch (node->schema->nodetype) {
1175 case LYS_ACTION:
1176 case LYS_NOTIF:
1177 case LYS_CONTAINER:
1178 case LYS_LIST:
1179 dup = calloc(1, sizeof(struct lyd_node_inner));
1180 break;
1181 case LYS_LEAF:
1182 case LYS_LEAFLIST:
1183 dup = calloc(1, sizeof(struct lyd_node_term));
1184 break;
1185 case LYS_ANYDATA:
1186 case LYS_ANYXML:
1187 dup = calloc(1, sizeof(struct lyd_node_any));
1188 break;
1189 default:
1190 LOGINT(ctx);
1191 goto error;
1192 }
1193
1194 /* TODO implement LYD_DUP_WITH_WHEN */
1195 dup->flags = node->flags;
1196 dup->schema = node->schema;
1197
1198 /* interconnect the node at the end */
1199 dup->parent = parent;
1200 if (prev) {
1201 dup->prev = prev;
1202 prev->next = dup;
1203 } else {
1204 dup->prev = dup;
1205 if (parent) {
1206 parent->child = dup;
1207 }
1208 }
1209 if (parent) {
1210 parent->child->prev = dup;
1211 } else if (prev) {
1212 struct lyd_node *first;
1213 for (first = prev; first->prev != prev; first = first->prev);
1214 first->prev = dup;
1215 }
1216
1217 /* TODO duplicate attributes, implement LYD_DUP_NO_ATTR */
1218
1219 /* nodetype-specific work */
1220 if (dup->schema->nodetype & LYD_NODE_TERM) {
1221 struct lyd_node_term *term = (struct lyd_node_term*)dup;
1222 struct lyd_node_term *orig = (struct lyd_node_term*)node;
1223
1224 term->hash = orig->hash;
1225 term->value.realtype = orig->value.realtype;
1226 LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(ctx, &orig->value, &term->value),
1227 LOGERR(ctx, LY_EINT, "Value duplication failed."), error);
1228 } else if (dup->schema->nodetype & LYD_NODE_INNER) {
1229 struct lyd_node_inner *inner = (struct lyd_node_inner*)dup;
1230 struct lyd_node_inner *orig = (struct lyd_node_inner*)node;
1231 struct lyd_node *child, *last = NULL;
1232
1233 if (options & LYD_DUP_RECURSIVE) {
1234 /* duplicate all the children */
1235 LY_LIST_FOR(orig->child, child) {
1236 last = lyd_dup_recursive(child, inner, last, options);
1237 LY_CHECK_GOTO(!last, error);
1238 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02001239 } else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001240 /* always duplicate keys of a list */
Radek Krejci22ebdba2019-07-25 13:59:43 +02001241 child = orig->child;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001242 for (struct lysc_node *key = ((struct lysc_node_list*)dup->schema)->child;
1243 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1244 key = key->next) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001245 if (!child) {
1246 /* possibly not keys are present in filtered tree */
1247 break;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001248 } else if (child->schema != key) {
1249 /* possibly not all keys are present in filtered tree,
1250 * but there can be also some non-key nodes */
1251 continue;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001252 }
1253 last = lyd_dup_recursive(child, inner, last, options);
1254 child = child->next;
1255 }
1256 }
1257 lyd_hash(dup);
1258 } else if (dup->schema->nodetype & LYD_NODE_ANY) {
1259 struct lyd_node_any *any = (struct lyd_node_any*)dup;
1260 struct lyd_node_any *orig = (struct lyd_node_any*)node;
1261
1262 any->hash = orig->hash;
1263 any->value_type = orig->value_type;
1264 switch (any->value_type) {
1265 case LYD_ANYDATA_DATATREE:
1266 if (orig->value.tree) {
1267 any->value.tree = lyd_dup(orig->value.tree, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_SIBLINGS);
1268 LY_CHECK_GOTO(!any->value.tree, error);
1269 }
1270 break;
1271 case LYD_ANYDATA_STRING:
1272 case LYD_ANYDATA_XML:
1273 case LYD_ANYDATA_JSON:
1274 if (orig->value.str) {
1275 any->value.str = lydict_insert(ctx, orig->value.str, strlen(orig->value.str));
1276 }
1277 break;
1278 }
1279 }
1280
1281 lyd_insert_hash(dup);
1282 return dup;
1283
1284error:
1285 if (!parent && !prev) {
1286 lyd_free_tree(dup);
1287 }
1288 return NULL;
1289}
1290
1291API struct lyd_node *
1292lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
1293{
1294 struct ly_ctx *ctx;
1295 const struct lyd_node *orig; /* original node to be duplicated */
1296 struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
1297 struct lyd_node *last = NULL; /* the last sibling of the duplicated nodes */
1298 struct lyd_node *top = NULL; /* the most higher created node */
1299 struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
1300 int keyless_parent_list = 0;
1301
1302 LY_CHECK_ARG_RET(NULL, node, NULL);
1303 ctx = node->schema->module->ctx;
1304
1305 if (options & LYD_DUP_WITH_PARENTS) {
1306 struct lyd_node_inner *orig_parent, *iter;
1307 int repeat = 1;
1308 for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
1309 if (parent && parent->schema == orig_parent->schema) {
1310 /* stop creating parents, connect what we have into the provided parent */
1311 iter = parent;
1312 repeat = 0;
1313 /* get know if there is a keyless list which we will have to rehash */
1314 for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02001315 if (piter->schema->nodetype == LYS_LIST && (piter->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001316 keyless_parent_list = 1;
1317 break;
1318 }
1319 }
1320 } else {
1321 iter = (struct lyd_node_inner*)lyd_dup_recursive((struct lyd_node*)orig_parent, NULL, NULL, 0);
1322 LY_CHECK_GOTO(!iter, error);
1323 }
1324 if (!local_parent) {
1325 local_parent = iter;
1326 }
1327 if (iter->child) {
1328 /* 1) list - add after keys
1329 * 2) provided parent with some children */
1330 iter->child->prev->next = top;
1331 if (top) {
1332 top->prev = iter->child->prev;
1333 iter->child->prev = top;
1334 }
1335 } else {
1336 iter->child = top;
1337 if (iter->schema->nodetype == LYS_LIST) {
1338 /* keyless list - we will need to rehash it since we are going to add nodes into it */
1339 keyless_parent_list = 1;
1340 }
1341 }
1342 if (top) {
1343 top->parent = iter;
1344 }
1345 top = (struct lyd_node*)iter;
1346 }
1347 if (repeat && parent) {
1348 /* given parent and created parents chain actually do not interconnect */
1349 LOGERR(ctx, LY_EINVAL, "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
1350 goto error;
1351 }
1352 } else {
1353 local_parent = parent;
1354 }
1355
1356 if (local_parent && local_parent->child) {
1357 last = local_parent->child->prev;
1358 }
1359
1360 LY_LIST_FOR(node, orig) {
1361 last = lyd_dup_recursive(orig, local_parent, last, options);
1362 LY_CHECK_GOTO(!last, error);
1363 if (!first) {
1364 first = last;
1365 }
1366
1367 if (!(options & LYD_DUP_WITH_SIBLINGS)) {
1368 break;
1369 }
1370 }
1371 if (keyless_parent_list) {
1372 /* rehash */
1373 for (; local_parent; local_parent = local_parent->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02001374 if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001375 lyd_hash((struct lyd_node*)local_parent);
1376 }
1377 }
1378 }
1379 return first;
1380
1381error:
1382 if (top) {
1383 lyd_free_tree(top);
1384 } else {
1385 lyd_free_withsiblings(first);
1386 }
1387 return NULL;
1388}
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001389
1390static LY_ERR
1391lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
1392{
Michal Vasko14654712020-02-06 08:35:21 +01001393 /* ending \0 */
1394 ++reqlen;
1395
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001396 if (reqlen > *buflen) {
1397 if (is_static) {
1398 return LY_EINCOMPLETE;
1399 }
1400
1401 *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
1402 if (!*buffer) {
1403 return LY_EMEM;
1404 }
1405
1406 *buflen = reqlen;
1407 }
1408
1409 return LY_SUCCESS;
1410}
1411
1412/**
1413 * @brief Append all list key predicates to path.
1414 *
1415 * @param[in] node Node with keys to print.
1416 * @param[in,out] buffer Buffer to print to.
1417 * @param[in,out] buflen Current buffer length.
1418 * @param[in,out] bufused Current number of characters used in @p buffer.
1419 * @param[in] is_static Whether buffer is static or can be reallocated.
1420 * @return LY_ERR
1421 */
1422static LY_ERR
1423lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
1424{
1425 const struct lyd_node *key;
1426 int dynamic = 0;
1427 size_t len;
1428 const char *val;
1429 char quot;
1430 LY_ERR rc;
1431
Michal Vasko14654712020-02-06 08:35:21 +01001432 for (key = lyd_node_children(node); key && (key->schema->flags & LYS_KEY); key = key->next) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001433 val = lyd_value2str((struct lyd_node_term *)key, &dynamic);
1434 len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
1435 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1436 if (rc != LY_SUCCESS) {
1437 if (dynamic) {
1438 free((char *)val);
1439 }
1440 return rc;
1441 }
1442
1443 quot = '\'';
1444 if (strchr(val, '\'')) {
1445 quot = '"';
1446 }
1447 *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
1448
1449 if (dynamic) {
1450 free((char *)val);
1451 }
1452 }
1453
1454 return LY_SUCCESS;
1455}
1456
1457/**
1458 * @brief Append leaf-list value predicate to path.
1459 *
1460 * @param[in] node Node to print.
1461 * @param[in,out] buffer Buffer to print to.
1462 * @param[in,out] buflen Current buffer length.
1463 * @param[in,out] bufused Current number of characters used in @p buffer.
1464 * @param[in] is_static Whether buffer is static or can be reallocated.
1465 * @return LY_ERR
1466 */
1467static LY_ERR
1468lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
1469{
1470 int dynamic = 0;
1471 size_t len;
1472 const char *val;
1473 char quot;
1474 LY_ERR rc;
1475
1476 val = lyd_value2str((struct lyd_node_term *)node, &dynamic);
1477 len = 4 + strlen(val) + 2;
1478 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1479 if (rc != LY_SUCCESS) {
1480 goto cleanup;
1481 }
1482
1483 quot = '\'';
1484 if (strchr(val, '\'')) {
1485 quot = '"';
1486 }
1487 *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
1488
1489cleanup:
1490 if (dynamic) {
1491 free((char *)val);
1492 }
1493 return rc;
1494}
1495
1496/**
1497 * @brief Append node position (relative to its other instances) predicate to path.
1498 *
1499 * @param[in] node Node to print.
1500 * @param[in,out] buffer Buffer to print to.
1501 * @param[in,out] buflen Current buffer length.
1502 * @param[in,out] bufused Current number of characters used in @p buffer.
1503 * @param[in] is_static Whether buffer is static or can be reallocated.
1504 * @return LY_ERR
1505 */
1506static LY_ERR
1507lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
1508{
1509 const struct lyd_node *first, *iter;
1510 size_t len;
1511 int pos;
1512 char *val = NULL;
1513 LY_ERR rc;
1514
1515 if (node->parent) {
1516 first = node->parent->child;
1517 } else {
1518 for (first = node; node->prev->next; node = node->prev);
1519 }
1520 pos = 1;
1521 for (iter = first; iter != node; iter = iter->next) {
1522 if (iter->schema == node->schema) {
1523 ++pos;
1524 }
1525 }
1526 if (asprintf(&val, "%d", pos) == -1) {
1527 return LY_EMEM;
1528 }
1529
1530 len = 1 + strlen(val) + 1;
1531 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1532 if (rc != LY_SUCCESS) {
1533 goto cleanup;
1534 }
1535
1536 *bufused += sprintf(*buffer + *bufused, "[%s]", val);
1537
1538cleanup:
1539 free(val);
1540 return rc;
1541}
1542
1543API char *
1544lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
1545{
Michal Vasko14654712020-02-06 08:35:21 +01001546 int is_static = 0, i, depth;
1547 size_t bufused = 0, len;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001548 const struct lyd_node *iter;
1549 const struct lys_module *mod;
1550 LY_ERR rc;
1551
1552 LY_CHECK_ARG_RET(NULL, node, NULL);
1553 if (buffer) {
1554 LY_CHECK_ARG_RET(node->schema->module->ctx, buflen > 1, NULL);
1555 is_static = 1;
Michal Vasko14654712020-02-06 08:35:21 +01001556 } else {
1557 buflen = 0;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001558 }
1559
1560 switch (pathtype) {
Michal Vasko14654712020-02-06 08:35:21 +01001561 case LYD_PATH_LOG:
1562 depth = 1;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001563 for (iter = node; iter->parent; iter = (const struct lyd_node *)iter->parent) {
1564 ++depth;
1565 }
1566
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001567 goto iter_print;
Michal Vasko14654712020-02-06 08:35:21 +01001568 while (depth) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001569 /* find the right node */
Michal Vasko14654712020-02-06 08:35:21 +01001570 for (iter = node, i = 1; i < depth; iter = (const struct lyd_node *)iter->parent, ++i);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001571iter_print:
1572 /* print prefix and name */
1573 mod = NULL;
1574 if (!iter->parent || (iter->schema->module != iter->parent->schema->module)) {
1575 mod = iter->schema->module;
1576 }
1577
1578 /* realloc string */
1579 len = 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(iter->schema->name);
1580 rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
1581 if (rc != LY_SUCCESS) {
1582 break;
1583 }
1584
1585 /* print next node */
1586 bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", iter->schema->name);
1587
1588 switch (iter->schema->nodetype) {
1589 case LYS_LIST:
1590 if (iter->schema->flags & LYS_KEYLESS) {
1591 /* print its position */
1592 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
1593 } else {
1594 /* print all list keys in predicates */
1595 rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
1596 }
1597 break;
1598 case LYS_LEAFLIST:
1599 if (iter->schema->flags & LYS_CONFIG_W) {
1600 /* print leaf-list value */
1601 rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
1602 } else {
1603 /* print its position */
1604 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
1605 }
1606 break;
1607 default:
1608 /* nothing to print more */
1609 rc = LY_SUCCESS;
1610 break;
1611 }
1612 if (rc != LY_SUCCESS) {
1613 break;
1614 }
1615
Michal Vasko14654712020-02-06 08:35:21 +01001616 --depth;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001617 }
1618 break;
1619 }
1620
1621 return buffer;
1622}
Michal Vaskoe444f752020-02-10 12:20:06 +01001623
Michal Vasko9b368d32020-02-14 13:53:31 +01001624LY_ERR
1625lyd_find_sibling_next2(const struct lyd_node *first, const struct lysc_node *schema, const char *key_or_value,
1626 size_t val_len, struct lyd_node **match)
Michal Vaskoe444f752020-02-10 12:20:06 +01001627{
1628 LY_ERR rc;
1629 const struct lyd_node *node = NULL;
1630 struct lyd_node_term *term;
Michal Vaskoe444f752020-02-10 12:20:06 +01001631 struct ly_keys keys = {0};
Michal Vasko90932a92020-02-12 14:33:03 +01001632 struct lyd_value val = {0};
Michal Vaskoe444f752020-02-10 12:20:06 +01001633 size_t i;
Michal Vaskoe444f752020-02-10 12:20:06 +01001634
Michal Vasko9b368d32020-02-14 13:53:31 +01001635 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
Michal Vaskoe444f752020-02-10 12:20:06 +01001636
1637 if (!first) {
1638 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01001639 if (match) {
1640 *match = NULL;
1641 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001642 return LY_ENOTFOUND;
1643 }
1644
Michal Vaskoe444f752020-02-10 12:20:06 +01001645 if (key_or_value && !val_len) {
1646 val_len = strlen(key_or_value);
1647 }
1648
1649 if (key_or_value && (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko90932a92020-02-12 14:33:03 +01001650 /* store the value */
Michal Vasko9b368d32020-02-14 13:53:31 +01001651 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 +01001652 } else if (key_or_value && (schema->nodetype == LYS_LIST)) {
1653 /* parse keys into canonical values */
1654 LY_CHECK_GOTO(rc = ly_keys_parse(schema, key_or_value, val_len, 1, &keys), cleanup);
1655 }
1656
1657 /* find first matching value */
1658 LY_LIST_FOR(first, node) {
1659 if (node->schema != schema) {
1660 continue;
1661 }
1662
1663 if ((schema->nodetype == LYS_LIST) && keys.str) {
1664 /* compare all set keys */
1665 for (i = 0; i < keys.key_count; ++i) {
1666 /* find key */
1667 rc = lyd_find_sibling_val(lyd_node_children(node), (struct lysc_node *)keys.keys[i].schema, NULL, 0,
1668 (struct lyd_node **)&term);
1669 if (rc == LY_ENOTFOUND) {
1670 /* all keys must always exist */
Michal Vasko9b368d32020-02-14 13:53:31 +01001671 LOGINT_RET(schema->module->ctx);
Michal Vaskoe444f752020-02-10 12:20:06 +01001672 }
1673 LY_CHECK_GOTO(rc, cleanup);
1674
1675 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01001676 if (!term->value.realtype->plugin->compare(&term->value, &keys.keys[i].val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01001677 break;
1678 }
1679 }
1680
1681 if (i < keys.key_count) {
1682 /* not a match */
1683 continue;
1684 }
Michal Vasko90932a92020-02-12 14:33:03 +01001685 } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && val.realtype) {
Michal Vaskoe444f752020-02-10 12:20:06 +01001686 term = (struct lyd_node_term *)node;
1687
1688 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01001689 if (!term->value.realtype->plugin->compare(&term->value, &val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01001690 /* not a match */
1691 continue;
1692 }
1693 }
1694
1695 /* all criteria passed */
1696 break;
1697 }
1698
1699 if (!node) {
1700 rc = LY_ENOTFOUND;
Michal Vasko9b368d32020-02-14 13:53:31 +01001701 if (match) {
1702 *match = NULL;
1703 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001704 goto cleanup;
1705 }
1706
1707 /* success */
Michal Vasko9b368d32020-02-14 13:53:31 +01001708 if (match) {
1709 *match = (struct lyd_node *)node;
1710 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001711 rc = LY_SUCCESS;
1712
1713cleanup:
1714 ly_keys_clean(&keys);
Michal Vasko90932a92020-02-12 14:33:03 +01001715 if (val.realtype) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001716 val.realtype->plugin->free(schema->module->ctx, &val);
Michal Vasko90932a92020-02-12 14:33:03 +01001717 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001718 return rc;
1719}
1720
1721API LY_ERR
Michal Vasko9b368d32020-02-14 13:53:31 +01001722lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name, size_t name_len,
1723 const char *key_or_value, size_t val_len, struct lyd_node **match)
1724{
1725 const struct lysc_node *schema;
1726
1727 LY_CHECK_ARG_RET(NULL, module, name, match, LY_EINVAL);
1728
1729 if (!first) {
1730 /* no data */
1731 *match = NULL;
1732 return LY_ENOTFOUND;
1733 }
1734
1735 /* find schema */
1736 schema = lys_find_child(first->parent ? first->parent->schema : NULL, module, name, name_len, 0, 0);
1737 if (!schema) {
1738 LOGERR(module->ctx, LY_EINVAL, "Schema node not found.");
1739 return LY_EINVAL;
1740 }
1741
1742 return lyd_find_sibling_next2(first, schema, key_or_value, val_len, match);
1743}
1744
1745API LY_ERR
Michal Vaskoe444f752020-02-10 12:20:06 +01001746lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
1747{
1748 struct lyd_node **match_p;
1749 struct lyd_node_inner *parent;
1750
1751 LY_CHECK_ARG_RET(NULL, target, match, LY_EINVAL);
1752
1753 if (!siblings) {
1754 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01001755 if (match) {
1756 *match = NULL;
1757 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001758 return LY_ENOTFOUND;
1759 }
1760
1761 /* find first sibling */
1762 if (siblings->parent) {
1763 siblings = siblings->parent->child;
1764 } else {
1765 while (siblings->prev->next) {
1766 siblings = siblings->prev;
1767 }
1768 }
1769
1770 parent = (struct lyd_node_inner *)siblings->parent;
1771 if (parent && parent->children_ht) {
1772 assert(target->hash);
1773
1774 /* find by hash */
1775 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
1776 siblings = *match_p;
1777 } else {
1778 /* not found */
1779 siblings = NULL;
1780 }
1781 } else {
1782 /* no children hash table */
1783 for (; siblings; siblings = siblings->next) {
1784 if (!lyd_compare(siblings, target, 0)) {
1785 break;
1786 }
1787 }
1788 }
1789
1790 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001791 if (match) {
1792 *match = NULL;
1793 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001794 return LY_ENOTFOUND;
1795 }
1796
Michal Vasko9b368d32020-02-14 13:53:31 +01001797 if (match) {
1798 *match = (struct lyd_node *)siblings;
1799 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001800 return LY_SUCCESS;
1801}
1802
1803API LY_ERR
1804lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
1805{
1806 struct lyd_node_inner *parent;
1807 struct lyd_node *match;
1808 struct lyd_node **match_p;
1809 struct ly_set *ret;
1810
1811 LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
1812
1813 if (!siblings) {
1814 /* no data */
1815 return LY_ENOTFOUND;
1816 }
1817
1818 ret = ly_set_new();
1819 LY_CHECK_ERR_RET(!ret, LOGMEM(target->schema->module->ctx), LY_EMEM);
1820
1821 /* find first sibling */
1822 if (siblings->parent) {
1823 siblings = siblings->parent->child;
1824 } else {
1825 while (siblings->prev->next) {
1826 siblings = siblings->prev;
1827 }
1828 }
1829
1830 parent = (struct lyd_node_inner *)siblings->parent;
1831 if (parent && parent->children_ht) {
1832 assert(target->hash);
1833
1834 /* find by hash */
1835 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
1836 match = *match_p;
1837 } else {
1838 /* not found */
1839 match = NULL;
1840 }
1841 while (match) {
1842 /* add all found nodes into the return set */
1843 if (ly_set_add(ret, match, LY_SET_OPT_USEASLIST) == -1) {
1844 goto error;
1845 }
1846
1847 /* find next instance */
1848 if (lyht_find_next(parent->children_ht, &match, match->hash, (void **)&match_p)) {
1849 match = NULL;
1850 } else {
1851 match = *match_p;
1852 }
1853 }
1854 } else {
1855 /* no children hash table */
1856 for (; siblings; siblings = siblings->next) {
1857 if (!lyd_compare(siblings, target, 0)) {
1858 /* a match */
1859 if (ly_set_add(ret, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
1860 goto error;
1861 }
1862 }
1863 }
1864 }
1865
1866 if (!ret->count) {
1867 ly_set_free(ret, NULL);
1868 return LY_ENOTFOUND;
1869 }
1870
1871 *set = ret;
1872 return LY_SUCCESS;
1873
1874error:
1875 ly_set_free(ret, NULL);
1876 return LY_EMEM;
1877}
1878
Michal Vasko90932a92020-02-12 14:33:03 +01001879static int
1880lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
1881{
1882 struct lysc_node *val1;
1883 struct lyd_node *val2;
1884
1885 val1 = *((struct lysc_node **)val1_p);
1886 val2 = *((struct lyd_node **)val2_p);
1887
1888 assert(val1->nodetype & (LYD_NODE_INNER | LYS_LEAF));
1889
1890 if (val1 == val2->schema) {
1891 /* schema match is enough */
1892 return 1;
1893 } else {
1894 return 0;
1895 }
1896}
1897
1898static LY_ERR
1899lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
1900{
1901 struct lyd_node **match_p;
1902 struct lyd_node_inner *parent;
1903 uint32_t hash;
1904 values_equal_cb ht_cb;
1905
1906 assert(siblings && schema && (schema->nodetype & (LYD_NODE_INNER | LYS_LEAF)));
1907
1908 /* find first sibling */
1909 if (siblings->parent) {
1910 siblings = siblings->parent->child;
1911 } else {
1912 while (siblings->prev->next) {
1913 siblings = siblings->prev;
1914 }
1915 }
1916
1917 parent = (struct lyd_node_inner *)siblings->parent;
1918 if (parent && parent->children_ht) {
1919 /* calculate our hash */
1920 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
1921 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
1922 hash = dict_hash_multi(hash, NULL, 0);
1923
1924 /* use special hash table function */
1925 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
1926
1927 /* find by hash */
1928 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
1929 siblings = *match_p;
1930 } else {
1931 /* not found */
1932 siblings = NULL;
1933 }
1934
1935 /* set the original hash table compare function back */
1936 lyht_set_cb(parent->children_ht, ht_cb);
1937 } else {
1938 /* no children hash table */
1939 for (; siblings; siblings = siblings->next) {
1940 if (siblings->schema == schema) {
1941 /* schema match is enough */
1942 break;
1943 }
1944 }
1945 }
1946
1947 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001948 if (match) {
1949 *match = NULL;
1950 }
Michal Vasko90932a92020-02-12 14:33:03 +01001951 return LY_ENOTFOUND;
1952 }
1953
Michal Vasko9b368d32020-02-14 13:53:31 +01001954 if (match) {
1955 *match = (struct lyd_node *)siblings;
1956 }
Michal Vasko90932a92020-02-12 14:33:03 +01001957 return LY_SUCCESS;
1958}
1959
Michal Vaskoe444f752020-02-10 12:20:06 +01001960API LY_ERR
1961lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
1962 size_t val_len, struct lyd_node **match)
1963{
1964 LY_ERR rc;
1965 struct lyd_node *target = NULL;
1966
1967 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
1968 if ((schema->nodetype == LYS_LIST) && schema->flags & LYS_KEYLESS) {
1969 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
1970 return LY_EINVAL;
1971 } else if ((schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && !key_or_value) {
1972 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - no value/keys for a (leaf-)list (%s()).", __func__);
1973 return LY_EINVAL;
1974 } else if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1975 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
1976 lys_nodetype2str(schema->nodetype), __func__);
1977 return LY_EINVAL;
1978 }
1979
1980 if (!siblings) {
1981 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01001982 if (match) {
1983 *match = NULL;
1984 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001985 return LY_ENOTFOUND;
1986 }
1987
Michal Vasko90932a92020-02-12 14:33:03 +01001988 /* create data node if needed and find it */
Michal Vaskoe444f752020-02-10 12:20:06 +01001989 switch (schema->nodetype) {
1990 case LYS_CONTAINER:
1991 case LYS_ANYXML:
1992 case LYS_ANYDATA:
1993 case LYS_NOTIF:
Michal Vasko9b368d32020-02-14 13:53:31 +01001994 case LYS_ACTION:
Michal Vaskoe444f752020-02-10 12:20:06 +01001995 case LYS_LEAF:
Michal Vasko90932a92020-02-12 14:33:03 +01001996 /* find it based on schema only */
1997 rc = lyd_find_sibling_schema(siblings, schema, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01001998 break;
1999 case LYS_LEAFLIST:
2000 /* target used attributes: schema, hash, value */
Michal Vasko90932a92020-02-12 14:33:03 +01002001 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 +01002002 /* fallthrough */
Michal Vaskoe444f752020-02-10 12:20:06 +01002003 case LYS_LIST:
Michal Vasko90932a92020-02-12 14:33:03 +01002004 if (schema->nodetype == LYS_LIST) {
2005 /* target used attributes: schema, hash, child (all keys) */
2006 LY_CHECK_RET(lyd_create_list(schema, key_or_value, val_len, &target));
Michal Vasko90932a92020-02-12 14:33:03 +01002007 }
2008
2009 /* find it */
2010 rc = lyd_find_sibling_first(siblings, target, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01002011 break;
2012 default:
2013 /* unreachable */
2014 LOGINT(schema->module->ctx);
2015 return LY_EINT;
2016 }
2017
Michal Vaskoe444f752020-02-10 12:20:06 +01002018 lyd_free_tree(target);
2019 return rc;
2020}