blob: f6cd61f7be4b0b1483c8763e1fc84453c88aae6d [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 Vasko8d544252020-03-02 10:19:52 +0100188lyd_value_parse_attr(struct ly_ctx *ctx, struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic,
189 int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
190 const struct lysc_node *ctx_snode, const struct lyd_node **trees)
Radek Krejci38d85362019-09-05 16:26:38 +0200191{
Michal Vasko90932a92020-02-12 14:33:03 +0100192 LY_ERR ret = LY_SUCCESS;
Radek Krejci38d85362019-09-05 16:26:38 +0200193 struct ly_err_item *err = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200194 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
Michal Vasko8d544252020-03-02 10:19:52 +0100198 assert(ctx && attr && ((trees && attr->parent) || ctx_snode));
199
Radek Krejci38d85362019-09-05 16:26:38 +0200200 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,
Michal Vasko8d544252020-03-02 10:19:52 +0100206 trees ? (void *)attr->parent : (void *)ctx_snode, trees, &attr->value, NULL, &err);
Michal Vasko90932a92020-02-12 14:33:03 +0100207 if (ret && (ret != LY_EINCOMPLETE)) {
Radek Krejci38d85362019-09-05 16:26:38 +0200208 if (err) {
209 ly_err_print(err);
210 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
211 ly_err_free(err);
212 }
213 goto error;
Michal Vasko90932a92020-02-12 14:33:03 +0100214 } else if (dynamic) {
215 *dynamic = 0;
Radek Krejci38d85362019-09-05 16:26:38 +0200216 }
217
218error:
219 return ret;
220}
221
Radek Krejci084289f2019-07-09 17:35:30 +0200222API LY_ERR
223lys_value_validate(struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
224 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format)
225{
226 LY_ERR rc = LY_SUCCESS;
227 struct ly_err_item *err = NULL;
228 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200229
230 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
231
232 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
233 LOGARG(ctx, node);
234 return LY_EINVAL;
235 }
236
237 type = ((struct lysc_node_leaf*)node)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200238 /* just validate, no storing of enything */
239 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, LY_TYPE_OPTS_INCOMPLETE_DATA,
240 get_prefix, get_prefix_data, format, node, NULL, NULL, NULL, &err);
241 if (rc == LY_EINCOMPLETE) {
242 /* actually success since we do not provide the context tree and call validation with
243 * LY_TYPE_OPTS_INCOMPLETE_DATA */
244 rc = LY_SUCCESS;
245 } else if (rc && err) {
246 if (ctx) {
247 /* log only in case the ctx was provided as input parameter */
248 ly_err_print(err);
249 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200250 }
Radek Krejci73dead22019-07-11 16:46:16 +0200251 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200252 }
253
254 return rc;
255}
256
257API LY_ERR
258lyd_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 +0200259 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 +0200260{
261 LY_ERR rc;
262 struct ly_err_item *err = NULL;
263 struct lysc_type *type;
Radek Krejci73dead22019-07-11 16:46:16 +0200264 int options = (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200265
266 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
267
268 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200269 rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
270 get_prefix, get_prefix_data, format, trees ? (void*)node : (void*)node->schema, trees,
271 NULL, NULL, &err);
272 if (rc == LY_EINCOMPLETE) {
273 return rc;
274 } else if (rc) {
275 if (err) {
276 if (ctx) {
277 ly_err_print(err);
278 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200279 }
Radek Krejci73dead22019-07-11 16:46:16 +0200280 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200281 }
Radek Krejci73dead22019-07-11 16:46:16 +0200282 return rc;
Radek Krejci084289f2019-07-09 17:35:30 +0200283 }
284
285 return LY_SUCCESS;
286}
287
288API LY_ERR
289lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
Michal Vasko14654712020-02-06 08:35:21 +0100290 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 +0200291{
292 LY_ERR ret = LY_SUCCESS, rc;
293 struct ly_err_item *err = NULL;
294 struct ly_ctx *ctx;
295 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200296 struct lyd_value data = {0};
Radek Krejci73dead22019-07-11 16:46:16 +0200297 int options = LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200298
299 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
300
301 ctx = node->schema->module->ctx;
302 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200303 rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, get_prefix_data, format, (struct lyd_node*)node,
304 trees, &data, NULL, &err);
305 if (rc == LY_EINCOMPLETE) {
306 ret = rc;
307 /* continue with comparing, just remember what to return if storing is ok */
308 } else if (rc) {
309 /* value to compare is invalid */
310 ret = LY_EINVAL;
311 if (err) {
312 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200313 }
Radek Krejci73dead22019-07-11 16:46:16 +0200314 goto cleanup;
Radek Krejci084289f2019-07-09 17:35:30 +0200315 }
316
317 /* compare data */
Radek Krejci5af04842019-07-12 11:32:07 +0200318 if (type->plugin->compare(&node->value, &data)) {
319 /* do not assign it directly from the compare callback to keep possible LY_EINCOMPLETE from validation */
320 ret = LY_EVALID;
321 }
Radek Krejci084289f2019-07-09 17:35:30 +0200322
323cleanup:
Radek Krejci62903c32019-07-15 14:42:05 +0200324 type->plugin->free(ctx, &data);
Radek Krejci084289f2019-07-09 17:35:30 +0200325
326 return ret;
327}
328
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200329API const char *
330lyd_value2str(const struct lyd_node_term *node, int *dynamic)
331{
332 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, dynamic, NULL);
333
334 return node->value.realtype->plugin->print(&node->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
335}
336
337API const char *
338lyd_attr2str(const struct lyd_attr *attr, int *dynamic)
339{
340 LY_CHECK_ARG_RET(attr ? attr->parent->schema->module->ctx : NULL, attr, dynamic, NULL);
341
342 return attr->value.realtype->plugin->print(&attr->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
343}
344
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200345API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100346lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200347{
Radek Krejcie7b95092019-05-15 11:03:07 +0200348 struct lyd_node *result = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200349#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200350 const char *yang_data_name = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200351#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200352
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200353 LY_CHECK_ARG_RET(ctx, ctx, NULL);
354
Michal Vaskoa3881362020-01-21 15:57:35 +0100355#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200356 if (options & LYD_OPT_RPCREPLY) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200357 /* first item in trees is mandatory - the RPC/action request */
358 LY_CHECK_ARG_RET(ctx, trees, LY_ARRAY_SIZE(trees) >= 1, NULL);
359 if (!trees[0] || trees[0]->parent || !(trees[0]->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
360 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
361 lyd_parse_options_type2str(options));
Radek Krejcie7b95092019-05-15 11:03:07 +0200362 return NULL;
363 }
364 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200365
Radek Krejcie7b95092019-05-15 11:03:07 +0200366 if (options & LYD_OPT_DATA_TEMPLATE) {
367 yang_data_name = va_arg(ap, const char *);
368 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200369#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200370
371 if (!format) {
372 /* TODO try to detect format from the content */
373 }
374
375 switch (format) {
376 case LYD_XML:
Michal Vaskoa3881362020-01-21 15:57:35 +0100377 lyd_parse_xml(ctx, data, options, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200378 break;
379#if 0
380 case LYD_JSON:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200381 lyd_parse_json(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200382 break;
383 case LYD_LYB:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200384 lyd_parse_lyb(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200385 break;
386#endif
387 case LYD_UNKNOWN:
388 LOGINT(ctx);
389 break;
390 }
391
Radek Krejcie7b95092019-05-15 11:03:07 +0200392 return result;
393}
394
395API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100396lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200397{
398 struct lyd_node *result;
399 size_t length;
400 char *addr;
401
402 LY_CHECK_ARG_RET(ctx, ctx, NULL);
403 if (fd < 0) {
404 LOGARG(ctx, fd);
405 return NULL;
406 }
407
408 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
Michal Vaskoa3881362020-01-21 15:57:35 +0100409 result = lyd_parse_mem(ctx, addr ? addr : "", format, options);
Radek Krejcidf3da792019-05-17 10:32:24 +0200410 if (addr) {
411 ly_munmap(addr, length);
412 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200413
414 return result;
415}
416
417API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100418lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200419{
420 int fd;
421 struct lyd_node *result;
422 size_t len;
Radek Krejcie7b95092019-05-15 11:03:07 +0200423
424 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
425
426 fd = open(path, O_RDONLY);
427 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
428
429 if (!format) {
430 /* unknown format - try to detect it from filename's suffix */
431 len = strlen(path);
432
433 /* ignore trailing whitespaces */
434 for (; len > 0 && isspace(path[len - 1]); len--);
435
436 if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
437 format = LYD_XML;
438#if 0
439 } else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
440 format = LYD_JSON;
441 } else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
442 format = LYD_LYB;
443#endif
444 } /* else still unknown, try later to detect it from the content */
445 }
446
Michal Vaskoa3881362020-01-21 15:57:35 +0100447 result = lyd_parse_fd(ctx, fd, format, options);
Radek Krejcie7b95092019-05-15 11:03:07 +0200448 close(fd);
449
450 return result;
451}
Radek Krejci084289f2019-07-09 17:35:30 +0200452
Michal Vasko90932a92020-02-12 14:33:03 +0100453LY_ERR
454lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
455 ly_clb_resolve_prefix get_prefix, void *prefix_data, LYD_FORMAT format, struct lyd_node **node)
456{
457 LY_ERR ret;
458 struct lyd_node_term *term;
459
Michal Vasko9b368d32020-02-14 13:53:31 +0100460 assert(schema->nodetype & LYD_NODE_TERM);
461
Michal Vasko90932a92020-02-12 14:33:03 +0100462 term = calloc(1, sizeof *term);
463 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
464
465 term->schema = schema;
466 term->prev = (struct lyd_node *)term;
Michal Vasko9b368d32020-02-14 13:53:31 +0100467 term->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100468
469 ret = lyd_value_parse(term, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
470 if (ret && (ret != LY_EINCOMPLETE)) {
471 free(term);
472 return ret;
473 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100474 lyd_hash((struct lyd_node *)term);
475
476 *node = (struct lyd_node *)term;
477 return ret;
478}
479
480LY_ERR
481lyd_create_term2(const struct lysc_node *schema, const struct lyd_value *val, struct lyd_node **node)
482{
483 LY_ERR ret;
484 struct lyd_node_term *term;
485 struct lysc_type *type;
486
487 assert(schema->nodetype & LYD_NODE_TERM);
488
489 term = calloc(1, sizeof *term);
490 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
491
492 term->schema = schema;
493 term->prev = (struct lyd_node *)term;
494 term->flags = LYD_NEW;
495
496 type = ((struct lysc_node_leaf *)schema)->type;
497 ret = type->plugin->duplicate(schema->module->ctx, val, &term->value);
498 if (ret) {
499 LOGERR(schema->module->ctx, ret, "Value duplication failed.");
500 free(term);
501 return ret;
502 }
503 lyd_hash((struct lyd_node *)term);
Michal Vasko90932a92020-02-12 14:33:03 +0100504
505 *node = (struct lyd_node *)term;
506 return ret;
507}
508
509LY_ERR
510lyd_create_inner(const struct lysc_node *schema, struct lyd_node **node)
511{
512 struct lyd_node_inner *in;
513
Michal Vasko9b368d32020-02-14 13:53:31 +0100514 assert(schema->nodetype & LYD_NODE_INNER);
515
Michal Vasko90932a92020-02-12 14:33:03 +0100516 in = calloc(1, sizeof *in);
517 LY_CHECK_ERR_RET(!in, LOGMEM(schema->module->ctx), LY_EMEM);
518
519 in->schema = schema;
520 in->prev = (struct lyd_node *)in;
Michal Vasko9b368d32020-02-14 13:53:31 +0100521 in->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100522
Michal Vasko9b368d32020-02-14 13:53:31 +0100523 /* do not hash list with keys, we need them for the hash */
524 if ((schema->nodetype != LYS_LIST) || (schema->flags & LYS_KEYLESS)) {
525 lyd_hash((struct lyd_node *)in);
526 }
527 if ((schema->nodetype == LYS_CONTAINER) && !(schema->flags & LYS_PRESENCE)) {
528 /* NP cotnainer always a default */
529 in->flags |= LYD_DEFAULT;
Michal Vasko90932a92020-02-12 14:33:03 +0100530 }
531
532 *node = (struct lyd_node *)in;
533 return LY_SUCCESS;
534}
535
536static void
537ly_keys_clean(struct ly_keys *keys)
538{
539 size_t i;
540
541 for (i = 0; i < keys->key_count; ++i) {
542 keys->keys[i].schema->type->plugin->free(keys->keys[i].schema->module->ctx, &keys->keys[i].val);
543 }
544 free(keys->str);
545 free(keys->keys);
546}
547
548static char *
549ly_keys_parse_next(char **next_key, char **key_name)
550{
551 char *ptr, *ptr2, *val, quot;
552
553 ptr = *next_key;
554
555 /* "[" */
556 LY_CHECK_GOTO(ptr[0] != '[', error);
557 ++ptr;
558
559 /* key name */
560 ptr2 = strchr(ptr, '=');
561 LY_CHECK_GOTO(!ptr2, error);
562
563 *key_name = ptr;
564 ptr2[0] = '\0';
565
566 /* \0, was '=' */
567 ptr = ptr2 + 1;
568
569 /* quote */
570 LY_CHECK_GOTO((ptr[0] != '\'') && (ptr[0] != '\"'), error);
571 quot = ptr[0];
572 ++ptr;
573
574 /* value, terminate it */
575 val = ptr;
576 ptr2 = strchr(ptr, quot);
577 LY_CHECK_GOTO(!ptr2, error);
578 ptr2[0] = '\0';
579
580 /* \0, was quote */
581 ptr = ptr2 + 1;
582
583 /* "]" */
584 LY_CHECK_GOTO(ptr[0] != ']', error);
585 ++ptr;
586
587 *next_key = ptr;
588 return val;
589
590error:
591 *next_key = ptr;
592 return NULL;
593}
594
595/* fill keys structure; if store is set, fill also each val */
596static LY_ERR
597ly_keys_parse(const struct lysc_node *list, const char *keys_str, size_t keys_len, int store, struct ly_keys *keys)
598{
599 LY_ERR ret = LY_SUCCESS;
600 char *next_key, *name;
601 const struct lysc_node *key;
602 size_t i;
603
604 assert(list->nodetype == LYS_LIST);
605
606 memset(keys, 0, sizeof *keys);
607
608 keys->str = strndup(keys_str, keys_len ? keys_len : strlen(keys_str));
609 LY_CHECK_ERR_GOTO(!keys->str, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
610
611 next_key = keys->str;
612 while (next_key[0]) {
613 /* new key */
614 keys->keys = ly_realloc(keys->keys, (keys->key_count + 1) * sizeof *keys->keys);
615 LY_CHECK_ERR_GOTO(!keys->keys, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
616
617 /* fill */
618 keys->keys[keys->key_count].value = ly_keys_parse_next(&next_key, &name);
619 if (!keys->keys[keys->key_count].value) {
620 LOGERR(list->module->ctx, LY_EINVAL, "Invalid keys string (at \"%s\").", next_key);
621 ret = LY_EINVAL;
622 goto cleanup;
623 }
624
625 /* find schema node */
626 key = lys_find_child(list, list->module, name, 0, LYS_LEAF, 0);
627 if (!key) {
628 LOGERR(list->module->ctx, LY_EINVAL, "List \"%s\" has no key \"%s\".", list->name, name);
629 ret = LY_EINVAL;
630 goto cleanup;
631 }
632 keys->keys[keys->key_count].schema = (const struct lysc_node_leaf *)key;
633
634 /* check that we do not have it already */
635 for (i = 0; i < keys->key_count; ++i) {
636 if (keys->keys[i].schema == keys->keys[keys->key_count].schema) {
637 LOGERR(list->module->ctx, LY_EINVAL, "Duplicit key \"%s\" value.", name);
638 ret = LY_EINVAL;
639 goto cleanup;
640 }
641 }
642
643 if (store) {
644 /* store the value */
645 ret = lyd_value_store(&keys->keys[keys->key_count].val, key, keys->keys[keys->key_count].value, 0, 0,
646 lydjson_resolve_prefix, NULL, LYD_JSON);
647 LY_CHECK_GOTO(ret, cleanup);
648 }
649
650 /* another valid key */
651 ++keys->key_count;
652 }
653
654cleanup:
655 ly_keys_clean(keys);
656 return ret;
657}
658
659LY_ERR
660lyd_create_list(const struct lysc_node *schema, const char *keys_str, size_t keys_len, struct lyd_node **node)
661{
662 LY_ERR ret = LY_SUCCESS;
663 const struct lysc_node *key_s;
664 struct lyd_node *list = NULL, *key;
665 struct ly_keys keys = {0};
666 size_t i;
667
668 assert((schema->nodetype == LYS_LIST) && !(schema->flags & LYS_KEYLESS));
669
670 /* parse keys */
671 LY_CHECK_GOTO(ret = ly_keys_parse(schema, keys_str, keys_len, 0, &keys), cleanup);
672
673 /* create list */
674 LY_CHECK_GOTO(ret = lyd_create_inner(schema, &list), cleanup);
675
676 /* everything was checked except that all keys are set */
677 i = 0;
678 for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
679 ++i;
680 }
681 if (i != keys.key_count) {
682 LOGERR(schema->module->ctx, LY_EINVAL, "List \"%s\" is missing some keys.", schema->name);
683 ret = LY_EINVAL;
684 goto cleanup;
685 }
686
687 /* create and insert all the keys */
688 for (i = 0; i < keys.key_count; ++i) {
689 LY_CHECK_GOTO(ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value, 0, 0,
690 lydjson_resolve_prefix, NULL, LYD_JSON, &key), cleanup);
691 lyd_insert_node(list, NULL, key);
692 }
693
Michal Vasko9b368d32020-02-14 13:53:31 +0100694 /* hash having all the keys */
695 lyd_hash(list);
696
Michal Vasko90932a92020-02-12 14:33:03 +0100697 /* success */
698 *node = list;
699 list = NULL;
700
701cleanup:
702 lyd_free_tree(list);
703 ly_keys_clean(&keys);
704 return ret;
705}
706
707LY_ERR
708lyd_create_any(const struct lysc_node *schema, const void *value, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
709{
710 struct lyd_node_any *any;
711
Michal Vasko9b368d32020-02-14 13:53:31 +0100712 assert(schema->nodetype & LYD_NODE_ANY);
713
Michal Vasko90932a92020-02-12 14:33:03 +0100714 any = calloc(1, sizeof *any);
715 LY_CHECK_ERR_RET(!any, LOGMEM(schema->module->ctx), LY_EMEM);
716
717 any->schema = schema;
718 any->prev = (struct lyd_node *)any;
Michal Vasko9b368d32020-02-14 13:53:31 +0100719 any->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100720
721 any->value.xml = value;
722 any->value_type = value_type;
Michal Vasko9b368d32020-02-14 13:53:31 +0100723 lyd_hash((struct lyd_node *)any);
Michal Vasko90932a92020-02-12 14:33:03 +0100724
725 *node = (struct lyd_node *)any;
726 return LY_SUCCESS;
727}
728
729struct lyd_node *
730lyd_get_prev_key_anchor(const struct lyd_node *first_sibling, const struct lysc_node *new_key)
731{
732 const struct lysc_node *prev_key;
733 struct lyd_node *match = NULL;
734
735 if (!first_sibling) {
736 return NULL;
737 }
738
739 for (prev_key = new_key->prev; !match && prev_key->next; prev_key = prev_key->prev) {
740 lyd_find_sibling_val(first_sibling, prev_key, NULL, 0, &match);
741 }
742
743 return match;
744}
745
746/**
747 * @brief Insert node after a sibling.
748 *
749 * @param[in] sibling Sibling to insert after.
750 * @param[in] node Node to insert.
751 */
752static void
753lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
754{
755 assert(!node->next && (node->prev == node));
756
757 node->next = sibling->next;
758 node->prev = sibling;
759 sibling->next = node;
760 if (node->next) {
761 /* sibling had a succeeding node */
762 node->next->prev = node;
763 } else {
764 /* sibling was last, find first sibling and change its prev */
765 if (sibling->parent) {
766 sibling = sibling->parent->child;
767 } else {
768 for (; sibling->prev->next != node; sibling = sibling->prev);
769 }
770 sibling->prev = node;
771 }
772 node->parent = sibling->parent;
773}
774
775/**
776 * @brief Insert node before a sibling.
777 *
778 * @param[in] sibling Sibling to insert before.
779 * @param[in] node Node to insert.
780 */
781static void
782lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
783{
784 assert(!node->next && (node->prev == node));
785
786 node->next = sibling;
787 /* covers situation of sibling being first */
788 node->prev = sibling->prev;
789 sibling->prev = node;
790 if (node->prev->next) {
791 /* sibling had a preceding node */
792 node->prev->next = node;
793 } else if (sibling->parent) {
794 /* sibling was first and we must also change parent child pointer */
795 sibling->parent->child = node;
796 }
797 node->parent = sibling->parent;
798}
799
800/**
801 * @brief Insert node as the last child of a parent.
802 *
803 * @param[in] parent Parent to insert into.
804 * @param[in] node Node to insert.
805 */
806static void
807lyd_insert_last(struct lyd_node *parent, struct lyd_node *node)
808{
809 struct lyd_node_inner *par;
810
811 assert(!node->next && (node->prev == node));
812 assert(parent->schema->nodetype & LYD_NODE_INNER);
813
814 par = (struct lyd_node_inner *)parent;
815
816 if (!par->child) {
817 par->child = node;
818 } else {
819 node->prev = par->child->prev;
820 par->child->prev->next = node;
821 par->child->prev = node;
822 }
823 node->parent = par;
824}
825
826void
Michal Vasko9b368d32020-02-14 13:53:31 +0100827lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100828{
Michal Vasko9b368d32020-02-14 13:53:31 +0100829 struct lyd_node *anchor;
Michal Vasko90932a92020-02-12 14:33:03 +0100830
Michal Vasko9b368d32020-02-14 13:53:31 +0100831 assert((parent || first_sibling) && node && node->hash);
832
833 if (!parent && first_sibling && (*first_sibling) && (*first_sibling)->parent) {
834 parent = (struct lyd_node *)(*first_sibling)->parent;
835 }
Michal Vasko90932a92020-02-12 14:33:03 +0100836
837 if (parent) {
838 if (node->schema->flags & LYS_KEY) {
839 /* it is key and we need to insert it at the correct place */
Michal Vasko9b368d32020-02-14 13:53:31 +0100840 anchor = lyd_get_prev_key_anchor(lyd_node_children(parent), node->schema);
841 if (anchor) {
842 lyd_insert_after(anchor, node);
Michal Vasko90932a92020-02-12 14:33:03 +0100843 } else if (lyd_node_children(parent)) {
844 lyd_insert_before((struct lyd_node *)lyd_node_children(parent), node);
845 } else {
846 lyd_insert_last(parent, node);
847 }
848 } else {
849 /* last child */
850 lyd_insert_last(parent, node);
851 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100852 } else if (*first_sibling) {
853 /* top-level siblings, find the last one from this module, or simply the last */
854 anchor = (*first_sibling)->prev;
855 while (anchor->prev->next && (lyd_top_node_module(anchor) != lyd_top_node_module(node))) {
856 anchor = anchor->prev;
857 }
858
859 /* insert */
860 lyd_insert_after(anchor, node);
Michal Vasko90932a92020-02-12 14:33:03 +0100861 } else {
Michal Vasko9b368d32020-02-14 13:53:31 +0100862 /* the only sibling */
863 *first_sibling = node;
Michal Vasko90932a92020-02-12 14:33:03 +0100864 }
865
Michal Vasko9b368d32020-02-14 13:53:31 +0100866 if (!(node->flags & LYD_DEFAULT)) {
867 /* remove default flags from NP containers */
868 while (parent && (parent->flags & LYD_DEFAULT)) {
869 parent->flags &= ~LYD_DEFAULT;
870 parent = (struct lyd_node *)parent->parent;
871 }
Michal Vasko90932a92020-02-12 14:33:03 +0100872 }
873
874 /* insert into hash table */
875 lyd_insert_hash(node);
876}
877
878LY_ERR
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100879lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct lys_module *mod, const char *name,
880 size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix get_prefix,
Michal Vasko8d544252020-03-02 10:19:52 +0100881 void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode)
Michal Vasko90932a92020-02-12 14:33:03 +0100882{
883 LY_ERR ret;
884 struct lysc_ext_instance *ant = NULL;
885 struct lyd_attr *at, *last;
886 uint32_t v;
887
Michal Vasko8d544252020-03-02 10:19:52 +0100888 assert((parent || attr) && mod);
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100889
Michal Vasko90932a92020-02-12 14:33:03 +0100890 LY_ARRAY_FOR(mod->compiled->exts, v) {
891 if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
892 !ly_strncmp(mod->compiled->exts[v].argument, name, name_len)) {
893 /* we have the annotation definition */
894 ant = &mod->compiled->exts[v];
895 break;
896 }
897 }
898 if (!ant) {
899 /* attribute is not defined as a metadata annotation (RFC 7952) */
900 LOGERR(mod->ctx, LY_EINVAL, "Annotation definition for attribute \"%s:%.*s\" not found.",
901 mod->name, name_len, name);
902 return LY_EINVAL;
903 }
904
905 at = calloc(1, sizeof *at);
906 LY_CHECK_ERR_RET(!at, LOGMEM(mod->ctx), LY_EMEM);
907 at->parent = parent;
908 at->annotation = ant;
Michal Vasko8d544252020-03-02 10:19:52 +0100909 ret = lyd_value_parse_attr(mod->ctx, at, value, value_len, dynamic, 0, get_prefix, prefix_data, format, ctx_snode, NULL);
Michal Vasko90932a92020-02-12 14:33:03 +0100910 if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
911 free(at);
912 return ret;
913 }
914 at->name = lydict_insert(mod->ctx, name, name_len);
915
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100916 /* insert as the last attribute */
917 if (parent) {
918 if (parent->attr) {
919 for (last = parent->attr; last->next; last = last->next);
920 last->next = at;
921 } else {
922 parent->attr = at;
923 }
924 } else if (*attr) {
925 for (last = *attr; last->next; last = last->next);
Michal Vasko90932a92020-02-12 14:33:03 +0100926 last->next = at;
Michal Vasko90932a92020-02-12 14:33:03 +0100927 }
928
929 /* remove default flags from NP containers */
930 while (parent && (parent->flags & LYD_DEFAULT)) {
931 parent->flags &= ~LYD_DEFAULT;
932 parent = (struct lyd_node *)parent->parent;
933 }
934
935 if (attr) {
936 *attr = at;
937 }
938 return ret;
939}
940
Radek Krejci084289f2019-07-09 17:35:30 +0200941API const struct lyd_node_term *
Radek Krejci576b23f2019-07-12 14:06:32 +0200942lyd_target(struct lyd_value_path *path, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200943{
944 unsigned int u, v, x;
Michal Vaskoe444f752020-02-10 12:20:06 +0100945 const struct lyd_node *parent = NULL, *start_search;
946 struct lyd_node *node = NULL;
Radek Krejci084289f2019-07-09 17:35:30 +0200947 uint64_t pos = 1;
948
949 LY_CHECK_ARG_RET(NULL, path, trees, NULL);
950
951 LY_ARRAY_FOR(path, u) {
952 if (parent) {
953 start_search = lyd_node_children(parent);
954search_inner:
Michal Vaskoe444f752020-02-10 12:20:06 +0100955 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 +0200956 } else {
957 LY_ARRAY_FOR(trees, v) {
958 start_search = trees[v];
959search_toplevel:
960 /* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
Michal Vaskoe444f752020-02-10 12:20:06 +0100961 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 +0200962 if (node) {
963 break;
964 }
965 }
966 }
967 if (!node) {
968 return NULL;
969 }
970
971 /* check predicate if any */
972 LY_ARRAY_FOR(path[u].predicates, x) {
973 if (path[u].predicates[x].type == 0) {
974 /* position predicate */
975 if (pos != path[u].predicates[x].position) {
976 pos++;
977 goto search_repeat;
978 }
979 /* done, no more predicates are allowed here */
980 break;
981 } else if (path[u].predicates[x].type == 1) {
982 /* key-predicate */
983 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].predicates[x].key)->type;
Michal Vaskoe444f752020-02-10 12:20:06 +0100984 struct lyd_node *key;
985 lyd_find_sibling_next(lyd_node_children(node), path[u].predicates[x].key->module,
986 path[u].predicates[x].key->name, 0, NULL, 0, &key);
Radek Krejci084289f2019-07-09 17:35:30 +0200987 if (!key) {
988 /* probably error and we shouldn't be here due to previous checks when creating path */
989 goto search_repeat;
990 }
991 if (type->plugin->compare(&((struct lyd_node_term*)key)->value, path[u].predicates[x].value)) {
992 goto search_repeat;
993 }
994 } else if (path[u].predicates[x].type == 2) {
995 /* leaf-list-predicate */
996 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].node)->type;
997 if (type->plugin->compare(&((struct lyd_node_term*)node)->value, path[u].predicates[x].value)) {
998 goto search_repeat;
999 }
1000 } else {
1001 LOGINT(NULL);
1002 }
1003 }
1004
1005 parent = node;
1006 }
1007
1008 return (const struct lyd_node_term*)node;
1009
1010search_repeat:
1011 start_search = node->next;
1012 if (parent) {
1013 goto search_inner;
1014 } else {
1015 goto search_toplevel;
1016 }
1017}
1018
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001019API LY_ERR
1020lyd_compare(const struct lyd_node *node1, const struct lyd_node *node2, int options)
1021{
1022 const struct lyd_node *iter1, *iter2;
1023 struct lyd_node_term *term1, *term2;
1024 struct lyd_node_any *any1, *any2;
1025 struct lysc_type *type;
1026 size_t len1, len2;
Radek Krejci084289f2019-07-09 17:35:30 +02001027
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001028 if (!node1 || !node2) {
1029 if (node1 == node2) {
1030 return LY_SUCCESS;
1031 } else {
1032 return LY_ENOT;
1033 }
1034 }
1035
Michal Vasko14654712020-02-06 08:35:21 +01001036 if (node1->schema->module->ctx != node2->schema->module->ctx || node1->schema != node2->schema) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001037 return LY_ENOT;
1038 }
1039
1040 if (node1->hash != node2->hash) {
1041 return LY_ENOT;
1042 }
1043
1044 /* equal hashes do not mean equal nodes, they can be just in collision so the nodes must be checked explicitly */
1045
1046 switch (node1->schema->nodetype) {
1047 case LYS_LEAF:
1048 case LYS_LEAFLIST:
1049 if (options & LYD_COMPARE_DEFAULTS) {
1050 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1051 return LY_ENOT;
1052 }
1053 }
1054
1055 term1 = (struct lyd_node_term*)node1;
1056 term2 = (struct lyd_node_term*)node2;
1057 type = ((struct lysc_node_leaf*)node1->schema)->type;
1058
1059 return type->plugin->compare(&term1->value, &term2->value);
1060 case LYS_CONTAINER:
1061 if (options & LYD_COMPARE_DEFAULTS) {
1062 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1063 return LY_ENOT;
1064 }
1065 }
1066 if (options & LYD_COMPARE_FULL_RECURSION) {
1067 iter1 = ((struct lyd_node_inner*)node1)->child;
1068 iter2 = ((struct lyd_node_inner*)node2)->child;
1069 goto all_children_compare;
1070 }
1071 return LY_SUCCESS;
1072 case LYS_ACTION:
1073 if (options & LYD_COMPARE_FULL_RECURSION) {
1074 /* TODO action/RPC
1075 goto all_children_compare;
1076 */
1077 }
1078 return LY_SUCCESS;
1079 case LYS_NOTIF:
1080 if (options & LYD_COMPARE_FULL_RECURSION) {
1081 /* TODO Notification
1082 goto all_children_compare;
1083 */
1084 }
1085 return LY_SUCCESS;
1086 case LYS_LIST:
1087 iter1 = ((struct lyd_node_inner*)node1)->child;
1088 iter2 = ((struct lyd_node_inner*)node2)->child;
1089
Radek Krejci0fe9b512019-07-26 17:51:05 +02001090 if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001091 /* lists with keys, their equivalence is based on their keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +02001092 for (struct lysc_node *key = ((struct lysc_node_list*)node1->schema)->child;
1093 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1094 key = key->next) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001095 if (lyd_compare(iter1, iter2, options)) {
1096 return LY_ENOT;
1097 }
1098 iter1 = iter1->next;
1099 iter2 = iter2->next;
1100 }
1101 } else {
1102 /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
1103
1104all_children_compare:
1105 if (!iter1 && !iter2) {
1106 /* no children, nothing to compare */
1107 return LY_SUCCESS;
1108 }
1109
1110 for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
1111 if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
1112 return LY_ENOT;
1113 }
1114 }
1115 if (iter1 || iter2) {
1116 return LY_ENOT;
1117 }
1118 }
1119 return LY_SUCCESS;
1120 case LYS_ANYXML:
1121 case LYS_ANYDATA:
1122 any1 = (struct lyd_node_any*)node1;
1123 any2 = (struct lyd_node_any*)node2;
1124
1125 if (any1->value_type != any2->value_type) {
1126 return LY_ENOT;
1127 }
1128 switch (any1->value_type) {
1129 case LYD_ANYDATA_DATATREE:
1130 iter1 = any1->value.tree;
1131 iter2 = any2->value.tree;
1132 goto all_children_compare;
1133 case LYD_ANYDATA_STRING:
1134 case LYD_ANYDATA_XML:
1135 case LYD_ANYDATA_JSON:
1136 len1 = strlen(any1->value.str);
1137 len2 = strlen(any2->value.str);
1138 if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
1139 return LY_ENOT;
1140 }
1141 return LY_SUCCESS;
1142#if 0 /* TODO LYB format */
1143 case LYD_ANYDATA_LYB:
1144 int len1 = lyd_lyb_data_length(any1->value.mem);
1145 int len2 = lyd_lyb_data_length(any2->value.mem);
1146 if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
1147 return LY_ENOT;
1148 }
1149 return LY_SUCCESS;
1150#endif
1151 }
1152 }
1153
1154 LOGINT(node1->schema->module->ctx);
1155 return LY_EINT;
1156}
Radek Krejci22ebdba2019-07-25 13:59:43 +02001157
1158/**
1159 * @brief Duplicates just a single node and interconnect it into a @p parent (if present) and after the @p prev
1160 * sibling (if present).
1161 *
1162 * Ignores LYD_DUP_WITH_PARENTS and LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
1163 */
1164static struct lyd_node *
1165lyd_dup_recursive(const struct lyd_node *node, struct lyd_node_inner *parent, struct lyd_node *prev, int options)
1166{
1167 struct ly_ctx *ctx;
1168 struct lyd_node *dup = NULL;
1169
1170 LY_CHECK_ARG_RET(NULL, node, NULL);
1171 ctx = node->schema->module->ctx;
1172
1173 switch (node->schema->nodetype) {
1174 case LYS_ACTION:
1175 case LYS_NOTIF:
1176 case LYS_CONTAINER:
1177 case LYS_LIST:
1178 dup = calloc(1, sizeof(struct lyd_node_inner));
1179 break;
1180 case LYS_LEAF:
1181 case LYS_LEAFLIST:
1182 dup = calloc(1, sizeof(struct lyd_node_term));
1183 break;
1184 case LYS_ANYDATA:
1185 case LYS_ANYXML:
1186 dup = calloc(1, sizeof(struct lyd_node_any));
1187 break;
1188 default:
1189 LOGINT(ctx);
1190 goto error;
1191 }
1192
1193 /* TODO implement LYD_DUP_WITH_WHEN */
1194 dup->flags = node->flags;
1195 dup->schema = node->schema;
1196
1197 /* interconnect the node at the end */
1198 dup->parent = parent;
1199 if (prev) {
1200 dup->prev = prev;
1201 prev->next = dup;
1202 } else {
1203 dup->prev = dup;
1204 if (parent) {
1205 parent->child = dup;
1206 }
1207 }
1208 if (parent) {
1209 parent->child->prev = dup;
1210 } else if (prev) {
1211 struct lyd_node *first;
1212 for (first = prev; first->prev != prev; first = first->prev);
1213 first->prev = dup;
1214 }
1215
1216 /* TODO duplicate attributes, implement LYD_DUP_NO_ATTR */
1217
1218 /* nodetype-specific work */
1219 if (dup->schema->nodetype & LYD_NODE_TERM) {
1220 struct lyd_node_term *term = (struct lyd_node_term*)dup;
1221 struct lyd_node_term *orig = (struct lyd_node_term*)node;
1222
1223 term->hash = orig->hash;
1224 term->value.realtype = orig->value.realtype;
1225 LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(ctx, &orig->value, &term->value),
1226 LOGERR(ctx, LY_EINT, "Value duplication failed."), error);
1227 } else if (dup->schema->nodetype & LYD_NODE_INNER) {
1228 struct lyd_node_inner *inner = (struct lyd_node_inner*)dup;
1229 struct lyd_node_inner *orig = (struct lyd_node_inner*)node;
1230 struct lyd_node *child, *last = NULL;
1231
1232 if (options & LYD_DUP_RECURSIVE) {
1233 /* duplicate all the children */
1234 LY_LIST_FOR(orig->child, child) {
1235 last = lyd_dup_recursive(child, inner, last, options);
1236 LY_CHECK_GOTO(!last, error);
1237 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02001238 } else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001239 /* always duplicate keys of a list */
Radek Krejci22ebdba2019-07-25 13:59:43 +02001240 child = orig->child;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001241 for (struct lysc_node *key = ((struct lysc_node_list*)dup->schema)->child;
1242 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1243 key = key->next) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001244 if (!child) {
1245 /* possibly not keys are present in filtered tree */
1246 break;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001247 } else if (child->schema != key) {
1248 /* possibly not all keys are present in filtered tree,
1249 * but there can be also some non-key nodes */
1250 continue;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001251 }
1252 last = lyd_dup_recursive(child, inner, last, options);
1253 child = child->next;
1254 }
1255 }
1256 lyd_hash(dup);
1257 } else if (dup->schema->nodetype & LYD_NODE_ANY) {
1258 struct lyd_node_any *any = (struct lyd_node_any*)dup;
1259 struct lyd_node_any *orig = (struct lyd_node_any*)node;
1260
1261 any->hash = orig->hash;
1262 any->value_type = orig->value_type;
1263 switch (any->value_type) {
1264 case LYD_ANYDATA_DATATREE:
1265 if (orig->value.tree) {
1266 any->value.tree = lyd_dup(orig->value.tree, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_SIBLINGS);
1267 LY_CHECK_GOTO(!any->value.tree, error);
1268 }
1269 break;
1270 case LYD_ANYDATA_STRING:
1271 case LYD_ANYDATA_XML:
1272 case LYD_ANYDATA_JSON:
1273 if (orig->value.str) {
1274 any->value.str = lydict_insert(ctx, orig->value.str, strlen(orig->value.str));
1275 }
1276 break;
1277 }
1278 }
1279
1280 lyd_insert_hash(dup);
1281 return dup;
1282
1283error:
1284 if (!parent && !prev) {
1285 lyd_free_tree(dup);
1286 }
1287 return NULL;
1288}
1289
1290API struct lyd_node *
1291lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
1292{
1293 struct ly_ctx *ctx;
1294 const struct lyd_node *orig; /* original node to be duplicated */
1295 struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
1296 struct lyd_node *last = NULL; /* the last sibling of the duplicated nodes */
1297 struct lyd_node *top = NULL; /* the most higher created node */
1298 struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
1299 int keyless_parent_list = 0;
1300
1301 LY_CHECK_ARG_RET(NULL, node, NULL);
1302 ctx = node->schema->module->ctx;
1303
1304 if (options & LYD_DUP_WITH_PARENTS) {
1305 struct lyd_node_inner *orig_parent, *iter;
1306 int repeat = 1;
1307 for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
1308 if (parent && parent->schema == orig_parent->schema) {
1309 /* stop creating parents, connect what we have into the provided parent */
1310 iter = parent;
1311 repeat = 0;
1312 /* get know if there is a keyless list which we will have to rehash */
1313 for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02001314 if (piter->schema->nodetype == LYS_LIST && (piter->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001315 keyless_parent_list = 1;
1316 break;
1317 }
1318 }
1319 } else {
1320 iter = (struct lyd_node_inner*)lyd_dup_recursive((struct lyd_node*)orig_parent, NULL, NULL, 0);
1321 LY_CHECK_GOTO(!iter, error);
1322 }
1323 if (!local_parent) {
1324 local_parent = iter;
1325 }
1326 if (iter->child) {
1327 /* 1) list - add after keys
1328 * 2) provided parent with some children */
1329 iter->child->prev->next = top;
1330 if (top) {
1331 top->prev = iter->child->prev;
1332 iter->child->prev = top;
1333 }
1334 } else {
1335 iter->child = top;
1336 if (iter->schema->nodetype == LYS_LIST) {
1337 /* keyless list - we will need to rehash it since we are going to add nodes into it */
1338 keyless_parent_list = 1;
1339 }
1340 }
1341 if (top) {
1342 top->parent = iter;
1343 }
1344 top = (struct lyd_node*)iter;
1345 }
1346 if (repeat && parent) {
1347 /* given parent and created parents chain actually do not interconnect */
1348 LOGERR(ctx, LY_EINVAL, "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
1349 goto error;
1350 }
1351 } else {
1352 local_parent = parent;
1353 }
1354
1355 if (local_parent && local_parent->child) {
1356 last = local_parent->child->prev;
1357 }
1358
1359 LY_LIST_FOR(node, orig) {
1360 last = lyd_dup_recursive(orig, local_parent, last, options);
1361 LY_CHECK_GOTO(!last, error);
1362 if (!first) {
1363 first = last;
1364 }
1365
1366 if (!(options & LYD_DUP_WITH_SIBLINGS)) {
1367 break;
1368 }
1369 }
1370 if (keyless_parent_list) {
1371 /* rehash */
1372 for (; local_parent; local_parent = local_parent->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02001373 if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001374 lyd_hash((struct lyd_node*)local_parent);
1375 }
1376 }
1377 }
1378 return first;
1379
1380error:
1381 if (top) {
1382 lyd_free_tree(top);
1383 } else {
1384 lyd_free_withsiblings(first);
1385 }
1386 return NULL;
1387}
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001388
1389static LY_ERR
1390lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
1391{
Michal Vasko14654712020-02-06 08:35:21 +01001392 /* ending \0 */
1393 ++reqlen;
1394
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001395 if (reqlen > *buflen) {
1396 if (is_static) {
1397 return LY_EINCOMPLETE;
1398 }
1399
1400 *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
1401 if (!*buffer) {
1402 return LY_EMEM;
1403 }
1404
1405 *buflen = reqlen;
1406 }
1407
1408 return LY_SUCCESS;
1409}
1410
1411/**
1412 * @brief Append all list key predicates to path.
1413 *
1414 * @param[in] node Node with keys to print.
1415 * @param[in,out] buffer Buffer to print to.
1416 * @param[in,out] buflen Current buffer length.
1417 * @param[in,out] bufused Current number of characters used in @p buffer.
1418 * @param[in] is_static Whether buffer is static or can be reallocated.
1419 * @return LY_ERR
1420 */
1421static LY_ERR
1422lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
1423{
1424 const struct lyd_node *key;
1425 int dynamic = 0;
1426 size_t len;
1427 const char *val;
1428 char quot;
1429 LY_ERR rc;
1430
Michal Vasko14654712020-02-06 08:35:21 +01001431 for (key = lyd_node_children(node); key && (key->schema->flags & LYS_KEY); key = key->next) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001432 val = lyd_value2str((struct lyd_node_term *)key, &dynamic);
1433 len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
1434 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1435 if (rc != LY_SUCCESS) {
1436 if (dynamic) {
1437 free((char *)val);
1438 }
1439 return rc;
1440 }
1441
1442 quot = '\'';
1443 if (strchr(val, '\'')) {
1444 quot = '"';
1445 }
1446 *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
1447
1448 if (dynamic) {
1449 free((char *)val);
1450 }
1451 }
1452
1453 return LY_SUCCESS;
1454}
1455
1456/**
1457 * @brief Append leaf-list value predicate to path.
1458 *
1459 * @param[in] node Node to print.
1460 * @param[in,out] buffer Buffer to print to.
1461 * @param[in,out] buflen Current buffer length.
1462 * @param[in,out] bufused Current number of characters used in @p buffer.
1463 * @param[in] is_static Whether buffer is static or can be reallocated.
1464 * @return LY_ERR
1465 */
1466static LY_ERR
1467lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
1468{
1469 int dynamic = 0;
1470 size_t len;
1471 const char *val;
1472 char quot;
1473 LY_ERR rc;
1474
1475 val = lyd_value2str((struct lyd_node_term *)node, &dynamic);
1476 len = 4 + strlen(val) + 2;
1477 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1478 if (rc != LY_SUCCESS) {
1479 goto cleanup;
1480 }
1481
1482 quot = '\'';
1483 if (strchr(val, '\'')) {
1484 quot = '"';
1485 }
1486 *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
1487
1488cleanup:
1489 if (dynamic) {
1490 free((char *)val);
1491 }
1492 return rc;
1493}
1494
1495/**
1496 * @brief Append node position (relative to its other instances) predicate to path.
1497 *
1498 * @param[in] node Node to print.
1499 * @param[in,out] buffer Buffer to print to.
1500 * @param[in,out] buflen Current buffer length.
1501 * @param[in,out] bufused Current number of characters used in @p buffer.
1502 * @param[in] is_static Whether buffer is static or can be reallocated.
1503 * @return LY_ERR
1504 */
1505static LY_ERR
1506lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
1507{
1508 const struct lyd_node *first, *iter;
1509 size_t len;
1510 int pos;
1511 char *val = NULL;
1512 LY_ERR rc;
1513
1514 if (node->parent) {
1515 first = node->parent->child;
1516 } else {
1517 for (first = node; node->prev->next; node = node->prev);
1518 }
1519 pos = 1;
1520 for (iter = first; iter != node; iter = iter->next) {
1521 if (iter->schema == node->schema) {
1522 ++pos;
1523 }
1524 }
1525 if (asprintf(&val, "%d", pos) == -1) {
1526 return LY_EMEM;
1527 }
1528
1529 len = 1 + strlen(val) + 1;
1530 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1531 if (rc != LY_SUCCESS) {
1532 goto cleanup;
1533 }
1534
1535 *bufused += sprintf(*buffer + *bufused, "[%s]", val);
1536
1537cleanup:
1538 free(val);
1539 return rc;
1540}
1541
1542API char *
1543lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
1544{
Michal Vasko14654712020-02-06 08:35:21 +01001545 int is_static = 0, i, depth;
1546 size_t bufused = 0, len;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001547 const struct lyd_node *iter;
1548 const struct lys_module *mod;
1549 LY_ERR rc;
1550
1551 LY_CHECK_ARG_RET(NULL, node, NULL);
1552 if (buffer) {
1553 LY_CHECK_ARG_RET(node->schema->module->ctx, buflen > 1, NULL);
1554 is_static = 1;
Michal Vasko14654712020-02-06 08:35:21 +01001555 } else {
1556 buflen = 0;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001557 }
1558
1559 switch (pathtype) {
Michal Vasko14654712020-02-06 08:35:21 +01001560 case LYD_PATH_LOG:
1561 depth = 1;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001562 for (iter = node; iter->parent; iter = (const struct lyd_node *)iter->parent) {
1563 ++depth;
1564 }
1565
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001566 goto iter_print;
Michal Vasko14654712020-02-06 08:35:21 +01001567 while (depth) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001568 /* find the right node */
Michal Vasko14654712020-02-06 08:35:21 +01001569 for (iter = node, i = 1; i < depth; iter = (const struct lyd_node *)iter->parent, ++i);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001570iter_print:
1571 /* print prefix and name */
1572 mod = NULL;
1573 if (!iter->parent || (iter->schema->module != iter->parent->schema->module)) {
1574 mod = iter->schema->module;
1575 }
1576
1577 /* realloc string */
1578 len = 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(iter->schema->name);
1579 rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
1580 if (rc != LY_SUCCESS) {
1581 break;
1582 }
1583
1584 /* print next node */
1585 bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", iter->schema->name);
1586
1587 switch (iter->schema->nodetype) {
1588 case LYS_LIST:
1589 if (iter->schema->flags & LYS_KEYLESS) {
1590 /* print its position */
1591 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
1592 } else {
1593 /* print all list keys in predicates */
1594 rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
1595 }
1596 break;
1597 case LYS_LEAFLIST:
1598 if (iter->schema->flags & LYS_CONFIG_W) {
1599 /* print leaf-list value */
1600 rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
1601 } else {
1602 /* print its position */
1603 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
1604 }
1605 break;
1606 default:
1607 /* nothing to print more */
1608 rc = LY_SUCCESS;
1609 break;
1610 }
1611 if (rc != LY_SUCCESS) {
1612 break;
1613 }
1614
Michal Vasko14654712020-02-06 08:35:21 +01001615 --depth;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001616 }
1617 break;
1618 }
1619
1620 return buffer;
1621}
Michal Vaskoe444f752020-02-10 12:20:06 +01001622
Michal Vasko9b368d32020-02-14 13:53:31 +01001623LY_ERR
1624lyd_find_sibling_next2(const struct lyd_node *first, const struct lysc_node *schema, const char *key_or_value,
1625 size_t val_len, struct lyd_node **match)
Michal Vaskoe444f752020-02-10 12:20:06 +01001626{
1627 LY_ERR rc;
1628 const struct lyd_node *node = NULL;
1629 struct lyd_node_term *term;
Michal Vaskoe444f752020-02-10 12:20:06 +01001630 struct ly_keys keys = {0};
Michal Vasko90932a92020-02-12 14:33:03 +01001631 struct lyd_value val = {0};
Michal Vaskoe444f752020-02-10 12:20:06 +01001632 size_t i;
Michal Vaskoe444f752020-02-10 12:20:06 +01001633
Michal Vasko9b368d32020-02-14 13:53:31 +01001634 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
Michal Vaskoe444f752020-02-10 12:20:06 +01001635
1636 if (!first) {
1637 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01001638 if (match) {
1639 *match = NULL;
1640 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001641 return LY_ENOTFOUND;
1642 }
1643
Michal Vaskoe444f752020-02-10 12:20:06 +01001644 if (key_or_value && !val_len) {
1645 val_len = strlen(key_or_value);
1646 }
1647
1648 if (key_or_value && (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko90932a92020-02-12 14:33:03 +01001649 /* store the value */
Michal Vasko9b368d32020-02-14 13:53:31 +01001650 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 +01001651 } else if (key_or_value && (schema->nodetype == LYS_LIST)) {
1652 /* parse keys into canonical values */
1653 LY_CHECK_GOTO(rc = ly_keys_parse(schema, key_or_value, val_len, 1, &keys), cleanup);
1654 }
1655
1656 /* find first matching value */
1657 LY_LIST_FOR(first, node) {
1658 if (node->schema != schema) {
1659 continue;
1660 }
1661
1662 if ((schema->nodetype == LYS_LIST) && keys.str) {
1663 /* compare all set keys */
1664 for (i = 0; i < keys.key_count; ++i) {
1665 /* find key */
1666 rc = lyd_find_sibling_val(lyd_node_children(node), (struct lysc_node *)keys.keys[i].schema, NULL, 0,
1667 (struct lyd_node **)&term);
1668 if (rc == LY_ENOTFOUND) {
1669 /* all keys must always exist */
Michal Vasko9b368d32020-02-14 13:53:31 +01001670 LOGINT_RET(schema->module->ctx);
Michal Vaskoe444f752020-02-10 12:20:06 +01001671 }
1672 LY_CHECK_GOTO(rc, cleanup);
1673
1674 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01001675 if (!term->value.realtype->plugin->compare(&term->value, &keys.keys[i].val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01001676 break;
1677 }
1678 }
1679
1680 if (i < keys.key_count) {
1681 /* not a match */
1682 continue;
1683 }
Michal Vasko90932a92020-02-12 14:33:03 +01001684 } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && val.realtype) {
Michal Vaskoe444f752020-02-10 12:20:06 +01001685 term = (struct lyd_node_term *)node;
1686
1687 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01001688 if (!term->value.realtype->plugin->compare(&term->value, &val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01001689 /* not a match */
1690 continue;
1691 }
1692 }
1693
1694 /* all criteria passed */
1695 break;
1696 }
1697
1698 if (!node) {
1699 rc = LY_ENOTFOUND;
Michal Vasko9b368d32020-02-14 13:53:31 +01001700 if (match) {
1701 *match = NULL;
1702 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001703 goto cleanup;
1704 }
1705
1706 /* success */
Michal Vasko9b368d32020-02-14 13:53:31 +01001707 if (match) {
1708 *match = (struct lyd_node *)node;
1709 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001710 rc = LY_SUCCESS;
1711
1712cleanup:
1713 ly_keys_clean(&keys);
Michal Vasko90932a92020-02-12 14:33:03 +01001714 if (val.realtype) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001715 val.realtype->plugin->free(schema->module->ctx, &val);
Michal Vasko90932a92020-02-12 14:33:03 +01001716 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001717 return rc;
1718}
1719
1720API LY_ERR
Michal Vasko9b368d32020-02-14 13:53:31 +01001721lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name, size_t name_len,
1722 const char *key_or_value, size_t val_len, struct lyd_node **match)
1723{
1724 const struct lysc_node *schema;
1725
1726 LY_CHECK_ARG_RET(NULL, module, name, match, LY_EINVAL);
1727
1728 if (!first) {
1729 /* no data */
1730 *match = NULL;
1731 return LY_ENOTFOUND;
1732 }
1733
1734 /* find schema */
1735 schema = lys_find_child(first->parent ? first->parent->schema : NULL, module, name, name_len, 0, 0);
1736 if (!schema) {
1737 LOGERR(module->ctx, LY_EINVAL, "Schema node not found.");
1738 return LY_EINVAL;
1739 }
1740
1741 return lyd_find_sibling_next2(first, schema, key_or_value, val_len, match);
1742}
1743
1744API LY_ERR
Michal Vaskoe444f752020-02-10 12:20:06 +01001745lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
1746{
1747 struct lyd_node **match_p;
1748 struct lyd_node_inner *parent;
1749
1750 LY_CHECK_ARG_RET(NULL, target, match, LY_EINVAL);
1751
1752 if (!siblings) {
1753 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01001754 if (match) {
1755 *match = NULL;
1756 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001757 return LY_ENOTFOUND;
1758 }
1759
1760 /* find first sibling */
1761 if (siblings->parent) {
1762 siblings = siblings->parent->child;
1763 } else {
1764 while (siblings->prev->next) {
1765 siblings = siblings->prev;
1766 }
1767 }
1768
1769 parent = (struct lyd_node_inner *)siblings->parent;
1770 if (parent && parent->children_ht) {
1771 assert(target->hash);
1772
1773 /* find by hash */
1774 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
1775 siblings = *match_p;
1776 } else {
1777 /* not found */
1778 siblings = NULL;
1779 }
1780 } else {
1781 /* no children hash table */
1782 for (; siblings; siblings = siblings->next) {
1783 if (!lyd_compare(siblings, target, 0)) {
1784 break;
1785 }
1786 }
1787 }
1788
1789 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001790 if (match) {
1791 *match = NULL;
1792 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001793 return LY_ENOTFOUND;
1794 }
1795
Michal Vasko9b368d32020-02-14 13:53:31 +01001796 if (match) {
1797 *match = (struct lyd_node *)siblings;
1798 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001799 return LY_SUCCESS;
1800}
1801
1802API LY_ERR
1803lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
1804{
1805 struct lyd_node_inner *parent;
1806 struct lyd_node *match;
1807 struct lyd_node **match_p;
1808 struct ly_set *ret;
1809
1810 LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
1811
1812 if (!siblings) {
1813 /* no data */
1814 return LY_ENOTFOUND;
1815 }
1816
1817 ret = ly_set_new();
1818 LY_CHECK_ERR_RET(!ret, LOGMEM(target->schema->module->ctx), LY_EMEM);
1819
1820 /* find first sibling */
1821 if (siblings->parent) {
1822 siblings = siblings->parent->child;
1823 } else {
1824 while (siblings->prev->next) {
1825 siblings = siblings->prev;
1826 }
1827 }
1828
1829 parent = (struct lyd_node_inner *)siblings->parent;
1830 if (parent && parent->children_ht) {
1831 assert(target->hash);
1832
1833 /* find by hash */
1834 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
1835 match = *match_p;
1836 } else {
1837 /* not found */
1838 match = NULL;
1839 }
1840 while (match) {
1841 /* add all found nodes into the return set */
1842 if (ly_set_add(ret, match, LY_SET_OPT_USEASLIST) == -1) {
1843 goto error;
1844 }
1845
1846 /* find next instance */
1847 if (lyht_find_next(parent->children_ht, &match, match->hash, (void **)&match_p)) {
1848 match = NULL;
1849 } else {
1850 match = *match_p;
1851 }
1852 }
1853 } else {
1854 /* no children hash table */
1855 for (; siblings; siblings = siblings->next) {
1856 if (!lyd_compare(siblings, target, 0)) {
1857 /* a match */
1858 if (ly_set_add(ret, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
1859 goto error;
1860 }
1861 }
1862 }
1863 }
1864
1865 if (!ret->count) {
1866 ly_set_free(ret, NULL);
1867 return LY_ENOTFOUND;
1868 }
1869
1870 *set = ret;
1871 return LY_SUCCESS;
1872
1873error:
1874 ly_set_free(ret, NULL);
1875 return LY_EMEM;
1876}
1877
Michal Vasko90932a92020-02-12 14:33:03 +01001878static int
1879lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
1880{
1881 struct lysc_node *val1;
1882 struct lyd_node *val2;
1883
1884 val1 = *((struct lysc_node **)val1_p);
1885 val2 = *((struct lyd_node **)val2_p);
1886
1887 assert(val1->nodetype & (LYD_NODE_INNER | LYS_LEAF));
1888
1889 if (val1 == val2->schema) {
1890 /* schema match is enough */
1891 return 1;
1892 } else {
1893 return 0;
1894 }
1895}
1896
1897static LY_ERR
1898lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
1899{
1900 struct lyd_node **match_p;
1901 struct lyd_node_inner *parent;
1902 uint32_t hash;
1903 values_equal_cb ht_cb;
1904
1905 assert(siblings && schema && (schema->nodetype & (LYD_NODE_INNER | LYS_LEAF)));
1906
1907 /* find first sibling */
1908 if (siblings->parent) {
1909 siblings = siblings->parent->child;
1910 } else {
1911 while (siblings->prev->next) {
1912 siblings = siblings->prev;
1913 }
1914 }
1915
1916 parent = (struct lyd_node_inner *)siblings->parent;
1917 if (parent && parent->children_ht) {
1918 /* calculate our hash */
1919 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
1920 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
1921 hash = dict_hash_multi(hash, NULL, 0);
1922
1923 /* use special hash table function */
1924 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
1925
1926 /* find by hash */
1927 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
1928 siblings = *match_p;
1929 } else {
1930 /* not found */
1931 siblings = NULL;
1932 }
1933
1934 /* set the original hash table compare function back */
1935 lyht_set_cb(parent->children_ht, ht_cb);
1936 } else {
1937 /* no children hash table */
1938 for (; siblings; siblings = siblings->next) {
1939 if (siblings->schema == schema) {
1940 /* schema match is enough */
1941 break;
1942 }
1943 }
1944 }
1945
1946 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001947 if (match) {
1948 *match = NULL;
1949 }
Michal Vasko90932a92020-02-12 14:33:03 +01001950 return LY_ENOTFOUND;
1951 }
1952
Michal Vasko9b368d32020-02-14 13:53:31 +01001953 if (match) {
1954 *match = (struct lyd_node *)siblings;
1955 }
Michal Vasko90932a92020-02-12 14:33:03 +01001956 return LY_SUCCESS;
1957}
1958
Michal Vaskoe444f752020-02-10 12:20:06 +01001959API LY_ERR
1960lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
1961 size_t val_len, struct lyd_node **match)
1962{
1963 LY_ERR rc;
1964 struct lyd_node *target = NULL;
1965
1966 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
1967 if ((schema->nodetype == LYS_LIST) && schema->flags & LYS_KEYLESS) {
1968 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
1969 return LY_EINVAL;
1970 } else if ((schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && !key_or_value) {
1971 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - no value/keys for a (leaf-)list (%s()).", __func__);
1972 return LY_EINVAL;
1973 } else if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1974 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
1975 lys_nodetype2str(schema->nodetype), __func__);
1976 return LY_EINVAL;
1977 }
1978
1979 if (!siblings) {
1980 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01001981 if (match) {
1982 *match = NULL;
1983 }
Michal Vaskoe444f752020-02-10 12:20:06 +01001984 return LY_ENOTFOUND;
1985 }
1986
Michal Vasko90932a92020-02-12 14:33:03 +01001987 /* create data node if needed and find it */
Michal Vaskoe444f752020-02-10 12:20:06 +01001988 switch (schema->nodetype) {
1989 case LYS_CONTAINER:
1990 case LYS_ANYXML:
1991 case LYS_ANYDATA:
1992 case LYS_NOTIF:
Michal Vasko9b368d32020-02-14 13:53:31 +01001993 case LYS_ACTION:
Michal Vaskoe444f752020-02-10 12:20:06 +01001994 case LYS_LEAF:
Michal Vasko90932a92020-02-12 14:33:03 +01001995 /* find it based on schema only */
1996 rc = lyd_find_sibling_schema(siblings, schema, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01001997 break;
1998 case LYS_LEAFLIST:
1999 /* target used attributes: schema, hash, value */
Michal Vasko90932a92020-02-12 14:33:03 +01002000 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 +01002001 /* fallthrough */
Michal Vaskoe444f752020-02-10 12:20:06 +01002002 case LYS_LIST:
Michal Vasko90932a92020-02-12 14:33:03 +01002003 if (schema->nodetype == LYS_LIST) {
2004 /* target used attributes: schema, hash, child (all keys) */
2005 LY_CHECK_RET(lyd_create_list(schema, key_or_value, val_len, &target));
Michal Vasko90932a92020-02-12 14:33:03 +01002006 }
2007
2008 /* find it */
2009 rc = lyd_find_sibling_first(siblings, target, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01002010 break;
2011 default:
2012 /* unreachable */
2013 LOGINT(schema->module->ctx);
2014 return LY_EINT;
2015 }
2016
Michal Vaskoe444f752020-02-10 12:20:06 +01002017 lyd_free_tree(target);
2018 return rc;
2019}