blob: 018259f2dc06f8977d6e3788683ad442bb676738 [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"
30#include "tree_schema.h"
Radek Krejci38d85362019-09-05 16:26:38 +020031#include "plugins_exts_metadata.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032
Michal Vaskoe444f752020-02-10 12:20:06 +010033struct ly_keys {
34 char *str;
35 struct {
36 const struct lysc_node_leaf *schema;
37 char *value;
38 const char *can_val;
39 } *keys;
40 size_t key_count;
41};
42
Radek Krejci576b23f2019-07-12 14:06:32 +020043API void
44lyd_trees_free(const struct lyd_node **trees, int free_data)
45{
46 if (!trees) {
47 return;
48 }
49
50 if (free_data) {
51 unsigned int u;
52 LY_ARRAY_FOR(trees, u) {
53 lyd_free_all((struct lyd_node *)trees[u]);
54 }
55 }
56 LY_ARRAY_FREE(trees);
57}
58
59static const struct lyd_node *
60lyd_trees_getstart(const struct lyd_node *tree)
61{
62 if (!tree) {
63 return NULL;
64 }
65 while (tree->prev->next) {
66 tree = tree->prev;
67 }
68 return tree;
69}
70
71API const struct lyd_node **
72lyd_trees_new(size_t count, const struct lyd_node *tree, ...)
73{
74 LY_ERR ret;
75 const struct lyd_node **trees = NULL;
76 va_list ap;
77
78 LY_CHECK_ARG_RET(NULL, tree, count > 0, NULL);
79
80 va_start(ap, tree);
81
82 LY_ARRAY_CREATE_GOTO(tree->schema->module->ctx, trees, count, ret, error);
83 /* first, mandatory, tree to insert */
84 trees[0] = lyd_trees_getstart(tree);
85 LY_ARRAY_INCREMENT(trees);
86
87 /* variable arguments */
88 for (unsigned int u = 1; u < count; ++u) {
89 trees[u] = lyd_trees_getstart(va_arg(ap, const struct lyd_node *));
90 LY_ARRAY_INCREMENT(trees);
91 }
92
93 va_end(ap);
94 return trees;
95
96error:
97 (void)ret; /* unused */
98 lyd_trees_free(trees, 1);
99 va_end(ap);
100 return NULL;
101}
102
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200103API const struct lyd_node **
104lyd_trees_add(const struct lyd_node **trees, const struct lyd_node *tree)
105{
106 const struct lyd_node **t = NULL;
107
108 LY_CHECK_ARG_RET(NULL, tree, trees, trees);
109
110 LY_ARRAY_NEW_RET(tree->schema->module->ctx, trees, t, NULL);
111 *t = lyd_trees_getstart(tree);
112
113 return trees;
114}
115
Radek Krejci084289f2019-07-09 17:35:30 +0200116LY_ERR
Radek Krejci3c9758d2019-07-11 16:49:10 +0200117lyd_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 +0200118 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200119{
120 LY_ERR ret = LY_SUCCESS, rc;
121 struct ly_err_item *err = NULL;
122 struct ly_ctx *ctx;
123 struct lysc_type *type;
Radek Krejci3c9758d2019-07-11 16:49:10 +0200124 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
125 (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200126 assert(node);
127
128 ctx = node->schema->module->ctx;
Radek Krejci084289f2019-07-09 17:35:30 +0200129
Radek Krejci73dead22019-07-11 16:46:16 +0200130 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci62903c32019-07-15 14:42:05 +0200131 if (!second) {
132 node->value.realtype = type;
133 }
Radek Krejci73dead22019-07-11 16:46:16 +0200134 rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
135 trees ? (void*)node : (void*)node->schema, trees,
136 &node->value, NULL, &err);
137 if (rc == LY_EINCOMPLETE) {
138 ret = rc;
139 /* continue with storing, just remember what to return if storing is ok */
140 } else if (rc) {
141 ret = rc;
142 if (err) {
143 ly_err_print(err);
144 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
145 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200146 }
Radek Krejci73dead22019-07-11 16:46:16 +0200147 goto error;
Radek Krejci084289f2019-07-09 17:35:30 +0200148 }
149
150error:
151 return ret;
152}
153
Radek Krejci38d85362019-09-05 16:26:38 +0200154LY_ERR
155lyd_value_parse_attr(struct lyd_attr *attr, const char *value, size_t value_len, int dynamic, int second,
156 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
157{
158 LY_ERR ret = LY_SUCCESS, rc;
159 struct ly_err_item *err = NULL;
160 struct ly_ctx *ctx;
161 struct lyext_metadata *ant;
162 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
163 (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
164 assert(attr);
165
166 ctx = attr->parent->schema->module->ctx;
167 ant = attr->annotation->data;
168
169 if (!second) {
170 attr->value.realtype = ant->type;
171 }
172 rc = ant->type->plugin->store(ctx, ant->type, value, value_len, options, get_prefix, parser, format,
173 trees ? (void*)attr->parent : (void*)attr->parent->schema, trees,
174 &attr->value, NULL, &err);
175 if (rc == LY_EINCOMPLETE) {
176 ret = rc;
177 /* continue with storing, just remember what to return if storing is ok */
178 } else if (rc) {
179 ret = rc;
180 if (err) {
181 ly_err_print(err);
182 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
183 ly_err_free(err);
184 }
185 goto error;
186 }
187
188error:
189 return ret;
190}
191
Radek Krejci084289f2019-07-09 17:35:30 +0200192API LY_ERR
193lys_value_validate(struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
194 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format)
195{
196 LY_ERR rc = LY_SUCCESS;
197 struct ly_err_item *err = NULL;
198 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200199
200 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
201
202 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
203 LOGARG(ctx, node);
204 return LY_EINVAL;
205 }
206
207 type = ((struct lysc_node_leaf*)node)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200208 /* just validate, no storing of enything */
209 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, LY_TYPE_OPTS_INCOMPLETE_DATA,
210 get_prefix, get_prefix_data, format, node, NULL, NULL, NULL, &err);
211 if (rc == LY_EINCOMPLETE) {
212 /* actually success since we do not provide the context tree and call validation with
213 * LY_TYPE_OPTS_INCOMPLETE_DATA */
214 rc = LY_SUCCESS;
215 } else if (rc && err) {
216 if (ctx) {
217 /* log only in case the ctx was provided as input parameter */
218 ly_err_print(err);
219 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200220 }
Radek Krejci73dead22019-07-11 16:46:16 +0200221 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200222 }
223
224 return rc;
225}
226
227API LY_ERR
228lyd_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 +0200229 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 +0200230{
231 LY_ERR rc;
232 struct ly_err_item *err = NULL;
233 struct lysc_type *type;
Radek Krejci73dead22019-07-11 16:46:16 +0200234 int options = (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200235
236 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
237
238 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200239 rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
240 get_prefix, get_prefix_data, format, trees ? (void*)node : (void*)node->schema, trees,
241 NULL, NULL, &err);
242 if (rc == LY_EINCOMPLETE) {
243 return rc;
244 } else if (rc) {
245 if (err) {
246 if (ctx) {
247 ly_err_print(err);
248 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200249 }
Radek Krejci73dead22019-07-11 16:46:16 +0200250 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200251 }
Radek Krejci73dead22019-07-11 16:46:16 +0200252 return rc;
Radek Krejci084289f2019-07-09 17:35:30 +0200253 }
254
255 return LY_SUCCESS;
256}
257
258API LY_ERR
259lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
Michal Vasko14654712020-02-06 08:35:21 +0100260 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 ret = LY_SUCCESS, rc;
263 struct ly_err_item *err = NULL;
264 struct ly_ctx *ctx;
265 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200266 struct lyd_value data = {0};
Radek Krejci73dead22019-07-11 16:46:16 +0200267 int options = LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200268
269 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
270
271 ctx = node->schema->module->ctx;
272 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200273 rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, get_prefix_data, format, (struct lyd_node*)node,
274 trees, &data, NULL, &err);
275 if (rc == LY_EINCOMPLETE) {
276 ret = rc;
277 /* continue with comparing, just remember what to return if storing is ok */
278 } else if (rc) {
279 /* value to compare is invalid */
280 ret = LY_EINVAL;
281 if (err) {
282 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200283 }
Radek Krejci73dead22019-07-11 16:46:16 +0200284 goto cleanup;
Radek Krejci084289f2019-07-09 17:35:30 +0200285 }
286
287 /* compare data */
Radek Krejci5af04842019-07-12 11:32:07 +0200288 if (type->plugin->compare(&node->value, &data)) {
289 /* do not assign it directly from the compare callback to keep possible LY_EINCOMPLETE from validation */
290 ret = LY_EVALID;
291 }
Radek Krejci084289f2019-07-09 17:35:30 +0200292
293cleanup:
Radek Krejci62903c32019-07-15 14:42:05 +0200294 type->plugin->free(ctx, &data);
Radek Krejci084289f2019-07-09 17:35:30 +0200295
296 return ret;
297}
298
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200299API const char *
300lyd_value2str(const struct lyd_node_term *node, int *dynamic)
301{
302 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, dynamic, NULL);
303
304 return node->value.realtype->plugin->print(&node->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
305}
306
307API const char *
308lyd_attr2str(const struct lyd_attr *attr, int *dynamic)
309{
310 LY_CHECK_ARG_RET(attr ? attr->parent->schema->module->ctx : NULL, attr, dynamic, NULL);
311
312 return attr->value.realtype->plugin->print(&attr->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
313}
314
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200315API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100316lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200317{
Radek Krejcie7b95092019-05-15 11:03:07 +0200318 struct lyd_node *result = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200319#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200320 const char *yang_data_name = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200321#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200322
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200323 LY_CHECK_ARG_RET(ctx, ctx, NULL);
324
Michal Vaskoa3881362020-01-21 15:57:35 +0100325#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200326 if (options & LYD_OPT_RPCREPLY) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200327 /* first item in trees is mandatory - the RPC/action request */
328 LY_CHECK_ARG_RET(ctx, trees, LY_ARRAY_SIZE(trees) >= 1, NULL);
329 if (!trees[0] || trees[0]->parent || !(trees[0]->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
330 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
331 lyd_parse_options_type2str(options));
Radek Krejcie7b95092019-05-15 11:03:07 +0200332 return NULL;
333 }
334 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200335
Radek Krejcie7b95092019-05-15 11:03:07 +0200336 if (options & LYD_OPT_DATA_TEMPLATE) {
337 yang_data_name = va_arg(ap, const char *);
338 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200339#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200340
341 if (!format) {
342 /* TODO try to detect format from the content */
343 }
344
345 switch (format) {
346 case LYD_XML:
Michal Vaskoa3881362020-01-21 15:57:35 +0100347 lyd_parse_xml(ctx, data, options, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200348 break;
349#if 0
350 case LYD_JSON:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200351 lyd_parse_json(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200352 break;
353 case LYD_LYB:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200354 lyd_parse_lyb(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200355 break;
356#endif
357 case LYD_UNKNOWN:
358 LOGINT(ctx);
359 break;
360 }
361
Radek Krejcie7b95092019-05-15 11:03:07 +0200362 return result;
363}
364
365API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100366lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200367{
368 struct lyd_node *result;
369 size_t length;
370 char *addr;
371
372 LY_CHECK_ARG_RET(ctx, ctx, NULL);
373 if (fd < 0) {
374 LOGARG(ctx, fd);
375 return NULL;
376 }
377
378 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
Michal Vaskoa3881362020-01-21 15:57:35 +0100379 result = lyd_parse_mem(ctx, addr ? addr : "", format, options);
Radek Krejcidf3da792019-05-17 10:32:24 +0200380 if (addr) {
381 ly_munmap(addr, length);
382 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200383
384 return result;
385}
386
387API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100388lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200389{
390 int fd;
391 struct lyd_node *result;
392 size_t len;
Radek Krejcie7b95092019-05-15 11:03:07 +0200393
394 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
395
396 fd = open(path, O_RDONLY);
397 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
398
399 if (!format) {
400 /* unknown format - try to detect it from filename's suffix */
401 len = strlen(path);
402
403 /* ignore trailing whitespaces */
404 for (; len > 0 && isspace(path[len - 1]); len--);
405
406 if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
407 format = LYD_XML;
408#if 0
409 } else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
410 format = LYD_JSON;
411 } else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
412 format = LYD_LYB;
413#endif
414 } /* else still unknown, try later to detect it from the content */
415 }
416
Michal Vaskoa3881362020-01-21 15:57:35 +0100417 result = lyd_parse_fd(ctx, fd, format, options);
Radek Krejcie7b95092019-05-15 11:03:07 +0200418 close(fd);
419
420 return result;
421}
Radek Krejci084289f2019-07-09 17:35:30 +0200422
423API const struct lyd_node_term *
Radek Krejci576b23f2019-07-12 14:06:32 +0200424lyd_target(struct lyd_value_path *path, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200425{
426 unsigned int u, v, x;
Michal Vaskoe444f752020-02-10 12:20:06 +0100427 const struct lyd_node *parent = NULL, *start_search;
428 struct lyd_node *node = NULL;
Radek Krejci084289f2019-07-09 17:35:30 +0200429 uint64_t pos = 1;
430
431 LY_CHECK_ARG_RET(NULL, path, trees, NULL);
432
433 LY_ARRAY_FOR(path, u) {
434 if (parent) {
435 start_search = lyd_node_children(parent);
436search_inner:
Michal Vaskoe444f752020-02-10 12:20:06 +0100437 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 +0200438 } else {
439 LY_ARRAY_FOR(trees, v) {
440 start_search = trees[v];
441search_toplevel:
442 /* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
Michal Vaskoe444f752020-02-10 12:20:06 +0100443 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 +0200444 if (node) {
445 break;
446 }
447 }
448 }
449 if (!node) {
450 return NULL;
451 }
452
453 /* check predicate if any */
454 LY_ARRAY_FOR(path[u].predicates, x) {
455 if (path[u].predicates[x].type == 0) {
456 /* position predicate */
457 if (pos != path[u].predicates[x].position) {
458 pos++;
459 goto search_repeat;
460 }
461 /* done, no more predicates are allowed here */
462 break;
463 } else if (path[u].predicates[x].type == 1) {
464 /* key-predicate */
465 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].predicates[x].key)->type;
Michal Vaskoe444f752020-02-10 12:20:06 +0100466 struct lyd_node *key;
467 lyd_find_sibling_next(lyd_node_children(node), path[u].predicates[x].key->module,
468 path[u].predicates[x].key->name, 0, NULL, 0, &key);
Radek Krejci084289f2019-07-09 17:35:30 +0200469 if (!key) {
470 /* probably error and we shouldn't be here due to previous checks when creating path */
471 goto search_repeat;
472 }
473 if (type->plugin->compare(&((struct lyd_node_term*)key)->value, path[u].predicates[x].value)) {
474 goto search_repeat;
475 }
476 } else if (path[u].predicates[x].type == 2) {
477 /* leaf-list-predicate */
478 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].node)->type;
479 if (type->plugin->compare(&((struct lyd_node_term*)node)->value, path[u].predicates[x].value)) {
480 goto search_repeat;
481 }
482 } else {
483 LOGINT(NULL);
484 }
485 }
486
487 parent = node;
488 }
489
490 return (const struct lyd_node_term*)node;
491
492search_repeat:
493 start_search = node->next;
494 if (parent) {
495 goto search_inner;
496 } else {
497 goto search_toplevel;
498 }
499}
500
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200501API LY_ERR
502lyd_compare(const struct lyd_node *node1, const struct lyd_node *node2, int options)
503{
504 const struct lyd_node *iter1, *iter2;
505 struct lyd_node_term *term1, *term2;
506 struct lyd_node_any *any1, *any2;
507 struct lysc_type *type;
508 size_t len1, len2;
Radek Krejci084289f2019-07-09 17:35:30 +0200509
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200510 if (!node1 || !node2) {
511 if (node1 == node2) {
512 return LY_SUCCESS;
513 } else {
514 return LY_ENOT;
515 }
516 }
517
Michal Vasko14654712020-02-06 08:35:21 +0100518 if (node1->schema->module->ctx != node2->schema->module->ctx || node1->schema != node2->schema) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200519 return LY_ENOT;
520 }
521
522 if (node1->hash != node2->hash) {
523 return LY_ENOT;
524 }
525
526 /* equal hashes do not mean equal nodes, they can be just in collision so the nodes must be checked explicitly */
527
528 switch (node1->schema->nodetype) {
529 case LYS_LEAF:
530 case LYS_LEAFLIST:
531 if (options & LYD_COMPARE_DEFAULTS) {
532 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
533 return LY_ENOT;
534 }
535 }
536
537 term1 = (struct lyd_node_term*)node1;
538 term2 = (struct lyd_node_term*)node2;
539 type = ((struct lysc_node_leaf*)node1->schema)->type;
540
541 return type->plugin->compare(&term1->value, &term2->value);
542 case LYS_CONTAINER:
543 if (options & LYD_COMPARE_DEFAULTS) {
544 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
545 return LY_ENOT;
546 }
547 }
548 if (options & LYD_COMPARE_FULL_RECURSION) {
549 iter1 = ((struct lyd_node_inner*)node1)->child;
550 iter2 = ((struct lyd_node_inner*)node2)->child;
551 goto all_children_compare;
552 }
553 return LY_SUCCESS;
554 case LYS_ACTION:
555 if (options & LYD_COMPARE_FULL_RECURSION) {
556 /* TODO action/RPC
557 goto all_children_compare;
558 */
559 }
560 return LY_SUCCESS;
561 case LYS_NOTIF:
562 if (options & LYD_COMPARE_FULL_RECURSION) {
563 /* TODO Notification
564 goto all_children_compare;
565 */
566 }
567 return LY_SUCCESS;
568 case LYS_LIST:
569 iter1 = ((struct lyd_node_inner*)node1)->child;
570 iter2 = ((struct lyd_node_inner*)node2)->child;
571
Radek Krejci0fe9b512019-07-26 17:51:05 +0200572 if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200573 /* lists with keys, their equivalence is based on their keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +0200574 for (struct lysc_node *key = ((struct lysc_node_list*)node1->schema)->child;
575 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
576 key = key->next) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200577 if (lyd_compare(iter1, iter2, options)) {
578 return LY_ENOT;
579 }
580 iter1 = iter1->next;
581 iter2 = iter2->next;
582 }
583 } else {
584 /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
585
586all_children_compare:
587 if (!iter1 && !iter2) {
588 /* no children, nothing to compare */
589 return LY_SUCCESS;
590 }
591
592 for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
593 if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
594 return LY_ENOT;
595 }
596 }
597 if (iter1 || iter2) {
598 return LY_ENOT;
599 }
600 }
601 return LY_SUCCESS;
602 case LYS_ANYXML:
603 case LYS_ANYDATA:
604 any1 = (struct lyd_node_any*)node1;
605 any2 = (struct lyd_node_any*)node2;
606
607 if (any1->value_type != any2->value_type) {
608 return LY_ENOT;
609 }
610 switch (any1->value_type) {
611 case LYD_ANYDATA_DATATREE:
612 iter1 = any1->value.tree;
613 iter2 = any2->value.tree;
614 goto all_children_compare;
615 case LYD_ANYDATA_STRING:
616 case LYD_ANYDATA_XML:
617 case LYD_ANYDATA_JSON:
618 len1 = strlen(any1->value.str);
619 len2 = strlen(any2->value.str);
620 if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
621 return LY_ENOT;
622 }
623 return LY_SUCCESS;
624#if 0 /* TODO LYB format */
625 case LYD_ANYDATA_LYB:
626 int len1 = lyd_lyb_data_length(any1->value.mem);
627 int len2 = lyd_lyb_data_length(any2->value.mem);
628 if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
629 return LY_ENOT;
630 }
631 return LY_SUCCESS;
632#endif
633 }
634 }
635
636 LOGINT(node1->schema->module->ctx);
637 return LY_EINT;
638}
Radek Krejci22ebdba2019-07-25 13:59:43 +0200639
640/**
641 * @brief Duplicates just a single node and interconnect it into a @p parent (if present) and after the @p prev
642 * sibling (if present).
643 *
644 * Ignores LYD_DUP_WITH_PARENTS and LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
645 */
646static struct lyd_node *
647lyd_dup_recursive(const struct lyd_node *node, struct lyd_node_inner *parent, struct lyd_node *prev, int options)
648{
649 struct ly_ctx *ctx;
650 struct lyd_node *dup = NULL;
651
652 LY_CHECK_ARG_RET(NULL, node, NULL);
653 ctx = node->schema->module->ctx;
654
655 switch (node->schema->nodetype) {
656 case LYS_ACTION:
657 case LYS_NOTIF:
658 case LYS_CONTAINER:
659 case LYS_LIST:
660 dup = calloc(1, sizeof(struct lyd_node_inner));
661 break;
662 case LYS_LEAF:
663 case LYS_LEAFLIST:
664 dup = calloc(1, sizeof(struct lyd_node_term));
665 break;
666 case LYS_ANYDATA:
667 case LYS_ANYXML:
668 dup = calloc(1, sizeof(struct lyd_node_any));
669 break;
670 default:
671 LOGINT(ctx);
672 goto error;
673 }
674
675 /* TODO implement LYD_DUP_WITH_WHEN */
676 dup->flags = node->flags;
677 dup->schema = node->schema;
678
679 /* interconnect the node at the end */
680 dup->parent = parent;
681 if (prev) {
682 dup->prev = prev;
683 prev->next = dup;
684 } else {
685 dup->prev = dup;
686 if (parent) {
687 parent->child = dup;
688 }
689 }
690 if (parent) {
691 parent->child->prev = dup;
692 } else if (prev) {
693 struct lyd_node *first;
694 for (first = prev; first->prev != prev; first = first->prev);
695 first->prev = dup;
696 }
697
698 /* TODO duplicate attributes, implement LYD_DUP_NO_ATTR */
699
700 /* nodetype-specific work */
701 if (dup->schema->nodetype & LYD_NODE_TERM) {
702 struct lyd_node_term *term = (struct lyd_node_term*)dup;
703 struct lyd_node_term *orig = (struct lyd_node_term*)node;
704
705 term->hash = orig->hash;
706 term->value.realtype = orig->value.realtype;
707 LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(ctx, &orig->value, &term->value),
708 LOGERR(ctx, LY_EINT, "Value duplication failed."), error);
709 } else if (dup->schema->nodetype & LYD_NODE_INNER) {
710 struct lyd_node_inner *inner = (struct lyd_node_inner*)dup;
711 struct lyd_node_inner *orig = (struct lyd_node_inner*)node;
712 struct lyd_node *child, *last = NULL;
713
714 if (options & LYD_DUP_RECURSIVE) {
715 /* duplicate all the children */
716 LY_LIST_FOR(orig->child, child) {
717 last = lyd_dup_recursive(child, inner, last, options);
718 LY_CHECK_GOTO(!last, error);
719 }
Radek Krejci0fe9b512019-07-26 17:51:05 +0200720 } else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +0200721 /* always duplicate keys of a list */
Radek Krejci22ebdba2019-07-25 13:59:43 +0200722 child = orig->child;
Radek Krejci0fe9b512019-07-26 17:51:05 +0200723 for (struct lysc_node *key = ((struct lysc_node_list*)dup->schema)->child;
724 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
725 key = key->next) {
Radek Krejci22ebdba2019-07-25 13:59:43 +0200726 if (!child) {
727 /* possibly not keys are present in filtered tree */
728 break;
Radek Krejci0fe9b512019-07-26 17:51:05 +0200729 } else if (child->schema != key) {
730 /* possibly not all keys are present in filtered tree,
731 * but there can be also some non-key nodes */
732 continue;
Radek Krejci22ebdba2019-07-25 13:59:43 +0200733 }
734 last = lyd_dup_recursive(child, inner, last, options);
735 child = child->next;
736 }
737 }
738 lyd_hash(dup);
739 } else if (dup->schema->nodetype & LYD_NODE_ANY) {
740 struct lyd_node_any *any = (struct lyd_node_any*)dup;
741 struct lyd_node_any *orig = (struct lyd_node_any*)node;
742
743 any->hash = orig->hash;
744 any->value_type = orig->value_type;
745 switch (any->value_type) {
746 case LYD_ANYDATA_DATATREE:
747 if (orig->value.tree) {
748 any->value.tree = lyd_dup(orig->value.tree, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_SIBLINGS);
749 LY_CHECK_GOTO(!any->value.tree, error);
750 }
751 break;
752 case LYD_ANYDATA_STRING:
753 case LYD_ANYDATA_XML:
754 case LYD_ANYDATA_JSON:
755 if (orig->value.str) {
756 any->value.str = lydict_insert(ctx, orig->value.str, strlen(orig->value.str));
757 }
758 break;
759 }
760 }
761
762 lyd_insert_hash(dup);
763 return dup;
764
765error:
766 if (!parent && !prev) {
767 lyd_free_tree(dup);
768 }
769 return NULL;
770}
771
772API struct lyd_node *
773lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
774{
775 struct ly_ctx *ctx;
776 const struct lyd_node *orig; /* original node to be duplicated */
777 struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
778 struct lyd_node *last = NULL; /* the last sibling of the duplicated nodes */
779 struct lyd_node *top = NULL; /* the most higher created node */
780 struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
781 int keyless_parent_list = 0;
782
783 LY_CHECK_ARG_RET(NULL, node, NULL);
784 ctx = node->schema->module->ctx;
785
786 if (options & LYD_DUP_WITH_PARENTS) {
787 struct lyd_node_inner *orig_parent, *iter;
788 int repeat = 1;
789 for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
790 if (parent && parent->schema == orig_parent->schema) {
791 /* stop creating parents, connect what we have into the provided parent */
792 iter = parent;
793 repeat = 0;
794 /* get know if there is a keyless list which we will have to rehash */
795 for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +0200796 if (piter->schema->nodetype == LYS_LIST && (piter->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +0200797 keyless_parent_list = 1;
798 break;
799 }
800 }
801 } else {
802 iter = (struct lyd_node_inner*)lyd_dup_recursive((struct lyd_node*)orig_parent, NULL, NULL, 0);
803 LY_CHECK_GOTO(!iter, error);
804 }
805 if (!local_parent) {
806 local_parent = iter;
807 }
808 if (iter->child) {
809 /* 1) list - add after keys
810 * 2) provided parent with some children */
811 iter->child->prev->next = top;
812 if (top) {
813 top->prev = iter->child->prev;
814 iter->child->prev = top;
815 }
816 } else {
817 iter->child = top;
818 if (iter->schema->nodetype == LYS_LIST) {
819 /* keyless list - we will need to rehash it since we are going to add nodes into it */
820 keyless_parent_list = 1;
821 }
822 }
823 if (top) {
824 top->parent = iter;
825 }
826 top = (struct lyd_node*)iter;
827 }
828 if (repeat && parent) {
829 /* given parent and created parents chain actually do not interconnect */
830 LOGERR(ctx, LY_EINVAL, "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
831 goto error;
832 }
833 } else {
834 local_parent = parent;
835 }
836
837 if (local_parent && local_parent->child) {
838 last = local_parent->child->prev;
839 }
840
841 LY_LIST_FOR(node, orig) {
842 last = lyd_dup_recursive(orig, local_parent, last, options);
843 LY_CHECK_GOTO(!last, error);
844 if (!first) {
845 first = last;
846 }
847
848 if (!(options & LYD_DUP_WITH_SIBLINGS)) {
849 break;
850 }
851 }
852 if (keyless_parent_list) {
853 /* rehash */
854 for (; local_parent; local_parent = local_parent->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +0200855 if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +0200856 lyd_hash((struct lyd_node*)local_parent);
857 }
858 }
859 }
860 return first;
861
862error:
863 if (top) {
864 lyd_free_tree(top);
865 } else {
866 lyd_free_withsiblings(first);
867 }
868 return NULL;
869}
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200870
871static LY_ERR
872lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
873{
Michal Vasko14654712020-02-06 08:35:21 +0100874 /* ending \0 */
875 ++reqlen;
876
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200877 if (reqlen > *buflen) {
878 if (is_static) {
879 return LY_EINCOMPLETE;
880 }
881
882 *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
883 if (!*buffer) {
884 return LY_EMEM;
885 }
886
887 *buflen = reqlen;
888 }
889
890 return LY_SUCCESS;
891}
892
893/**
894 * @brief Append all list key predicates to path.
895 *
896 * @param[in] node Node with keys to print.
897 * @param[in,out] buffer Buffer to print to.
898 * @param[in,out] buflen Current buffer length.
899 * @param[in,out] bufused Current number of characters used in @p buffer.
900 * @param[in] is_static Whether buffer is static or can be reallocated.
901 * @return LY_ERR
902 */
903static LY_ERR
904lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
905{
906 const struct lyd_node *key;
907 int dynamic = 0;
908 size_t len;
909 const char *val;
910 char quot;
911 LY_ERR rc;
912
Michal Vasko14654712020-02-06 08:35:21 +0100913 for (key = lyd_node_children(node); key && (key->schema->flags & LYS_KEY); key = key->next) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200914 val = lyd_value2str((struct lyd_node_term *)key, &dynamic);
915 len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
916 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
917 if (rc != LY_SUCCESS) {
918 if (dynamic) {
919 free((char *)val);
920 }
921 return rc;
922 }
923
924 quot = '\'';
925 if (strchr(val, '\'')) {
926 quot = '"';
927 }
928 *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
929
930 if (dynamic) {
931 free((char *)val);
932 }
933 }
934
935 return LY_SUCCESS;
936}
937
938/**
939 * @brief Append leaf-list value predicate to path.
940 *
941 * @param[in] node Node to print.
942 * @param[in,out] buffer Buffer to print to.
943 * @param[in,out] buflen Current buffer length.
944 * @param[in,out] bufused Current number of characters used in @p buffer.
945 * @param[in] is_static Whether buffer is static or can be reallocated.
946 * @return LY_ERR
947 */
948static LY_ERR
949lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
950{
951 int dynamic = 0;
952 size_t len;
953 const char *val;
954 char quot;
955 LY_ERR rc;
956
957 val = lyd_value2str((struct lyd_node_term *)node, &dynamic);
958 len = 4 + strlen(val) + 2;
959 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
960 if (rc != LY_SUCCESS) {
961 goto cleanup;
962 }
963
964 quot = '\'';
965 if (strchr(val, '\'')) {
966 quot = '"';
967 }
968 *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
969
970cleanup:
971 if (dynamic) {
972 free((char *)val);
973 }
974 return rc;
975}
976
977/**
978 * @brief Append node position (relative to its other instances) predicate to path.
979 *
980 * @param[in] node Node to print.
981 * @param[in,out] buffer Buffer to print to.
982 * @param[in,out] buflen Current buffer length.
983 * @param[in,out] bufused Current number of characters used in @p buffer.
984 * @param[in] is_static Whether buffer is static or can be reallocated.
985 * @return LY_ERR
986 */
987static LY_ERR
988lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
989{
990 const struct lyd_node *first, *iter;
991 size_t len;
992 int pos;
993 char *val = NULL;
994 LY_ERR rc;
995
996 if (node->parent) {
997 first = node->parent->child;
998 } else {
999 for (first = node; node->prev->next; node = node->prev);
1000 }
1001 pos = 1;
1002 for (iter = first; iter != node; iter = iter->next) {
1003 if (iter->schema == node->schema) {
1004 ++pos;
1005 }
1006 }
1007 if (asprintf(&val, "%d", pos) == -1) {
1008 return LY_EMEM;
1009 }
1010
1011 len = 1 + strlen(val) + 1;
1012 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
1013 if (rc != LY_SUCCESS) {
1014 goto cleanup;
1015 }
1016
1017 *bufused += sprintf(*buffer + *bufused, "[%s]", val);
1018
1019cleanup:
1020 free(val);
1021 return rc;
1022}
1023
1024API char *
1025lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
1026{
Michal Vasko14654712020-02-06 08:35:21 +01001027 int is_static = 0, i, depth;
1028 size_t bufused = 0, len;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001029 const struct lyd_node *iter;
1030 const struct lys_module *mod;
1031 LY_ERR rc;
1032
1033 LY_CHECK_ARG_RET(NULL, node, NULL);
1034 if (buffer) {
1035 LY_CHECK_ARG_RET(node->schema->module->ctx, buflen > 1, NULL);
1036 is_static = 1;
Michal Vasko14654712020-02-06 08:35:21 +01001037 } else {
1038 buflen = 0;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001039 }
1040
1041 switch (pathtype) {
Michal Vasko14654712020-02-06 08:35:21 +01001042 case LYD_PATH_LOG:
1043 depth = 1;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001044 for (iter = node; iter->parent; iter = (const struct lyd_node *)iter->parent) {
1045 ++depth;
1046 }
1047
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001048 goto iter_print;
Michal Vasko14654712020-02-06 08:35:21 +01001049 while (depth) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001050 /* find the right node */
Michal Vasko14654712020-02-06 08:35:21 +01001051 for (iter = node, i = 1; i < depth; iter = (const struct lyd_node *)iter->parent, ++i);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001052iter_print:
1053 /* print prefix and name */
1054 mod = NULL;
1055 if (!iter->parent || (iter->schema->module != iter->parent->schema->module)) {
1056 mod = iter->schema->module;
1057 }
1058
1059 /* realloc string */
1060 len = 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(iter->schema->name);
1061 rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
1062 if (rc != LY_SUCCESS) {
1063 break;
1064 }
1065
1066 /* print next node */
1067 bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", iter->schema->name);
1068
1069 switch (iter->schema->nodetype) {
1070 case LYS_LIST:
1071 if (iter->schema->flags & LYS_KEYLESS) {
1072 /* print its position */
1073 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
1074 } else {
1075 /* print all list keys in predicates */
1076 rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
1077 }
1078 break;
1079 case LYS_LEAFLIST:
1080 if (iter->schema->flags & LYS_CONFIG_W) {
1081 /* print leaf-list value */
1082 rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
1083 } else {
1084 /* print its position */
1085 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
1086 }
1087 break;
1088 default:
1089 /* nothing to print more */
1090 rc = LY_SUCCESS;
1091 break;
1092 }
1093 if (rc != LY_SUCCESS) {
1094 break;
1095 }
1096
Michal Vasko14654712020-02-06 08:35:21 +01001097 --depth;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02001098 }
1099 break;
1100 }
1101
1102 return buffer;
1103}
Michal Vaskoe444f752020-02-10 12:20:06 +01001104
1105API struct ly_set *
1106lyd_find_instance(const struct lyd_node *sibling, const struct lysc_node *schema)
1107{
1108 struct ly_set *ret, *ret_aux, *spath;
1109 const struct lysc_node *siter, *sparent;
1110 const struct lyd_node *iter;
1111 unsigned int i, j;
1112
1113 LY_CHECK_ARG_RET(NULL, sibling, schema, NULL);
1114 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1115 LOGARG(schema->module->ctx, schema);
1116 return NULL;
1117 }
1118
1119 ret = ly_set_new();
1120 spath = ly_set_new();
1121 LY_CHECK_ERR_GOTO(!ret || !spath, LOGMEM(schema->module->ctx), error);
1122
1123 /* build schema path until sibling parent */
1124 sparent = sibling->parent ? sibling->parent->schema : NULL;
1125 for (siter = schema; siter && (siter != sparent); siter = siter->parent) {
1126 if (siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC | LYS_ACTION)) {
1127 /* standard data node */
1128 ly_set_add(spath, (void *)siter, LY_SET_OPT_USEASLIST);
1129
1130 } /* else skip the rest node types */
1131 }
1132 /* no valid path */
1133 LY_CHECK_GOTO(!spath->count, error);
1134
1135 /* start searching */
1136 LY_LIST_FOR(sibling, iter) {
1137 if (iter->schema == spath->objs[spath->count - 1]) {
1138 ly_set_add(ret, (void *)iter, LY_SET_OPT_USEASLIST);
1139 }
1140 }
1141 for (i = spath->count - 1; i; i--) {
1142 if (!ret->count) {
1143 /* nothing found */
1144 break;
1145 }
1146
1147 ret_aux = ly_set_new();
1148 LY_CHECK_ERR_GOTO(!ret_aux, LOGMEM(schema->module->ctx), error);
1149 for (j = 0; j < ret->count; j++) {
1150 LY_LIST_FOR(lyd_node_children(ret->objs[j]), iter) {
1151 if (iter->schema == spath->objs[i - 1]) {
1152 ly_set_add(ret_aux, (void *)iter, LY_SET_OPT_USEASLIST);
1153 }
1154 }
1155 }
1156 ly_set_free(ret, NULL);
1157 ret = ret_aux;
1158 }
1159
1160 ly_set_free(spath, NULL);
1161 return ret;
1162
1163error:
1164 ly_set_free(ret, NULL);
1165 ly_set_free(spath, NULL);
1166
1167 return NULL;
1168}
1169
1170static char *
1171lyd_keys_parse_next(char **next_key, char **key_name)
1172{
1173 char *ptr, *ptr2, *val, quot;
1174
1175 ptr = *next_key;
1176
1177 /* "[" */
1178 LY_CHECK_GOTO(ptr[0] != '[', error);
1179 ++ptr;
1180
1181 /* key name */
1182 ptr2 = strchr(ptr, '=');
1183 LY_CHECK_GOTO(!ptr2, error);
1184
1185 *key_name = ptr;
1186 ptr2[0] = '\0';
1187
1188 /* \0, was '=' */
1189 ptr = ptr2 + 1;
1190
1191 /* quote */
1192 LY_CHECK_GOTO((ptr[0] != '\'') && (ptr[0] != '\"'), error);
1193 quot = ptr[0];
1194 ++ptr;
1195
1196 /* value, terminate it */
1197 val = ptr;
1198 ptr2 = strchr(ptr, quot);
1199 LY_CHECK_GOTO(!ptr2, error);
1200 ptr2[0] = '\0';
1201
1202 /* \0, was quote */
1203 ptr = ptr2 + 1;
1204
1205 /* "]" */
1206 LY_CHECK_GOTO(ptr[0] != ']', error);
1207 ++ptr;
1208
1209 *next_key = ptr;
1210 return val;
1211
1212error:
1213 LOGERR(NULL, LY_EINVAL, "Invalid arguments - keys at \"%s\" (%s()).", ptr, __func__);
1214 return NULL;
1215}
1216
1217static void
1218ly_keys_clean(struct ly_keys *keys)
1219{
1220 size_t i;
1221
1222 for (i = 0; i < keys->key_count; ++i) {
1223 lydict_remove(keys->keys[i].schema->module->ctx, keys->keys[i].can_val);
1224 }
1225 free(keys->str);
1226 free(keys->keys);
1227}
1228
1229static LY_ERR
1230lyd_value_canonize(const struct lysc_node *schema, const char *value, size_t val_len, const char **can_val)
1231{
1232 LY_ERR rc = LY_SUCCESS;
1233 struct lysc_type *type;
1234 struct ly_err_item *err;
1235
1236 assert(schema->nodetype & (LYS_LEAF | LYS_LEAFLIST));
1237
1238 if (!val_len) {
1239 val_len = strlen(value);
1240 }
1241
1242 /* check canonical value exists */
1243 type = (struct lysc_type *)&((struct lysc_node_leaf *)schema)->type;
1244 if (!type->plugin->has_canon(type)) {
1245 LOGERR(schema->module->ctx, LY_EINVAL, "Key \"%s\" has no canonical value.", schema->name);
1246 return LY_EINVAL;
1247 }
1248
1249 /* make the value canonical */
1250 rc = type->plugin->store(schema->module->ctx, type, value, val_len, LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_SCHEMA,
1251 NULL, NULL, 0, NULL, NULL, NULL, can_val, &err);
1252 if (rc != LY_SUCCESS) {
1253 ly_err_print(err);
1254 ly_err_free(err);
1255 return rc;
1256 }
1257
1258 return LY_SUCCESS;
1259}
1260
1261static LY_ERR
1262ly_keys_parse(const struct lysc_node *list, const char *keys_str, size_t keys_len, int canonize, struct ly_keys *keys)
1263{
1264 LY_ERR rc = LY_SUCCESS;
1265 char *next_key, *name;
1266 const struct lysc_node *key;
1267
1268 assert(list->nodetype == LYS_LIST);
1269
1270 memset(keys, 0, sizeof *keys);
1271
1272 keys->str = strndup(keys_str, keys_len ? keys_len : strlen(keys_str));
1273 LY_CHECK_ERR_GOTO(!keys->str, LOGMEM(list->module->ctx); rc = LY_EMEM, cleanup);
1274
1275 next_key = keys->str;
1276 while (next_key[0]) {
1277 /* new key */
1278 keys->keys = ly_realloc(keys->keys, (keys->key_count + 1) * sizeof *keys->keys);
1279 LY_CHECK_ERR_GOTO(!keys->keys, LOGMEM(list->module->ctx); rc = LY_EMEM, cleanup);
1280
1281 /* fill */
1282 keys->keys[keys->key_count].value = lyd_keys_parse_next(&next_key, &name);
1283
1284 /* find schema node */
1285 key = lys_find_child(list, list->module, name, 0, LYS_LEAF, 0);
1286 if (!key) {
1287 LOGERR(list->module->ctx, LY_EINVAL, "Node \"%s\" has no key \"%s\".", list->name, name);
1288 rc = LY_EINVAL;
1289 goto cleanup;
1290 }
1291 keys->keys[keys->key_count].schema = (const struct lysc_node_leaf *)key;
1292
1293 if (canonize) {
1294 /* canonize the value */
1295 rc = lyd_value_canonize(key, keys->keys[keys->key_count].value, 0, &keys->keys[keys->key_count].can_val);
1296 LY_CHECK_GOTO(rc != LY_SUCCESS, cleanup);
1297 }
1298
1299 /* another valid key */
1300 ++keys->key_count;
1301 }
1302
1303cleanup:
1304 ly_keys_clean(keys);
1305 return rc;
1306}
1307
1308API LY_ERR
1309lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name, size_t name_len,
1310 const char *key_or_value, size_t val_len, struct lyd_node **match)
1311{
1312 LY_ERR rc;
1313 const struct lyd_node *node = NULL;
1314 struct lyd_node_term *term;
1315 const struct lysc_node *schema;
1316 struct ly_keys keys = {0};
1317 const char *value = NULL, *node_val;
1318 size_t i;
1319 int dynamic;
1320
1321 LY_CHECK_ARG_RET(NULL, module, name, LY_EINVAL);
1322
1323 if (!first) {
1324 /* no data */
1325 *match = NULL;
1326 return LY_ENOTFOUND;
1327 }
1328
1329 /* find schema */
1330 schema = lys_find_child(first->parent ? first->parent->schema : NULL, module, name, name_len, 0, 0);
1331 if (!schema) {
1332 LOGERR(module->ctx, LY_EINVAL, "Schema node not found.");
1333 return LY_EINVAL;
1334 }
1335
1336 if (key_or_value && !val_len) {
1337 val_len = strlen(key_or_value);
1338 }
1339
1340 if (key_or_value && (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
1341 /* canonize the value */
1342 LY_CHECK_GOTO(rc = lyd_value_canonize(schema, key_or_value, val_len, &value), cleanup);
1343 } else if (key_or_value && (schema->nodetype == LYS_LIST)) {
1344 /* parse keys into canonical values */
1345 LY_CHECK_GOTO(rc = ly_keys_parse(schema, key_or_value, val_len, 1, &keys), cleanup);
1346 }
1347
1348 /* find first matching value */
1349 LY_LIST_FOR(first, node) {
1350 if (node->schema != schema) {
1351 continue;
1352 }
1353
1354 if ((schema->nodetype == LYS_LIST) && keys.str) {
1355 /* compare all set keys */
1356 for (i = 0; i < keys.key_count; ++i) {
1357 /* find key */
1358 rc = lyd_find_sibling_val(lyd_node_children(node), (struct lysc_node *)keys.keys[i].schema, NULL, 0,
1359 (struct lyd_node **)&term);
1360 if (rc == LY_ENOTFOUND) {
1361 /* all keys must always exist */
1362 LOGINT_RET(module->ctx);
1363 }
1364 LY_CHECK_GOTO(rc, cleanup);
1365
1366 /* compare values */
1367 node_val = term->value.realtype->plugin->print(&term->value, 0, NULL, NULL, &dynamic);
1368 assert(!dynamic);
1369 if (strcmp(node_val, keys.keys[i].can_val)) {
1370 break;
1371 }
1372 }
1373
1374 if (i < keys.key_count) {
1375 /* not a match */
1376 continue;
1377 }
1378 } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && value) {
1379 term = (struct lyd_node_term *)node;
1380
1381 /* compare values */
1382 node_val = term->value.realtype->plugin->print(&term->value, 0, NULL, NULL, &dynamic);
1383 assert(!dynamic);
1384 if (strcmp(node_val, value)) {
1385 /* not a match */
1386 continue;
1387 }
1388 }
1389
1390 /* all criteria passed */
1391 break;
1392 }
1393
1394 if (!node) {
1395 rc = LY_ENOTFOUND;
1396 *match = NULL;
1397 goto cleanup;
1398 }
1399
1400 /* success */
1401 *match = (struct lyd_node *)node;
1402 rc = LY_SUCCESS;
1403
1404cleanup:
1405 ly_keys_clean(&keys);
1406 lydict_remove(module->ctx, value);
1407 return rc;
1408}
1409
1410API LY_ERR
1411lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
1412{
1413 struct lyd_node **match_p;
1414 struct lyd_node_inner *parent;
1415
1416 LY_CHECK_ARG_RET(NULL, target, match, LY_EINVAL);
1417
1418 if (!siblings) {
1419 /* no data */
1420 *match = NULL;
1421 return LY_ENOTFOUND;
1422 }
1423
1424 /* find first sibling */
1425 if (siblings->parent) {
1426 siblings = siblings->parent->child;
1427 } else {
1428 while (siblings->prev->next) {
1429 siblings = siblings->prev;
1430 }
1431 }
1432
1433 parent = (struct lyd_node_inner *)siblings->parent;
1434 if (parent && parent->children_ht) {
1435 assert(target->hash);
1436
1437 /* find by hash */
1438 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
1439 siblings = *match_p;
1440 } else {
1441 /* not found */
1442 siblings = NULL;
1443 }
1444 } else {
1445 /* no children hash table */
1446 for (; siblings; siblings = siblings->next) {
1447 if (!lyd_compare(siblings, target, 0)) {
1448 break;
1449 }
1450 }
1451 }
1452
1453 if (!siblings) {
1454 *match = NULL;
1455 return LY_ENOTFOUND;
1456 }
1457
1458 *match = (struct lyd_node *)siblings;
1459 return LY_SUCCESS;
1460}
1461
1462API LY_ERR
1463lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
1464{
1465 struct lyd_node_inner *parent;
1466 struct lyd_node *match;
1467 struct lyd_node **match_p;
1468 struct ly_set *ret;
1469
1470 LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
1471
1472 if (!siblings) {
1473 /* no data */
1474 return LY_ENOTFOUND;
1475 }
1476
1477 ret = ly_set_new();
1478 LY_CHECK_ERR_RET(!ret, LOGMEM(target->schema->module->ctx), LY_EMEM);
1479
1480 /* find first sibling */
1481 if (siblings->parent) {
1482 siblings = siblings->parent->child;
1483 } else {
1484 while (siblings->prev->next) {
1485 siblings = siblings->prev;
1486 }
1487 }
1488
1489 parent = (struct lyd_node_inner *)siblings->parent;
1490 if (parent && parent->children_ht) {
1491 assert(target->hash);
1492
1493 /* find by hash */
1494 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
1495 match = *match_p;
1496 } else {
1497 /* not found */
1498 match = NULL;
1499 }
1500 while (match) {
1501 /* add all found nodes into the return set */
1502 if (ly_set_add(ret, match, LY_SET_OPT_USEASLIST) == -1) {
1503 goto error;
1504 }
1505
1506 /* find next instance */
1507 if (lyht_find_next(parent->children_ht, &match, match->hash, (void **)&match_p)) {
1508 match = NULL;
1509 } else {
1510 match = *match_p;
1511 }
1512 }
1513 } else {
1514 /* no children hash table */
1515 for (; siblings; siblings = siblings->next) {
1516 if (!lyd_compare(siblings, target, 0)) {
1517 /* a match */
1518 if (ly_set_add(ret, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
1519 goto error;
1520 }
1521 }
1522 }
1523 }
1524
1525 if (!ret->count) {
1526 ly_set_free(ret, NULL);
1527 return LY_ENOTFOUND;
1528 }
1529
1530 *set = ret;
1531 return LY_SUCCESS;
1532
1533error:
1534 ly_set_free(ret, NULL);
1535 return LY_EMEM;
1536}
1537
1538API LY_ERR
1539lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
1540 size_t val_len, struct lyd_node **match)
1541{
1542 LY_ERR rc;
1543 struct lyd_node *target = NULL;
1544
1545 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
1546 if ((schema->nodetype == LYS_LIST) && schema->flags & LYS_KEYLESS) {
1547 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
1548 return LY_EINVAL;
1549 } else if ((schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && !key_or_value) {
1550 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - no value/keys for a (leaf-)list (%s()).", __func__);
1551 return LY_EINVAL;
1552 } else if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1553 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
1554 lys_nodetype2str(schema->nodetype), __func__);
1555 return LY_EINVAL;
1556 }
1557
1558 if (!siblings) {
1559 /* no data */
1560 *match = NULL;
1561 return LY_ENOTFOUND;
1562 }
1563
1564 /* create data node */
1565 switch (schema->nodetype) {
1566 case LYS_CONTAINER:
1567 case LYS_ANYXML:
1568 case LYS_ANYDATA:
1569 case LYS_NOTIF:
1570 case LYS_RPC:
1571 /* target used attributes: schema, hash */
1572 //TODO target = lyd_create(schema, 0);
1573 LY_CHECK_RET(!target, LY_EMEM);
1574 break;
1575 case LYS_LEAF:
1576 /* target used attributes: schema, hash */
1577 //TODO target = lyd_create_term(schema, NULL, 0, 0);
1578 LY_CHECK_RET(!target, LY_EMEM);
1579 break;
1580 case LYS_LEAFLIST:
1581 /* target used attributes: schema, hash, value */
1582 //TODO target = lyd_create_term(schema, key_or_value, val_len, 0);
1583 LY_CHECK_RET(!target, LY_EMEM);
1584 break;
1585 case LYS_LIST:
1586 /* target used attributes: schema, hash, child (all keys) */
1587 //TODO target = lyd_create_list(schema, key_or_value, val_len);
1588 LY_CHECK_RET(!target, LY_EMEM);
1589 break;
1590 default:
1591 /* unreachable */
1592 LOGINT(schema->module->ctx);
1593 return LY_EINT;
1594 }
1595
1596 /* find it */
1597 rc = lyd_find_sibling_first(siblings, target, match);
1598
1599 lyd_free_tree(target);
1600 return rc;
1601}