blob: b7e695e30ac27e8aa59d9c37d77b96b9e82a3222 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
Michal Vaskob1b5c262020-03-05 14:29:47 +01002 * @file tree_data.c
Radek Krejcie7b95092019-05-15 11:03:07 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Schema tree implementation
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Michal Vaskod86997b2020-05-26 15:19:54 +020014#define _POSIX_C_SOURCE 200809L /* strndup */
Radek Krejcie7b95092019-05-15 11:03:07 +020015
16#include "common.h"
17
Radek Krejci084289f2019-07-09 17:35:30 +020018#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019#include <ctype.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <stdarg.h>
23#include <stdint.h>
24#include <string.h>
25#include <unistd.h>
26
27#include "log.h"
28#include "tree.h"
29#include "tree_data.h"
30#include "tree_data_internal.h"
Michal Vaskod3678892020-05-21 10:06:58 +020031#include "tree_schema_internal.h"
Michal Vasko90932a92020-02-12 14:33:03 +010032#include "hash_table.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020033#include "tree_schema.h"
Michal Vaskod3678892020-05-21 10:06:58 +020034#include "xpath.h"
Michal Vasko52927e22020-03-16 17:26:14 +010035#include "xml.h"
Radek Krejci38d85362019-09-05 16:26:38 +020036#include "plugins_exts_metadata.h"
Michal Vasko90932a92020-02-12 14:33:03 +010037#include "plugins_exts_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020038
Michal Vaskoe444f752020-02-10 12:20:06 +010039struct ly_keys {
40 char *str;
41 struct {
42 const struct lysc_node_leaf *schema;
43 char *value;
Michal Vasko90932a92020-02-12 14:33:03 +010044 struct lyd_value val;
Michal Vaskoe444f752020-02-10 12:20:06 +010045 } *keys;
46 size_t key_count;
47};
48
Radek Krejci084289f2019-07-09 17:35:30 +020049LY_ERR
Michal Vasko90932a92020-02-12 14:33:03 +010050lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second,
Michal Vaskof03ed032020-03-04 13:31:44 +010051 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +020052{
Michal Vasko90932a92020-02-12 14:33:03 +010053 LY_ERR ret = LY_SUCCESS;
Radek Krejci084289f2019-07-09 17:35:30 +020054 struct ly_err_item *err = NULL;
55 struct ly_ctx *ctx;
56 struct lysc_type *type;
Radek Krejci3c9758d2019-07-11 16:49:10 +020057 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
Michal Vaskof03ed032020-03-04 13:31:44 +010058 (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +020059 assert(node);
60
61 ctx = node->schema->module->ctx;
Radek Krejci084289f2019-07-09 17:35:30 +020062
Radek Krejci73dead22019-07-11 16:46:16 +020063 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci62903c32019-07-15 14:42:05 +020064 if (!second) {
65 node->value.realtype = type;
66 }
Michal Vasko90932a92020-02-12 14:33:03 +010067 ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
Michal Vaskof03ed032020-03-04 13:31:44 +010068 tree ? (void *)node : (void *)node->schema, tree,
Radek Krejci73dead22019-07-11 16:46:16 +020069 &node->value, NULL, &err);
Michal Vasko90932a92020-02-12 14:33:03 +010070 if (ret && (ret != LY_EINCOMPLETE)) {
Radek Krejci73dead22019-07-11 16:46:16 +020071 if (err) {
Michal Vasko3544d1e2020-05-27 11:17:51 +020072 /* node may not be connected yet so use the schema node */
Michal Vaskof872e202020-05-27 11:49:06 +020073 if (!node->parent && lysc_data_parent(node->schema)) {
74 LOGVAL(ctx, LY_VLOG_LYSC, node->schema, err->vecode, err->msg);
75 } else {
76 LOGVAL(ctx, LY_VLOG_LYD, node, err->vecode, err->msg);
77 }
Radek Krejci73dead22019-07-11 16:46:16 +020078 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +020079 }
Radek Krejci73dead22019-07-11 16:46:16 +020080 goto error;
Michal Vasko90932a92020-02-12 14:33:03 +010081 } else if (dynamic) {
82 *dynamic = 0;
Radek Krejci084289f2019-07-09 17:35:30 +020083 }
84
85error:
86 return ret;
87}
88
Michal Vasko90932a92020-02-12 14:33:03 +010089/* similar to lyd_value_parse except can be used just to store the value, hence does also not support a second call */
90static LY_ERR
91lyd_value_store(struct lyd_value *val, const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
92 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format)
93{
94 LY_ERR ret = LY_SUCCESS;
95 struct ly_err_item *err = NULL;
96 struct ly_ctx *ctx;
97 struct lysc_type *type;
98 int options = LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA | (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0);
99
100 assert(val && schema && (schema->nodetype & LYD_NODE_TERM));
101
102 ctx = schema->module->ctx;
103 type = ((struct lysc_node_leaf *)schema)->type;
104 val->realtype = type;
105 ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format, (void *)schema, NULL,
106 val, NULL, &err);
107 if (ret == LY_EINCOMPLETE) {
108 /* this is fine, we do not need it resolved */
109 ret = LY_SUCCESS;
110 } else if (ret && err) {
111 ly_err_print(err);
112 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
113 ly_err_free(err);
114 }
115 if (!ret && dynamic) {
116 *dynamic = 0;
117 }
118
119 return ret;
120}
121
Radek Krejci38d85362019-09-05 16:26:38 +0200122LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100123lyd_value_parse_meta(struct ly_ctx *ctx, struct lyd_meta *meta, const char *value, size_t value_len, int *dynamic,
Michal Vasko8d544252020-03-02 10:19:52 +0100124 int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
Michal Vaskof03ed032020-03-04 13:31:44 +0100125 const struct lysc_node *ctx_snode, const struct lyd_node *tree)
Radek Krejci38d85362019-09-05 16:26:38 +0200126{
Michal Vasko90932a92020-02-12 14:33:03 +0100127 LY_ERR ret = LY_SUCCESS;
Radek Krejci38d85362019-09-05 16:26:38 +0200128 struct ly_err_item *err = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200129 struct lyext_metadata *ant;
130 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
Michal Vaskof03ed032020-03-04 13:31:44 +0100131 (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci38d85362019-09-05 16:26:38 +0200132
Michal Vasko9f96a052020-03-10 09:41:45 +0100133 assert(ctx && meta && ((tree && meta->parent) || ctx_snode));
Michal Vasko8d544252020-03-02 10:19:52 +0100134
Michal Vasko9f96a052020-03-10 09:41:45 +0100135 ant = meta->annotation->data;
Radek Krejci38d85362019-09-05 16:26:38 +0200136
137 if (!second) {
Michal Vasko9f96a052020-03-10 09:41:45 +0100138 meta->value.realtype = ant->type;
Radek Krejci38d85362019-09-05 16:26:38 +0200139 }
Michal Vasko90932a92020-02-12 14:33:03 +0100140 ret = ant->type->plugin->store(ctx, ant->type, value, value_len, options, get_prefix, parser, format,
Michal Vasko9f96a052020-03-10 09:41:45 +0100141 tree ? (void *)meta->parent : (void *)ctx_snode, tree, &meta->value, NULL, &err);
Michal Vasko90932a92020-02-12 14:33:03 +0100142 if (ret && (ret != LY_EINCOMPLETE)) {
Radek Krejci38d85362019-09-05 16:26:38 +0200143 if (err) {
144 ly_err_print(err);
145 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
146 ly_err_free(err);
147 }
148 goto error;
Michal Vasko90932a92020-02-12 14:33:03 +0100149 } else if (dynamic) {
150 *dynamic = 0;
Radek Krejci38d85362019-09-05 16:26:38 +0200151 }
152
153error:
154 return ret;
155}
156
Radek Krejci084289f2019-07-09 17:35:30 +0200157API LY_ERR
Michal Vasko44685da2020-03-17 15:38:06 +0100158lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
Radek Krejci084289f2019-07-09 17:35:30 +0200159 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format)
160{
161 LY_ERR rc = LY_SUCCESS;
162 struct ly_err_item *err = NULL;
163 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200164
165 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
166
167 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
168 LOGARG(ctx, node);
169 return LY_EINVAL;
170 }
171
172 type = ((struct lysc_node_leaf*)node)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200173 /* just validate, no storing of enything */
174 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, LY_TYPE_OPTS_INCOMPLETE_DATA,
175 get_prefix, get_prefix_data, format, node, NULL, NULL, NULL, &err);
176 if (rc == LY_EINCOMPLETE) {
177 /* actually success since we do not provide the context tree and call validation with
178 * LY_TYPE_OPTS_INCOMPLETE_DATA */
179 rc = LY_SUCCESS;
180 } else if (rc && err) {
181 if (ctx) {
182 /* log only in case the ctx was provided as input parameter */
183 ly_err_print(err);
184 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200185 }
Radek Krejci73dead22019-07-11 16:46:16 +0200186 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200187 }
188
189 return rc;
190}
191
192API LY_ERR
Michal Vasko44685da2020-03-17 15:38:06 +0100193lyd_value_validate(const struct ly_ctx *ctx, const struct lyd_node_term *node, const char *value, size_t value_len,
Michal Vaskof03ed032020-03-04 13:31:44 +0100194 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +0200195{
196 LY_ERR rc;
197 struct ly_err_item *err = NULL;
198 struct lysc_type *type;
Michal Vaskof03ed032020-03-04 13:31:44 +0100199 int options = (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200200
201 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
202
203 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200204 rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
Michal Vaskof03ed032020-03-04 13:31:44 +0100205 get_prefix, get_prefix_data, format, tree ? (void*)node : (void*)node->schema, tree,
Radek Krejci73dead22019-07-11 16:46:16 +0200206 NULL, NULL, &err);
207 if (rc == LY_EINCOMPLETE) {
208 return rc;
209 } else if (rc) {
210 if (err) {
211 if (ctx) {
212 ly_err_print(err);
213 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200214 }
Radek Krejci73dead22019-07-11 16:46:16 +0200215 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200216 }
Radek Krejci73dead22019-07-11 16:46:16 +0200217 return rc;
Radek Krejci084289f2019-07-09 17:35:30 +0200218 }
219
220 return LY_SUCCESS;
221}
222
223API LY_ERR
224lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
Michal Vaskof03ed032020-03-04 13:31:44 +0100225 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +0200226{
227 LY_ERR ret = LY_SUCCESS, rc;
228 struct ly_err_item *err = NULL;
229 struct ly_ctx *ctx;
230 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200231 struct lyd_value data = {0};
Michal Vaskof03ed032020-03-04 13:31:44 +0100232 int options = LY_TYPE_OPTS_STORE | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200233
234 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
235
236 ctx = node->schema->module->ctx;
237 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200238 rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, get_prefix_data, format, (struct lyd_node*)node,
Michal Vaskof03ed032020-03-04 13:31:44 +0100239 tree, &data, NULL, &err);
Radek Krejci73dead22019-07-11 16:46:16 +0200240 if (rc == LY_EINCOMPLETE) {
241 ret = rc;
242 /* continue with comparing, just remember what to return if storing is ok */
243 } else if (rc) {
244 /* value to compare is invalid */
245 ret = LY_EINVAL;
246 if (err) {
247 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200248 }
Radek Krejci73dead22019-07-11 16:46:16 +0200249 goto cleanup;
Radek Krejci084289f2019-07-09 17:35:30 +0200250 }
251
252 /* compare data */
Radek Krejci5af04842019-07-12 11:32:07 +0200253 if (type->plugin->compare(&node->value, &data)) {
254 /* do not assign it directly from the compare callback to keep possible LY_EINCOMPLETE from validation */
255 ret = LY_EVALID;
256 }
Radek Krejci084289f2019-07-09 17:35:30 +0200257
258cleanup:
Radek Krejci62903c32019-07-15 14:42:05 +0200259 type->plugin->free(ctx, &data);
Radek Krejci084289f2019-07-09 17:35:30 +0200260
261 return ret;
262}
263
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200264API const char *
265lyd_value2str(const struct lyd_node_term *node, int *dynamic)
266{
267 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, dynamic, NULL);
268
269 return node->value.realtype->plugin->print(&node->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
270}
271
272API const char *
Michal Vasko9f96a052020-03-10 09:41:45 +0100273lyd_meta2str(const struct lyd_meta *meta, int *dynamic)
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200274{
Michal Vasko9f96a052020-03-10 09:41:45 +0100275 LY_CHECK_ARG_RET(meta ? meta->parent->schema->module->ctx : NULL, meta, dynamic, NULL);
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200276
Michal Vasko9f96a052020-03-10 09:41:45 +0100277 return meta->value.realtype->plugin->print(&meta->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
Michal Vasko5ec7cda2019-09-11 13:43:08 +0200278}
279
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200280API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100281lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200282{
Radek Krejcie7b95092019-05-15 11:03:07 +0200283 struct lyd_node *result = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200284#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200285 const char *yang_data_name = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200286#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200287
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200288 LY_CHECK_ARG_RET(ctx, ctx, NULL);
289
Michal Vasko5b37a352020-03-06 13:38:33 +0100290 if ((options & LYD_OPT_PARSE_ONLY) && (options & LYD_VALOPT_MASK)) {
291 LOGERR(ctx, LY_EINVAL, "Passing validation flags with LYD_OPT_PARSE_ONLY is not allowed.");
292 return NULL;
293 }
294
Michal Vaskoa3881362020-01-21 15:57:35 +0100295#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200296 if (options & LYD_OPT_RPCREPLY) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200297 /* first item in trees is mandatory - the RPC/action request */
298 LY_CHECK_ARG_RET(ctx, trees, LY_ARRAY_SIZE(trees) >= 1, NULL);
299 if (!trees[0] || trees[0]->parent || !(trees[0]->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
300 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
301 lyd_parse_options_type2str(options));
Radek Krejcie7b95092019-05-15 11:03:07 +0200302 return NULL;
303 }
304 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200305
Radek Krejcie7b95092019-05-15 11:03:07 +0200306 if (options & LYD_OPT_DATA_TEMPLATE) {
307 yang_data_name = va_arg(ap, const char *);
308 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200309#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200310
311 if (!format) {
312 /* TODO try to detect format from the content */
313 }
314
315 switch (format) {
316 case LYD_XML:
Michal Vasko9f96a052020-03-10 09:41:45 +0100317 lyd_parse_xml_data(ctx, data, options, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200318 break;
319#if 0
320 case LYD_JSON:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200321 lyd_parse_json(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200322 break;
323 case LYD_LYB:
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200324 lyd_parse_lyb(ctx, data, options, trees, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200325 break;
326#endif
Michal Vasko52927e22020-03-16 17:26:14 +0100327 case LYD_SCHEMA:
Radek Krejcie7b95092019-05-15 11:03:07 +0200328 LOGINT(ctx);
329 break;
330 }
331
Radek Krejcie7b95092019-05-15 11:03:07 +0200332 return result;
333}
334
335API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100336lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200337{
338 struct lyd_node *result;
339 size_t length;
340 char *addr;
341
342 LY_CHECK_ARG_RET(ctx, ctx, NULL);
343 if (fd < 0) {
344 LOGARG(ctx, fd);
345 return NULL;
346 }
347
348 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
Michal Vaskoa3881362020-01-21 15:57:35 +0100349 result = lyd_parse_mem(ctx, addr ? addr : "", format, options);
Radek Krejcidf3da792019-05-17 10:32:24 +0200350 if (addr) {
351 ly_munmap(addr, length);
352 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200353
354 return result;
355}
356
357API struct lyd_node *
Michal Vaskoa3881362020-01-21 15:57:35 +0100358lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200359{
360 int fd;
361 struct lyd_node *result;
362 size_t len;
Radek Krejcie7b95092019-05-15 11:03:07 +0200363
364 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
365
366 fd = open(path, O_RDONLY);
367 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
368
369 if (!format) {
370 /* unknown format - try to detect it from filename's suffix */
371 len = strlen(path);
372
373 /* ignore trailing whitespaces */
374 for (; len > 0 && isspace(path[len - 1]); len--);
375
376 if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
377 format = LYD_XML;
378#if 0
379 } else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
380 format = LYD_JSON;
381 } else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
382 format = LYD_LYB;
383#endif
384 } /* else still unknown, try later to detect it from the content */
385 }
386
Michal Vaskoa3881362020-01-21 15:57:35 +0100387 result = lyd_parse_fd(ctx, fd, format, options);
Radek Krejcie7b95092019-05-15 11:03:07 +0200388 close(fd);
389
390 return result;
391}
Radek Krejci084289f2019-07-09 17:35:30 +0200392
Michal Vasko90932a92020-02-12 14:33:03 +0100393LY_ERR
394lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
395 ly_clb_resolve_prefix get_prefix, void *prefix_data, LYD_FORMAT format, struct lyd_node **node)
396{
397 LY_ERR ret;
398 struct lyd_node_term *term;
399
Michal Vasko9b368d32020-02-14 13:53:31 +0100400 assert(schema->nodetype & LYD_NODE_TERM);
401
Michal Vasko90932a92020-02-12 14:33:03 +0100402 term = calloc(1, sizeof *term);
403 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
404
405 term->schema = schema;
406 term->prev = (struct lyd_node *)term;
Michal Vasko9b368d32020-02-14 13:53:31 +0100407 term->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100408
409 ret = lyd_value_parse(term, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
410 if (ret && (ret != LY_EINCOMPLETE)) {
411 free(term);
412 return ret;
413 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100414 lyd_hash((struct lyd_node *)term);
415
416 *node = (struct lyd_node *)term;
417 return ret;
418}
419
420LY_ERR
421lyd_create_term2(const struct lysc_node *schema, const struct lyd_value *val, struct lyd_node **node)
422{
423 LY_ERR ret;
424 struct lyd_node_term *term;
425 struct lysc_type *type;
426
427 assert(schema->nodetype & LYD_NODE_TERM);
428
429 term = calloc(1, sizeof *term);
430 LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
431
432 term->schema = schema;
433 term->prev = (struct lyd_node *)term;
434 term->flags = LYD_NEW;
435
436 type = ((struct lysc_node_leaf *)schema)->type;
437 ret = type->plugin->duplicate(schema->module->ctx, val, &term->value);
438 if (ret) {
439 LOGERR(schema->module->ctx, ret, "Value duplication failed.");
440 free(term);
441 return ret;
442 }
443 lyd_hash((struct lyd_node *)term);
Michal Vasko90932a92020-02-12 14:33:03 +0100444
445 *node = (struct lyd_node *)term;
446 return ret;
447}
448
449LY_ERR
450lyd_create_inner(const struct lysc_node *schema, struct lyd_node **node)
451{
452 struct lyd_node_inner *in;
453
Michal Vasko9b368d32020-02-14 13:53:31 +0100454 assert(schema->nodetype & LYD_NODE_INNER);
455
Michal Vasko90932a92020-02-12 14:33:03 +0100456 in = calloc(1, sizeof *in);
457 LY_CHECK_ERR_RET(!in, LOGMEM(schema->module->ctx), LY_EMEM);
458
459 in->schema = schema;
460 in->prev = (struct lyd_node *)in;
Michal Vasko9b368d32020-02-14 13:53:31 +0100461 in->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100462
Michal Vasko9b368d32020-02-14 13:53:31 +0100463 /* do not hash list with keys, we need them for the hash */
464 if ((schema->nodetype != LYS_LIST) || (schema->flags & LYS_KEYLESS)) {
465 lyd_hash((struct lyd_node *)in);
466 }
Michal Vasko90932a92020-02-12 14:33:03 +0100467
468 *node = (struct lyd_node *)in;
469 return LY_SUCCESS;
470}
471
472static void
473ly_keys_clean(struct ly_keys *keys)
474{
475 size_t i;
476
477 for (i = 0; i < keys->key_count; ++i) {
478 keys->keys[i].schema->type->plugin->free(keys->keys[i].schema->module->ctx, &keys->keys[i].val);
479 }
480 free(keys->str);
481 free(keys->keys);
482}
483
484static char *
485ly_keys_parse_next(char **next_key, char **key_name)
486{
487 char *ptr, *ptr2, *val, quot;
Michal Vaskoc2f11292020-05-22 16:43:47 +0200488 const char *pref;
489 size_t pref_len, key_len;
490 int have_equal = 0;
Michal Vasko90932a92020-02-12 14:33:03 +0100491
492 ptr = *next_key;
493
494 /* "[" */
495 LY_CHECK_GOTO(ptr[0] != '[', error);
496 ++ptr;
497
Michal Vaskoc2f11292020-05-22 16:43:47 +0200498 /* skip WS */
499 while (isspace(ptr[0])) {
500 ++ptr;
501 }
Michal Vasko90932a92020-02-12 14:33:03 +0100502
Michal Vaskoc2f11292020-05-22 16:43:47 +0200503 /* key name without prefix */
504 LY_CHECK_GOTO(ly_parse_nodeid((const char **)&ptr, &pref, &pref_len, (const char **)key_name, &key_len), error);
505 if (pref) {
506 goto error;
507 }
Michal Vasko90932a92020-02-12 14:33:03 +0100508
Michal Vaskoc2f11292020-05-22 16:43:47 +0200509 /* terminate it */
510 LY_CHECK_GOTO((ptr[0] != '=') && !isspace(ptr[0]), error);
511 if (ptr[0] == '=') {
512 have_equal = 1;
513 }
514 ptr[0] = '\0';
515 ++ptr;
516
517 if (!have_equal) {
518 /* skip WS */
519 while (isspace(ptr[0])) {
520 ++ptr;
521 }
522
523 /* '=' */
524 LY_CHECK_GOTO(ptr[0] != '=', error);
525 ++ptr;
526 }
527
528 /* skip WS */
529 while (isspace(ptr[0])) {
530 ++ptr;
531 }
Michal Vasko90932a92020-02-12 14:33:03 +0100532
533 /* quote */
534 LY_CHECK_GOTO((ptr[0] != '\'') && (ptr[0] != '\"'), error);
535 quot = ptr[0];
536 ++ptr;
537
538 /* value, terminate it */
539 val = ptr;
540 ptr2 = strchr(ptr, quot);
541 LY_CHECK_GOTO(!ptr2, error);
542 ptr2[0] = '\0';
543
544 /* \0, was quote */
545 ptr = ptr2 + 1;
546
Michal Vaskoc2f11292020-05-22 16:43:47 +0200547 /* skip WS */
548 while (isspace(ptr[0])) {
549 ++ptr;
550 }
551
Michal Vasko90932a92020-02-12 14:33:03 +0100552 /* "]" */
553 LY_CHECK_GOTO(ptr[0] != ']', error);
554 ++ptr;
555
556 *next_key = ptr;
557 return val;
558
559error:
560 *next_key = ptr;
561 return NULL;
562}
563
Michal Vaskod3678892020-05-21 10:06:58 +0200564/* fill keys structure that is expected to be zeroed and must always be cleaned (even on error);
565 * if store is set, fill also each val */
Michal Vasko90932a92020-02-12 14:33:03 +0100566static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +0200567ly_keys_parse(const struct lysc_node *list, const char *keys_str, size_t keys_len, int store, int log,
568 struct ly_keys *keys)
Michal Vasko90932a92020-02-12 14:33:03 +0100569{
570 LY_ERR ret = LY_SUCCESS;
571 char *next_key, *name;
572 const struct lysc_node *key;
573 size_t i;
574
575 assert(list->nodetype == LYS_LIST);
576
Michal Vaskof03ed032020-03-04 13:31:44 +0100577 if (!keys_str) {
578 /* nothing to parse */
579 return LY_SUCCESS;
580 }
581
582 keys->str = strndup(keys_str, keys_len);
Michal Vasko90932a92020-02-12 14:33:03 +0100583 LY_CHECK_ERR_GOTO(!keys->str, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
584
585 next_key = keys->str;
586 while (next_key[0]) {
587 /* new key */
588 keys->keys = ly_realloc(keys->keys, (keys->key_count + 1) * sizeof *keys->keys);
589 LY_CHECK_ERR_GOTO(!keys->keys, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
590
591 /* fill */
592 keys->keys[keys->key_count].value = ly_keys_parse_next(&next_key, &name);
593 if (!keys->keys[keys->key_count].value) {
Michal Vaskod3678892020-05-21 10:06:58 +0200594 if (log) {
595 LOGERR(list->module->ctx, LY_EINVAL, "Invalid keys string (at \"%s\").", next_key);
596 }
Michal Vasko90932a92020-02-12 14:33:03 +0100597 ret = LY_EINVAL;
598 goto cleanup;
599 }
600
601 /* find schema node */
602 key = lys_find_child(list, list->module, name, 0, LYS_LEAF, 0);
603 if (!key) {
Michal Vaskod3678892020-05-21 10:06:58 +0200604 if (log) {
605 LOGERR(list->module->ctx, LY_EINVAL, "List \"%s\" has no key \"%s\".", list->name, name);
606 }
Michal Vasko90932a92020-02-12 14:33:03 +0100607 ret = LY_EINVAL;
608 goto cleanup;
609 }
610 keys->keys[keys->key_count].schema = (const struct lysc_node_leaf *)key;
611
612 /* check that we do not have it already */
613 for (i = 0; i < keys->key_count; ++i) {
614 if (keys->keys[i].schema == keys->keys[keys->key_count].schema) {
Michal Vaskod3678892020-05-21 10:06:58 +0200615 if (log) {
616 LOGERR(list->module->ctx, LY_EINVAL, "Duplicit key \"%s\" value.", name);
617 }
Michal Vasko90932a92020-02-12 14:33:03 +0100618 ret = LY_EINVAL;
619 goto cleanup;
620 }
621 }
622
623 if (store) {
624 /* store the value */
625 ret = lyd_value_store(&keys->keys[keys->key_count].val, key, keys->keys[keys->key_count].value, 0, 0,
626 lydjson_resolve_prefix, NULL, LYD_JSON);
627 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskoae420e92020-05-21 10:00:40 +0200628 } else {
629 memset(&keys->keys[keys->key_count].val, 0, sizeof keys->keys[keys->key_count].val);
Michal Vasko90932a92020-02-12 14:33:03 +0100630 }
631
632 /* another valid key */
633 ++keys->key_count;
634 }
635
636cleanup:
Michal Vasko90932a92020-02-12 14:33:03 +0100637 return ret;
638}
639
640LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +0200641lyd_create_list(const struct lysc_node *schema, const char *keys_str, size_t keys_len, LYD_FORMAT keys_format, int log,
642 struct lyd_node **node)
Michal Vasko90932a92020-02-12 14:33:03 +0100643{
644 LY_ERR ret = LY_SUCCESS;
645 const struct lysc_node *key_s;
646 struct lyd_node *list = NULL, *key;
647 struct ly_keys keys = {0};
648 size_t i;
649
Michal Vaskod3678892020-05-21 10:06:58 +0200650 assert((schema->nodetype == LYS_LIST) && !(schema->flags & LYS_KEYLESS) && (keys_format != LYD_XML));
Michal Vasko90932a92020-02-12 14:33:03 +0100651
652 /* parse keys */
Michal Vaskod3678892020-05-21 10:06:58 +0200653 LY_CHECK_GOTO(ret = ly_keys_parse(schema, keys_str, keys_len, 0, log, &keys), cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100654
655 /* create list */
656 LY_CHECK_GOTO(ret = lyd_create_inner(schema, &list), cleanup);
657
658 /* everything was checked except that all keys are set */
659 i = 0;
660 for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
661 ++i;
662 }
663 if (i != keys.key_count) {
Michal Vaskod3678892020-05-21 10:06:58 +0200664 if (log) {
665 LOGERR(schema->module->ctx, LY_EINVAL, "List \"%s\" is missing some keys.", schema->name);
666 }
Michal Vasko90932a92020-02-12 14:33:03 +0100667 ret = LY_EINVAL;
668 goto cleanup;
669 }
670
671 /* create and insert all the keys */
672 for (i = 0; i < keys.key_count; ++i) {
Michal Vaskod3678892020-05-21 10:06:58 +0200673 if (keys_format == LYD_JSON) {
674 ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value, strlen(keys.keys[i].value),
675 NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key);
676 } else {
677 assert(keys_format == LYD_SCHEMA);
678 ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value, strlen(keys.keys[i].value),
679 NULL, lys_resolve_prefix, NULL, LYD_SCHEMA, &key);
680 }
681 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100682 lyd_insert_node(list, NULL, key);
683 }
684
Michal Vasko9b368d32020-02-14 13:53:31 +0100685 /* hash having all the keys */
686 lyd_hash(list);
687
Michal Vasko90932a92020-02-12 14:33:03 +0100688 /* success */
689 *node = list;
690 list = NULL;
691
692cleanup:
693 lyd_free_tree(list);
694 ly_keys_clean(&keys);
695 return ret;
696}
697
698LY_ERR
699lyd_create_any(const struct lysc_node *schema, const void *value, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
700{
701 struct lyd_node_any *any;
702
Michal Vasko9b368d32020-02-14 13:53:31 +0100703 assert(schema->nodetype & LYD_NODE_ANY);
704
Michal Vasko90932a92020-02-12 14:33:03 +0100705 any = calloc(1, sizeof *any);
706 LY_CHECK_ERR_RET(!any, LOGMEM(schema->module->ctx), LY_EMEM);
707
708 any->schema = schema;
709 any->prev = (struct lyd_node *)any;
Michal Vasko9b368d32020-02-14 13:53:31 +0100710 any->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100711
712 any->value.xml = value;
713 any->value_type = value_type;
Michal Vasko9b368d32020-02-14 13:53:31 +0100714 lyd_hash((struct lyd_node *)any);
Michal Vasko90932a92020-02-12 14:33:03 +0100715
716 *node = (struct lyd_node *)any;
717 return LY_SUCCESS;
718}
719
Michal Vasko52927e22020-03-16 17:26:14 +0100720LY_ERR
721lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *value, size_t value_len,
722 int *dynamic, LYD_FORMAT format, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
723 const char *ns, struct lyd_node **node)
724{
725 struct lyd_node_opaq *opaq;
726
727 assert(ctx && name && name_len && ns);
728
729 if (!value_len) {
730 value = "";
731 }
732
733 opaq = calloc(1, sizeof *opaq);
734 LY_CHECK_ERR_RET(!opaq, LOGMEM(ctx), LY_EMEM);
735
736 opaq->prev = (struct lyd_node *)opaq;
737
738 opaq->name = lydict_insert(ctx, name, name_len);
739 opaq->format = format;
740 if (pref_len) {
741 opaq->prefix.pref = lydict_insert(ctx, prefix, pref_len);
742 }
743 opaq->prefix.ns = lydict_insert(ctx, ns, 0);
744 opaq->val_prefs = val_prefs;
745 if (dynamic && *dynamic) {
746 opaq->value = lydict_insert_zc(ctx, (char *)value);
747 *dynamic = 0;
748 } else {
749 opaq->value = lydict_insert(ctx, value, value_len);
750 }
751 opaq->ctx = ctx;
752
753 *node = (struct lyd_node *)opaq;
754 return LY_SUCCESS;
755}
756
Michal Vasko013a8182020-03-03 10:46:53 +0100757API struct lyd_node *
758lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name)
759{
760 struct lyd_node *ret = NULL;
761 const struct lysc_node *schema;
762 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
763
764 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
765
Michal Vaskof03ed032020-03-04 13:31:44 +0100766 if (!module) {
767 module = parent->schema->module;
768 }
769
Michal Vasko1bf09392020-03-27 12:38:10 +0100770 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_CONTAINER | LYS_NOTIF | LYS_RPC | LYS_ACTION, 0);
Michal Vaskob00f3cf2020-05-27 11:20:13 +0200771 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Inner node (and not a list) \"%s\" not found.", name), NULL);
Michal Vasko013a8182020-03-03 10:46:53 +0100772
773 if (!lyd_create_inner(schema, &ret) && parent) {
774 lyd_insert_node(parent, NULL, ret);
775 }
776 return ret;
777}
778
779API struct lyd_node *
780lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, ...)
781{
782 struct lyd_node *ret = NULL, *key;
783 const struct lysc_node *schema, *key_s;
784 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
785 va_list ap;
786 const char *key_val;
787 LY_ERR rc = LY_SUCCESS;
788
789 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
790
Michal Vaskof03ed032020-03-04 13:31:44 +0100791 if (!module) {
792 module = parent->schema->module;
793 }
794
Michal Vasko013a8182020-03-03 10:46:53 +0100795 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
796 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
797
798 /* create list inner node */
799 LY_CHECK_RET(lyd_create_inner(schema, &ret), NULL);
800
801 va_start(ap, name);
802
803 /* create and insert all the keys */
804 for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
805 key_val = va_arg(ap, const char *);
806
Michal Vaskof03ed032020-03-04 13:31:44 +0100807 rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key);
808 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko013a8182020-03-03 10:46:53 +0100809 lyd_insert_node(ret, NULL, key);
810 }
811
812 /* hash having all the keys */
813 lyd_hash(ret);
814
815 if (parent) {
816 lyd_insert_node(parent, NULL, ret);
817 }
818
819cleanup:
820 if (rc) {
821 lyd_free_tree(ret);
822 ret = NULL;
823 }
824 va_end(ap);
825 return ret;
826}
827
828API struct lyd_node *
829lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys)
830{
831 struct lyd_node *ret = NULL;
832 const struct lysc_node *schema;
833 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
834
835 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
836
Michal Vaskof03ed032020-03-04 13:31:44 +0100837 if (!module) {
838 module = parent->schema->module;
839 }
840
Michal Vasko013a8182020-03-03 10:46:53 +0100841 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
842 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
843
Michal Vaskod3678892020-05-21 10:06:58 +0200844 if (!lyd_create_list(schema, keys, keys ? strlen(keys) : 0, LYD_JSON, 1, &ret) && parent) {
Michal Vasko013a8182020-03-03 10:46:53 +0100845 lyd_insert_node(parent, NULL, ret);
846 }
847 return ret;
848}
849
850API struct lyd_node *
851lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
852{
853 struct lyd_node *ret = NULL;
854 const struct lysc_node *schema;
855 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
856
857 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
858
Michal Vaskof03ed032020-03-04 13:31:44 +0100859 if (!module) {
860 module = parent->schema->module;
861 }
862
Michal Vasko013a8182020-03-03 10:46:53 +0100863 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, 0);
864 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), NULL);
865
Michal Vaskof03ed032020-03-04 13:31:44 +0100866 if (!lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &ret)
867 && parent) {
Michal Vasko013a8182020-03-03 10:46:53 +0100868 lyd_insert_node(parent, NULL, ret);
869 }
870 return ret;
871}
872
873API struct lyd_node *
874lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
875 LYD_ANYDATA_VALUETYPE value_type)
876{
877 struct lyd_node *ret = NULL;
878 const struct lysc_node *schema;
879 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
880
881 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
882
Michal Vaskof03ed032020-03-04 13:31:44 +0100883 if (!module) {
884 module = parent->schema->module;
885 }
886
Michal Vasko013a8182020-03-03 10:46:53 +0100887 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, 0);
888 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Any node \"%s\" not found.", name), NULL);
889
890 if (!lyd_create_any(schema, value, value_type, &ret) && parent) {
891 lyd_insert_node(parent, NULL, ret);
892 }
893 return ret;
894}
895
Michal Vaskod86997b2020-05-26 15:19:54 +0200896API struct lyd_meta *
897lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
898{
899 struct lyd_meta *ret = NULL;
900 struct ly_ctx *ctx = parent->schema->module->ctx;
901 const char *prefix, *tmp;
902 char *str;
903 size_t pref_len, name_len;
904
905 LY_CHECK_ARG_RET(ctx, parent, name, module || strchr(name, ':'), NULL);
906
907 /* parse the name */
908 tmp = name;
909 if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
910 LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
911 return NULL;
912 }
913
914 /* find the module */
915 if (prefix) {
916 str = strndup(name, name_len);
917 module = ly_ctx_get_module_implemented(ctx, str);
918 free(str);
919 LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%*.s\" not found.", pref_len, prefix), NULL);
920 }
921
922 /* set value if none */
923 if (!val_str) {
924 val_str = "";
925 }
926
927 lyd_create_meta(parent, &ret, module, name, name_len, val_str, strlen(val_str), NULL, lydjson_resolve_prefix, NULL,
928 LYD_JSON, parent->schema);
929 return ret;
930}
931
Michal Vasko90932a92020-02-12 14:33:03 +0100932struct lyd_node *
933lyd_get_prev_key_anchor(const struct lyd_node *first_sibling, const struct lysc_node *new_key)
934{
935 const struct lysc_node *prev_key;
936 struct lyd_node *match = NULL;
937
938 if (!first_sibling) {
939 return NULL;
940 }
941
942 for (prev_key = new_key->prev; !match && prev_key->next; prev_key = prev_key->prev) {
943 lyd_find_sibling_val(first_sibling, prev_key, NULL, 0, &match);
944 }
945
946 return match;
947}
948
949/**
950 * @brief Insert node after a sibling.
951 *
Michal Vasko9f96a052020-03-10 09:41:45 +0100952 * Handles inserting into NP containers and key-less lists.
953 *
Michal Vasko90932a92020-02-12 14:33:03 +0100954 * @param[in] sibling Sibling to insert after.
955 * @param[in] node Node to insert.
956 */
957static void
Michal Vaskof03ed032020-03-04 13:31:44 +0100958lyd_insert_after_node(struct lyd_node *sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100959{
Michal Vasko0249f7c2020-03-05 16:36:40 +0100960 struct lyd_node_inner *par;
961
Michal Vasko90932a92020-02-12 14:33:03 +0100962 assert(!node->next && (node->prev == node));
963
964 node->next = sibling->next;
965 node->prev = sibling;
966 sibling->next = node;
967 if (node->next) {
968 /* sibling had a succeeding node */
969 node->next->prev = node;
970 } else {
971 /* sibling was last, find first sibling and change its prev */
972 if (sibling->parent) {
973 sibling = sibling->parent->child;
974 } else {
975 for (; sibling->prev->next != node; sibling = sibling->prev);
976 }
977 sibling->prev = node;
978 }
979 node->parent = sibling->parent;
Michal Vasko0249f7c2020-03-05 16:36:40 +0100980
Michal Vasko9f96a052020-03-10 09:41:45 +0100981 for (par = node->parent; par; par = par->parent) {
982 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
983 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +0100984 par->flags &= ~LYD_DEFAULT;
985 }
Michal Vasko9f96a052020-03-10 09:41:45 +0100986 if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
987 /* rehash key-less list */
988 lyd_hash((struct lyd_node *)par);
989 }
Michal Vasko0249f7c2020-03-05 16:36:40 +0100990 }
991
992 /* insert into hash table */
993 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +0100994}
995
996/**
997 * @brief Insert node before a sibling.
998 *
Michal Vasko9f96a052020-03-10 09:41:45 +0100999 * Handles inserting into NP containers and key-less lists.
1000 *
Michal Vasko90932a92020-02-12 14:33:03 +01001001 * @param[in] sibling Sibling to insert before.
1002 * @param[in] node Node to insert.
1003 */
1004static void
Michal Vaskof03ed032020-03-04 13:31:44 +01001005lyd_insert_before_node(struct lyd_node *sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +01001006{
Michal Vasko0249f7c2020-03-05 16:36:40 +01001007 struct lyd_node_inner *par;
1008
Michal Vasko90932a92020-02-12 14:33:03 +01001009 assert(!node->next && (node->prev == node));
1010
1011 node->next = sibling;
1012 /* covers situation of sibling being first */
1013 node->prev = sibling->prev;
1014 sibling->prev = node;
1015 if (node->prev->next) {
1016 /* sibling had a preceding node */
1017 node->prev->next = node;
1018 } else if (sibling->parent) {
1019 /* sibling was first and we must also change parent child pointer */
1020 sibling->parent->child = node;
1021 }
1022 node->parent = sibling->parent;
Michal Vasko0249f7c2020-03-05 16:36:40 +01001023
Michal Vasko9f96a052020-03-10 09:41:45 +01001024 for (par = node->parent; par; par = par->parent) {
1025 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
1026 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +01001027 par->flags &= ~LYD_DEFAULT;
1028 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001029 if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
1030 /* rehash key-less list */
1031 lyd_hash((struct lyd_node *)par);
1032 }
Michal Vasko0249f7c2020-03-05 16:36:40 +01001033 }
1034
1035 /* insert into hash table */
1036 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +01001037}
1038
1039/**
1040 * @brief Insert node as the last child of a parent.
1041 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001042 * Handles inserting into NP containers and key-less lists.
1043 *
Michal Vasko90932a92020-02-12 14:33:03 +01001044 * @param[in] parent Parent to insert into.
1045 * @param[in] node Node to insert.
1046 */
1047static void
Michal Vaskof03ed032020-03-04 13:31:44 +01001048lyd_insert_last_node(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +01001049{
1050 struct lyd_node_inner *par;
1051
Michal Vasko0249f7c2020-03-05 16:36:40 +01001052 assert(parent && !node->next && (node->prev == node));
Michal Vasko52927e22020-03-16 17:26:14 +01001053 assert(!parent->schema || (parent->schema->nodetype & LYD_NODE_INNER));
Michal Vasko90932a92020-02-12 14:33:03 +01001054
1055 par = (struct lyd_node_inner *)parent;
1056
1057 if (!par->child) {
1058 par->child = node;
1059 } else {
1060 node->prev = par->child->prev;
1061 par->child->prev->next = node;
1062 par->child->prev = node;
1063 }
1064 node->parent = par;
Michal Vasko0249f7c2020-03-05 16:36:40 +01001065
Michal Vasko9f96a052020-03-10 09:41:45 +01001066 for (; par; par = par->parent) {
1067 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
1068 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +01001069 par->flags &= ~LYD_DEFAULT;
1070 }
Michal Vasko52927e22020-03-16 17:26:14 +01001071 if (par->schema && (par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001072 /* rehash key-less list */
1073 lyd_hash((struct lyd_node *)par);
1074 }
Michal Vasko0249f7c2020-03-05 16:36:40 +01001075 }
1076
1077 /* insert into hash table */
1078 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +01001079}
1080
1081void
Michal Vasko9b368d32020-02-14 13:53:31 +01001082lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +01001083{
Michal Vasko9b368d32020-02-14 13:53:31 +01001084 struct lyd_node *anchor;
Michal Vasko9f96a052020-03-10 09:41:45 +01001085 const struct lysc_node *skey = NULL;
1086 int has_keys;
Michal Vasko90932a92020-02-12 14:33:03 +01001087
Michal Vasko52927e22020-03-16 17:26:14 +01001088 assert((parent || first_sibling) && node && (node->hash || !node->schema));
Michal Vasko9b368d32020-02-14 13:53:31 +01001089
1090 if (!parent && first_sibling && (*first_sibling) && (*first_sibling)->parent) {
1091 parent = (struct lyd_node *)(*first_sibling)->parent;
1092 }
Michal Vasko90932a92020-02-12 14:33:03 +01001093
1094 if (parent) {
Michal Vasko52927e22020-03-16 17:26:14 +01001095 if (node->schema && (node->schema->flags & LYS_KEY)) {
Michal Vasko90932a92020-02-12 14:33:03 +01001096 /* it is key and we need to insert it at the correct place */
Michal Vasko9b368d32020-02-14 13:53:31 +01001097 anchor = lyd_get_prev_key_anchor(lyd_node_children(parent), node->schema);
1098 if (anchor) {
Michal Vaskof03ed032020-03-04 13:31:44 +01001099 lyd_insert_after_node(anchor, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001100 } else if (lyd_node_children(parent)) {
Radek Krejcidae0ee82020-05-06 16:53:24 +02001101 lyd_insert_before_node(lyd_node_children(parent), node);
Michal Vasko90932a92020-02-12 14:33:03 +01001102 } else {
Michal Vaskof03ed032020-03-04 13:31:44 +01001103 lyd_insert_last_node(parent, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001104 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001105
1106 /* hash list if all its keys were added */
1107 assert(parent->schema->nodetype == LYS_LIST);
Radek Krejcidae0ee82020-05-06 16:53:24 +02001108 anchor = lyd_node_children(parent);
Michal Vasko9f96a052020-03-10 09:41:45 +01001109 has_keys = 1;
1110 while ((skey = lys_getnext(skey, parent->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
1111 if (!anchor || (anchor->schema != skey)) {
1112 /* key missing */
1113 has_keys = 0;
1114 break;
1115 }
1116
1117 anchor = anchor->next;
1118 }
1119 if (has_keys) {
1120 lyd_hash(parent);
1121 }
1122
Michal Vasko90932a92020-02-12 14:33:03 +01001123 } else {
1124 /* last child */
Michal Vaskof03ed032020-03-04 13:31:44 +01001125 lyd_insert_last_node(parent, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001126 }
Michal Vasko9b368d32020-02-14 13:53:31 +01001127 } else if (*first_sibling) {
Michal Vaskob1b5c262020-03-05 14:29:47 +01001128 /* top-level siblings */
Michal Vasko9b368d32020-02-14 13:53:31 +01001129 anchor = (*first_sibling)->prev;
Michal Vaskoc193ce92020-03-06 11:04:48 +01001130 while (anchor->prev->next && (lyd_owner_module(anchor) != lyd_owner_module(node))) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001131 anchor = anchor->prev;
1132 }
1133
Michal Vaskoc193ce92020-03-06 11:04:48 +01001134 if (lyd_owner_module(anchor) == lyd_owner_module(node)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +01001135 /* insert after last sibling from this module */
1136 lyd_insert_after_node(anchor, node);
1137 } else {
1138 /* no data from this module, insert at the last position */
1139 lyd_insert_after_node((*first_sibling)->prev, node);
1140 }
Michal Vasko90932a92020-02-12 14:33:03 +01001141 } else {
Michal Vasko9b368d32020-02-14 13:53:31 +01001142 /* the only sibling */
1143 *first_sibling = node;
Michal Vasko90932a92020-02-12 14:33:03 +01001144 }
Michal Vasko90932a92020-02-12 14:33:03 +01001145}
1146
Michal Vaskof03ed032020-03-04 13:31:44 +01001147static LY_ERR
1148lyd_insert_check_schema(const struct lysc_node *parent, const struct lysc_node *schema)
1149{
1150 const struct lysc_node *par2;
1151
1152 assert(schema);
Michal Vasko62ed12d2020-05-21 10:08:25 +02001153 assert(!parent || !(parent->nodetype & (LYS_CASE | LYS_CHOICE)));
Michal Vaskof03ed032020-03-04 13:31:44 +01001154
1155 /* find schema parent */
Michal Vasko62ed12d2020-05-21 10:08:25 +02001156 par2 = lysc_data_parent(schema);
Michal Vaskof03ed032020-03-04 13:31:44 +01001157
1158 if (parent) {
1159 /* inner node */
1160 if (par2 != parent) {
1161 LOGERR(parent->module->ctx, LY_EINVAL, "Cannot insert, parent of \"%s\" is not \"%s\".", schema->name, parent->name);
1162 return LY_EINVAL;
1163 }
1164 } else {
1165 /* top-level node */
1166 if (par2) {
1167 LOGERR(parent->module->ctx, LY_EINVAL, "Cannot insert, node \"%s\" is not top-level.", schema->name);
1168 return LY_EINVAL;
1169 }
1170 }
1171
1172 return LY_SUCCESS;
1173}
1174
1175API LY_ERR
1176lyd_insert(struct lyd_node *parent, struct lyd_node *node)
1177{
1178 struct lyd_node *iter;
1179
1180 LY_CHECK_ARG_RET(NULL, parent, node, !(parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
1181
1182 LY_CHECK_RET(lyd_insert_check_schema(parent->schema, node->schema));
1183
1184 if (node->schema->flags & LYS_KEY) {
1185 LOGERR(parent->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1186 return LY_EINVAL;
1187 }
1188
1189 if (node->parent || node->prev->next) {
1190 lyd_unlink_tree(node);
1191 }
1192
1193 while (node) {
1194 iter = node->next;
1195 lyd_unlink_tree(node);
1196 lyd_insert_node(parent, NULL, node);
1197 node = iter;
1198 }
1199 return LY_SUCCESS;
1200}
1201
1202API LY_ERR
Michal Vaskob1b5c262020-03-05 14:29:47 +01001203lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node)
1204{
1205 struct lyd_node *iter;
1206
1207 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1208
Michal Vasko62ed12d2020-05-21 10:08:25 +02001209 LY_CHECK_RET(lyd_insert_check_schema(lysc_data_parent(sibling->schema), node->schema));
Michal Vaskob1b5c262020-03-05 14:29:47 +01001210
1211 if (node->schema->flags & LYS_KEY) {
1212 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1213 return LY_EINVAL;
1214 }
1215
1216 if (node->parent || node->prev->next) {
1217 lyd_unlink_tree(node);
1218 }
1219
1220 while (node) {
1221 iter = node->next;
1222 lyd_unlink_tree(node);
1223 lyd_insert_node(NULL, &sibling, node);
1224 node = iter;
1225 }
1226 return LY_SUCCESS;
1227}
1228
Michal Vasko0249f7c2020-03-05 16:36:40 +01001229static LY_ERR
1230lyd_insert_after_check_place(struct lyd_node *anchor, struct lyd_node *sibling, struct lyd_node *node)
1231{
1232 if (sibling->parent) {
1233 /* nested, we do not care for the order */
1234 return LY_SUCCESS;
1235 }
1236
1237 if (anchor) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001238 if (anchor->next && (lyd_owner_module(anchor) == lyd_owner_module(anchor->next))
1239 && (lyd_owner_module(node) != lyd_owner_module(anchor))) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001240 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert top-level module \"%s\" data into module \"%s\" data.",
Michal Vaskoc193ce92020-03-06 11:04:48 +01001241 lyd_owner_module(node)->name, lyd_owner_module(anchor)->name);
Michal Vasko0249f7c2020-03-05 16:36:40 +01001242 return LY_EINVAL;
1243 }
1244
Michal Vaskoc193ce92020-03-06 11:04:48 +01001245 if ((lyd_owner_module(node) == lyd_owner_module(anchor))
1246 || (anchor->next && (lyd_owner_module(node) == lyd_owner_module(anchor->next)))) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001247 /* inserting before/after its module data */
1248 return LY_SUCCESS;
1249 }
1250 }
1251
1252 /* find first sibling */
1253 while (sibling->prev->next) {
1254 sibling = sibling->prev;
1255 }
1256
1257 if (!anchor) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001258 if (lyd_owner_module(node) == lyd_owner_module(sibling)) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001259 /* inserting before its module data */
1260 return LY_SUCCESS;
1261 }
1262 }
1263
1264 /* check there are no data of this module */
1265 LY_LIST_FOR(sibling, sibling) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001266 if (lyd_owner_module(node) == lyd_owner_module(sibling)) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001267 /* some data of this module found */
1268 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Top-level data of module \"%s\" already exist,"
Michal Vaskoc193ce92020-03-06 11:04:48 +01001269 " they must be directly connected.", lyd_owner_module(node)->name);
Michal Vasko0249f7c2020-03-05 16:36:40 +01001270 return LY_EINVAL;
1271 }
1272 }
1273
1274 return LY_SUCCESS;
1275}
1276
Michal Vaskob1b5c262020-03-05 14:29:47 +01001277API LY_ERR
Michal Vaskof03ed032020-03-04 13:31:44 +01001278lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
1279{
1280 struct lyd_node *iter;
1281
1282 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1283
Michal Vasko62ed12d2020-05-21 10:08:25 +02001284 LY_CHECK_RET(lyd_insert_check_schema(lysc_data_parent(sibling->schema), node->schema));
Michal Vaskof03ed032020-03-04 13:31:44 +01001285
1286 if (node->schema->flags & LYS_KEY) {
1287 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1288 return LY_EINVAL;
1289 } else if (sibling->schema->flags & LYS_KEY) {
1290 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert into keys.");
1291 return LY_EINVAL;
1292 }
1293
Michal Vasko0249f7c2020-03-05 16:36:40 +01001294 LY_CHECK_RET(lyd_insert_after_check_place(sibling->prev->next ? sibling->prev : NULL, sibling, node));
1295
Michal Vaskof03ed032020-03-04 13:31:44 +01001296 if (node->parent || node->prev->next) {
1297 lyd_unlink_tree(node);
1298 }
1299
1300 /* insert in reverse order to get the original order */
1301 node = node->prev;
1302 while (node) {
1303 iter = node->prev;
1304 lyd_unlink_tree(node);
1305
1306 lyd_insert_before_node(sibling, node);
1307 /* move the anchor accordingly */
1308 sibling = node;
1309
1310 node = (iter == node) ? NULL : iter;
1311 }
1312 return LY_SUCCESS;
1313}
1314
1315API LY_ERR
1316lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
1317{
1318 struct lyd_node *iter;
1319
1320 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1321
Michal Vasko62ed12d2020-05-21 10:08:25 +02001322 LY_CHECK_RET(lyd_insert_check_schema(lysc_data_parent(sibling->schema), node->schema));
Michal Vaskof03ed032020-03-04 13:31:44 +01001323
1324 if (node->schema->flags & LYS_KEY) {
1325 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1326 return LY_EINVAL;
1327 } else if (sibling->next && (sibling->next->schema->flags & LYS_KEY)) {
1328 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert into keys.");
1329 return LY_EINVAL;
1330 }
1331
Michal Vasko0249f7c2020-03-05 16:36:40 +01001332 LY_CHECK_RET(lyd_insert_after_check_place(sibling, sibling, node));
1333
Michal Vaskof03ed032020-03-04 13:31:44 +01001334 if (node->parent || node->prev->next) {
1335 lyd_unlink_tree(node);
1336 }
1337
1338 while (node) {
1339 iter = node->next;
1340 lyd_unlink_tree(node);
1341
1342 lyd_insert_after_node(sibling, node);
1343 /* move the anchor accordingly */
1344 sibling = node;
1345
1346 node = iter;
1347 }
1348 return LY_SUCCESS;
1349}
1350
1351API void
1352lyd_unlink_tree(struct lyd_node *node)
1353{
1354 struct lyd_node *iter;
1355
1356 if (!node) {
1357 return;
1358 }
1359
1360 /* unlink from siblings */
1361 if (node->prev->next) {
1362 node->prev->next = node->next;
1363 }
1364 if (node->next) {
1365 node->next->prev = node->prev;
1366 } else {
1367 /* unlinking the last node */
1368 if (node->parent) {
1369 iter = node->parent->child;
1370 } else {
1371 iter = node->prev;
1372 while (iter->prev != node) {
1373 iter = iter->prev;
1374 }
1375 }
1376 /* update the "last" pointer from the first node */
1377 iter->prev = node->prev;
1378 }
1379
1380 /* unlink from parent */
1381 if (node->parent) {
1382 if (node->parent->child == node) {
1383 /* the node is the first child */
1384 node->parent->child = node->next;
1385 }
1386
1387 lyd_unlink_hash(node);
1388
1389 /* check for keyless list and update its hash */
1390 for (iter = (struct lyd_node *)node->parent; iter; iter = (struct lyd_node *)iter->parent) {
Michal Vasko413c7f22020-05-05 12:34:06 +02001391 if (iter->schema && (iter->schema->flags & LYS_KEYLESS)) {
Michal Vaskof03ed032020-03-04 13:31:44 +01001392 lyd_hash(iter);
1393 }
1394 }
1395
1396 node->parent = NULL;
1397 }
1398
1399 node->next = NULL;
1400 node->prev = node;
1401}
1402
Michal Vasko90932a92020-02-12 14:33:03 +01001403LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +01001404lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
Michal Vasko52927e22020-03-16 17:26:14 +01001405 size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix resolve_prefix,
Michal Vasko8d544252020-03-02 10:19:52 +01001406 void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode)
Michal Vasko90932a92020-02-12 14:33:03 +01001407{
1408 LY_ERR ret;
1409 struct lysc_ext_instance *ant = NULL;
Michal Vasko9f96a052020-03-10 09:41:45 +01001410 struct lyd_meta *mt, *last;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001411 LY_ARRAY_SIZE_TYPE u;
Michal Vasko90932a92020-02-12 14:33:03 +01001412
Michal Vasko9f96a052020-03-10 09:41:45 +01001413 assert((parent || meta) && mod);
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001414
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001415 LY_ARRAY_FOR(mod->compiled->exts, u) {
1416 if (mod->compiled->exts[u].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
1417 !ly_strncmp(mod->compiled->exts[u].argument, name, name_len)) {
Michal Vasko90932a92020-02-12 14:33:03 +01001418 /* we have the annotation definition */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001419 ant = &mod->compiled->exts[u];
Michal Vasko90932a92020-02-12 14:33:03 +01001420 break;
1421 }
1422 }
1423 if (!ant) {
1424 /* attribute is not defined as a metadata annotation (RFC 7952) */
1425 LOGERR(mod->ctx, LY_EINVAL, "Annotation definition for attribute \"%s:%.*s\" not found.",
1426 mod->name, name_len, name);
1427 return LY_EINVAL;
1428 }
1429
Michal Vasko9f96a052020-03-10 09:41:45 +01001430 mt = calloc(1, sizeof *mt);
1431 LY_CHECK_ERR_RET(!mt, LOGMEM(mod->ctx), LY_EMEM);
1432 mt->parent = parent;
1433 mt->annotation = ant;
Michal Vasko52927e22020-03-16 17:26:14 +01001434 ret = lyd_value_parse_meta(mod->ctx, mt, value, value_len, dynamic, 0, resolve_prefix, prefix_data, format, ctx_snode, NULL);
Michal Vasko90932a92020-02-12 14:33:03 +01001435 if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001436 free(mt);
Michal Vasko90932a92020-02-12 14:33:03 +01001437 return ret;
1438 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001439 mt->name = lydict_insert(mod->ctx, name, name_len);
Michal Vasko90932a92020-02-12 14:33:03 +01001440
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001441 /* insert as the last attribute */
1442 if (parent) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001443 if (parent->meta) {
1444 for (last = parent->meta; last->next; last = last->next);
1445 last->next = mt;
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001446 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01001447 parent->meta = mt;
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001448 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001449 } else if (*meta) {
1450 for (last = *meta; last->next; last = last->next);
1451 last->next = mt;
Michal Vasko90932a92020-02-12 14:33:03 +01001452 }
1453
1454 /* remove default flags from NP containers */
1455 while (parent && (parent->flags & LYD_DEFAULT)) {
1456 parent->flags &= ~LYD_DEFAULT;
1457 parent = (struct lyd_node *)parent->parent;
1458 }
1459
Michal Vasko9f96a052020-03-10 09:41:45 +01001460 if (meta) {
1461 *meta = mt;
Michal Vasko90932a92020-02-12 14:33:03 +01001462 }
1463 return ret;
1464}
1465
Michal Vasko52927e22020-03-16 17:26:14 +01001466LY_ERR
1467ly_create_attr(struct lyd_node *parent, struct ly_attr **attr, const struct ly_ctx *ctx, const char *name,
1468 size_t name_len, const char *value, size_t value_len, int *dynamic, LYD_FORMAT format,
1469 struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *ns)
1470{
1471 struct ly_attr *at, *last;
1472 struct lyd_node_opaq *opaq;
1473
1474 assert(ctx && (parent || attr) && (!parent || !parent->schema));
1475 assert(name && name_len);
1476 assert((prefix_len && ns) || (!prefix_len && !ns));
1477
1478 if (!value_len) {
1479 value = "";
1480 }
1481
1482 at = calloc(1, sizeof *at);
1483 LY_CHECK_ERR_RET(!at, LOGMEM(ctx), LY_EMEM);
1484 at->parent = (struct lyd_node_opaq *)parent;
1485 at->name = lydict_insert(ctx, name, name_len);
1486 if (dynamic && *dynamic) {
1487 at->value = lydict_insert_zc(ctx, (char *)value);
1488 *dynamic = 0;
1489 } else {
1490 at->value = lydict_insert(ctx, value, value_len);
1491 }
1492
1493 at->format = format;
1494 at->val_prefs = val_prefs;
1495 if (ns) {
1496 at->prefix.pref = lydict_insert(ctx, prefix, prefix_len);
1497 at->prefix.ns = lydict_insert(ctx, ns, 0);
1498 }
1499
1500 /* insert as the last attribute */
1501 if (parent) {
1502 opaq = (struct lyd_node_opaq *)parent;
1503 if (opaq->attr) {
1504 for (last = opaq->attr; last->next; last = last->next);
1505 last->next = at;
1506 } else {
1507 opaq->attr = at;
1508 }
1509 } else if (*attr) {
1510 for (last = *attr; last->next; last = last->next);
1511 last->next = at;
1512 }
1513
1514 if (attr) {
1515 *attr = at;
1516 }
1517 return LY_SUCCESS;
1518}
1519
Radek Krejci084289f2019-07-09 17:35:30 +02001520API const struct lyd_node_term *
Michal Vaskof03ed032020-03-04 13:31:44 +01001521lyd_target(struct lyd_value_path *path, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +02001522{
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001523 LY_ARRAY_SIZE_TYPE u, v;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001524 const struct lyd_node *start_sibling;
Michal Vaskoe444f752020-02-10 12:20:06 +01001525 struct lyd_node *node = NULL;
Radek Krejci084289f2019-07-09 17:35:30 +02001526 uint64_t pos = 1;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001527 int match;
Radek Krejci084289f2019-07-09 17:35:30 +02001528
Michal Vaskof03ed032020-03-04 13:31:44 +01001529 LY_CHECK_ARG_RET(NULL, path, tree, NULL);
Radek Krejci084289f2019-07-09 17:35:30 +02001530
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001531 /* first iteration */
1532 start_sibling = tree;
1533 u = 0;
1534 while (u < LY_ARRAY_SIZE(path)) {
1535 /* find next node instance */
Michal Vasko84c9f1b2020-05-14 12:08:11 +02001536 if (start_sibling && !start_sibling->prev->next && !(path[u].node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
1537 /* starting from the beginning using hashes */
1538 lyd_find_sibling_val(start_sibling, path[u].node, NULL, 0, &node);
1539 } else {
1540 /* next matching sibling */
1541 lyd_find_sibling_next2(start_sibling, path[u].node, NULL, 0, &node);
1542 }
Radek Krejci084289f2019-07-09 17:35:30 +02001543 if (!node) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001544 break;
Radek Krejci084289f2019-07-09 17:35:30 +02001545 }
1546
1547 /* check predicate if any */
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001548 match = 1;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001549 LY_ARRAY_FOR(path[u].predicates, v) {
1550 if (path[u].predicates[v].type == 0) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001551 assert(LY_ARRAY_SIZE(path[u].predicates) == 1);
Radek Krejci084289f2019-07-09 17:35:30 +02001552 /* position predicate */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001553 if (pos != path[u].predicates[v].position) {
Radek Krejci084289f2019-07-09 17:35:30 +02001554 pos++;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001555 match = 0;
Radek Krejci084289f2019-07-09 17:35:30 +02001556 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001557 } else if (path[u].predicates[v].type == 1) {
Radek Krejci084289f2019-07-09 17:35:30 +02001558 /* key-predicate */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001559 struct lysc_type *type = ((struct lysc_node_leaf *)path[u].predicates[v].key)->type;
Michal Vaskoe444f752020-02-10 12:20:06 +01001560 struct lyd_node *key;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001561
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001562 lyd_find_sibling_val(lyd_node_children(node), path[u].predicates[v].key, NULL, 0, &key);
Radek Krejci084289f2019-07-09 17:35:30 +02001563 if (!key) {
1564 /* probably error and we shouldn't be here due to previous checks when creating path */
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001565 match = 0;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001566 } else if (type->plugin->compare(&((struct lyd_node_term *)key)->value, path[u].predicates[v].value)) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001567 match = 0;
Radek Krejci084289f2019-07-09 17:35:30 +02001568 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001569 } else if (path[u].predicates[v].type == 2) {
Radek Krejci084289f2019-07-09 17:35:30 +02001570 /* leaf-list-predicate */
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001571 struct lysc_type *type = ((struct lysc_node_leaf *)path[u].node)->type;
1572
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001573 if (type->plugin->compare(&((struct lyd_node_term *)node)->value, path[u].predicates[v].value)) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001574 match = 0;
Radek Krejci084289f2019-07-09 17:35:30 +02001575 }
1576 } else {
1577 LOGINT(NULL);
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001578 return NULL;
1579 }
1580
1581 if (!match) {
1582 /* useless to check more predicates */
1583 break;
Radek Krejci084289f2019-07-09 17:35:30 +02001584 }
1585 }
1586
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001587 if (!match) {
1588 /* try to match next sibling */
1589 start_sibling = node->next;
1590 } else {
1591 /* matched, move to the next path segment */
1592 ++u;
1593 start_sibling = lyd_node_children(node);
1594 pos = 1;
1595 }
Radek Krejci084289f2019-07-09 17:35:30 +02001596 }
1597
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001598 return (const struct lyd_node_term *)node;
Radek Krejci084289f2019-07-09 17:35:30 +02001599}
1600
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001601API LY_ERR
1602lyd_compare(const struct lyd_node *node1, const struct lyd_node *node2, int options)
1603{
1604 const struct lyd_node *iter1, *iter2;
1605 struct lyd_node_term *term1, *term2;
1606 struct lyd_node_any *any1, *any2;
Michal Vasko52927e22020-03-16 17:26:14 +01001607 struct lyd_node_opaq *opaq1, *opaq2;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001608 struct lysc_type *type;
1609 size_t len1, len2;
Radek Krejci084289f2019-07-09 17:35:30 +02001610
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001611 if (!node1 || !node2) {
1612 if (node1 == node2) {
1613 return LY_SUCCESS;
1614 } else {
1615 return LY_ENOT;
1616 }
1617 }
1618
Michal Vasko52927e22020-03-16 17:26:14 +01001619 if ((LYD_NODE_CTX(node1) != LYD_NODE_CTX(node2)) || (node1->schema != node2->schema)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001620 return LY_ENOT;
1621 }
1622
1623 if (node1->hash != node2->hash) {
1624 return LY_ENOT;
1625 }
Michal Vasko52927e22020-03-16 17:26:14 +01001626 /* equal hashes do not mean equal nodes, they can be just in collision (or both be 0) so the nodes must be checked explicitly */
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001627
Michal Vasko52927e22020-03-16 17:26:14 +01001628 if (!node1->schema) {
1629 opaq1 = (struct lyd_node_opaq *)node1;
1630 opaq2 = (struct lyd_node_opaq *)node2;
1631 if ((opaq1->name != opaq2->name) || (opaq1->prefix.ns != opaq2->prefix.ns) || (opaq1->format != opaq2->format)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001632 return LY_ENOT;
1633 }
Michal Vasko52927e22020-03-16 17:26:14 +01001634 switch (opaq1->format) {
1635 case LYD_XML:
1636 if (lyxml_value_compare(opaq1->value, opaq1->val_prefs, opaq2->value, opaq2->val_prefs)) {
1637 return LY_ENOT;
1638 }
1639 break;
1640 case LYD_SCHEMA:
1641 /* not allowed */
1642 LOGINT(LYD_NODE_CTX(node1));
1643 return LY_EINT;
1644 }
1645 if (options & LYD_COMPARE_FULL_RECURSION) {
1646 iter1 = opaq1->child;
1647 iter2 = opaq2->child;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001648 goto all_children_compare;
Michal Vasko52927e22020-03-16 17:26:14 +01001649 }
1650 return LY_SUCCESS;
1651 } else {
1652 switch (node1->schema->nodetype) {
1653 case LYS_LEAF:
1654 case LYS_LEAFLIST:
1655 if (options & LYD_COMPARE_DEFAULTS) {
1656 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1657 return LY_ENOT;
1658 }
1659 }
1660
1661 term1 = (struct lyd_node_term*)node1;
1662 term2 = (struct lyd_node_term*)node2;
1663 type = ((struct lysc_node_leaf*)node1->schema)->type;
1664
1665 return type->plugin->compare(&term1->value, &term2->value);
1666 case LYS_CONTAINER:
1667 if (options & LYD_COMPARE_DEFAULTS) {
1668 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1669 return LY_ENOT;
1670 }
1671 }
1672 if (options & LYD_COMPARE_FULL_RECURSION) {
1673 iter1 = ((struct lyd_node_inner*)node1)->child;
1674 iter2 = ((struct lyd_node_inner*)node2)->child;
1675 goto all_children_compare;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001676 }
1677 return LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +01001678 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +01001679 case LYS_ACTION:
1680 if (options & LYD_COMPARE_FULL_RECURSION) {
1681 /* TODO action/RPC
1682 goto all_children_compare;
1683 */
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001684 }
1685 return LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +01001686 case LYS_NOTIF:
1687 if (options & LYD_COMPARE_FULL_RECURSION) {
1688 /* TODO Notification
1689 goto all_children_compare;
1690 */
1691 }
1692 return LY_SUCCESS;
1693 case LYS_LIST:
1694 iter1 = ((struct lyd_node_inner*)node1)->child;
1695 iter2 = ((struct lyd_node_inner*)node2)->child;
1696
1697 if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
1698 /* lists with keys, their equivalence is based on their keys */
1699 for (struct lysc_node *key = ((struct lysc_node_list*)node1->schema)->child;
1700 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1701 key = key->next) {
1702 if (lyd_compare(iter1, iter2, options)) {
1703 return LY_ENOT;
1704 }
1705 iter1 = iter1->next;
1706 iter2 = iter2->next;
1707 }
1708 } else {
1709 /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
1710
1711 all_children_compare:
1712 if (!iter1 && !iter2) {
1713 /* no children, nothing to compare */
1714 return LY_SUCCESS;
1715 }
1716
1717 for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
1718 if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
1719 return LY_ENOT;
1720 }
1721 }
1722 if (iter1 || iter2) {
1723 return LY_ENOT;
1724 }
1725 }
1726 return LY_SUCCESS;
1727 case LYS_ANYXML:
1728 case LYS_ANYDATA:
1729 any1 = (struct lyd_node_any*)node1;
1730 any2 = (struct lyd_node_any*)node2;
1731
1732 if (any1->value_type != any2->value_type) {
1733 return LY_ENOT;
1734 }
1735 switch (any1->value_type) {
1736 case LYD_ANYDATA_DATATREE:
1737 iter1 = any1->value.tree;
1738 iter2 = any2->value.tree;
1739 goto all_children_compare;
1740 case LYD_ANYDATA_STRING:
1741 case LYD_ANYDATA_XML:
1742 case LYD_ANYDATA_JSON:
1743 len1 = strlen(any1->value.str);
1744 len2 = strlen(any2->value.str);
1745 if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
1746 return LY_ENOT;
1747 }
1748 return LY_SUCCESS;
1749 #if 0 /* TODO LYB format */
1750 case LYD_ANYDATA_LYB:
1751 int len1 = lyd_lyb_data_length(any1->value.mem);
1752 int len2 = lyd_lyb_data_length(any2->value.mem);
1753 if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
1754 return LY_ENOT;
1755 }
1756 return LY_SUCCESS;
1757 #endif
1758 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001759 }
1760 }
1761
Michal Vasko52927e22020-03-16 17:26:14 +01001762 LOGINT(LYD_NODE_CTX(node1));
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001763 return LY_EINT;
1764}
Radek Krejci22ebdba2019-07-25 13:59:43 +02001765
1766/**
Michal Vasko52927e22020-03-16 17:26:14 +01001767 * @brief Duplicate a single node and connect it into @p parent (if present) or last of @p first siblings.
Radek Krejci22ebdba2019-07-25 13:59:43 +02001768 *
1769 * Ignores LYD_DUP_WITH_PARENTS and LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
Radek Krejcif8b95172020-05-15 14:51:06 +02001770 *
1771 * @param[in] node Original node to duplicate
1772 * @param[in] parent Parent to insert into, NULL for top-level sibling.
1773 * @param[in,out] first First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
1774 * @param[in] options Bitmask of options flags, see @ref dupoptions.
1775 * @param[out] dup_p Pointer where the created duplicated node is placed (besides connecting it int @p parent / @p first sibling).
1776 * @return LY_ERR value
Radek Krejci22ebdba2019-07-25 13:59:43 +02001777 */
Michal Vasko52927e22020-03-16 17:26:14 +01001778static LY_ERR
1779lyd_dup_recursive(const struct lyd_node *node, struct lyd_node *parent, struct lyd_node **first, int options,
1780 struct lyd_node **dup_p)
Radek Krejci22ebdba2019-07-25 13:59:43 +02001781{
Michal Vasko52927e22020-03-16 17:26:14 +01001782 LY_ERR ret;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001783 struct lyd_node *dup = NULL;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001784 LY_ARRAY_SIZE_TYPE u;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001785
Michal Vasko52927e22020-03-16 17:26:14 +01001786 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001787
Michal Vasko52927e22020-03-16 17:26:14 +01001788 if (!node->schema) {
1789 dup = calloc(1, sizeof(struct lyd_node_opaq));
1790 } else {
1791 switch (node->schema->nodetype) {
Michal Vasko1bf09392020-03-27 12:38:10 +01001792 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +01001793 case LYS_ACTION:
1794 case LYS_NOTIF:
1795 case LYS_CONTAINER:
1796 case LYS_LIST:
1797 dup = calloc(1, sizeof(struct lyd_node_inner));
1798 break;
1799 case LYS_LEAF:
1800 case LYS_LEAFLIST:
1801 dup = calloc(1, sizeof(struct lyd_node_term));
1802 break;
1803 case LYS_ANYDATA:
1804 case LYS_ANYXML:
1805 dup = calloc(1, sizeof(struct lyd_node_any));
1806 break;
1807 default:
1808 LOGINT(LYD_NODE_CTX(node));
1809 ret = LY_EINT;
1810 goto error;
1811 }
Radek Krejci22ebdba2019-07-25 13:59:43 +02001812 }
Michal Vasko52927e22020-03-16 17:26:14 +01001813 LY_CHECK_ERR_GOTO(!dup, LOGMEM(LYD_NODE_CTX(node)); ret = LY_EMEM, error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001814
1815 /* TODO implement LYD_DUP_WITH_WHEN */
1816 dup->flags = node->flags;
1817 dup->schema = node->schema;
Michal Vasko52927e22020-03-16 17:26:14 +01001818 dup->prev = dup;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001819
1820 /* TODO duplicate attributes, implement LYD_DUP_NO_ATTR */
1821
1822 /* nodetype-specific work */
Michal Vasko52927e22020-03-16 17:26:14 +01001823 if (!dup->schema) {
1824 struct lyd_node_opaq *opaq = (struct lyd_node_opaq *)dup;
1825 struct lyd_node_opaq *orig = (struct lyd_node_opaq *)node;
1826 struct lyd_node *child;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001827
1828 if (options & LYD_DUP_RECURSIVE) {
1829 /* duplicate all the children */
1830 LY_LIST_FOR(orig->child, child) {
Michal Vasko52927e22020-03-16 17:26:14 +01001831 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
1832 }
1833 }
1834 opaq->name = lydict_insert(LYD_NODE_CTX(node), orig->name, 0);
1835 opaq->format = orig->format;
1836 if (orig->prefix.pref) {
1837 opaq->prefix.pref = lydict_insert(LYD_NODE_CTX(node), orig->prefix.pref, 0);
1838 }
1839 if (orig->prefix.ns) {
1840 opaq->prefix.ns = lydict_insert(LYD_NODE_CTX(node), orig->prefix.ns, 0);
1841 }
1842 if (orig->val_prefs) {
1843 LY_ARRAY_CREATE_GOTO(LYD_NODE_CTX(node), opaq->val_prefs, LY_ARRAY_SIZE(orig->val_prefs), ret, error);
1844 LY_ARRAY_FOR(orig->val_prefs, u) {
1845 opaq->val_prefs[u].pref = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].pref, 0);
1846 opaq->val_prefs[u].ns = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].ns, 0);
1847 LY_ARRAY_INCREMENT(opaq->val_prefs);
1848 }
1849 }
1850 opaq->value = lydict_insert(LYD_NODE_CTX(node), orig->value, 0);
1851 opaq->ctx = orig->ctx;
1852 } else if (dup->schema->nodetype & LYD_NODE_TERM) {
1853 struct lyd_node_term *term = (struct lyd_node_term *)dup;
1854 struct lyd_node_term *orig = (struct lyd_node_term *)node;
1855
1856 term->hash = orig->hash;
1857 term->value.realtype = orig->value.realtype;
1858 LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &orig->value, &term->value),
1859 LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."); ret = LY_EINT, error);
1860 } else if (dup->schema->nodetype & LYD_NODE_INNER) {
1861 struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
1862 struct lyd_node *child;
1863
1864 if (options & LYD_DUP_RECURSIVE) {
1865 /* duplicate all the children */
1866 LY_LIST_FOR(orig->child, child) {
1867 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001868 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02001869 } else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001870 /* always duplicate keys of a list */
Radek Krejci22ebdba2019-07-25 13:59:43 +02001871 child = orig->child;
Michal Vasko52927e22020-03-16 17:26:14 +01001872 for (struct lysc_node *key = ((struct lysc_node_list *)dup->schema)->child;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001873 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1874 key = key->next) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001875 if (!child) {
1876 /* possibly not keys are present in filtered tree */
1877 break;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001878 } else if (child->schema != key) {
1879 /* possibly not all keys are present in filtered tree,
1880 * but there can be also some non-key nodes */
1881 continue;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001882 }
Michal Vasko52927e22020-03-16 17:26:14 +01001883 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001884 child = child->next;
1885 }
1886 }
1887 lyd_hash(dup);
1888 } else if (dup->schema->nodetype & LYD_NODE_ANY) {
Michal Vasko52927e22020-03-16 17:26:14 +01001889 struct lyd_node_any *any = (struct lyd_node_any *)dup;
1890 struct lyd_node_any *orig = (struct lyd_node_any *)node;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001891
1892 any->hash = orig->hash;
1893 any->value_type = orig->value_type;
1894 switch (any->value_type) {
1895 case LYD_ANYDATA_DATATREE:
1896 if (orig->value.tree) {
1897 any->value.tree = lyd_dup(orig->value.tree, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_SIBLINGS);
Radek Krejci25dc3432020-05-15 14:42:12 +02001898 if (!any->value.tree) {
1899 /* get the last error's error code recorded by lyd_dup */
1900 struct ly_err_item *ei = ly_err_first(LYD_NODE_CTX(node));
1901 ret = ei ? ei->prev->no : LY_EOTHER;
1902 goto error;
1903 }
1904 LY_CHECK_ERR_GOTO(!any->value.tree, ret = 0 ,error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001905 }
1906 break;
1907 case LYD_ANYDATA_STRING:
1908 case LYD_ANYDATA_XML:
1909 case LYD_ANYDATA_JSON:
1910 if (orig->value.str) {
Michal Vasko52927e22020-03-16 17:26:14 +01001911 any->value.str = lydict_insert(LYD_NODE_CTX(node), orig->value.str, strlen(orig->value.str));
Radek Krejci22ebdba2019-07-25 13:59:43 +02001912 }
1913 break;
1914 }
1915 }
1916
Michal Vasko52927e22020-03-16 17:26:14 +01001917 /* insert */
1918 lyd_insert_node(parent, first, dup);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001919 lyd_insert_hash(dup);
Michal Vasko52927e22020-03-16 17:26:14 +01001920
1921 if (dup_p) {
1922 *dup_p = dup;
1923 }
1924 return LY_SUCCESS;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001925
1926error:
Michal Vasko52927e22020-03-16 17:26:14 +01001927 lyd_free_tree(dup);
1928 return ret;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001929}
1930
1931API struct lyd_node *
1932lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
1933{
1934 struct ly_ctx *ctx;
1935 const struct lyd_node *orig; /* original node to be duplicated */
1936 struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
Radek Krejci22ebdba2019-07-25 13:59:43 +02001937 struct lyd_node *top = NULL; /* the most higher created node */
1938 struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
1939 int keyless_parent_list = 0;
1940
1941 LY_CHECK_ARG_RET(NULL, node, NULL);
1942 ctx = node->schema->module->ctx;
1943
1944 if (options & LYD_DUP_WITH_PARENTS) {
1945 struct lyd_node_inner *orig_parent, *iter;
1946 int repeat = 1;
1947 for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
1948 if (parent && parent->schema == orig_parent->schema) {
1949 /* stop creating parents, connect what we have into the provided parent */
1950 iter = parent;
1951 repeat = 0;
1952 /* get know if there is a keyless list which we will have to rehash */
1953 for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02001954 if (piter->schema->nodetype == LYS_LIST && (piter->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001955 keyless_parent_list = 1;
1956 break;
1957 }
1958 }
1959 } else {
Michal Vasko52927e22020-03-16 17:26:14 +01001960 iter = NULL;
1961 LY_CHECK_GOTO(lyd_dup_recursive((struct lyd_node *)orig_parent, NULL, (struct lyd_node **)&iter, 0,
1962 (struct lyd_node **)&iter), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001963 }
1964 if (!local_parent) {
1965 local_parent = iter;
1966 }
1967 if (iter->child) {
1968 /* 1) list - add after keys
1969 * 2) provided parent with some children */
1970 iter->child->prev->next = top;
1971 if (top) {
1972 top->prev = iter->child->prev;
1973 iter->child->prev = top;
1974 }
1975 } else {
1976 iter->child = top;
1977 if (iter->schema->nodetype == LYS_LIST) {
1978 /* keyless list - we will need to rehash it since we are going to add nodes into it */
1979 keyless_parent_list = 1;
1980 }
1981 }
1982 if (top) {
1983 top->parent = iter;
1984 }
1985 top = (struct lyd_node*)iter;
1986 }
1987 if (repeat && parent) {
1988 /* given parent and created parents chain actually do not interconnect */
1989 LOGERR(ctx, LY_EINVAL, "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
1990 goto error;
1991 }
1992 } else {
1993 local_parent = parent;
1994 }
1995
Radek Krejci22ebdba2019-07-25 13:59:43 +02001996 LY_LIST_FOR(node, orig) {
Michal Vasko52927e22020-03-16 17:26:14 +01001997 /* if there is no local parent, it will be inserted into first */
1998 LY_CHECK_GOTO(lyd_dup_recursive(orig, (struct lyd_node *)local_parent, &first, options, first ? NULL : &first), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001999 if (!(options & LYD_DUP_WITH_SIBLINGS)) {
2000 break;
2001 }
2002 }
2003 if (keyless_parent_list) {
2004 /* rehash */
2005 for (; local_parent; local_parent = local_parent->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02002006 if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02002007 lyd_hash((struct lyd_node*)local_parent);
2008 }
2009 }
2010 }
2011 return first;
2012
2013error:
2014 if (top) {
2015 lyd_free_tree(top);
2016 } else {
Michal Vaskof03ed032020-03-04 13:31:44 +01002017 lyd_free_siblings(first);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002018 }
2019 return NULL;
2020}
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002021
2022static LY_ERR
2023lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
2024{
Michal Vasko14654712020-02-06 08:35:21 +01002025 /* ending \0 */
2026 ++reqlen;
2027
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002028 if (reqlen > *buflen) {
2029 if (is_static) {
2030 return LY_EINCOMPLETE;
2031 }
2032
2033 *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
2034 if (!*buffer) {
2035 return LY_EMEM;
2036 }
2037
2038 *buflen = reqlen;
2039 }
2040
2041 return LY_SUCCESS;
2042}
2043
2044/**
2045 * @brief Append all list key predicates to path.
2046 *
2047 * @param[in] node Node with keys to print.
2048 * @param[in,out] buffer Buffer to print to.
2049 * @param[in,out] buflen Current buffer length.
2050 * @param[in,out] bufused Current number of characters used in @p buffer.
2051 * @param[in] is_static Whether buffer is static or can be reallocated.
2052 * @return LY_ERR
2053 */
2054static LY_ERR
2055lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2056{
2057 const struct lyd_node *key;
2058 int dynamic = 0;
2059 size_t len;
2060 const char *val;
2061 char quot;
2062 LY_ERR rc;
2063
Michal Vasko14654712020-02-06 08:35:21 +01002064 for (key = lyd_node_children(node); key && (key->schema->flags & LYS_KEY); key = key->next) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002065 val = lyd_value2str((struct lyd_node_term *)key, &dynamic);
2066 len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
2067 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2068 if (rc != LY_SUCCESS) {
2069 if (dynamic) {
2070 free((char *)val);
2071 }
2072 return rc;
2073 }
2074
2075 quot = '\'';
2076 if (strchr(val, '\'')) {
2077 quot = '"';
2078 }
2079 *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
2080
2081 if (dynamic) {
2082 free((char *)val);
2083 }
2084 }
2085
2086 return LY_SUCCESS;
2087}
2088
2089/**
2090 * @brief Append leaf-list value predicate to path.
2091 *
2092 * @param[in] node Node to print.
2093 * @param[in,out] buffer Buffer to print to.
2094 * @param[in,out] buflen Current buffer length.
2095 * @param[in,out] bufused Current number of characters used in @p buffer.
2096 * @param[in] is_static Whether buffer is static or can be reallocated.
2097 * @return LY_ERR
2098 */
2099static LY_ERR
2100lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2101{
2102 int dynamic = 0;
2103 size_t len;
2104 const char *val;
2105 char quot;
2106 LY_ERR rc;
2107
2108 val = lyd_value2str((struct lyd_node_term *)node, &dynamic);
2109 len = 4 + strlen(val) + 2;
2110 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2111 if (rc != LY_SUCCESS) {
2112 goto cleanup;
2113 }
2114
2115 quot = '\'';
2116 if (strchr(val, '\'')) {
2117 quot = '"';
2118 }
2119 *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
2120
2121cleanup:
2122 if (dynamic) {
2123 free((char *)val);
2124 }
2125 return rc;
2126}
2127
2128/**
2129 * @brief Append node position (relative to its other instances) predicate to path.
2130 *
2131 * @param[in] node Node to print.
2132 * @param[in,out] buffer Buffer to print to.
2133 * @param[in,out] buflen Current buffer length.
2134 * @param[in,out] bufused Current number of characters used in @p buffer.
2135 * @param[in] is_static Whether buffer is static or can be reallocated.
2136 * @return LY_ERR
2137 */
2138static LY_ERR
2139lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2140{
2141 const struct lyd_node *first, *iter;
2142 size_t len;
2143 int pos;
2144 char *val = NULL;
2145 LY_ERR rc;
2146
2147 if (node->parent) {
2148 first = node->parent->child;
2149 } else {
2150 for (first = node; node->prev->next; node = node->prev);
2151 }
2152 pos = 1;
2153 for (iter = first; iter != node; iter = iter->next) {
2154 if (iter->schema == node->schema) {
2155 ++pos;
2156 }
2157 }
2158 if (asprintf(&val, "%d", pos) == -1) {
2159 return LY_EMEM;
2160 }
2161
2162 len = 1 + strlen(val) + 1;
2163 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2164 if (rc != LY_SUCCESS) {
2165 goto cleanup;
2166 }
2167
2168 *bufused += sprintf(*buffer + *bufused, "[%s]", val);
2169
2170cleanup:
2171 free(val);
2172 return rc;
2173}
2174
2175API char *
2176lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
2177{
Michal Vasko14654712020-02-06 08:35:21 +01002178 int is_static = 0, i, depth;
2179 size_t bufused = 0, len;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002180 const struct lyd_node *iter;
2181 const struct lys_module *mod;
2182 LY_ERR rc;
2183
2184 LY_CHECK_ARG_RET(NULL, node, NULL);
2185 if (buffer) {
2186 LY_CHECK_ARG_RET(node->schema->module->ctx, buflen > 1, NULL);
2187 is_static = 1;
Michal Vasko14654712020-02-06 08:35:21 +01002188 } else {
2189 buflen = 0;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002190 }
2191
2192 switch (pathtype) {
Michal Vasko14654712020-02-06 08:35:21 +01002193 case LYD_PATH_LOG:
2194 depth = 1;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002195 for (iter = node; iter->parent; iter = (const struct lyd_node *)iter->parent) {
2196 ++depth;
2197 }
2198
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002199 goto iter_print;
Michal Vasko14654712020-02-06 08:35:21 +01002200 while (depth) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002201 /* find the right node */
Michal Vasko14654712020-02-06 08:35:21 +01002202 for (iter = node, i = 1; i < depth; iter = (const struct lyd_node *)iter->parent, ++i);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002203iter_print:
2204 /* print prefix and name */
2205 mod = NULL;
2206 if (!iter->parent || (iter->schema->module != iter->parent->schema->module)) {
2207 mod = iter->schema->module;
2208 }
2209
2210 /* realloc string */
2211 len = 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(iter->schema->name);
2212 rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
2213 if (rc != LY_SUCCESS) {
2214 break;
2215 }
2216
2217 /* print next node */
2218 bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", iter->schema->name);
2219
2220 switch (iter->schema->nodetype) {
2221 case LYS_LIST:
2222 if (iter->schema->flags & LYS_KEYLESS) {
2223 /* print its position */
2224 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
2225 } else {
2226 /* print all list keys in predicates */
2227 rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
2228 }
2229 break;
2230 case LYS_LEAFLIST:
2231 if (iter->schema->flags & LYS_CONFIG_W) {
2232 /* print leaf-list value */
2233 rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
2234 } else {
2235 /* print its position */
2236 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
2237 }
2238 break;
2239 default:
2240 /* nothing to print more */
2241 rc = LY_SUCCESS;
2242 break;
2243 }
2244 if (rc != LY_SUCCESS) {
2245 break;
2246 }
2247
Michal Vasko14654712020-02-06 08:35:21 +01002248 --depth;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002249 }
2250 break;
2251 }
2252
2253 return buffer;
2254}
Michal Vaskoe444f752020-02-10 12:20:06 +01002255
Michal Vasko9b368d32020-02-14 13:53:31 +01002256LY_ERR
2257lyd_find_sibling_next2(const struct lyd_node *first, const struct lysc_node *schema, const char *key_or_value,
2258 size_t val_len, struct lyd_node **match)
Michal Vaskoe444f752020-02-10 12:20:06 +01002259{
2260 LY_ERR rc;
2261 const struct lyd_node *node = NULL;
2262 struct lyd_node_term *term;
Michal Vaskoe444f752020-02-10 12:20:06 +01002263 struct ly_keys keys = {0};
Michal Vasko90932a92020-02-12 14:33:03 +01002264 struct lyd_value val = {0};
Michal Vaskoe444f752020-02-10 12:20:06 +01002265 size_t i;
Michal Vaskoe444f752020-02-10 12:20:06 +01002266
Michal Vasko9b368d32020-02-14 13:53:31 +01002267 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
Michal Vaskoe444f752020-02-10 12:20:06 +01002268
2269 if (!first) {
2270 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01002271 if (match) {
2272 *match = NULL;
2273 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002274 return LY_ENOTFOUND;
2275 }
2276
Michal Vaskoe444f752020-02-10 12:20:06 +01002277 if (key_or_value && !val_len) {
2278 val_len = strlen(key_or_value);
2279 }
2280
2281 if (key_or_value && (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko90932a92020-02-12 14:33:03 +01002282 /* store the value */
Michal Vasko9b368d32020-02-14 13:53:31 +01002283 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 +01002284 } else if (key_or_value && (schema->nodetype == LYS_LIST)) {
2285 /* parse keys into canonical values */
Michal Vaskod3678892020-05-21 10:06:58 +02002286 LY_CHECK_GOTO(rc = ly_keys_parse(schema, key_or_value, val_len, 1, 1, &keys), cleanup);
Michal Vaskoe444f752020-02-10 12:20:06 +01002287 }
2288
2289 /* find first matching value */
2290 LY_LIST_FOR(first, node) {
2291 if (node->schema != schema) {
2292 continue;
2293 }
2294
2295 if ((schema->nodetype == LYS_LIST) && keys.str) {
2296 /* compare all set keys */
2297 for (i = 0; i < keys.key_count; ++i) {
2298 /* find key */
2299 rc = lyd_find_sibling_val(lyd_node_children(node), (struct lysc_node *)keys.keys[i].schema, NULL, 0,
2300 (struct lyd_node **)&term);
2301 if (rc == LY_ENOTFOUND) {
2302 /* all keys must always exist */
Michal Vasko9b368d32020-02-14 13:53:31 +01002303 LOGINT_RET(schema->module->ctx);
Michal Vaskoe444f752020-02-10 12:20:06 +01002304 }
2305 LY_CHECK_GOTO(rc, cleanup);
2306
2307 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01002308 if (!term->value.realtype->plugin->compare(&term->value, &keys.keys[i].val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002309 break;
2310 }
2311 }
2312
2313 if (i < keys.key_count) {
2314 /* not a match */
2315 continue;
2316 }
Michal Vasko90932a92020-02-12 14:33:03 +01002317 } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && val.realtype) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002318 term = (struct lyd_node_term *)node;
2319
2320 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01002321 if (!term->value.realtype->plugin->compare(&term->value, &val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002322 /* not a match */
2323 continue;
2324 }
2325 }
2326
2327 /* all criteria passed */
2328 break;
2329 }
2330
2331 if (!node) {
2332 rc = LY_ENOTFOUND;
Michal Vasko9b368d32020-02-14 13:53:31 +01002333 if (match) {
2334 *match = NULL;
2335 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002336 goto cleanup;
2337 }
2338
2339 /* success */
Michal Vasko9b368d32020-02-14 13:53:31 +01002340 if (match) {
2341 *match = (struct lyd_node *)node;
2342 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002343 rc = LY_SUCCESS;
2344
2345cleanup:
2346 ly_keys_clean(&keys);
Michal Vasko90932a92020-02-12 14:33:03 +01002347 if (val.realtype) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002348 val.realtype->plugin->free(schema->module->ctx, &val);
Michal Vasko90932a92020-02-12 14:33:03 +01002349 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002350 return rc;
2351}
2352
2353API LY_ERR
Michal Vasko9b368d32020-02-14 13:53:31 +01002354lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name, size_t name_len,
2355 const char *key_or_value, size_t val_len, struct lyd_node **match)
2356{
2357 const struct lysc_node *schema;
2358
2359 LY_CHECK_ARG_RET(NULL, module, name, match, LY_EINVAL);
2360
2361 if (!first) {
2362 /* no data */
2363 *match = NULL;
2364 return LY_ENOTFOUND;
2365 }
2366
2367 /* find schema */
2368 schema = lys_find_child(first->parent ? first->parent->schema : NULL, module, name, name_len, 0, 0);
2369 if (!schema) {
2370 LOGERR(module->ctx, LY_EINVAL, "Schema node not found.");
2371 return LY_EINVAL;
2372 }
2373
2374 return lyd_find_sibling_next2(first, schema, key_or_value, val_len, match);
2375}
2376
2377API LY_ERR
Michal Vaskoe444f752020-02-10 12:20:06 +01002378lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
2379{
2380 struct lyd_node **match_p;
2381 struct lyd_node_inner *parent;
2382
Michal Vaskof03ed032020-03-04 13:31:44 +01002383 LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
Michal Vaskoe444f752020-02-10 12:20:06 +01002384
Michal Vasko62ed12d2020-05-21 10:08:25 +02002385 if (!siblings || (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema))) {
2386 /* no data or schema mismatch */
Michal Vasko9b368d32020-02-14 13:53:31 +01002387 if (match) {
2388 *match = NULL;
2389 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002390 return LY_ENOTFOUND;
2391 }
2392
2393 /* find first sibling */
2394 if (siblings->parent) {
2395 siblings = siblings->parent->child;
2396 } else {
2397 while (siblings->prev->next) {
2398 siblings = siblings->prev;
2399 }
2400 }
2401
2402 parent = (struct lyd_node_inner *)siblings->parent;
2403 if (parent && parent->children_ht) {
2404 assert(target->hash);
2405
2406 /* find by hash */
2407 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
2408 siblings = *match_p;
2409 } else {
2410 /* not found */
2411 siblings = NULL;
2412 }
2413 } else {
2414 /* no children hash table */
2415 for (; siblings; siblings = siblings->next) {
2416 if (!lyd_compare(siblings, target, 0)) {
2417 break;
2418 }
2419 }
2420 }
2421
2422 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002423 if (match) {
2424 *match = NULL;
2425 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002426 return LY_ENOTFOUND;
2427 }
2428
Michal Vasko9b368d32020-02-14 13:53:31 +01002429 if (match) {
2430 *match = (struct lyd_node *)siblings;
2431 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002432 return LY_SUCCESS;
2433}
2434
2435API LY_ERR
2436lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
2437{
2438 struct lyd_node_inner *parent;
2439 struct lyd_node *match;
2440 struct lyd_node **match_p;
2441 struct ly_set *ret;
2442
2443 LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
2444
Michal Vasko62ed12d2020-05-21 10:08:25 +02002445 if (!siblings || (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema))) {
2446 /* no data or schema mismatch */
Michal Vaskoe444f752020-02-10 12:20:06 +01002447 return LY_ENOTFOUND;
2448 }
2449
2450 ret = ly_set_new();
2451 LY_CHECK_ERR_RET(!ret, LOGMEM(target->schema->module->ctx), LY_EMEM);
2452
2453 /* find first sibling */
2454 if (siblings->parent) {
2455 siblings = siblings->parent->child;
2456 } else {
2457 while (siblings->prev->next) {
2458 siblings = siblings->prev;
2459 }
2460 }
2461
2462 parent = (struct lyd_node_inner *)siblings->parent;
2463 if (parent && parent->children_ht) {
2464 assert(target->hash);
2465
2466 /* find by hash */
2467 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
2468 match = *match_p;
2469 } else {
2470 /* not found */
2471 match = NULL;
2472 }
2473 while (match) {
2474 /* add all found nodes into the return set */
2475 if (ly_set_add(ret, match, LY_SET_OPT_USEASLIST) == -1) {
2476 goto error;
2477 }
2478
2479 /* find next instance */
2480 if (lyht_find_next(parent->children_ht, &match, match->hash, (void **)&match_p)) {
2481 match = NULL;
2482 } else {
2483 match = *match_p;
2484 }
2485 }
2486 } else {
2487 /* no children hash table */
2488 for (; siblings; siblings = siblings->next) {
2489 if (!lyd_compare(siblings, target, 0)) {
2490 /* a match */
2491 if (ly_set_add(ret, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
2492 goto error;
2493 }
2494 }
2495 }
2496 }
2497
2498 if (!ret->count) {
2499 ly_set_free(ret, NULL);
2500 return LY_ENOTFOUND;
2501 }
2502
2503 *set = ret;
2504 return LY_SUCCESS;
2505
2506error:
2507 ly_set_free(ret, NULL);
2508 return LY_EMEM;
2509}
2510
Michal Vasko90932a92020-02-12 14:33:03 +01002511static int
2512lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
2513{
2514 struct lysc_node *val1;
2515 struct lyd_node *val2;
2516
2517 val1 = *((struct lysc_node **)val1_p);
2518 val2 = *((struct lyd_node **)val2_p);
2519
2520 assert(val1->nodetype & (LYD_NODE_INNER | LYS_LEAF));
2521
2522 if (val1 == val2->schema) {
2523 /* schema match is enough */
2524 return 1;
2525 } else {
2526 return 0;
2527 }
2528}
2529
2530static LY_ERR
2531lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
2532{
2533 struct lyd_node **match_p;
2534 struct lyd_node_inner *parent;
2535 uint32_t hash;
2536 values_equal_cb ht_cb;
2537
2538 assert(siblings && schema && (schema->nodetype & (LYD_NODE_INNER | LYS_LEAF)));
2539
2540 /* find first sibling */
2541 if (siblings->parent) {
2542 siblings = siblings->parent->child;
2543 } else {
2544 while (siblings->prev->next) {
2545 siblings = siblings->prev;
2546 }
2547 }
2548
2549 parent = (struct lyd_node_inner *)siblings->parent;
2550 if (parent && parent->children_ht) {
2551 /* calculate our hash */
2552 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
2553 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
2554 hash = dict_hash_multi(hash, NULL, 0);
2555
2556 /* use special hash table function */
2557 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
2558
2559 /* find by hash */
2560 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
2561 siblings = *match_p;
2562 } else {
2563 /* not found */
2564 siblings = NULL;
2565 }
2566
2567 /* set the original hash table compare function back */
2568 lyht_set_cb(parent->children_ht, ht_cb);
2569 } else {
2570 /* no children hash table */
2571 for (; siblings; siblings = siblings->next) {
2572 if (siblings->schema == schema) {
2573 /* schema match is enough */
2574 break;
2575 }
2576 }
2577 }
2578
2579 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002580 if (match) {
2581 *match = NULL;
2582 }
Michal Vasko90932a92020-02-12 14:33:03 +01002583 return LY_ENOTFOUND;
2584 }
2585
Michal Vasko9b368d32020-02-14 13:53:31 +01002586 if (match) {
2587 *match = (struct lyd_node *)siblings;
2588 }
Michal Vasko90932a92020-02-12 14:33:03 +01002589 return LY_SUCCESS;
2590}
2591
Michal Vaskoe444f752020-02-10 12:20:06 +01002592API LY_ERR
2593lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
2594 size_t val_len, struct lyd_node **match)
2595{
2596 LY_ERR rc;
2597 struct lyd_node *target = NULL;
2598
2599 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
Michal Vasko62ed12d2020-05-21 10:08:25 +02002600 if ((schema->nodetype == LYS_LIST) && (schema->flags & LYS_KEYLESS)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002601 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
2602 return LY_EINVAL;
2603 } else if ((schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && !key_or_value) {
2604 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - no value/keys for a (leaf-)list (%s()).", __func__);
2605 return LY_EINVAL;
2606 } else if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
2607 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
2608 lys_nodetype2str(schema->nodetype), __func__);
2609 return LY_EINVAL;
2610 }
2611
Michal Vasko62ed12d2020-05-21 10:08:25 +02002612 if (!siblings || (lysc_data_parent(siblings->schema) != lysc_data_parent(schema))) {
2613 /* no data or schema mismatch */
Michal Vasko9b368d32020-02-14 13:53:31 +01002614 if (match) {
2615 *match = NULL;
2616 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002617 return LY_ENOTFOUND;
2618 }
2619
Michal Vaskof03ed032020-03-04 13:31:44 +01002620 if (key_or_value && !val_len) {
2621 val_len = strlen(key_or_value);
2622 }
2623
Michal Vasko90932a92020-02-12 14:33:03 +01002624 /* create data node if needed and find it */
Michal Vaskoe444f752020-02-10 12:20:06 +01002625 switch (schema->nodetype) {
2626 case LYS_CONTAINER:
2627 case LYS_ANYXML:
2628 case LYS_ANYDATA:
2629 case LYS_NOTIF:
Michal Vasko1bf09392020-03-27 12:38:10 +01002630 case LYS_RPC:
Michal Vasko9b368d32020-02-14 13:53:31 +01002631 case LYS_ACTION:
Michal Vaskoe444f752020-02-10 12:20:06 +01002632 case LYS_LEAF:
Michal Vasko90932a92020-02-12 14:33:03 +01002633 /* find it based on schema only */
2634 rc = lyd_find_sibling_schema(siblings, schema, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01002635 break;
2636 case LYS_LEAFLIST:
2637 /* target used attributes: schema, hash, value */
Michal Vasko90932a92020-02-12 14:33:03 +01002638 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 +01002639 /* fallthrough */
Michal Vaskoe444f752020-02-10 12:20:06 +01002640 case LYS_LIST:
Michal Vasko90932a92020-02-12 14:33:03 +01002641 if (schema->nodetype == LYS_LIST) {
2642 /* target used attributes: schema, hash, child (all keys) */
Michal Vaskod3678892020-05-21 10:06:58 +02002643 LY_CHECK_RET(lyd_create_list(schema, key_or_value, val_len, LYD_JSON, 1, &target));
Michal Vasko90932a92020-02-12 14:33:03 +01002644 }
2645
2646 /* find it */
2647 rc = lyd_find_sibling_first(siblings, target, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01002648 break;
2649 default:
2650 /* unreachable */
2651 LOGINT(schema->module->ctx);
2652 return LY_EINT;
2653 }
2654
Michal Vaskoe444f752020-02-10 12:20:06 +01002655 lyd_free_tree(target);
2656 return rc;
2657}
Michal Vaskoccc02342020-05-21 10:09:21 +02002658
2659API LY_ERR
2660lyd_find_xpath(const struct lyd_node *ctx_node, const char *xpath, struct ly_set **set)
2661{
2662 LY_ERR ret = LY_SUCCESS;
2663 struct lyxp_set xp_set;
2664 struct lyxp_expr *exp;
2665 uint32_t i;
2666
2667 LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
2668
2669 memset(&xp_set, 0, sizeof xp_set);
2670
2671 /* compile expression */
2672 exp = lyxp_expr_parse((struct ly_ctx *)LYD_NODE_CTX(ctx_node), xpath);
2673 LY_CHECK_ERR_GOTO(!exp, ret = LY_EINVAL, cleanup);
2674
2675 /* evaluate expression */
2676 ret = lyxp_eval(exp, LYD_JSON, ctx_node->schema->module, ctx_node, LYXP_NODE_ELEM, ctx_node, &xp_set, 0);
2677 LY_CHECK_GOTO(ret, cleanup);
2678
2679 /* allocate return set */
2680 *set = ly_set_new();
2681 LY_CHECK_ERR_GOTO(!*set, LOGMEM(LYD_NODE_CTX(ctx_node)); ret = LY_EMEM, cleanup);
2682
2683 /* transform into ly_set */
2684 if (xp_set.type == LYXP_SET_NODE_SET) {
2685 /* allocate memory for all the elements once (even though not all items must be elements but most likely will be) */
2686 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
2687 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(LYD_NODE_CTX(ctx_node)); ret = LY_EMEM, cleanup);
2688 (*set)->size = xp_set.used;
2689
2690 for (i = 0; i < xp_set.used; ++i) {
2691 if (xp_set.val.nodes[i].type == LYXP_NODE_ELEM) {
2692 ly_set_add(*set, xp_set.val.nodes[i].node, LY_SET_OPT_USEASLIST);
2693 }
2694 }
2695 }
2696
2697cleanup:
Michal Vasko0691d522020-05-21 13:21:47 +02002698 lyxp_set_free_content(&xp_set);
Michal Vaskoccc02342020-05-21 10:09:21 +02002699 lyxp_expr_free((struct ly_ctx *)LYD_NODE_CTX(ctx_node), exp);
2700 return ret;
2701}