blob: b2ecee1c2f3f087158e73964aa4c7ccc271339e1 [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 }
Michal Vaskocbff3e92020-05-27 12:56:41 +0200681 LY_CHECK_GOTO(ret && (ret != LY_EINCOMPLETE), cleanup);
682 ret = LY_SUCCESS;
Michal Vasko90932a92020-02-12 14:33:03 +0100683 lyd_insert_node(list, NULL, key);
684 }
685
Michal Vasko9b368d32020-02-14 13:53:31 +0100686 /* hash having all the keys */
687 lyd_hash(list);
688
Michal Vasko90932a92020-02-12 14:33:03 +0100689 /* success */
690 *node = list;
691 list = NULL;
692
693cleanup:
694 lyd_free_tree(list);
695 ly_keys_clean(&keys);
696 return ret;
697}
698
699LY_ERR
700lyd_create_any(const struct lysc_node *schema, const void *value, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
701{
702 struct lyd_node_any *any;
703
Michal Vasko9b368d32020-02-14 13:53:31 +0100704 assert(schema->nodetype & LYD_NODE_ANY);
705
Michal Vasko90932a92020-02-12 14:33:03 +0100706 any = calloc(1, sizeof *any);
707 LY_CHECK_ERR_RET(!any, LOGMEM(schema->module->ctx), LY_EMEM);
708
709 any->schema = schema;
710 any->prev = (struct lyd_node *)any;
Michal Vasko9b368d32020-02-14 13:53:31 +0100711 any->flags = LYD_NEW;
Michal Vasko90932a92020-02-12 14:33:03 +0100712
713 any->value.xml = value;
714 any->value_type = value_type;
Michal Vasko9b368d32020-02-14 13:53:31 +0100715 lyd_hash((struct lyd_node *)any);
Michal Vasko90932a92020-02-12 14:33:03 +0100716
717 *node = (struct lyd_node *)any;
718 return LY_SUCCESS;
719}
720
Michal Vasko52927e22020-03-16 17:26:14 +0100721LY_ERR
722lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *value, size_t value_len,
723 int *dynamic, LYD_FORMAT format, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
724 const char *ns, struct lyd_node **node)
725{
726 struct lyd_node_opaq *opaq;
727
728 assert(ctx && name && name_len && ns);
729
730 if (!value_len) {
731 value = "";
732 }
733
734 opaq = calloc(1, sizeof *opaq);
735 LY_CHECK_ERR_RET(!opaq, LOGMEM(ctx), LY_EMEM);
736
737 opaq->prev = (struct lyd_node *)opaq;
738
739 opaq->name = lydict_insert(ctx, name, name_len);
740 opaq->format = format;
741 if (pref_len) {
742 opaq->prefix.pref = lydict_insert(ctx, prefix, pref_len);
743 }
744 opaq->prefix.ns = lydict_insert(ctx, ns, 0);
745 opaq->val_prefs = val_prefs;
746 if (dynamic && *dynamic) {
747 opaq->value = lydict_insert_zc(ctx, (char *)value);
748 *dynamic = 0;
749 } else {
750 opaq->value = lydict_insert(ctx, value, value_len);
751 }
752 opaq->ctx = ctx;
753
754 *node = (struct lyd_node *)opaq;
755 return LY_SUCCESS;
756}
757
Michal Vasko013a8182020-03-03 10:46:53 +0100758API struct lyd_node *
759lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name)
760{
761 struct lyd_node *ret = NULL;
762 const struct lysc_node *schema;
763 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
764
765 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
766
Michal Vaskof03ed032020-03-04 13:31:44 +0100767 if (!module) {
768 module = parent->schema->module;
769 }
770
Michal Vasko1bf09392020-03-27 12:38:10 +0100771 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 +0200772 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 +0100773
774 if (!lyd_create_inner(schema, &ret) && parent) {
775 lyd_insert_node(parent, NULL, ret);
776 }
777 return ret;
778}
779
780API struct lyd_node *
781lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, ...)
782{
783 struct lyd_node *ret = NULL, *key;
784 const struct lysc_node *schema, *key_s;
785 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
786 va_list ap;
787 const char *key_val;
788 LY_ERR rc = LY_SUCCESS;
789
790 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
791
Michal Vaskof03ed032020-03-04 13:31:44 +0100792 if (!module) {
793 module = parent->schema->module;
794 }
795
Michal Vasko013a8182020-03-03 10:46:53 +0100796 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
797 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
798
799 /* create list inner node */
800 LY_CHECK_RET(lyd_create_inner(schema, &ret), NULL);
801
802 va_start(ap, name);
803
804 /* create and insert all the keys */
805 for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
806 key_val = va_arg(ap, const char *);
807
Michal Vaskof03ed032020-03-04 13:31:44 +0100808 rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key);
Michal Vaskocbff3e92020-05-27 12:56:41 +0200809 LY_CHECK_GOTO(rc && (rc != LY_EINCOMPLETE), cleanup);
810 rc = LY_SUCCESS;
Michal Vasko013a8182020-03-03 10:46:53 +0100811 lyd_insert_node(ret, NULL, key);
812 }
813
814 /* hash having all the keys */
815 lyd_hash(ret);
816
817 if (parent) {
818 lyd_insert_node(parent, NULL, ret);
819 }
820
821cleanup:
822 if (rc) {
823 lyd_free_tree(ret);
824 ret = NULL;
825 }
826 va_end(ap);
827 return ret;
828}
829
830API struct lyd_node *
831lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys)
832{
833 struct lyd_node *ret = NULL;
834 const struct lysc_node *schema;
835 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
836
837 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
838
Michal Vaskof03ed032020-03-04 13:31:44 +0100839 if (!module) {
840 module = parent->schema->module;
841 }
842
Michal Vasko013a8182020-03-03 10:46:53 +0100843 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
844 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
845
Michal Vaskod3678892020-05-21 10:06:58 +0200846 if (!lyd_create_list(schema, keys, keys ? strlen(keys) : 0, LYD_JSON, 1, &ret) && parent) {
Michal Vasko013a8182020-03-03 10:46:53 +0100847 lyd_insert_node(parent, NULL, ret);
848 }
849 return ret;
850}
851
852API struct lyd_node *
853lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
854{
Michal Vaskocbff3e92020-05-27 12:56:41 +0200855 LY_ERR rc;
Michal Vasko013a8182020-03-03 10:46:53 +0100856 struct lyd_node *ret = NULL;
857 const struct lysc_node *schema;
858 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
859
860 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
861
Michal Vaskof03ed032020-03-04 13:31:44 +0100862 if (!module) {
863 module = parent->schema->module;
864 }
865
Michal Vasko013a8182020-03-03 10:46:53 +0100866 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, 0);
867 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), NULL);
868
Michal Vaskocbff3e92020-05-27 12:56:41 +0200869 rc = lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &ret);
870 LY_CHECK_RET(rc && (rc != LY_EINCOMPLETE), NULL);
871
872 if (parent) {
Michal Vasko013a8182020-03-03 10:46:53 +0100873 lyd_insert_node(parent, NULL, ret);
874 }
875 return ret;
876}
877
878API struct lyd_node *
879lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
880 LYD_ANYDATA_VALUETYPE value_type)
881{
882 struct lyd_node *ret = NULL;
883 const struct lysc_node *schema;
884 struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
885
886 LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
887
Michal Vaskof03ed032020-03-04 13:31:44 +0100888 if (!module) {
889 module = parent->schema->module;
890 }
891
Michal Vasko013a8182020-03-03 10:46:53 +0100892 schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, 0);
893 LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Any node \"%s\" not found.", name), NULL);
894
895 if (!lyd_create_any(schema, value, value_type, &ret) && parent) {
896 lyd_insert_node(parent, NULL, ret);
897 }
898 return ret;
899}
900
Michal Vaskod86997b2020-05-26 15:19:54 +0200901API struct lyd_meta *
902lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
903{
904 struct lyd_meta *ret = NULL;
905 struct ly_ctx *ctx = parent->schema->module->ctx;
906 const char *prefix, *tmp;
907 char *str;
908 size_t pref_len, name_len;
909
910 LY_CHECK_ARG_RET(ctx, parent, name, module || strchr(name, ':'), NULL);
911
912 /* parse the name */
913 tmp = name;
914 if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
915 LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
916 return NULL;
917 }
918
919 /* find the module */
920 if (prefix) {
921 str = strndup(name, name_len);
922 module = ly_ctx_get_module_implemented(ctx, str);
923 free(str);
924 LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%*.s\" not found.", pref_len, prefix), NULL);
925 }
926
927 /* set value if none */
928 if (!val_str) {
929 val_str = "";
930 }
931
932 lyd_create_meta(parent, &ret, module, name, name_len, val_str, strlen(val_str), NULL, lydjson_resolve_prefix, NULL,
933 LYD_JSON, parent->schema);
934 return ret;
935}
936
Michal Vasko90932a92020-02-12 14:33:03 +0100937struct lyd_node *
938lyd_get_prev_key_anchor(const struct lyd_node *first_sibling, const struct lysc_node *new_key)
939{
940 const struct lysc_node *prev_key;
941 struct lyd_node *match = NULL;
942
943 if (!first_sibling) {
944 return NULL;
945 }
946
947 for (prev_key = new_key->prev; !match && prev_key->next; prev_key = prev_key->prev) {
948 lyd_find_sibling_val(first_sibling, prev_key, NULL, 0, &match);
949 }
950
951 return match;
952}
953
954/**
955 * @brief Insert node after a sibling.
956 *
Michal Vasko9f96a052020-03-10 09:41:45 +0100957 * Handles inserting into NP containers and key-less lists.
958 *
Michal Vasko90932a92020-02-12 14:33:03 +0100959 * @param[in] sibling Sibling to insert after.
960 * @param[in] node Node to insert.
961 */
962static void
Michal Vaskof03ed032020-03-04 13:31:44 +0100963lyd_insert_after_node(struct lyd_node *sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +0100964{
Michal Vasko0249f7c2020-03-05 16:36:40 +0100965 struct lyd_node_inner *par;
966
Michal Vasko90932a92020-02-12 14:33:03 +0100967 assert(!node->next && (node->prev == node));
968
969 node->next = sibling->next;
970 node->prev = sibling;
971 sibling->next = node;
972 if (node->next) {
973 /* sibling had a succeeding node */
974 node->next->prev = node;
975 } else {
976 /* sibling was last, find first sibling and change its prev */
977 if (sibling->parent) {
978 sibling = sibling->parent->child;
979 } else {
980 for (; sibling->prev->next != node; sibling = sibling->prev);
981 }
982 sibling->prev = node;
983 }
984 node->parent = sibling->parent;
Michal Vasko0249f7c2020-03-05 16:36:40 +0100985
Michal Vasko9f96a052020-03-10 09:41:45 +0100986 for (par = node->parent; par; par = par->parent) {
987 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
988 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +0100989 par->flags &= ~LYD_DEFAULT;
990 }
Michal Vasko9f96a052020-03-10 09:41:45 +0100991 if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
992 /* rehash key-less list */
993 lyd_hash((struct lyd_node *)par);
994 }
Michal Vasko0249f7c2020-03-05 16:36:40 +0100995 }
996
997 /* insert into hash table */
998 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +0100999}
1000
1001/**
1002 * @brief Insert node before a sibling.
1003 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001004 * Handles inserting into NP containers and key-less lists.
1005 *
Michal Vasko90932a92020-02-12 14:33:03 +01001006 * @param[in] sibling Sibling to insert before.
1007 * @param[in] node Node to insert.
1008 */
1009static void
Michal Vaskof03ed032020-03-04 13:31:44 +01001010lyd_insert_before_node(struct lyd_node *sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +01001011{
Michal Vasko0249f7c2020-03-05 16:36:40 +01001012 struct lyd_node_inner *par;
1013
Michal Vasko90932a92020-02-12 14:33:03 +01001014 assert(!node->next && (node->prev == node));
1015
1016 node->next = sibling;
1017 /* covers situation of sibling being first */
1018 node->prev = sibling->prev;
1019 sibling->prev = node;
1020 if (node->prev->next) {
1021 /* sibling had a preceding node */
1022 node->prev->next = node;
1023 } else if (sibling->parent) {
1024 /* sibling was first and we must also change parent child pointer */
1025 sibling->parent->child = node;
1026 }
1027 node->parent = sibling->parent;
Michal Vasko0249f7c2020-03-05 16:36:40 +01001028
Michal Vasko9f96a052020-03-10 09:41:45 +01001029 for (par = node->parent; par; par = par->parent) {
1030 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
1031 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +01001032 par->flags &= ~LYD_DEFAULT;
1033 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001034 if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
1035 /* rehash key-less list */
1036 lyd_hash((struct lyd_node *)par);
1037 }
Michal Vasko0249f7c2020-03-05 16:36:40 +01001038 }
1039
1040 /* insert into hash table */
1041 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +01001042}
1043
1044/**
1045 * @brief Insert node as the last child of a parent.
1046 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001047 * Handles inserting into NP containers and key-less lists.
1048 *
Michal Vasko90932a92020-02-12 14:33:03 +01001049 * @param[in] parent Parent to insert into.
1050 * @param[in] node Node to insert.
1051 */
1052static void
Michal Vaskof03ed032020-03-04 13:31:44 +01001053lyd_insert_last_node(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +01001054{
1055 struct lyd_node_inner *par;
1056
Michal Vasko0249f7c2020-03-05 16:36:40 +01001057 assert(parent && !node->next && (node->prev == node));
Michal Vasko52927e22020-03-16 17:26:14 +01001058 assert(!parent->schema || (parent->schema->nodetype & LYD_NODE_INNER));
Michal Vasko90932a92020-02-12 14:33:03 +01001059
1060 par = (struct lyd_node_inner *)parent;
1061
1062 if (!par->child) {
1063 par->child = node;
1064 } else {
1065 node->prev = par->child->prev;
1066 par->child->prev->next = node;
1067 par->child->prev = node;
1068 }
1069 node->parent = par;
Michal Vasko0249f7c2020-03-05 16:36:40 +01001070
Michal Vasko9f96a052020-03-10 09:41:45 +01001071 for (; par; par = par->parent) {
1072 if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
1073 /* remove default flags from NP containers */
Michal Vasko0249f7c2020-03-05 16:36:40 +01001074 par->flags &= ~LYD_DEFAULT;
1075 }
Michal Vasko52927e22020-03-16 17:26:14 +01001076 if (par->schema && (par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001077 /* rehash key-less list */
1078 lyd_hash((struct lyd_node *)par);
1079 }
Michal Vasko0249f7c2020-03-05 16:36:40 +01001080 }
1081
1082 /* insert into hash table */
1083 lyd_insert_hash(node);
Michal Vasko90932a92020-02-12 14:33:03 +01001084}
1085
1086void
Michal Vasko9b368d32020-02-14 13:53:31 +01001087lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node)
Michal Vasko90932a92020-02-12 14:33:03 +01001088{
Michal Vasko9b368d32020-02-14 13:53:31 +01001089 struct lyd_node *anchor;
Michal Vasko9f96a052020-03-10 09:41:45 +01001090 const struct lysc_node *skey = NULL;
1091 int has_keys;
Michal Vasko90932a92020-02-12 14:33:03 +01001092
Michal Vasko52927e22020-03-16 17:26:14 +01001093 assert((parent || first_sibling) && node && (node->hash || !node->schema));
Michal Vasko9b368d32020-02-14 13:53:31 +01001094
1095 if (!parent && first_sibling && (*first_sibling) && (*first_sibling)->parent) {
1096 parent = (struct lyd_node *)(*first_sibling)->parent;
1097 }
Michal Vasko90932a92020-02-12 14:33:03 +01001098
1099 if (parent) {
Michal Vasko52927e22020-03-16 17:26:14 +01001100 if (node->schema && (node->schema->flags & LYS_KEY)) {
Michal Vasko90932a92020-02-12 14:33:03 +01001101 /* it is key and we need to insert it at the correct place */
Michal Vasko9b368d32020-02-14 13:53:31 +01001102 anchor = lyd_get_prev_key_anchor(lyd_node_children(parent), node->schema);
1103 if (anchor) {
Michal Vaskof03ed032020-03-04 13:31:44 +01001104 lyd_insert_after_node(anchor, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001105 } else if (lyd_node_children(parent)) {
Radek Krejcidae0ee82020-05-06 16:53:24 +02001106 lyd_insert_before_node(lyd_node_children(parent), node);
Michal Vasko90932a92020-02-12 14:33:03 +01001107 } else {
Michal Vaskof03ed032020-03-04 13:31:44 +01001108 lyd_insert_last_node(parent, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001109 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001110
1111 /* hash list if all its keys were added */
1112 assert(parent->schema->nodetype == LYS_LIST);
Radek Krejcidae0ee82020-05-06 16:53:24 +02001113 anchor = lyd_node_children(parent);
Michal Vasko9f96a052020-03-10 09:41:45 +01001114 has_keys = 1;
1115 while ((skey = lys_getnext(skey, parent->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
1116 if (!anchor || (anchor->schema != skey)) {
1117 /* key missing */
1118 has_keys = 0;
1119 break;
1120 }
1121
1122 anchor = anchor->next;
1123 }
1124 if (has_keys) {
1125 lyd_hash(parent);
1126 }
1127
Michal Vasko90932a92020-02-12 14:33:03 +01001128 } else {
1129 /* last child */
Michal Vaskof03ed032020-03-04 13:31:44 +01001130 lyd_insert_last_node(parent, node);
Michal Vasko90932a92020-02-12 14:33:03 +01001131 }
Michal Vasko9b368d32020-02-14 13:53:31 +01001132 } else if (*first_sibling) {
Michal Vaskob1b5c262020-03-05 14:29:47 +01001133 /* top-level siblings */
Michal Vasko9b368d32020-02-14 13:53:31 +01001134 anchor = (*first_sibling)->prev;
Michal Vaskoc193ce92020-03-06 11:04:48 +01001135 while (anchor->prev->next && (lyd_owner_module(anchor) != lyd_owner_module(node))) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001136 anchor = anchor->prev;
1137 }
1138
Michal Vaskoc193ce92020-03-06 11:04:48 +01001139 if (lyd_owner_module(anchor) == lyd_owner_module(node)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +01001140 /* insert after last sibling from this module */
1141 lyd_insert_after_node(anchor, node);
1142 } else {
1143 /* no data from this module, insert at the last position */
1144 lyd_insert_after_node((*first_sibling)->prev, node);
1145 }
Michal Vasko90932a92020-02-12 14:33:03 +01001146 } else {
Michal Vasko9b368d32020-02-14 13:53:31 +01001147 /* the only sibling */
1148 *first_sibling = node;
Michal Vasko90932a92020-02-12 14:33:03 +01001149 }
Michal Vasko90932a92020-02-12 14:33:03 +01001150}
1151
Michal Vaskof03ed032020-03-04 13:31:44 +01001152static LY_ERR
1153lyd_insert_check_schema(const struct lysc_node *parent, const struct lysc_node *schema)
1154{
1155 const struct lysc_node *par2;
1156
1157 assert(schema);
Michal Vasko62ed12d2020-05-21 10:08:25 +02001158 assert(!parent || !(parent->nodetype & (LYS_CASE | LYS_CHOICE)));
Michal Vaskof03ed032020-03-04 13:31:44 +01001159
1160 /* find schema parent */
Michal Vasko62ed12d2020-05-21 10:08:25 +02001161 par2 = lysc_data_parent(schema);
Michal Vaskof03ed032020-03-04 13:31:44 +01001162
1163 if (parent) {
1164 /* inner node */
1165 if (par2 != parent) {
1166 LOGERR(parent->module->ctx, LY_EINVAL, "Cannot insert, parent of \"%s\" is not \"%s\".", schema->name, parent->name);
1167 return LY_EINVAL;
1168 }
1169 } else {
1170 /* top-level node */
1171 if (par2) {
1172 LOGERR(parent->module->ctx, LY_EINVAL, "Cannot insert, node \"%s\" is not top-level.", schema->name);
1173 return LY_EINVAL;
1174 }
1175 }
1176
1177 return LY_SUCCESS;
1178}
1179
1180API LY_ERR
1181lyd_insert(struct lyd_node *parent, struct lyd_node *node)
1182{
1183 struct lyd_node *iter;
1184
1185 LY_CHECK_ARG_RET(NULL, parent, node, !(parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
1186
1187 LY_CHECK_RET(lyd_insert_check_schema(parent->schema, node->schema));
1188
1189 if (node->schema->flags & LYS_KEY) {
1190 LOGERR(parent->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1191 return LY_EINVAL;
1192 }
1193
1194 if (node->parent || node->prev->next) {
1195 lyd_unlink_tree(node);
1196 }
1197
1198 while (node) {
1199 iter = node->next;
1200 lyd_unlink_tree(node);
1201 lyd_insert_node(parent, NULL, node);
1202 node = iter;
1203 }
1204 return LY_SUCCESS;
1205}
1206
1207API LY_ERR
Michal Vaskob1b5c262020-03-05 14:29:47 +01001208lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node)
1209{
1210 struct lyd_node *iter;
1211
1212 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1213
Michal Vasko62ed12d2020-05-21 10:08:25 +02001214 LY_CHECK_RET(lyd_insert_check_schema(lysc_data_parent(sibling->schema), node->schema));
Michal Vaskob1b5c262020-03-05 14:29:47 +01001215
1216 if (node->schema->flags & LYS_KEY) {
1217 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1218 return LY_EINVAL;
1219 }
1220
1221 if (node->parent || node->prev->next) {
1222 lyd_unlink_tree(node);
1223 }
1224
1225 while (node) {
1226 iter = node->next;
1227 lyd_unlink_tree(node);
1228 lyd_insert_node(NULL, &sibling, node);
1229 node = iter;
1230 }
1231 return LY_SUCCESS;
1232}
1233
Michal Vasko0249f7c2020-03-05 16:36:40 +01001234static LY_ERR
1235lyd_insert_after_check_place(struct lyd_node *anchor, struct lyd_node *sibling, struct lyd_node *node)
1236{
1237 if (sibling->parent) {
1238 /* nested, we do not care for the order */
1239 return LY_SUCCESS;
1240 }
1241
1242 if (anchor) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001243 if (anchor->next && (lyd_owner_module(anchor) == lyd_owner_module(anchor->next))
1244 && (lyd_owner_module(node) != lyd_owner_module(anchor))) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001245 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 +01001246 lyd_owner_module(node)->name, lyd_owner_module(anchor)->name);
Michal Vasko0249f7c2020-03-05 16:36:40 +01001247 return LY_EINVAL;
1248 }
1249
Michal Vaskoc193ce92020-03-06 11:04:48 +01001250 if ((lyd_owner_module(node) == lyd_owner_module(anchor))
1251 || (anchor->next && (lyd_owner_module(node) == lyd_owner_module(anchor->next)))) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001252 /* inserting before/after its module data */
1253 return LY_SUCCESS;
1254 }
1255 }
1256
1257 /* find first sibling */
1258 while (sibling->prev->next) {
1259 sibling = sibling->prev;
1260 }
1261
1262 if (!anchor) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001263 if (lyd_owner_module(node) == lyd_owner_module(sibling)) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001264 /* inserting before its module data */
1265 return LY_SUCCESS;
1266 }
1267 }
1268
1269 /* check there are no data of this module */
1270 LY_LIST_FOR(sibling, sibling) {
Michal Vaskoc193ce92020-03-06 11:04:48 +01001271 if (lyd_owner_module(node) == lyd_owner_module(sibling)) {
Michal Vasko0249f7c2020-03-05 16:36:40 +01001272 /* some data of this module found */
1273 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Top-level data of module \"%s\" already exist,"
Michal Vaskoc193ce92020-03-06 11:04:48 +01001274 " they must be directly connected.", lyd_owner_module(node)->name);
Michal Vasko0249f7c2020-03-05 16:36:40 +01001275 return LY_EINVAL;
1276 }
1277 }
1278
1279 return LY_SUCCESS;
1280}
1281
Michal Vaskob1b5c262020-03-05 14:29:47 +01001282API LY_ERR
Michal Vaskof03ed032020-03-04 13:31:44 +01001283lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
1284{
1285 struct lyd_node *iter;
1286
1287 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1288
Michal Vasko62ed12d2020-05-21 10:08:25 +02001289 LY_CHECK_RET(lyd_insert_check_schema(lysc_data_parent(sibling->schema), node->schema));
Michal Vaskof03ed032020-03-04 13:31:44 +01001290
1291 if (node->schema->flags & LYS_KEY) {
1292 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1293 return LY_EINVAL;
1294 } else if (sibling->schema->flags & LYS_KEY) {
1295 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert into keys.");
1296 return LY_EINVAL;
1297 }
1298
Michal Vasko0249f7c2020-03-05 16:36:40 +01001299 LY_CHECK_RET(lyd_insert_after_check_place(sibling->prev->next ? sibling->prev : NULL, sibling, node));
1300
Michal Vaskof03ed032020-03-04 13:31:44 +01001301 if (node->parent || node->prev->next) {
1302 lyd_unlink_tree(node);
1303 }
1304
1305 /* insert in reverse order to get the original order */
1306 node = node->prev;
1307 while (node) {
1308 iter = node->prev;
1309 lyd_unlink_tree(node);
1310
1311 lyd_insert_before_node(sibling, node);
1312 /* move the anchor accordingly */
1313 sibling = node;
1314
1315 node = (iter == node) ? NULL : iter;
1316 }
1317 return LY_SUCCESS;
1318}
1319
1320API LY_ERR
1321lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
1322{
1323 struct lyd_node *iter;
1324
1325 LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
1326
Michal Vasko62ed12d2020-05-21 10:08:25 +02001327 LY_CHECK_RET(lyd_insert_check_schema(lysc_data_parent(sibling->schema), node->schema));
Michal Vaskof03ed032020-03-04 13:31:44 +01001328
1329 if (node->schema->flags & LYS_KEY) {
1330 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
1331 return LY_EINVAL;
1332 } else if (sibling->next && (sibling->next->schema->flags & LYS_KEY)) {
1333 LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert into keys.");
1334 return LY_EINVAL;
1335 }
1336
Michal Vasko0249f7c2020-03-05 16:36:40 +01001337 LY_CHECK_RET(lyd_insert_after_check_place(sibling, sibling, node));
1338
Michal Vaskof03ed032020-03-04 13:31:44 +01001339 if (node->parent || node->prev->next) {
1340 lyd_unlink_tree(node);
1341 }
1342
1343 while (node) {
1344 iter = node->next;
1345 lyd_unlink_tree(node);
1346
1347 lyd_insert_after_node(sibling, node);
1348 /* move the anchor accordingly */
1349 sibling = node;
1350
1351 node = iter;
1352 }
1353 return LY_SUCCESS;
1354}
1355
1356API void
1357lyd_unlink_tree(struct lyd_node *node)
1358{
1359 struct lyd_node *iter;
1360
1361 if (!node) {
1362 return;
1363 }
1364
1365 /* unlink from siblings */
1366 if (node->prev->next) {
1367 node->prev->next = node->next;
1368 }
1369 if (node->next) {
1370 node->next->prev = node->prev;
1371 } else {
1372 /* unlinking the last node */
1373 if (node->parent) {
1374 iter = node->parent->child;
1375 } else {
1376 iter = node->prev;
1377 while (iter->prev != node) {
1378 iter = iter->prev;
1379 }
1380 }
1381 /* update the "last" pointer from the first node */
1382 iter->prev = node->prev;
1383 }
1384
1385 /* unlink from parent */
1386 if (node->parent) {
1387 if (node->parent->child == node) {
1388 /* the node is the first child */
1389 node->parent->child = node->next;
1390 }
1391
1392 lyd_unlink_hash(node);
1393
1394 /* check for keyless list and update its hash */
1395 for (iter = (struct lyd_node *)node->parent; iter; iter = (struct lyd_node *)iter->parent) {
Michal Vasko413c7f22020-05-05 12:34:06 +02001396 if (iter->schema && (iter->schema->flags & LYS_KEYLESS)) {
Michal Vaskof03ed032020-03-04 13:31:44 +01001397 lyd_hash(iter);
1398 }
1399 }
1400
1401 node->parent = NULL;
1402 }
1403
1404 node->next = NULL;
1405 node->prev = node;
1406}
1407
Michal Vasko90932a92020-02-12 14:33:03 +01001408LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +01001409lyd_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 +01001410 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 +01001411 void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode)
Michal Vasko90932a92020-02-12 14:33:03 +01001412{
1413 LY_ERR ret;
1414 struct lysc_ext_instance *ant = NULL;
Michal Vasko9f96a052020-03-10 09:41:45 +01001415 struct lyd_meta *mt, *last;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001416 LY_ARRAY_SIZE_TYPE u;
Michal Vasko90932a92020-02-12 14:33:03 +01001417
Michal Vasko9f96a052020-03-10 09:41:45 +01001418 assert((parent || meta) && mod);
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001419
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001420 LY_ARRAY_FOR(mod->compiled->exts, u) {
1421 if (mod->compiled->exts[u].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
1422 !ly_strncmp(mod->compiled->exts[u].argument, name, name_len)) {
Michal Vasko90932a92020-02-12 14:33:03 +01001423 /* we have the annotation definition */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001424 ant = &mod->compiled->exts[u];
Michal Vasko90932a92020-02-12 14:33:03 +01001425 break;
1426 }
1427 }
1428 if (!ant) {
1429 /* attribute is not defined as a metadata annotation (RFC 7952) */
1430 LOGERR(mod->ctx, LY_EINVAL, "Annotation definition for attribute \"%s:%.*s\" not found.",
1431 mod->name, name_len, name);
1432 return LY_EINVAL;
1433 }
1434
Michal Vasko9f96a052020-03-10 09:41:45 +01001435 mt = calloc(1, sizeof *mt);
1436 LY_CHECK_ERR_RET(!mt, LOGMEM(mod->ctx), LY_EMEM);
1437 mt->parent = parent;
1438 mt->annotation = ant;
Michal Vasko52927e22020-03-16 17:26:14 +01001439 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 +01001440 if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001441 free(mt);
Michal Vasko90932a92020-02-12 14:33:03 +01001442 return ret;
1443 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001444 mt->name = lydict_insert(mod->ctx, name, name_len);
Michal Vasko90932a92020-02-12 14:33:03 +01001445
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001446 /* insert as the last attribute */
1447 if (parent) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001448 if (parent->meta) {
1449 for (last = parent->meta; last->next; last = last->next);
1450 last->next = mt;
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001451 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01001452 parent->meta = mt;
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001453 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001454 } else if (*meta) {
1455 for (last = *meta; last->next; last = last->next);
1456 last->next = mt;
Michal Vasko90932a92020-02-12 14:33:03 +01001457 }
1458
1459 /* remove default flags from NP containers */
1460 while (parent && (parent->flags & LYD_DEFAULT)) {
1461 parent->flags &= ~LYD_DEFAULT;
1462 parent = (struct lyd_node *)parent->parent;
1463 }
1464
Michal Vasko9f96a052020-03-10 09:41:45 +01001465 if (meta) {
1466 *meta = mt;
Michal Vasko90932a92020-02-12 14:33:03 +01001467 }
1468 return ret;
1469}
1470
Michal Vasko52927e22020-03-16 17:26:14 +01001471LY_ERR
1472ly_create_attr(struct lyd_node *parent, struct ly_attr **attr, const struct ly_ctx *ctx, const char *name,
1473 size_t name_len, const char *value, size_t value_len, int *dynamic, LYD_FORMAT format,
1474 struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *ns)
1475{
1476 struct ly_attr *at, *last;
1477 struct lyd_node_opaq *opaq;
1478
1479 assert(ctx && (parent || attr) && (!parent || !parent->schema));
1480 assert(name && name_len);
1481 assert((prefix_len && ns) || (!prefix_len && !ns));
1482
1483 if (!value_len) {
1484 value = "";
1485 }
1486
1487 at = calloc(1, sizeof *at);
1488 LY_CHECK_ERR_RET(!at, LOGMEM(ctx), LY_EMEM);
1489 at->parent = (struct lyd_node_opaq *)parent;
1490 at->name = lydict_insert(ctx, name, name_len);
1491 if (dynamic && *dynamic) {
1492 at->value = lydict_insert_zc(ctx, (char *)value);
1493 *dynamic = 0;
1494 } else {
1495 at->value = lydict_insert(ctx, value, value_len);
1496 }
1497
1498 at->format = format;
1499 at->val_prefs = val_prefs;
1500 if (ns) {
1501 at->prefix.pref = lydict_insert(ctx, prefix, prefix_len);
1502 at->prefix.ns = lydict_insert(ctx, ns, 0);
1503 }
1504
1505 /* insert as the last attribute */
1506 if (parent) {
1507 opaq = (struct lyd_node_opaq *)parent;
1508 if (opaq->attr) {
1509 for (last = opaq->attr; last->next; last = last->next);
1510 last->next = at;
1511 } else {
1512 opaq->attr = at;
1513 }
1514 } else if (*attr) {
1515 for (last = *attr; last->next; last = last->next);
1516 last->next = at;
1517 }
1518
1519 if (attr) {
1520 *attr = at;
1521 }
1522 return LY_SUCCESS;
1523}
1524
Radek Krejci084289f2019-07-09 17:35:30 +02001525API const struct lyd_node_term *
Michal Vaskof03ed032020-03-04 13:31:44 +01001526lyd_target(struct lyd_value_path *path, const struct lyd_node *tree)
Radek Krejci084289f2019-07-09 17:35:30 +02001527{
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001528 LY_ARRAY_SIZE_TYPE u, v;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001529 const struct lyd_node *start_sibling;
Michal Vaskoe444f752020-02-10 12:20:06 +01001530 struct lyd_node *node = NULL;
Radek Krejci084289f2019-07-09 17:35:30 +02001531 uint64_t pos = 1;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001532 int match;
Radek Krejci084289f2019-07-09 17:35:30 +02001533
Michal Vaskof03ed032020-03-04 13:31:44 +01001534 LY_CHECK_ARG_RET(NULL, path, tree, NULL);
Radek Krejci084289f2019-07-09 17:35:30 +02001535
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001536 /* first iteration */
1537 start_sibling = tree;
1538 u = 0;
1539 while (u < LY_ARRAY_SIZE(path)) {
1540 /* find next node instance */
Michal Vasko84c9f1b2020-05-14 12:08:11 +02001541 if (start_sibling && !start_sibling->prev->next && !(path[u].node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
1542 /* starting from the beginning using hashes */
1543 lyd_find_sibling_val(start_sibling, path[u].node, NULL, 0, &node);
1544 } else {
1545 /* next matching sibling */
1546 lyd_find_sibling_next2(start_sibling, path[u].node, NULL, 0, &node);
1547 }
Radek Krejci084289f2019-07-09 17:35:30 +02001548 if (!node) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001549 break;
Radek Krejci084289f2019-07-09 17:35:30 +02001550 }
1551
1552 /* check predicate if any */
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001553 match = 1;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001554 LY_ARRAY_FOR(path[u].predicates, v) {
1555 if (path[u].predicates[v].type == 0) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001556 assert(LY_ARRAY_SIZE(path[u].predicates) == 1);
Radek Krejci084289f2019-07-09 17:35:30 +02001557 /* position predicate */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001558 if (pos != path[u].predicates[v].position) {
Radek Krejci084289f2019-07-09 17:35:30 +02001559 pos++;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001560 match = 0;
Radek Krejci084289f2019-07-09 17:35:30 +02001561 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001562 } else if (path[u].predicates[v].type == 1) {
Radek Krejci084289f2019-07-09 17:35:30 +02001563 /* key-predicate */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001564 struct lysc_type *type = ((struct lysc_node_leaf *)path[u].predicates[v].key)->type;
Michal Vaskoe444f752020-02-10 12:20:06 +01001565 struct lyd_node *key;
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001566
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001567 lyd_find_sibling_val(lyd_node_children(node), path[u].predicates[v].key, NULL, 0, &key);
Radek Krejci084289f2019-07-09 17:35:30 +02001568 if (!key) {
1569 /* probably error and we shouldn't be here due to previous checks when creating path */
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001570 match = 0;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001571 } else if (type->plugin->compare(&((struct lyd_node_term *)key)->value, path[u].predicates[v].value)) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001572 match = 0;
Radek Krejci084289f2019-07-09 17:35:30 +02001573 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001574 } else if (path[u].predicates[v].type == 2) {
Radek Krejci084289f2019-07-09 17:35:30 +02001575 /* leaf-list-predicate */
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001576 struct lysc_type *type = ((struct lysc_node_leaf *)path[u].node)->type;
1577
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001578 if (type->plugin->compare(&((struct lyd_node_term *)node)->value, path[u].predicates[v].value)) {
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001579 match = 0;
Radek Krejci084289f2019-07-09 17:35:30 +02001580 }
1581 } else {
1582 LOGINT(NULL);
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001583 return NULL;
1584 }
1585
1586 if (!match) {
1587 /* useless to check more predicates */
1588 break;
Radek Krejci084289f2019-07-09 17:35:30 +02001589 }
1590 }
1591
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001592 if (!match) {
1593 /* try to match next sibling */
1594 start_sibling = node->next;
1595 } else {
1596 /* matched, move to the next path segment */
1597 ++u;
1598 start_sibling = lyd_node_children(node);
1599 pos = 1;
1600 }
Radek Krejci084289f2019-07-09 17:35:30 +02001601 }
1602
Michal Vasko6a12b4b2020-05-13 14:28:09 +02001603 return (const struct lyd_node_term *)node;
Radek Krejci084289f2019-07-09 17:35:30 +02001604}
1605
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001606API LY_ERR
1607lyd_compare(const struct lyd_node *node1, const struct lyd_node *node2, int options)
1608{
1609 const struct lyd_node *iter1, *iter2;
1610 struct lyd_node_term *term1, *term2;
1611 struct lyd_node_any *any1, *any2;
Michal Vasko52927e22020-03-16 17:26:14 +01001612 struct lyd_node_opaq *opaq1, *opaq2;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001613 struct lysc_type *type;
1614 size_t len1, len2;
Radek Krejci084289f2019-07-09 17:35:30 +02001615
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001616 if (!node1 || !node2) {
1617 if (node1 == node2) {
1618 return LY_SUCCESS;
1619 } else {
1620 return LY_ENOT;
1621 }
1622 }
1623
Michal Vasko52927e22020-03-16 17:26:14 +01001624 if ((LYD_NODE_CTX(node1) != LYD_NODE_CTX(node2)) || (node1->schema != node2->schema)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001625 return LY_ENOT;
1626 }
1627
1628 if (node1->hash != node2->hash) {
1629 return LY_ENOT;
1630 }
Michal Vasko52927e22020-03-16 17:26:14 +01001631 /* 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 +02001632
Michal Vasko52927e22020-03-16 17:26:14 +01001633 if (!node1->schema) {
1634 opaq1 = (struct lyd_node_opaq *)node1;
1635 opaq2 = (struct lyd_node_opaq *)node2;
1636 if ((opaq1->name != opaq2->name) || (opaq1->prefix.ns != opaq2->prefix.ns) || (opaq1->format != opaq2->format)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001637 return LY_ENOT;
1638 }
Michal Vasko52927e22020-03-16 17:26:14 +01001639 switch (opaq1->format) {
1640 case LYD_XML:
1641 if (lyxml_value_compare(opaq1->value, opaq1->val_prefs, opaq2->value, opaq2->val_prefs)) {
1642 return LY_ENOT;
1643 }
1644 break;
1645 case LYD_SCHEMA:
1646 /* not allowed */
1647 LOGINT(LYD_NODE_CTX(node1));
1648 return LY_EINT;
1649 }
1650 if (options & LYD_COMPARE_FULL_RECURSION) {
1651 iter1 = opaq1->child;
1652 iter2 = opaq2->child;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001653 goto all_children_compare;
Michal Vasko52927e22020-03-16 17:26:14 +01001654 }
1655 return LY_SUCCESS;
1656 } else {
1657 switch (node1->schema->nodetype) {
1658 case LYS_LEAF:
1659 case LYS_LEAFLIST:
1660 if (options & LYD_COMPARE_DEFAULTS) {
1661 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1662 return LY_ENOT;
1663 }
1664 }
1665
1666 term1 = (struct lyd_node_term*)node1;
1667 term2 = (struct lyd_node_term*)node2;
1668 type = ((struct lysc_node_leaf*)node1->schema)->type;
1669
1670 return type->plugin->compare(&term1->value, &term2->value);
1671 case LYS_CONTAINER:
1672 if (options & LYD_COMPARE_DEFAULTS) {
1673 if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
1674 return LY_ENOT;
1675 }
1676 }
1677 if (options & LYD_COMPARE_FULL_RECURSION) {
1678 iter1 = ((struct lyd_node_inner*)node1)->child;
1679 iter2 = ((struct lyd_node_inner*)node2)->child;
1680 goto all_children_compare;
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001681 }
1682 return LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +01001683 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +01001684 case LYS_ACTION:
1685 if (options & LYD_COMPARE_FULL_RECURSION) {
1686 /* TODO action/RPC
1687 goto all_children_compare;
1688 */
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001689 }
1690 return LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +01001691 case LYS_NOTIF:
1692 if (options & LYD_COMPARE_FULL_RECURSION) {
1693 /* TODO Notification
1694 goto all_children_compare;
1695 */
1696 }
1697 return LY_SUCCESS;
1698 case LYS_LIST:
1699 iter1 = ((struct lyd_node_inner*)node1)->child;
1700 iter2 = ((struct lyd_node_inner*)node2)->child;
1701
1702 if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
1703 /* lists with keys, their equivalence is based on their keys */
1704 for (struct lysc_node *key = ((struct lysc_node_list*)node1->schema)->child;
1705 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1706 key = key->next) {
1707 if (lyd_compare(iter1, iter2, options)) {
1708 return LY_ENOT;
1709 }
1710 iter1 = iter1->next;
1711 iter2 = iter2->next;
1712 }
1713 } else {
1714 /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
1715
1716 all_children_compare:
1717 if (!iter1 && !iter2) {
1718 /* no children, nothing to compare */
1719 return LY_SUCCESS;
1720 }
1721
1722 for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
1723 if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
1724 return LY_ENOT;
1725 }
1726 }
1727 if (iter1 || iter2) {
1728 return LY_ENOT;
1729 }
1730 }
1731 return LY_SUCCESS;
1732 case LYS_ANYXML:
1733 case LYS_ANYDATA:
1734 any1 = (struct lyd_node_any*)node1;
1735 any2 = (struct lyd_node_any*)node2;
1736
1737 if (any1->value_type != any2->value_type) {
1738 return LY_ENOT;
1739 }
1740 switch (any1->value_type) {
1741 case LYD_ANYDATA_DATATREE:
1742 iter1 = any1->value.tree;
1743 iter2 = any2->value.tree;
1744 goto all_children_compare;
1745 case LYD_ANYDATA_STRING:
1746 case LYD_ANYDATA_XML:
1747 case LYD_ANYDATA_JSON:
1748 len1 = strlen(any1->value.str);
1749 len2 = strlen(any2->value.str);
1750 if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
1751 return LY_ENOT;
1752 }
1753 return LY_SUCCESS;
1754 #if 0 /* TODO LYB format */
1755 case LYD_ANYDATA_LYB:
1756 int len1 = lyd_lyb_data_length(any1->value.mem);
1757 int len2 = lyd_lyb_data_length(any2->value.mem);
1758 if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
1759 return LY_ENOT;
1760 }
1761 return LY_SUCCESS;
1762 #endif
1763 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001764 }
1765 }
1766
Michal Vasko52927e22020-03-16 17:26:14 +01001767 LOGINT(LYD_NODE_CTX(node1));
Radek Krejci1f05b6a2019-07-18 16:15:06 +02001768 return LY_EINT;
1769}
Radek Krejci22ebdba2019-07-25 13:59:43 +02001770
1771/**
Michal Vasko52927e22020-03-16 17:26:14 +01001772 * @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 +02001773 *
1774 * 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 +02001775 *
1776 * @param[in] node Original node to duplicate
1777 * @param[in] parent Parent to insert into, NULL for top-level sibling.
1778 * @param[in,out] first First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
1779 * @param[in] options Bitmask of options flags, see @ref dupoptions.
1780 * @param[out] dup_p Pointer where the created duplicated node is placed (besides connecting it int @p parent / @p first sibling).
1781 * @return LY_ERR value
Radek Krejci22ebdba2019-07-25 13:59:43 +02001782 */
Michal Vasko52927e22020-03-16 17:26:14 +01001783static LY_ERR
1784lyd_dup_recursive(const struct lyd_node *node, struct lyd_node *parent, struct lyd_node **first, int options,
1785 struct lyd_node **dup_p)
Radek Krejci22ebdba2019-07-25 13:59:43 +02001786{
Michal Vasko52927e22020-03-16 17:26:14 +01001787 LY_ERR ret;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001788 struct lyd_node *dup = NULL;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001789 LY_ARRAY_SIZE_TYPE u;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001790
Michal Vasko52927e22020-03-16 17:26:14 +01001791 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001792
Michal Vasko52927e22020-03-16 17:26:14 +01001793 if (!node->schema) {
1794 dup = calloc(1, sizeof(struct lyd_node_opaq));
1795 } else {
1796 switch (node->schema->nodetype) {
Michal Vasko1bf09392020-03-27 12:38:10 +01001797 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +01001798 case LYS_ACTION:
1799 case LYS_NOTIF:
1800 case LYS_CONTAINER:
1801 case LYS_LIST:
1802 dup = calloc(1, sizeof(struct lyd_node_inner));
1803 break;
1804 case LYS_LEAF:
1805 case LYS_LEAFLIST:
1806 dup = calloc(1, sizeof(struct lyd_node_term));
1807 break;
1808 case LYS_ANYDATA:
1809 case LYS_ANYXML:
1810 dup = calloc(1, sizeof(struct lyd_node_any));
1811 break;
1812 default:
1813 LOGINT(LYD_NODE_CTX(node));
1814 ret = LY_EINT;
1815 goto error;
1816 }
Radek Krejci22ebdba2019-07-25 13:59:43 +02001817 }
Michal Vasko52927e22020-03-16 17:26:14 +01001818 LY_CHECK_ERR_GOTO(!dup, LOGMEM(LYD_NODE_CTX(node)); ret = LY_EMEM, error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001819
1820 /* TODO implement LYD_DUP_WITH_WHEN */
1821 dup->flags = node->flags;
1822 dup->schema = node->schema;
Michal Vasko52927e22020-03-16 17:26:14 +01001823 dup->prev = dup;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001824
1825 /* TODO duplicate attributes, implement LYD_DUP_NO_ATTR */
1826
1827 /* nodetype-specific work */
Michal Vasko52927e22020-03-16 17:26:14 +01001828 if (!dup->schema) {
1829 struct lyd_node_opaq *opaq = (struct lyd_node_opaq *)dup;
1830 struct lyd_node_opaq *orig = (struct lyd_node_opaq *)node;
1831 struct lyd_node *child;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001832
1833 if (options & LYD_DUP_RECURSIVE) {
1834 /* duplicate all the children */
1835 LY_LIST_FOR(orig->child, child) {
Michal Vasko52927e22020-03-16 17:26:14 +01001836 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
1837 }
1838 }
1839 opaq->name = lydict_insert(LYD_NODE_CTX(node), orig->name, 0);
1840 opaq->format = orig->format;
1841 if (orig->prefix.pref) {
1842 opaq->prefix.pref = lydict_insert(LYD_NODE_CTX(node), orig->prefix.pref, 0);
1843 }
1844 if (orig->prefix.ns) {
1845 opaq->prefix.ns = lydict_insert(LYD_NODE_CTX(node), orig->prefix.ns, 0);
1846 }
1847 if (orig->val_prefs) {
1848 LY_ARRAY_CREATE_GOTO(LYD_NODE_CTX(node), opaq->val_prefs, LY_ARRAY_SIZE(orig->val_prefs), ret, error);
1849 LY_ARRAY_FOR(orig->val_prefs, u) {
1850 opaq->val_prefs[u].pref = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].pref, 0);
1851 opaq->val_prefs[u].ns = lydict_insert(LYD_NODE_CTX(node), orig->val_prefs[u].ns, 0);
1852 LY_ARRAY_INCREMENT(opaq->val_prefs);
1853 }
1854 }
1855 opaq->value = lydict_insert(LYD_NODE_CTX(node), orig->value, 0);
1856 opaq->ctx = orig->ctx;
1857 } else if (dup->schema->nodetype & LYD_NODE_TERM) {
1858 struct lyd_node_term *term = (struct lyd_node_term *)dup;
1859 struct lyd_node_term *orig = (struct lyd_node_term *)node;
1860
1861 term->hash = orig->hash;
1862 term->value.realtype = orig->value.realtype;
1863 LY_CHECK_ERR_GOTO(term->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &orig->value, &term->value),
1864 LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."); ret = LY_EINT, error);
1865 } else if (dup->schema->nodetype & LYD_NODE_INNER) {
1866 struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
1867 struct lyd_node *child;
1868
1869 if (options & LYD_DUP_RECURSIVE) {
1870 /* duplicate all the children */
1871 LY_LIST_FOR(orig->child, child) {
1872 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001873 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02001874 } else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001875 /* always duplicate keys of a list */
Radek Krejci22ebdba2019-07-25 13:59:43 +02001876 child = orig->child;
Michal Vasko52927e22020-03-16 17:26:14 +01001877 for (struct lysc_node *key = ((struct lysc_node_list *)dup->schema)->child;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001878 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY);
1879 key = key->next) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001880 if (!child) {
1881 /* possibly not keys are present in filtered tree */
1882 break;
Radek Krejci0fe9b512019-07-26 17:51:05 +02001883 } else if (child->schema != key) {
1884 /* possibly not all keys are present in filtered tree,
1885 * but there can be also some non-key nodes */
1886 continue;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001887 }
Michal Vasko52927e22020-03-16 17:26:14 +01001888 LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001889 child = child->next;
1890 }
1891 }
1892 lyd_hash(dup);
1893 } else if (dup->schema->nodetype & LYD_NODE_ANY) {
Michal Vasko52927e22020-03-16 17:26:14 +01001894 struct lyd_node_any *any = (struct lyd_node_any *)dup;
1895 struct lyd_node_any *orig = (struct lyd_node_any *)node;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001896
1897 any->hash = orig->hash;
1898 any->value_type = orig->value_type;
1899 switch (any->value_type) {
1900 case LYD_ANYDATA_DATATREE:
1901 if (orig->value.tree) {
1902 any->value.tree = lyd_dup(orig->value.tree, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_SIBLINGS);
Radek Krejci25dc3432020-05-15 14:42:12 +02001903 if (!any->value.tree) {
1904 /* get the last error's error code recorded by lyd_dup */
1905 struct ly_err_item *ei = ly_err_first(LYD_NODE_CTX(node));
1906 ret = ei ? ei->prev->no : LY_EOTHER;
1907 goto error;
1908 }
1909 LY_CHECK_ERR_GOTO(!any->value.tree, ret = 0 ,error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001910 }
1911 break;
1912 case LYD_ANYDATA_STRING:
1913 case LYD_ANYDATA_XML:
1914 case LYD_ANYDATA_JSON:
1915 if (orig->value.str) {
Michal Vasko52927e22020-03-16 17:26:14 +01001916 any->value.str = lydict_insert(LYD_NODE_CTX(node), orig->value.str, strlen(orig->value.str));
Radek Krejci22ebdba2019-07-25 13:59:43 +02001917 }
1918 break;
1919 }
1920 }
1921
Michal Vasko52927e22020-03-16 17:26:14 +01001922 /* insert */
1923 lyd_insert_node(parent, first, dup);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001924 lyd_insert_hash(dup);
Michal Vasko52927e22020-03-16 17:26:14 +01001925
1926 if (dup_p) {
1927 *dup_p = dup;
1928 }
1929 return LY_SUCCESS;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001930
1931error:
Michal Vasko52927e22020-03-16 17:26:14 +01001932 lyd_free_tree(dup);
1933 return ret;
Radek Krejci22ebdba2019-07-25 13:59:43 +02001934}
1935
1936API struct lyd_node *
1937lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
1938{
1939 struct ly_ctx *ctx;
1940 const struct lyd_node *orig; /* original node to be duplicated */
1941 struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
Radek Krejci22ebdba2019-07-25 13:59:43 +02001942 struct lyd_node *top = NULL; /* the most higher created node */
1943 struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
1944 int keyless_parent_list = 0;
1945
1946 LY_CHECK_ARG_RET(NULL, node, NULL);
1947 ctx = node->schema->module->ctx;
1948
1949 if (options & LYD_DUP_WITH_PARENTS) {
1950 struct lyd_node_inner *orig_parent, *iter;
1951 int repeat = 1;
1952 for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
1953 if (parent && parent->schema == orig_parent->schema) {
1954 /* stop creating parents, connect what we have into the provided parent */
1955 iter = parent;
1956 repeat = 0;
1957 /* get know if there is a keyless list which we will have to rehash */
1958 for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02001959 if (piter->schema->nodetype == LYS_LIST && (piter->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02001960 keyless_parent_list = 1;
1961 break;
1962 }
1963 }
1964 } else {
Michal Vasko52927e22020-03-16 17:26:14 +01001965 iter = NULL;
1966 LY_CHECK_GOTO(lyd_dup_recursive((struct lyd_node *)orig_parent, NULL, (struct lyd_node **)&iter, 0,
1967 (struct lyd_node **)&iter), error);
Radek Krejci22ebdba2019-07-25 13:59:43 +02001968 }
1969 if (!local_parent) {
1970 local_parent = iter;
1971 }
1972 if (iter->child) {
1973 /* 1) list - add after keys
1974 * 2) provided parent with some children */
1975 iter->child->prev->next = top;
1976 if (top) {
1977 top->prev = iter->child->prev;
1978 iter->child->prev = top;
1979 }
1980 } else {
1981 iter->child = top;
1982 if (iter->schema->nodetype == LYS_LIST) {
1983 /* keyless list - we will need to rehash it since we are going to add nodes into it */
1984 keyless_parent_list = 1;
1985 }
1986 }
1987 if (top) {
1988 top->parent = iter;
1989 }
1990 top = (struct lyd_node*)iter;
1991 }
1992 if (repeat && parent) {
1993 /* given parent and created parents chain actually do not interconnect */
1994 LOGERR(ctx, LY_EINVAL, "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
1995 goto error;
1996 }
1997 } else {
1998 local_parent = parent;
1999 }
2000
Radek Krejci22ebdba2019-07-25 13:59:43 +02002001 LY_LIST_FOR(node, orig) {
Michal Vasko52927e22020-03-16 17:26:14 +01002002 /* if there is no local parent, it will be inserted into first */
2003 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 +02002004 if (!(options & LYD_DUP_WITH_SIBLINGS)) {
2005 break;
2006 }
2007 }
2008 if (keyless_parent_list) {
2009 /* rehash */
2010 for (; local_parent; local_parent = local_parent->parent) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02002011 if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
Radek Krejci22ebdba2019-07-25 13:59:43 +02002012 lyd_hash((struct lyd_node*)local_parent);
2013 }
2014 }
2015 }
2016 return first;
2017
2018error:
2019 if (top) {
2020 lyd_free_tree(top);
2021 } else {
Michal Vaskof03ed032020-03-04 13:31:44 +01002022 lyd_free_siblings(first);
Radek Krejci22ebdba2019-07-25 13:59:43 +02002023 }
2024 return NULL;
2025}
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002026
2027static LY_ERR
2028lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
2029{
Michal Vasko14654712020-02-06 08:35:21 +01002030 /* ending \0 */
2031 ++reqlen;
2032
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002033 if (reqlen > *buflen) {
2034 if (is_static) {
2035 return LY_EINCOMPLETE;
2036 }
2037
2038 *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
2039 if (!*buffer) {
2040 return LY_EMEM;
2041 }
2042
2043 *buflen = reqlen;
2044 }
2045
2046 return LY_SUCCESS;
2047}
2048
2049/**
2050 * @brief Append all list key predicates to path.
2051 *
2052 * @param[in] node Node with keys to print.
2053 * @param[in,out] buffer Buffer to print to.
2054 * @param[in,out] buflen Current buffer length.
2055 * @param[in,out] bufused Current number of characters used in @p buffer.
2056 * @param[in] is_static Whether buffer is static or can be reallocated.
2057 * @return LY_ERR
2058 */
2059static LY_ERR
2060lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2061{
2062 const struct lyd_node *key;
2063 int dynamic = 0;
2064 size_t len;
2065 const char *val;
2066 char quot;
2067 LY_ERR rc;
2068
Michal Vasko14654712020-02-06 08:35:21 +01002069 for (key = lyd_node_children(node); key && (key->schema->flags & LYS_KEY); key = key->next) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002070 val = lyd_value2str((struct lyd_node_term *)key, &dynamic);
2071 len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
2072 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2073 if (rc != LY_SUCCESS) {
2074 if (dynamic) {
2075 free((char *)val);
2076 }
2077 return rc;
2078 }
2079
2080 quot = '\'';
2081 if (strchr(val, '\'')) {
2082 quot = '"';
2083 }
2084 *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
2085
2086 if (dynamic) {
2087 free((char *)val);
2088 }
2089 }
2090
2091 return LY_SUCCESS;
2092}
2093
2094/**
2095 * @brief Append leaf-list value predicate to path.
2096 *
2097 * @param[in] node Node to print.
2098 * @param[in,out] buffer Buffer to print to.
2099 * @param[in,out] buflen Current buffer length.
2100 * @param[in,out] bufused Current number of characters used in @p buffer.
2101 * @param[in] is_static Whether buffer is static or can be reallocated.
2102 * @return LY_ERR
2103 */
2104static LY_ERR
2105lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2106{
2107 int dynamic = 0;
2108 size_t len;
2109 const char *val;
2110 char quot;
2111 LY_ERR rc;
2112
2113 val = lyd_value2str((struct lyd_node_term *)node, &dynamic);
2114 len = 4 + strlen(val) + 2;
2115 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2116 if (rc != LY_SUCCESS) {
2117 goto cleanup;
2118 }
2119
2120 quot = '\'';
2121 if (strchr(val, '\'')) {
2122 quot = '"';
2123 }
2124 *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
2125
2126cleanup:
2127 if (dynamic) {
2128 free((char *)val);
2129 }
2130 return rc;
2131}
2132
2133/**
2134 * @brief Append node position (relative to its other instances) predicate to path.
2135 *
2136 * @param[in] node Node to print.
2137 * @param[in,out] buffer Buffer to print to.
2138 * @param[in,out] buflen Current buffer length.
2139 * @param[in,out] bufused Current number of characters used in @p buffer.
2140 * @param[in] is_static Whether buffer is static or can be reallocated.
2141 * @return LY_ERR
2142 */
2143static LY_ERR
2144lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
2145{
2146 const struct lyd_node *first, *iter;
2147 size_t len;
2148 int pos;
2149 char *val = NULL;
2150 LY_ERR rc;
2151
2152 if (node->parent) {
2153 first = node->parent->child;
2154 } else {
2155 for (first = node; node->prev->next; node = node->prev);
2156 }
2157 pos = 1;
2158 for (iter = first; iter != node; iter = iter->next) {
2159 if (iter->schema == node->schema) {
2160 ++pos;
2161 }
2162 }
2163 if (asprintf(&val, "%d", pos) == -1) {
2164 return LY_EMEM;
2165 }
2166
2167 len = 1 + strlen(val) + 1;
2168 rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
2169 if (rc != LY_SUCCESS) {
2170 goto cleanup;
2171 }
2172
2173 *bufused += sprintf(*buffer + *bufused, "[%s]", val);
2174
2175cleanup:
2176 free(val);
2177 return rc;
2178}
2179
2180API char *
2181lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
2182{
Michal Vasko14654712020-02-06 08:35:21 +01002183 int is_static = 0, i, depth;
2184 size_t bufused = 0, len;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002185 const struct lyd_node *iter;
2186 const struct lys_module *mod;
2187 LY_ERR rc;
2188
2189 LY_CHECK_ARG_RET(NULL, node, NULL);
2190 if (buffer) {
2191 LY_CHECK_ARG_RET(node->schema->module->ctx, buflen > 1, NULL);
2192 is_static = 1;
Michal Vasko14654712020-02-06 08:35:21 +01002193 } else {
2194 buflen = 0;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002195 }
2196
2197 switch (pathtype) {
Michal Vasko14654712020-02-06 08:35:21 +01002198 case LYD_PATH_LOG:
2199 depth = 1;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002200 for (iter = node; iter->parent; iter = (const struct lyd_node *)iter->parent) {
2201 ++depth;
2202 }
2203
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002204 goto iter_print;
Michal Vasko14654712020-02-06 08:35:21 +01002205 while (depth) {
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002206 /* find the right node */
Michal Vasko14654712020-02-06 08:35:21 +01002207 for (iter = node, i = 1; i < depth; iter = (const struct lyd_node *)iter->parent, ++i);
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002208iter_print:
2209 /* print prefix and name */
2210 mod = NULL;
2211 if (!iter->parent || (iter->schema->module != iter->parent->schema->module)) {
2212 mod = iter->schema->module;
2213 }
2214
2215 /* realloc string */
2216 len = 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(iter->schema->name);
2217 rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
2218 if (rc != LY_SUCCESS) {
2219 break;
2220 }
2221
2222 /* print next node */
2223 bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", iter->schema->name);
2224
2225 switch (iter->schema->nodetype) {
2226 case LYS_LIST:
2227 if (iter->schema->flags & LYS_KEYLESS) {
2228 /* print its position */
2229 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
2230 } else {
2231 /* print all list keys in predicates */
2232 rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
2233 }
2234 break;
2235 case LYS_LEAFLIST:
2236 if (iter->schema->flags & LYS_CONFIG_W) {
2237 /* print leaf-list value */
2238 rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
2239 } else {
2240 /* print its position */
2241 rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
2242 }
2243 break;
2244 default:
2245 /* nothing to print more */
2246 rc = LY_SUCCESS;
2247 break;
2248 }
2249 if (rc != LY_SUCCESS) {
2250 break;
2251 }
2252
Michal Vasko14654712020-02-06 08:35:21 +01002253 --depth;
Michal Vasko5ec7cda2019-09-11 13:43:08 +02002254 }
2255 break;
2256 }
2257
2258 return buffer;
2259}
Michal Vaskoe444f752020-02-10 12:20:06 +01002260
Michal Vasko9b368d32020-02-14 13:53:31 +01002261LY_ERR
2262lyd_find_sibling_next2(const struct lyd_node *first, const struct lysc_node *schema, const char *key_or_value,
2263 size_t val_len, struct lyd_node **match)
Michal Vaskoe444f752020-02-10 12:20:06 +01002264{
2265 LY_ERR rc;
2266 const struct lyd_node *node = NULL;
2267 struct lyd_node_term *term;
Michal Vaskoe444f752020-02-10 12:20:06 +01002268 struct ly_keys keys = {0};
Michal Vasko90932a92020-02-12 14:33:03 +01002269 struct lyd_value val = {0};
Michal Vaskoe444f752020-02-10 12:20:06 +01002270 size_t i;
Michal Vaskoe444f752020-02-10 12:20:06 +01002271
Michal Vasko9b368d32020-02-14 13:53:31 +01002272 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
Michal Vaskoe444f752020-02-10 12:20:06 +01002273
2274 if (!first) {
2275 /* no data */
Michal Vasko9b368d32020-02-14 13:53:31 +01002276 if (match) {
2277 *match = NULL;
2278 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002279 return LY_ENOTFOUND;
2280 }
2281
Michal Vaskoe444f752020-02-10 12:20:06 +01002282 if (key_or_value && !val_len) {
2283 val_len = strlen(key_or_value);
2284 }
2285
2286 if (key_or_value && (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko90932a92020-02-12 14:33:03 +01002287 /* store the value */
Michal Vasko9b368d32020-02-14 13:53:31 +01002288 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 +01002289 } else if (key_or_value && (schema->nodetype == LYS_LIST)) {
2290 /* parse keys into canonical values */
Michal Vaskod3678892020-05-21 10:06:58 +02002291 LY_CHECK_GOTO(rc = ly_keys_parse(schema, key_or_value, val_len, 1, 1, &keys), cleanup);
Michal Vaskoe444f752020-02-10 12:20:06 +01002292 }
2293
2294 /* find first matching value */
2295 LY_LIST_FOR(first, node) {
2296 if (node->schema != schema) {
2297 continue;
2298 }
2299
2300 if ((schema->nodetype == LYS_LIST) && keys.str) {
2301 /* compare all set keys */
2302 for (i = 0; i < keys.key_count; ++i) {
2303 /* find key */
2304 rc = lyd_find_sibling_val(lyd_node_children(node), (struct lysc_node *)keys.keys[i].schema, NULL, 0,
2305 (struct lyd_node **)&term);
2306 if (rc == LY_ENOTFOUND) {
2307 /* all keys must always exist */
Michal Vasko9b368d32020-02-14 13:53:31 +01002308 LOGINT_RET(schema->module->ctx);
Michal Vaskoe444f752020-02-10 12:20:06 +01002309 }
2310 LY_CHECK_GOTO(rc, cleanup);
2311
2312 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01002313 if (!term->value.realtype->plugin->compare(&term->value, &keys.keys[i].val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002314 break;
2315 }
2316 }
2317
2318 if (i < keys.key_count) {
2319 /* not a match */
2320 continue;
2321 }
Michal Vasko90932a92020-02-12 14:33:03 +01002322 } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && val.realtype) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002323 term = (struct lyd_node_term *)node;
2324
2325 /* compare values */
Michal Vasko90932a92020-02-12 14:33:03 +01002326 if (!term->value.realtype->plugin->compare(&term->value, &val)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002327 /* not a match */
2328 continue;
2329 }
2330 }
2331
2332 /* all criteria passed */
2333 break;
2334 }
2335
2336 if (!node) {
2337 rc = LY_ENOTFOUND;
Michal Vasko9b368d32020-02-14 13:53:31 +01002338 if (match) {
2339 *match = NULL;
2340 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002341 goto cleanup;
2342 }
2343
2344 /* success */
Michal Vasko9b368d32020-02-14 13:53:31 +01002345 if (match) {
2346 *match = (struct lyd_node *)node;
2347 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002348 rc = LY_SUCCESS;
2349
2350cleanup:
2351 ly_keys_clean(&keys);
Michal Vasko90932a92020-02-12 14:33:03 +01002352 if (val.realtype) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002353 val.realtype->plugin->free(schema->module->ctx, &val);
Michal Vasko90932a92020-02-12 14:33:03 +01002354 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002355 return rc;
2356}
2357
2358API LY_ERR
Michal Vasko9b368d32020-02-14 13:53:31 +01002359lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name, size_t name_len,
2360 const char *key_or_value, size_t val_len, struct lyd_node **match)
2361{
2362 const struct lysc_node *schema;
2363
2364 LY_CHECK_ARG_RET(NULL, module, name, match, LY_EINVAL);
2365
2366 if (!first) {
2367 /* no data */
2368 *match = NULL;
2369 return LY_ENOTFOUND;
2370 }
2371
2372 /* find schema */
2373 schema = lys_find_child(first->parent ? first->parent->schema : NULL, module, name, name_len, 0, 0);
2374 if (!schema) {
2375 LOGERR(module->ctx, LY_EINVAL, "Schema node not found.");
2376 return LY_EINVAL;
2377 }
2378
2379 return lyd_find_sibling_next2(first, schema, key_or_value, val_len, match);
2380}
2381
2382API LY_ERR
Michal Vaskoe444f752020-02-10 12:20:06 +01002383lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
2384{
2385 struct lyd_node **match_p;
2386 struct lyd_node_inner *parent;
2387
Michal Vaskof03ed032020-03-04 13:31:44 +01002388 LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
Michal Vaskoe444f752020-02-10 12:20:06 +01002389
Michal Vasko62ed12d2020-05-21 10:08:25 +02002390 if (!siblings || (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema))) {
2391 /* no data or schema mismatch */
Michal Vasko9b368d32020-02-14 13:53:31 +01002392 if (match) {
2393 *match = NULL;
2394 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002395 return LY_ENOTFOUND;
2396 }
2397
2398 /* find first sibling */
2399 if (siblings->parent) {
2400 siblings = siblings->parent->child;
2401 } else {
2402 while (siblings->prev->next) {
2403 siblings = siblings->prev;
2404 }
2405 }
2406
2407 parent = (struct lyd_node_inner *)siblings->parent;
2408 if (parent && parent->children_ht) {
2409 assert(target->hash);
2410
2411 /* find by hash */
2412 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
2413 siblings = *match_p;
2414 } else {
2415 /* not found */
2416 siblings = NULL;
2417 }
2418 } else {
2419 /* no children hash table */
2420 for (; siblings; siblings = siblings->next) {
2421 if (!lyd_compare(siblings, target, 0)) {
2422 break;
2423 }
2424 }
2425 }
2426
2427 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002428 if (match) {
2429 *match = NULL;
2430 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002431 return LY_ENOTFOUND;
2432 }
2433
Michal Vasko9b368d32020-02-14 13:53:31 +01002434 if (match) {
2435 *match = (struct lyd_node *)siblings;
2436 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002437 return LY_SUCCESS;
2438}
2439
2440API LY_ERR
2441lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
2442{
2443 struct lyd_node_inner *parent;
2444 struct lyd_node *match;
2445 struct lyd_node **match_p;
2446 struct ly_set *ret;
2447
2448 LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
2449
Michal Vasko62ed12d2020-05-21 10:08:25 +02002450 if (!siblings || (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema))) {
2451 /* no data or schema mismatch */
Michal Vaskoe444f752020-02-10 12:20:06 +01002452 return LY_ENOTFOUND;
2453 }
2454
2455 ret = ly_set_new();
2456 LY_CHECK_ERR_RET(!ret, LOGMEM(target->schema->module->ctx), LY_EMEM);
2457
2458 /* find first sibling */
2459 if (siblings->parent) {
2460 siblings = siblings->parent->child;
2461 } else {
2462 while (siblings->prev->next) {
2463 siblings = siblings->prev;
2464 }
2465 }
2466
2467 parent = (struct lyd_node_inner *)siblings->parent;
2468 if (parent && parent->children_ht) {
2469 assert(target->hash);
2470
2471 /* find by hash */
2472 if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
2473 match = *match_p;
2474 } else {
2475 /* not found */
2476 match = NULL;
2477 }
2478 while (match) {
2479 /* add all found nodes into the return set */
2480 if (ly_set_add(ret, match, LY_SET_OPT_USEASLIST) == -1) {
2481 goto error;
2482 }
2483
2484 /* find next instance */
2485 if (lyht_find_next(parent->children_ht, &match, match->hash, (void **)&match_p)) {
2486 match = NULL;
2487 } else {
2488 match = *match_p;
2489 }
2490 }
2491 } else {
2492 /* no children hash table */
2493 for (; siblings; siblings = siblings->next) {
2494 if (!lyd_compare(siblings, target, 0)) {
2495 /* a match */
2496 if (ly_set_add(ret, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
2497 goto error;
2498 }
2499 }
2500 }
2501 }
2502
2503 if (!ret->count) {
2504 ly_set_free(ret, NULL);
2505 return LY_ENOTFOUND;
2506 }
2507
2508 *set = ret;
2509 return LY_SUCCESS;
2510
2511error:
2512 ly_set_free(ret, NULL);
2513 return LY_EMEM;
2514}
2515
Michal Vasko90932a92020-02-12 14:33:03 +01002516static int
2517lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
2518{
2519 struct lysc_node *val1;
2520 struct lyd_node *val2;
2521
2522 val1 = *((struct lysc_node **)val1_p);
2523 val2 = *((struct lyd_node **)val2_p);
2524
2525 assert(val1->nodetype & (LYD_NODE_INNER | LYS_LEAF));
2526
2527 if (val1 == val2->schema) {
2528 /* schema match is enough */
2529 return 1;
2530 } else {
2531 return 0;
2532 }
2533}
2534
2535static LY_ERR
2536lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
2537{
2538 struct lyd_node **match_p;
2539 struct lyd_node_inner *parent;
2540 uint32_t hash;
2541 values_equal_cb ht_cb;
2542
2543 assert(siblings && schema && (schema->nodetype & (LYD_NODE_INNER | LYS_LEAF)));
2544
2545 /* find first sibling */
2546 if (siblings->parent) {
2547 siblings = siblings->parent->child;
2548 } else {
2549 while (siblings->prev->next) {
2550 siblings = siblings->prev;
2551 }
2552 }
2553
2554 parent = (struct lyd_node_inner *)siblings->parent;
2555 if (parent && parent->children_ht) {
2556 /* calculate our hash */
2557 hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
2558 hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
2559 hash = dict_hash_multi(hash, NULL, 0);
2560
2561 /* use special hash table function */
2562 ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
2563
2564 /* find by hash */
2565 if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
2566 siblings = *match_p;
2567 } else {
2568 /* not found */
2569 siblings = NULL;
2570 }
2571
2572 /* set the original hash table compare function back */
2573 lyht_set_cb(parent->children_ht, ht_cb);
2574 } else {
2575 /* no children hash table */
2576 for (; siblings; siblings = siblings->next) {
2577 if (siblings->schema == schema) {
2578 /* schema match is enough */
2579 break;
2580 }
2581 }
2582 }
2583
2584 if (!siblings) {
Michal Vasko9b368d32020-02-14 13:53:31 +01002585 if (match) {
2586 *match = NULL;
2587 }
Michal Vasko90932a92020-02-12 14:33:03 +01002588 return LY_ENOTFOUND;
2589 }
2590
Michal Vasko9b368d32020-02-14 13:53:31 +01002591 if (match) {
2592 *match = (struct lyd_node *)siblings;
2593 }
Michal Vasko90932a92020-02-12 14:33:03 +01002594 return LY_SUCCESS;
2595}
2596
Michal Vaskoe444f752020-02-10 12:20:06 +01002597API LY_ERR
2598lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
2599 size_t val_len, struct lyd_node **match)
2600{
2601 LY_ERR rc;
2602 struct lyd_node *target = NULL;
2603
2604 LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
Michal Vasko62ed12d2020-05-21 10:08:25 +02002605 if ((schema->nodetype == LYS_LIST) && (schema->flags & LYS_KEYLESS)) {
Michal Vaskoe444f752020-02-10 12:20:06 +01002606 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
2607 return LY_EINVAL;
2608 } else if ((schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && !key_or_value) {
2609 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - no value/keys for a (leaf-)list (%s()).", __func__);
2610 return LY_EINVAL;
2611 } else if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
2612 LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
2613 lys_nodetype2str(schema->nodetype), __func__);
2614 return LY_EINVAL;
2615 }
2616
Michal Vasko62ed12d2020-05-21 10:08:25 +02002617 if (!siblings || (lysc_data_parent(siblings->schema) != lysc_data_parent(schema))) {
2618 /* no data or schema mismatch */
Michal Vasko9b368d32020-02-14 13:53:31 +01002619 if (match) {
2620 *match = NULL;
2621 }
Michal Vaskoe444f752020-02-10 12:20:06 +01002622 return LY_ENOTFOUND;
2623 }
2624
Michal Vaskof03ed032020-03-04 13:31:44 +01002625 if (key_or_value && !val_len) {
2626 val_len = strlen(key_or_value);
2627 }
2628
Michal Vasko90932a92020-02-12 14:33:03 +01002629 /* create data node if needed and find it */
Michal Vaskoe444f752020-02-10 12:20:06 +01002630 switch (schema->nodetype) {
2631 case LYS_CONTAINER:
2632 case LYS_ANYXML:
2633 case LYS_ANYDATA:
2634 case LYS_NOTIF:
Michal Vasko1bf09392020-03-27 12:38:10 +01002635 case LYS_RPC:
Michal Vasko9b368d32020-02-14 13:53:31 +01002636 case LYS_ACTION:
Michal Vaskoe444f752020-02-10 12:20:06 +01002637 case LYS_LEAF:
Michal Vasko90932a92020-02-12 14:33:03 +01002638 /* find it based on schema only */
2639 rc = lyd_find_sibling_schema(siblings, schema, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01002640 break;
2641 case LYS_LEAFLIST:
2642 /* target used attributes: schema, hash, value */
Michal Vaskocbff3e92020-05-27 12:56:41 +02002643 rc = lyd_create_term(schema, key_or_value, val_len, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &target);
2644 LY_CHECK_RET(rc && (rc != LY_EINCOMPLETE), rc);
2645 rc = LY_SUCCESS;
Michal Vasko90932a92020-02-12 14:33:03 +01002646 /* fallthrough */
Michal Vaskoe444f752020-02-10 12:20:06 +01002647 case LYS_LIST:
Michal Vasko90932a92020-02-12 14:33:03 +01002648 if (schema->nodetype == LYS_LIST) {
2649 /* target used attributes: schema, hash, child (all keys) */
Michal Vaskod3678892020-05-21 10:06:58 +02002650 LY_CHECK_RET(lyd_create_list(schema, key_or_value, val_len, LYD_JSON, 1, &target));
Michal Vasko90932a92020-02-12 14:33:03 +01002651 }
2652
2653 /* find it */
2654 rc = lyd_find_sibling_first(siblings, target, match);
Michal Vaskoe444f752020-02-10 12:20:06 +01002655 break;
2656 default:
2657 /* unreachable */
2658 LOGINT(schema->module->ctx);
2659 return LY_EINT;
2660 }
2661
Michal Vaskoe444f752020-02-10 12:20:06 +01002662 lyd_free_tree(target);
2663 return rc;
2664}
Michal Vaskoccc02342020-05-21 10:09:21 +02002665
2666API LY_ERR
2667lyd_find_xpath(const struct lyd_node *ctx_node, const char *xpath, struct ly_set **set)
2668{
2669 LY_ERR ret = LY_SUCCESS;
2670 struct lyxp_set xp_set;
2671 struct lyxp_expr *exp;
2672 uint32_t i;
2673
2674 LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
2675
2676 memset(&xp_set, 0, sizeof xp_set);
2677
2678 /* compile expression */
2679 exp = lyxp_expr_parse((struct ly_ctx *)LYD_NODE_CTX(ctx_node), xpath);
2680 LY_CHECK_ERR_GOTO(!exp, ret = LY_EINVAL, cleanup);
2681
2682 /* evaluate expression */
2683 ret = lyxp_eval(exp, LYD_JSON, ctx_node->schema->module, ctx_node, LYXP_NODE_ELEM, ctx_node, &xp_set, 0);
2684 LY_CHECK_GOTO(ret, cleanup);
2685
2686 /* allocate return set */
2687 *set = ly_set_new();
2688 LY_CHECK_ERR_GOTO(!*set, LOGMEM(LYD_NODE_CTX(ctx_node)); ret = LY_EMEM, cleanup);
2689
2690 /* transform into ly_set */
2691 if (xp_set.type == LYXP_SET_NODE_SET) {
2692 /* allocate memory for all the elements once (even though not all items must be elements but most likely will be) */
2693 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
2694 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(LYD_NODE_CTX(ctx_node)); ret = LY_EMEM, cleanup);
2695 (*set)->size = xp_set.used;
2696
2697 for (i = 0; i < xp_set.used; ++i) {
2698 if (xp_set.val.nodes[i].type == LYXP_NODE_ELEM) {
2699 ly_set_add(*set, xp_set.val.nodes[i].node, LY_SET_OPT_USEASLIST);
2700 }
2701 }
2702 }
2703
2704cleanup:
Michal Vasko0691d522020-05-21 13:21:47 +02002705 lyxp_set_free_content(&xp_set);
Michal Vaskoccc02342020-05-21 10:09:21 +02002706 lyxp_expr_free((struct ly_ctx *)LYD_NODE_CTX(ctx_node), exp);
2707 return ret;
2708}