blob: 3d0c11b0a65634499fb6e6b8891d44a71dd2a77a [file] [log] [blame]
Michal Vasko2d162e12015-09-24 14:33:29 +02001/**
2 * @file tree_data.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Manipulation with libyang data structures
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * 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
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko2d162e12015-09-24 14:33:29 +020013 */
Radek Krejci54f6fb32016-02-24 12:56:39 +010014
Michal Vasko2d162e12015-09-24 14:33:29 +020015#define _GNU_SOURCE
16
17#include <assert.h>
18#include <ctype.h>
Michal Vasko3e671b52015-10-23 16:23:15 +020019#include <limits.h>
Radek Krejci4a49bdf2016-01-12 17:17:01 +010020#include <stdarg.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020021#include <stdlib.h>
Michal Vasko662610a2015-12-07 11:25:45 +010022#include <sys/types.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020023#include <sys/mman.h>
24#include <sys/stat.h>
Michal Vasko662610a2015-12-07 11:25:45 +010025#include <fcntl.h>
26#include <unistd.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020027#include <string.h>
Michal Vasko662610a2015-12-07 11:25:45 +010028#include <errno.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020029
Michal Vasko662610a2015-12-07 11:25:45 +010030#include "libyang.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020031#include "common.h"
32#include "context.h"
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020033#include "tree_data.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020034#include "parser.h"
35#include "resolve.h"
Michal Vaskofc5744d2015-10-22 12:09:34 +020036#include "xml_internal.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020037#include "tree_internal.h"
38#include "validation.h"
Michal Vasko105cef12016-02-04 12:06:26 +010039#include "xpath.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020040
Michal Vasko36ef6932015-12-01 14:30:17 +010041static struct lyd_node *
42lyd_parse_(struct ly_ctx *ctx, const struct lys_node *parent, const char *data, LYD_FORMAT format, int options)
Michal Vasko2d162e12015-09-24 14:33:29 +020043{
Radek Krejcia2264b62016-02-05 13:14:05 +010044 struct lyxml_elem *xml, *xmlnext;
Radek Krejci5974c1f2015-10-09 09:53:24 +020045 struct lyd_node *result = NULL;
Radek Krejci722b0072016-02-01 17:09:45 +010046 int xmlopt = LYXML_PARSE_MULTIROOT;
Radek Krejci5974c1f2015-10-09 09:53:24 +020047
Michal Vasko2d162e12015-09-24 14:33:29 +020048 if (!ctx || !data) {
49 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
50 return NULL;
51 }
52
Radek Krejci86538212015-12-17 15:59:01 +010053 if (options & LYD_OPT_NOSIBLINGS) {
54 xmlopt = 0;
55 }
56
Michal Vasko2d162e12015-09-24 14:33:29 +020057 switch (format) {
58 case LYD_XML:
Radek Krejci452fb952015-10-02 16:07:46 +020059 case LYD_XML_FORMAT:
Radek Krejci722b0072016-02-01 17:09:45 +010060 xml = lyxml_parse_mem(ctx, data, xmlopt);
Radek Krejci88b3bad2016-02-10 13:08:08 +010061 if (ly_errno) {
62 return NULL;
63 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +010064 result = lyd_parse_xml(ctx, &xml, options, parent);
Radek Krejcia2264b62016-02-05 13:14:05 +010065 LY_TREE_FOR_SAFE(xml, xmlnext, xml) {
66 lyxml_free(ctx, xml);
67 }
Radek Krejci5974c1f2015-10-09 09:53:24 +020068 break;
Michal Vasko2d162e12015-09-24 14:33:29 +020069 case LYD_JSON:
Michal Vasko36ef6932015-12-01 14:30:17 +010070 result = lyd_parse_json(ctx, parent, data, options);
Radek Krejci5449d472015-10-26 14:35:56 +010071 break;
Michal Vasko2d162e12015-09-24 14:33:29 +020072 default:
Radek Krejci5449d472015-10-26 14:35:56 +010073 /* error */
Michal Vasko2d162e12015-09-24 14:33:29 +020074 return NULL;
75 }
76
Radek Krejci2342cf62016-01-29 16:48:23 +010077 if (!result && !ly_errno) {
78 /* is empty data tree really valid ? */
Radek Krejci1daa7a42016-02-10 13:09:59 +010079 lyd_validate(NULL, options, ctx);
Radek Krejci2342cf62016-01-29 16:48:23 +010080 }
Radek Krejci5974c1f2015-10-09 09:53:24 +020081 return result;
Michal Vasko2d162e12015-09-24 14:33:29 +020082}
83
Radek Krejci4a49bdf2016-01-12 17:17:01 +010084static struct lyd_node *
85lyd_parse_data_(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, va_list ap)
Michal Vasko36ef6932015-12-01 14:30:17 +010086{
Radek Krejci4a49bdf2016-01-12 17:17:01 +010087 const struct lys_node *rpc = NULL;
88
89 if (lyp_check_options(options)) {
90 LOGERR(LY_EINVAL, "%s: Invalid options (multiple data type flags set).", __func__);
91 return NULL;
92 }
93
94 if (options & LYD_OPT_RPCREPLY) {
95 rpc = va_arg(ap, struct lys_node*);
96 if (!rpc || (rpc->nodetype != LYS_RPC)) {
97 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
98 return NULL;
99 }
100 }
101
102 return lyd_parse_(ctx, rpc, data, format, options);
Michal Vasko36ef6932015-12-01 14:30:17 +0100103}
104
105API struct lyd_node *
Radek Krejci722b0072016-02-01 17:09:45 +0100106lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, ...)
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100107{
108 va_list ap;
109 struct lyd_node *result;
110
111 va_start(ap, options);
112 result = lyd_parse_data_(ctx, data, format, options, ap);
113 va_end(ap);
114
115 return result;
116}
117
118API struct lyd_node *
119lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, ...)
Michal Vasko662610a2015-12-07 11:25:45 +0100120{
121 struct lyd_node *ret;
122 struct stat sb;
123 char *data;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100124 va_list ap;
Michal Vasko662610a2015-12-07 11:25:45 +0100125
126 if (!ctx || (fd == -1)) {
127 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
128 return NULL;
129 }
130
131 if (fstat(fd, &sb) == -1) {
132 LOGERR(LY_ESYS, "Failed to stat the file descriptor (%s).", strerror(errno));
133 return NULL;
134 }
135
Radek Krejci3006be02015-12-17 11:24:33 +0100136 data = mmap(NULL, sb.st_size + 1, PROT_READ, MAP_PRIVATE, fd, 0);
Michal Vasko662610a2015-12-07 11:25:45 +0100137 if (data == MAP_FAILED) {
138 LOGERR(LY_ESYS, "Mapping file descriptor into memory failed.");
139 return NULL;
140 }
141
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100142 va_start(ap, options);
143 ret = lyd_parse_data_(ctx, data, format, options, ap);
144
145 va_end(ap);
Michal Vasko662610a2015-12-07 11:25:45 +0100146 munmap(data, sb.st_size);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100147
Michal Vasko662610a2015-12-07 11:25:45 +0100148 return ret;
149}
150
151API struct lyd_node *
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100152lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options, ...)
Michal Vasko662610a2015-12-07 11:25:45 +0100153{
154 int fd;
155 struct lyd_node *ret;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100156 va_list ap;
Michal Vasko662610a2015-12-07 11:25:45 +0100157
158 if (!ctx || !path) {
159 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
160 return NULL;
161 }
162
163 fd = open(path, O_RDONLY);
164 if (fd == -1) {
165 LOGERR(LY_ESYS, "Failed to open data file \"%s\" (%s).", path, strerror(errno));
166 return NULL;
167 }
168
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100169 va_start(ap, options);
Michal Vasko662610a2015-12-07 11:25:45 +0100170 ret = lyd_parse_fd(ctx, fd, format, options);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100171
172 va_end(ap);
Michal Vasko662610a2015-12-07 11:25:45 +0100173 close(fd);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100174
Michal Vasko662610a2015-12-07 11:25:45 +0100175 return ret;
176}
177
Michal Vasko7d051252016-03-16 13:16:29 +0100178static struct lyd_node *
179_lyd_new(struct lyd_node *parent, const struct lys_node *schema)
180{
181 struct lyd_node *ret;
182
183 ret = calloc(1, sizeof *ret);
184 if (!ret) {
185 LOGMEM;
186 return NULL;
187 }
188 ret->schema = (struct lys_node *)schema;
189 ret->validity = LYD_VAL_NOT;
190 ret->prev = ret;
191 if (parent) {
192 if (lyd_insert(parent, ret)) {
193 lyd_free(ret);
194 return NULL;
195 }
196 }
197
198 return ret;
199}
200
Michal Vasko662610a2015-12-07 11:25:45 +0100201API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100202lyd_new(struct lyd_node *parent, const struct lys_module *module, const char *name)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200203{
Michal Vasko1e62a092015-12-01 12:27:20 +0100204 const struct lys_node *snode = NULL, *siblings;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200205
206 if ((!parent && !module) || !name) {
207 ly_errno = LY_EINVAL;
208 return NULL;
209 }
210
211 if (!parent) {
212 siblings = module->data;
213 } else {
Michal Vaskoa5ef4d72015-09-29 16:05:21 +0200214 if (!parent->schema) {
215 return NULL;
216 }
217 siblings = parent->schema->child;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200218 }
219
Michal Vaskoa45cf2b2015-10-23 09:45:36 +0200220 if (lys_get_data_sibling(module, siblings, name, LYS_CONTAINER | LYS_LIST | LYS_NOTIF | LYS_RPC, &snode)
221 || !snode) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200222 return NULL;
223 }
224
Michal Vasko7d051252016-03-16 13:16:29 +0100225 return _lyd_new(parent, snode);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200226}
227
Michal Vasko50c0a872016-01-13 14:34:11 +0100228static struct lyd_node *
229lyd_create_leaf(const struct lys_node *schema, const char *val_str)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200230{
Michal Vasko50c0a872016-01-13 14:34:11 +0100231 struct lyd_node_leaf_list *ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200232
Michal Vasko3e671b52015-10-23 16:23:15 +0200233 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100234 if (!ret) {
235 LOGMEM;
236 return NULL;
237 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100238 ret->schema = (struct lys_node *)schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100239 ret->validity = LYD_VAL_NOT;
Michal Vasko3e671b52015-10-23 16:23:15 +0200240 ret->prev = (struct lyd_node *)ret;
Radek Krejci37b756f2016-01-18 10:15:03 +0100241 ret->value_type = ((struct lys_node_leaf *)schema)->type.base;
Michal Vasko50c0a872016-01-13 14:34:11 +0100242 ret->value_str = lydict_insert(schema->module->ctx, val_str, 0);
Michal Vasko3e671b52015-10-23 16:23:15 +0200243
244 /* resolve the type correctly */
Radek Krejci37b756f2016-01-18 10:15:03 +0100245 if (lyp_parse_value(ret, NULL, 1, NULL, 0)) {
246 lyd_free((struct lyd_node *)ret);
247 ly_errno = LY_EINVAL;
248 return NULL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200249 }
250
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200251 return (struct lyd_node *)ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200252}
253
Michal Vasko7d051252016-03-16 13:16:29 +0100254static struct lyd_node *
255_lyd_new_leaf(struct lyd_node *parent, const struct lys_node *schema, const char *val_str)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200256{
Michal Vasko50c0a872016-01-13 14:34:11 +0100257 struct lyd_node *ret;
Michal Vasko587998f2015-09-29 16:07:53 +0200258
Michal Vasko7d051252016-03-16 13:16:29 +0100259 ret = lyd_create_leaf(schema, val_str);
Michal Vasko50c0a872016-01-13 14:34:11 +0100260 if (!ret) {
261 return NULL;
262 }
263
264 /* connect to parent */
265 if (parent) {
266 if (lyd_insert(parent, ret)) {
267 lyd_free(ret);
268 return NULL;
269 }
270 }
271
Radek Krejcica7efb72016-01-18 13:06:01 +0100272 if (ret->schema->flags & LYS_UNIQUE) {
273 /* locate the first parent list */
274 for (parent = ret->parent; parent && parent->schema->nodetype != LYS_LIST; parent = parent->parent);
275
276 /* set flag for future validation */
277 if (parent) {
278 parent->validity |= LYD_VAL_UNIQUE;
279 }
280 }
281
Michal Vasko50c0a872016-01-13 14:34:11 +0100282 return ret;
Michal Vasko7d051252016-03-16 13:16:29 +0100283}
284
285API struct lyd_node *
286lyd_new_leaf(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
287{
288 const struct lys_node *snode = NULL, *siblings;
289
290 if ((!parent && !module) || !name) {
291 ly_errno = LY_EINVAL;
292 return NULL;
293 }
294
295 if (!parent) {
296 siblings = module->data;
297 } else {
298 if (!parent->schema) {
299 ly_errno = LY_EINVAL;
300 return NULL;
301 }
302 siblings = parent->schema->child;
303 }
304
305 if (lys_get_data_sibling(module, siblings, name, LYS_LEAFLIST | LYS_LEAF, &snode) || !snode) {
306 ly_errno = LY_EINVAL;
307 return NULL;
308 }
309
310 return _lyd_new_leaf(parent, snode, val_str);
Michal Vasko50c0a872016-01-13 14:34:11 +0100311
312}
313
Mislav Novakovice25a5c42016-03-10 18:06:11 +0100314API int
Radek Krejcib9b4d002016-01-18 13:08:51 +0100315lyd_change_leaf(struct lyd_node_leaf_list *leaf, const char *val_str)
316{
317 const char *backup;
318 struct lyd_node *parent;
319
320 if (!leaf) {
321 ly_errno = LY_EINVAL;
322 return EXIT_FAILURE;
323 }
324
325 backup = leaf->value_str;
326 leaf->value_str = val_str;
327
328 /* resolve the type correctly */
329 if (lyp_parse_value(leaf, NULL, 1, NULL, 0)) {
330 leaf->value_str = backup;
331 ly_errno = LY_EINVAL;
332 return EXIT_FAILURE;
333 }
334
335 /* value is correct, finish the changes in leaf */
336 lydict_remove(leaf->schema->module->ctx, backup);
337 leaf->value_str = lydict_insert(leaf->schema->module->ctx, val_str, 0);
338
339 if (leaf->schema->flags & LYS_UNIQUE) {
340 /* locate the first parent list */
341 for (parent = leaf->parent; parent && parent->schema->nodetype != LYS_LIST; parent = parent->parent);
342
343 /* set flag for future validation */
344 if (parent) {
345 parent->validity |= LYD_VAL_UNIQUE;
346 }
347 }
348
349 return EXIT_SUCCESS;
350}
351
Michal Vasko50c0a872016-01-13 14:34:11 +0100352static struct lyd_node *
353lyd_create_anyxml(const struct lys_node *schema, const char *val_xml)
354{
355 struct lyd_node_anyxml *ret;
356 struct lyxml_elem *root;
357 char *xml;
358
Michal Vasko587998f2015-09-29 16:07:53 +0200359 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100360 if (!ret) {
361 LOGMEM;
362 return NULL;
363 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100364 ret->schema = (struct lys_node *)schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100365 ret->validity = LYD_VAL_NOT;
Michal Vasko587998f2015-09-29 16:07:53 +0200366 ret->prev = (struct lyd_node *)ret;
Michal Vasko587998f2015-09-29 16:07:53 +0200367
Radek Krejci86538212015-12-17 15:59:01 +0100368 /* store the anyxml data together with the anyxml element */
Radek Krejci15412ca2016-03-03 11:16:52 +0100369 if (asprintf(&xml, "<%s>%s</%s>", schema->name, (val_xml ? val_xml : ""), schema->name) == -1) {
370 LOGMEM;
371 lyd_free((struct lyd_node *)ret);
372 return NULL;
373 }
Radek Krejci722b0072016-02-01 17:09:45 +0100374 root = lyxml_parse_mem(schema->module->ctx, xml, 0);
Michal Vasko17cc7062015-12-10 14:31:48 +0100375 free(xml);
376 if (!root) {
377 lyd_free((struct lyd_node *)ret);
378 return NULL;
Michal Vasko14d88772015-12-03 10:54:59 +0100379 }
Michal Vasko334a07d2016-02-29 11:30:10 +0100380 ret->value = root;
Michal Vasko17cc7062015-12-10 14:31:48 +0100381
Michal Vasko587998f2015-09-29 16:07:53 +0200382 return (struct lyd_node *)ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200383}
384
Michal Vasko7d051252016-03-16 13:16:29 +0100385static struct lyd_node *
386_lyd_new_anyxml(struct lyd_node *parent, const struct lys_node *schema, const char *val_xml)
387{
388 struct lyd_node *ret;
389
390 ret = lyd_create_anyxml(schema, val_xml);
391 if (!ret) {
392 return NULL;
393 }
394
395 /* connect to parent */
396 if (parent) {
397 if (lyd_insert(parent, ret)) {
398 lyd_free(ret);
399 return NULL;
400 }
401 }
402
403 return ret;
404}
405
Michal Vasko0df122f2015-12-14 13:38:21 +0100406API struct lyd_node *
Michal Vasko50c0a872016-01-13 14:34:11 +0100407lyd_new_anyxml(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_xml)
Michal Vasko0df122f2015-12-14 13:38:21 +0100408{
Michal Vasko50c0a872016-01-13 14:34:11 +0100409 const struct lys_node *siblings, *snode;
Michal Vasko0df122f2015-12-14 13:38:21 +0100410
Michal Vasko50c0a872016-01-13 14:34:11 +0100411 if ((!parent && !module) || !name) {
Michal Vasko0df122f2015-12-14 13:38:21 +0100412 ly_errno = LY_EINVAL;
413 return NULL;
414 }
415
Michal Vasko50c0a872016-01-13 14:34:11 +0100416 if (!parent) {
417 siblings = module->data;
Michal Vasko0df122f2015-12-14 13:38:21 +0100418 } else {
Michal Vasko50c0a872016-01-13 14:34:11 +0100419 if (!parent->schema) {
420 return NULL;
421 }
422 siblings = parent->schema->child;
423 }
424
425 if (lys_get_data_sibling(module, siblings, name, LYS_ANYXML, &snode) || !snode) {
426 return NULL;
427 }
428
Michal Vasko7d051252016-03-16 13:16:29 +0100429 return _lyd_new_anyxml(parent, snode, val_xml);
Michal Vasko50c0a872016-01-13 14:34:11 +0100430}
431
432API struct lyd_node *
433lyd_output_new(const struct lys_node *schema)
434{
435 struct lyd_node *ret;
436
437 if (!schema || !(schema->nodetype & (LYS_CONTAINER | LYS_LIST))
438 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
Michal Vasko0df122f2015-12-14 13:38:21 +0100439 ly_errno = LY_EINVAL;
440 return NULL;
441 }
442
443 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100444 if (!ret) {
445 LOGMEM;
446 return NULL;
447 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100448 ret->schema = (struct lys_node *)schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100449 ret->validity = LYD_VAL_NOT;
Michal Vasko0df122f2015-12-14 13:38:21 +0100450 ret->prev = ret;
451
Michal Vasko50c0a872016-01-13 14:34:11 +0100452 return ret;
453}
454
455API struct lyd_node *
456lyd_output_new_leaf(const struct lys_node *schema, const char *val_str)
457{
458 if (!schema || (schema->nodetype != LYS_LEAF)
459 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
460 ly_errno = LY_EINVAL;
461 return NULL;
462 }
463
464 return lyd_create_leaf(schema, val_str);
465}
466
467API struct lyd_node *
468lyd_output_new_anyxml(const struct lys_node *schema, const char *val_xml)
469{
470 if (!schema || (schema->nodetype != LYS_ANYXML)
471 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
472 ly_errno = LY_EINVAL;
473 return NULL;
474 }
475
476 return lyd_create_anyxml(schema, val_xml);
Michal Vasko0df122f2015-12-14 13:38:21 +0100477}
478
Michal Vaskof5299282016-03-16 13:32:02 +0100479static int
480lyd_new_path_list_keys(struct lyd_node *list, const char *list_name, const char *predicate, int *parsed)
481{
482 const char *name, *value;
483 char *key_val;
484 int r, i, nam_len, val_len, has_predicate = 1;
485 struct lys_node_list *slist;
486
487 slist = (struct lys_node_list *)list->schema;
488
489 for (i = 0; i < slist->keys_size; ++i) {
490 if (!has_predicate) {
491 LOGVAL(LYE_PATH_MISSKEY, 0, LY_VLOG_NONE, NULL, list_name);
492 return -1;
493 }
494
495 if ((r = parse_schema_list_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
496 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
497 return -1;
498 }
499 *parsed += r;
500 predicate += r;
501
502 if (strncmp(slist->keys[i]->name, name, nam_len) || slist->keys[i]->name[nam_len]) {
503 LOGVAL(LYE_PATH_INKEY, 0, LY_VLOG_NONE, NULL, name[0], name);
504 return -1;
505 }
506
507 key_val = malloc((val_len + 1) * sizeof(char));
508 if (!key_val) {
509 LOGMEM;
510 return -1;
511 }
512 strncpy(key_val, value, val_len);
513 key_val[val_len] = '\0';
514
515 if (!_lyd_new_leaf(list, (const struct lys_node *)slist->keys[i], key_val)) {
516 free(key_val);
517 return -1;
518 }
519 free(key_val);
520 }
521
522 return 0;
523}
524
525API struct lyd_node *
526lyd_new_path(struct lyd_node *data_tree, struct ly_ctx *ctx, const char *path, const char *value, int options)
527{
528 char module_name[LY_MODULE_NAME_MAX_LEN + 1];
529 const char *mod_name, *name, *node_mod_name;
530 struct lyd_node *ret = NULL, *node, *parent = NULL;
531 const struct lys_node *schild, *sparent;
532 const struct lys_node_list *slist;
533 const struct lys_module *module, *prev_mod;
534 int r, i, parsed = 0, mod_name_len, nam_len, is_relative = -1;
535
536 if (!path || (!data_tree && !ctx) || ((options & LYD_PATH_OPT_UPDATE) && !value)
537 || (data_tree && (data_tree->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)))) {
538 ly_errno = LY_EINVAL;
539 return NULL;
540 }
541
542 if (data_tree) {
543 parent = resolve_partial_json_data_nodeid(path, data_tree, &parsed);
544 if (!parent) {
545 return NULL;
546 }
547 path += parsed;
548 if (parsed) {
549 /* if we parsed something we have a relative path for sure, otherwise we don't know */
550 is_relative = 1;
551 }
552
553 if (!path[0]) {
554 /* the node exists */
555 if (!(options & LYD_PATH_OPT_UPDATE) || (parent->schema->nodetype != LYS_LEAF)) {
556 LOGVAL(LYE_PATH_EXISTS, 0, LY_VLOG_NONE, NULL);
557 return NULL;
558 }
559
560 /* update leaf value */
561 r = lyd_change_leaf((struct lyd_node_leaf_list *)parent, value);
562 if (r) {
563 return NULL;
564 }
565 return parent;
566 }
567
568 sparent = parent->schema;
569 module = lys_node_module(sparent);
570 prev_mod = module;
571 }
572
573 if ((r = parse_schema_nodeid(path, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
574 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, path[-r], &path[-r]);
575 return NULL;
576 }
577
578 path += r;
579
580 /* we are starting from scratch, absolute path */
581 if (!data_tree) {
582 if (!mod_name) {
583 LOGVAL(LYE_PATH_MISSMOD, 0, LY_VLOG_NONE, NULL, name);
584 return NULL;
585 } else if (mod_name_len > LY_MODULE_NAME_MAX_LEN) {
586 LOGINT;
587 return NULL;
588 }
589
590 strncpy(module_name, mod_name, mod_name_len);
591 module_name[mod_name_len] = '\0';
592 module = ly_ctx_get_module(ctx, module_name, NULL);
593 if (!module) {
594 LOGVAL(LYE_PATH_INMOD, 0, LY_VLOG_NONE, NULL, mod_name);
595 return NULL;
596 }
597 mod_name = NULL;
598 mod_name_len = 0;
599 prev_mod = module;
600
601 sparent = NULL;
602 }
603
604 /* create nodes in a loop */
605 while (1) {
606 /* find the schema node */
607 schild = NULL;
608 while ((schild = lys_getnext(schild, sparent, module, 0))) {
609 if (schild->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
610 /* module comparison */
611 if (mod_name) {
612 node_mod_name = lys_node_module(schild)->name;
613 if (strncmp(node_mod_name, mod_name, mod_name_len) || node_mod_name[mod_name_len]) {
614 continue;
615 }
616 } else if (lys_node_module(schild) != prev_mod) {
617 continue;
618 }
619
620 /* name check */
621 if (!strncmp(schild->name, name, nam_len) && !schild->name[nam_len]) {
622 break;
623 }
624 }
625 }
626
627 if (!schild) {
628 LOGVAL(LYE_PATH_INNODE, 0, LY_VLOG_NONE, NULL, name);
629 lyd_free(ret);
630 return NULL;
631 }
632
633 /* we have the right schema node */
634 switch (schild->nodetype) {
635 case LYS_CONTAINER:
636 case LYS_LIST:
637 case LYS_NOTIF:
638 case LYS_RPC:
639 node = _lyd_new(is_relative ? parent : NULL, schild);
640 break;
641 case LYS_LEAF:
642 case LYS_LEAFLIST:
643 if (path[0]) {
644 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, path[0], path);
645 return NULL;
646 }
647 node = _lyd_new_leaf(is_relative ? parent : NULL, schild, value);
648 break;
649 case LYS_ANYXML:
650 if (path[0]) {
651 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, path[0], path);
652 return NULL;
653 }
654 node = _lyd_new_anyxml(is_relative ? parent : NULL, schild, value);
655 break;
656 default:
657 LOGINT;
658 node = NULL;
659 break;
660 }
661
662 if (!node) {
663 lyd_free(ret);
664 return NULL;
665 }
666 if (!ret) {
667 ret = node;
668 }
669 /* special case when we are creating a sibling of a top-level data node */
670 if (!is_relative) {
671 if (data_tree) {
672 assert(data_tree == parent);
673 if (lyd_insert_before(data_tree, node)) {
674 lyd_free(ret);
675 return NULL;
676 }
677 }
678 is_relative = 1;
679 }
680
681 parsed = 0;
682 if ((schild->nodetype == LYS_LIST) && lyd_new_path_list_keys(node, name, path, &parsed)) {
683 lyd_free(ret);
684 return NULL;
685 }
686 path += parsed;
687
688 if (!path[0]) {
689 /* we are done */
690 return ret;
691 } else if (!(options & LYD_PATH_OPT_RECURSIVE)) {
692 /* we were supposed to be done */
693 LOGVAL(LYE_PATH_MISSPAR, 0, LY_VLOG_NONE, NULL, (mod_name ? mod_name : name));
694 return NULL;
695 }
696
697 /* prepare for another iteration */
698 parent = node;
699 sparent = schild;
700 prev_mod = lys_node_module(schild);
701
702 /* parse another node */
703 if ((r = parse_schema_nodeid(path, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
704 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, path[-r], &path[-r]);
705 lyd_free(ret);
706 return NULL;
707 }
708 path += r;
709
710 /* if a key of a list was supposed to be created, it is created as a part of the list instance
711 * creation and can cause several corner cases that can simply be avoided by forbidding this */
712 if ((schild->nodetype == LYS_LIST) && !mod_name) {
713 slist = (const struct lys_node_list *)schild;
714 for (i = 0; i < slist->keys_size; ++i) {
715 if (!strncmp(slist->keys[i]->name, name, nam_len) && !slist->keys[i]->name[nam_len]) {
716 LOGVAL(LYE_PATH_EXISTS, 0, LY_VLOG_NONE, NULL);
717 lyd_free(ret);
718 return NULL;
719 }
720 }
721 }
722 }
723
724 return ret;
725}
726
Radek Krejcica7efb72016-01-18 13:06:01 +0100727static void
728lyd_insert_setinvalid(struct lyd_node *node)
729{
730 struct lyd_node *next, *elem, *parent_list;
731
732 assert(node);
733
734 /* overall validity of the node itself */
735 node->validity = LYD_VAL_NOT;
736
737 /* explore changed unique leafs */
738 /* first, get know if there is a list in parents chain */
739 for (parent_list = node->parent;
740 parent_list && parent_list->schema->nodetype != LYS_LIST;
741 parent_list = parent_list->parent);
742 if (parent_list && !(parent_list->validity & LYD_VAL_UNIQUE)) {
743 /* there is a list, so check if we inserted a leaf supposed to be unique */
744 for (elem = node; elem; elem = next) {
745 if (elem->schema->nodetype == LYS_LIST) {
746 /* stop searching to the depth, children would be unique to a list in subtree */
747 goto nextsibling;
748 }
749
750 if (elem->schema->nodetype == LYS_LEAF && (elem->schema->flags & LYS_UNIQUE)) {
751 /* set flag to list for future validation */
752 parent_list->validity |= LYD_VAL_UNIQUE;
753 break;
754 }
755
Radek Krejci46c4cd72016-01-21 15:13:52 +0100756 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
757 goto nextsibling;
758 }
759
Radek Krejcica7efb72016-01-18 13:06:01 +0100760 /* select next elem to process */
761 /* go into children */
762 next = elem->child;
763 /* got through siblings */
764 if (!next) {
765nextsibling:
766 next = elem->next;
767 if (!next) {
768 /* no children */
769 if (elem == node) {
770 /* we are done, back in start node */
771 break;
772 }
773 /* try siblings */
774 next = elem->next;
775 }
776 }
777 /* go back to parents */
778 while (!next) {
779 if (elem->parent == node) {
780 /* we are done, back in start node */
781 break;
782 }
783 /* parent was actually already processed, so go to the parent's sibling */
784 next = elem->parent->next;
785 }
786 }
787 }
788}
789
Michal Vasko24337392015-10-16 09:58:16 +0200790API int
791lyd_insert(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko2d162e12015-09-24 14:33:29 +0200792{
793 struct lys_node *sparent;
Michal Vasko24337392015-10-16 09:58:16 +0200794 struct lyd_node *iter;
Radek Krejcica7efb72016-01-18 13:06:01 +0100795 int invalid = 0;
Michal Vasko2d162e12015-09-24 14:33:29 +0200796
Michal Vasko24337392015-10-16 09:58:16 +0200797 if (!node || !parent) {
798 ly_errno = LY_EINVAL;
799 return EXIT_FAILURE;
Michal Vasko2d162e12015-09-24 14:33:29 +0200800 }
801
Radek Krejcica7efb72016-01-18 13:06:01 +0100802 /* check placing the node to the appropriate place according to the schema */
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100803 for (sparent = lys_parent(node->schema);
Michal Vasko72d65c92015-12-07 14:02:35 +0100804 sparent && !(sparent->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100805 sparent = lys_parent(sparent));
Michal Vasko2d162e12015-09-24 14:33:29 +0200806 if (sparent != parent->schema) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200807 return EXIT_FAILURE;
808 }
809
Radek Krejcica7efb72016-01-18 13:06:01 +0100810 if (node->parent != parent || lyp_is_rpc(node->schema)) {
811 /* it is not just moving under a parent node or it is in an RPC where
812 * nodes order matters, so the validation will be necessary */
813 invalid = 1;
814 }
815
Michal Vasko24337392015-10-16 09:58:16 +0200816 if (node->parent || node->prev->next) {
817 lyd_unlink(node);
818 }
819
Michal Vasko2d162e12015-09-24 14:33:29 +0200820 if (!parent->child) {
821 /* add as the only child of the parent */
822 parent->child = node;
823 } else {
824 /* add as the last child of the parent */
825 parent->child->prev->next = node;
826 node->prev = parent->child->prev;
827 for (iter = node; iter->next; iter = iter->next);
828 parent->child->prev = iter;
829 }
Michal Vasko9cc2d0a2015-10-14 15:49:07 +0200830
Michal Vasko2d162e12015-09-24 14:33:29 +0200831 LY_TREE_FOR(node, iter) {
832 iter->parent = parent;
Radek Krejcica7efb72016-01-18 13:06:01 +0100833 if (invalid) {
834 lyd_insert_setinvalid(iter);
835 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200836 }
837
838 return EXIT_SUCCESS;
839}
840
Michal Vasko02592902015-10-15 12:14:40 +0200841static int
Michal Vasko24337392015-10-16 09:58:16 +0200842lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, int before)
Michal Vasko2d162e12015-09-24 14:33:29 +0200843{
844 struct lys_node *par1, *par2;
Radek Krejci20a5f292016-02-09 15:04:49 +0100845 struct lyd_node *iter;
Radek Krejcica7efb72016-01-18 13:06:01 +0100846 int invalid = 0;
Michal Vasko3f7dba12015-10-15 13:09:27 +0200847
848 if (sibling == node) {
849 return EXIT_SUCCESS;
850 }
851
Michal Vasko2d162e12015-09-24 14:33:29 +0200852 /* check placing the node to the appropriate place according to the schema */
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100853 for (par1 = lys_parent(sibling->schema);
Radek Krejci2b7bb492015-12-02 15:46:29 +0100854 par1 && !(par1->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100855 par1 = lys_parent(par1));
856 for (par2 = lys_parent(node->schema);
Radek Krejci2b7bb492015-12-02 15:46:29 +0100857 par2 && !(par2->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100858 par2 = lys_parent(par2));
Michal Vasko2d162e12015-09-24 14:33:29 +0200859 if (par1 != par2) {
860 ly_errno = LY_EINVAL;
861 return EXIT_FAILURE;
862 }
863
Radek Krejcic886a2a2016-02-09 15:07:16 +0100864 if (node->parent != sibling->parent || !node->parent || lyp_is_rpc(node->schema)) {
865 /* a) it is not just moving under a parent node or
866 * b) it is top-level where we don't know if it is the same tree, or
867 * c) it is in an RPC where nodes order matters,
868 * so the validation will be necessary */
869 if (!node->parent) {
870 /* b) search in siblings */
871 for (iter = node->prev; iter != node; iter = iter->prev) {
872 if (iter == sibling) {
873 break;
874 }
875 }
876 if (iter == node) {
877 /* node and siblings are not currently in the same data tree */
878 invalid = 1;
879 }
880 } else { /* a) and c) */
881 invalid = 1;
882 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100883 }
884
Radek Krejci20a5f292016-02-09 15:04:49 +0100885 if (node->parent || node->next || node->prev->next) {
Michal Vasko24337392015-10-16 09:58:16 +0200886 lyd_unlink(node);
887 }
888
Radek Krejci20a5f292016-02-09 15:04:49 +0100889 node->parent = sibling->parent;
890 if (invalid) {
891 lyd_insert_setinvalid(node);
Michal Vasko2d162e12015-09-24 14:33:29 +0200892 }
893
Michal Vasko02592902015-10-15 12:14:40 +0200894 if (before) {
895 if (sibling->prev->next) {
896 /* adding into the list */
897 sibling->prev->next = node;
898 } else if (sibling->parent) {
899 /* at the beginning */
900 sibling->parent->child = node;
Michal Vasko2d162e12015-09-24 14:33:29 +0200901 }
Michal Vasko02592902015-10-15 12:14:40 +0200902 node->prev = sibling->prev;
Radek Krejci20a5f292016-02-09 15:04:49 +0100903 sibling->prev = node;
904 node->next = sibling;
Michal Vasko02592902015-10-15 12:14:40 +0200905 } else {
906 if (sibling->next) {
907 /* adding into a middle - fix the prev pointer of the node after inserted nodes */
Radek Krejci20a5f292016-02-09 15:04:49 +0100908 node->next = sibling->next;
909 sibling->next->prev = node;
Michal Vasko02592902015-10-15 12:14:40 +0200910 } else {
911 /* at the end - fix the prev pointer of the first node */
912 if (sibling->parent) {
Radek Krejci20a5f292016-02-09 15:04:49 +0100913 sibling->parent->child->prev = node;
Michal Vasko02592902015-10-15 12:14:40 +0200914 } else {
915 for (iter = sibling; iter->prev->next; iter = iter->prev);
Radek Krejci20a5f292016-02-09 15:04:49 +0100916 iter->prev = node;
Michal Vasko02592902015-10-15 12:14:40 +0200917 }
918 }
919 sibling->next = node;
920 node->prev = sibling;
Michal Vasko2d162e12015-09-24 14:33:29 +0200921 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200922
Michal Vasko24337392015-10-16 09:58:16 +0200923 return EXIT_SUCCESS;
924}
Michal Vasko2d162e12015-09-24 14:33:29 +0200925
Michal Vasko24337392015-10-16 09:58:16 +0200926API int
927lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
928{
929 if (!node || !sibling || lyd_insert_sibling(sibling, node, 1)) {
930 ly_errno = LY_EINVAL;
931 return EXIT_FAILURE;
932 }
933
934 return EXIT_SUCCESS;
935}
936
937API int
938lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
939{
940 if (!node || !sibling || lyd_insert_sibling(sibling, node, 0)) {
941 ly_errno = LY_EINVAL;
942 return EXIT_FAILURE;
943 }
944
945 return EXIT_SUCCESS;
946}
947
948API int
Radek Krejci2342cf62016-01-29 16:48:23 +0100949lyd_validate(struct lyd_node *node, int options, ...)
Michal Vasko24337392015-10-16 09:58:16 +0200950{
Radek Krejci15c733d2016-01-27 16:31:17 +0100951 struct lyd_node *root, *next1, *next2, *iter, *to_free = NULL;
Radek Krejci2342cf62016-01-29 16:48:23 +0100952 const struct lys_node *schema;
953 struct ly_ctx *ctx;
954 int i;
955 va_list ap;
Michal Vasko24337392015-10-16 09:58:16 +0200956
957 ly_errno = 0;
Michal Vasko24337392015-10-16 09:58:16 +0200958
Radek Krejci2342cf62016-01-29 16:48:23 +0100959 if (!node) {
960 /* TODO what about LYD_OPT_NOTIF, LYD_OPT_RPC and LYD_OPT_RPCREPLY ? */
961 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
962 return EXIT_SUCCESS;
963 }
964 /* LYD_OPT_DATA || LYD_OPT_CONFIG */
965
966 /* get context with schemas from the variable arguments */
967 va_start(ap, options);
968 ctx = va_arg(ap, struct ly_ctx*);
969 if (!ctx) {
970 LOGERR(LY_EINVAL, "%s: Invalid variable argument.", __func__);
971 va_end(ap);
972 return EXIT_FAILURE;
973 }
974
975 /* check for missing mandatory elements according to schemas in context */
976 for (i = 0; i < ctx->models.used; i++) {
977 if (!ctx->models.list[i]->data) {
978 continue;
979 }
980 schema = ly_check_mandatory(NULL, ctx->models.list[i]->data);
981 if (schema) {
982 if (schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
Michal Vasko6ea3e362016-03-11 10:25:36 +0100983 LOGVAL(LYE_TOOMANY, 0, LY_VLOG_LYS, schema, schema->name, schema->parent ? schema->parent->name : "module");
984 LOGVAL(LYE_SPEC, 0, 0, NULL,
Radek Krejciadb57612016-02-16 13:34:34 +0100985 "Number of \"%s\" instances in \"%s\" does not follow min-elements constraint.",
Radek Krejci2342cf62016-01-29 16:48:23 +0100986 schema->name, schema->parent ? schema->parent->name : ctx->models.list[i]->name);
987 } else {
Radek Krejciadb57612016-02-16 13:34:34 +0100988 LOGVAL(LYE_MISSELEM, 0, LY_VLOG_LYS, schema,
989 schema->name, schema->parent ? schema->parent->name : ctx->models.list[i]->name);
Radek Krejci2342cf62016-01-29 16:48:23 +0100990 }
991 va_end(ap);
992 return EXIT_FAILURE;
993
994 }
995 }
996
997 va_end(ap);
998 return EXIT_SUCCESS;
999 }
1000
Radek Krejci27e82262016-01-21 17:15:05 +01001001 if (!(options & LYD_OPT_NOSIBLINGS)) {
1002 /* check that the node is the first sibling */
1003 while(node->prev->next) {
1004 node = node->prev;
Radek Krejcif03ec152015-12-03 13:18:37 +01001005 }
Radek Krejci27e82262016-01-21 17:15:05 +01001006 }
1007
Radek Krejci15c733d2016-01-27 16:31:17 +01001008 LY_TREE_FOR_SAFE(node, next1, root) {
1009 LY_TREE_DFS_BEGIN(root, next2, iter) {
Radek Krejci27e82262016-01-21 17:15:05 +01001010 if (to_free) {
1011 lyd_free(to_free);
1012 to_free = NULL;
1013 }
1014
1015 if (lyv_data_context(iter, options, 0, NULL)) {
Michal Vasko24337392015-10-16 09:58:16 +02001016 return EXIT_FAILURE;
Radek Krejci27e82262016-01-21 17:15:05 +01001017 }
Radek Krejci15c733d2016-01-27 16:31:17 +01001018 if (lyv_data_value(iter, options)) {
1019 return EXIT_FAILURE;
1020 }
Radek Krejci27e82262016-01-21 17:15:05 +01001021 if (lyv_data_content(iter, options, 0, NULL)) {
1022 if (ly_errno) {
1023 return EXIT_FAILURE;
1024 } else {
1025 /* safe deferred removal */
1026 to_free = iter;
Radek Krejci15c733d2016-01-27 16:31:17 +01001027 next2 = NULL;
1028 goto nextsiblings;
Radek Krejciefe6a142015-12-03 14:01:00 +01001029 }
Michal Vasko3f7dba12015-10-15 13:09:27 +02001030 }
Michal Vasko24337392015-10-16 09:58:16 +02001031
Radek Krejci27e82262016-01-21 17:15:05 +01001032 /* validation successful */
1033 iter->validity = LYD_VAL_OK;
Radek Krejcica7efb72016-01-18 13:06:01 +01001034
Radek Krejci15c733d2016-01-27 16:31:17 +01001035 /* where go next? - modified LY_TREE_DFS_END */
1036 if (iter->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1037 next2 = NULL;
1038 } else {
1039 next2 = iter->child;
1040 }
1041nextsiblings:
1042 if (!next2) {
1043 /* no children */
1044 if (iter == root) {
1045 /* we are done */
1046 break;
1047 }
1048 /* try siblings */
1049 next2 = iter->next;
1050 }
1051 while (!next2) {
1052 iter = iter->parent;
1053 /* parent is already processed, go to its sibling */
1054 if (iter->parent == root->parent) {
1055 /* we are done */
1056 break;
1057 }
1058 next2 = iter->next;
1059 } /* end of modified LY_TREE_DFS_END */
1060 }
1061
1062 if (to_free) {
1063 if (node == to_free) {
1064 /* we shouldn't be here */
1065 assert(0);
1066 }
1067 lyd_free(to_free);
1068 to_free = NULL;
1069 }
Radek Krejci27e82262016-01-21 17:15:05 +01001070
1071 if (options & LYD_OPT_NOSIBLINGS) {
1072 break;
1073 }
Michal Vasko2d162e12015-09-24 14:33:29 +02001074 }
1075
Michal Vasko02592902015-10-15 12:14:40 +02001076
1077 return EXIT_SUCCESS;
1078}
1079
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001080/* create an attribute copy */
Michal Vasko55f60be2015-10-14 13:12:58 +02001081static struct lyd_attr *
1082lyd_dup_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr)
1083{
1084 struct lyd_attr *ret;
1085
1086 /* allocate new attr */
1087 if (!parent->attr) {
1088 parent->attr = malloc(sizeof *parent->attr);
1089 ret = parent->attr;
1090 } else {
1091 for (ret = parent->attr; ret->next; ret = ret->next);
1092 ret->next = malloc(sizeof *ret);
1093 ret = ret->next;
1094 }
Michal Vasko253035f2015-12-17 16:58:13 +01001095 if (!ret) {
1096 LOGMEM;
1097 return NULL;
1098 }
Michal Vasko55f60be2015-10-14 13:12:58 +02001099
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001100 /* fill new attr except */
Michal Vasko55f60be2015-10-14 13:12:58 +02001101 ret->next = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001102 ret->module = attr->module;
Michal Vasko55f60be2015-10-14 13:12:58 +02001103 ret->name = lydict_insert(ctx, attr->name, 0);
1104 ret->value = lydict_insert(ctx, attr->value, 0);
1105
Michal Vasko55f60be2015-10-14 13:12:58 +02001106 return ret;
1107}
1108
Michal Vasko2d162e12015-09-24 14:33:29 +02001109API int
1110lyd_unlink(struct lyd_node *node)
1111{
Radek Krejci46c4cd72016-01-21 15:13:52 +01001112 struct lyd_node *iter, *next;
1113 struct ly_set *set, *data;
1114 unsigned int i, j;
Michal Vasko2d162e12015-09-24 14:33:29 +02001115
1116 if (!node) {
1117 ly_errno = LY_EINVAL;
1118 return EXIT_FAILURE;
1119 }
1120
Radek Krejci46c4cd72016-01-21 15:13:52 +01001121 /* fix leafrefs */
1122 LY_TREE_DFS_BEGIN(node, next, iter) {
1123 /* the node is target of a leafref */
1124 if ((iter->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && iter->schema->child) {
1125 set = (struct ly_set *)iter->schema->child;
1126 for (i = 0; i < set->number; i++) {
Michal Vasko105cef12016-02-04 12:06:26 +01001127 data = lyd_get_node2(iter, set->sset[i]);
Radek Krejci46c4cd72016-01-21 15:13:52 +01001128 if (data) {
1129 for (j = 0; j < data->number; j++) {
1130 if (((struct lyd_node_leaf_list *)data->dset[j])->value.leafref == iter) {
1131 /* remove reference to the node we are going to replace */
1132 ((struct lyd_node_leaf_list *)data->dset[j])->value.leafref = NULL;
1133 }
1134 }
1135 ly_set_free(data);
1136 }
1137 }
1138 }
1139 LY_TREE_DFS_END(node, next, iter)
1140 }
1141
Michal Vasko2d162e12015-09-24 14:33:29 +02001142 /* unlink from siblings */
1143 if (node->prev->next) {
1144 node->prev->next = node->next;
1145 }
1146 if (node->next) {
1147 node->next->prev = node->prev;
1148 } else {
1149 /* unlinking the last node */
Radek Krejci32636312016-01-07 13:49:48 +01001150 if (node->parent) {
1151 iter = node->parent->child;
1152 } else {
1153 iter = node->prev;
1154 while (iter->prev != node) {
1155 iter = iter->prev;
1156 }
Michal Vasko2d162e12015-09-24 14:33:29 +02001157 }
1158 /* update the "last" pointer from the first node */
1159 iter->prev = node->prev;
1160 }
1161
1162 /* unlink from parent */
1163 if (node->parent) {
1164 if (node->parent->child == node) {
1165 /* the node is the first child */
1166 node->parent->child = node->next;
1167 }
1168 node->parent = NULL;
1169 }
1170
1171 node->next = NULL;
1172 node->prev = node;
1173
1174 return EXIT_SUCCESS;
1175}
1176
Michal Vaskoc0797f82015-10-14 15:51:25 +02001177API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +01001178lyd_dup(const struct lyd_node *node, int recursive)
Michal Vaskoc0797f82015-10-14 15:51:25 +02001179{
Michal Vasko1e62a092015-12-01 12:27:20 +01001180 const struct lyd_node *next, *elem;
1181 struct lyd_node *ret, *parent, *new_node;
Michal Vaskoc0797f82015-10-14 15:51:25 +02001182 struct lyd_attr *attr;
1183 struct lyd_node_leaf_list *new_leaf;
1184 struct lyd_node_anyxml *new_axml;
1185 struct lys_type *type;
1186
1187 if (!node) {
1188 ly_errno = LY_EINVAL;
1189 return NULL;
1190 }
1191
1192 ret = NULL;
1193 parent = NULL;
1194
1195 /* LY_TREE_DFS */
1196 for (elem = next = node; elem; elem = next) {
1197
1198 /* fill specific part */
1199 switch (elem->schema->nodetype) {
1200 case LYS_LEAF:
1201 case LYS_LEAFLIST:
1202 new_leaf = malloc(sizeof *new_leaf);
1203 new_node = (struct lyd_node *)new_leaf;
Michal Vasko253035f2015-12-17 16:58:13 +01001204 if (!new_node) {
1205 LOGMEM;
1206 return NULL;
1207 }
Michal Vaskoc0797f82015-10-14 15:51:25 +02001208
1209 new_leaf->value = ((struct lyd_node_leaf_list *)elem)->value;
1210 new_leaf->value_str = lydict_insert(elem->schema->module->ctx,
1211 ((struct lyd_node_leaf_list *)elem)->value_str, 0);
1212 new_leaf->value_type = ((struct lyd_node_leaf_list *)elem)->value_type;
1213 /* bits type must be treated specially */
1214 if (new_leaf->value_type == LY_TYPE_BITS) {
1215 for (type = &((struct lys_node_leaf *)elem->schema)->type; type->der->module; type = &type->der->type) {
1216 if (type->base != LY_TYPE_BITS) {
1217 LOGINT;
Michal Vaskod80e6c72015-10-15 09:37:01 +02001218 lyd_free(new_node);
Michal Vaskoc0797f82015-10-14 15:51:25 +02001219 lyd_free(ret);
1220 return NULL;
1221 }
1222 }
1223
1224 new_leaf->value.bit = malloc(type->info.bits.count * sizeof *new_leaf->value.bit);
Michal Vasko253035f2015-12-17 16:58:13 +01001225 if (!new_leaf->value.bit) {
1226 LOGMEM;
1227 lyd_free(new_node);
1228 lyd_free(ret);
1229 return NULL;
1230 }
Michal Vaskoc0797f82015-10-14 15:51:25 +02001231 memcpy(new_leaf->value.bit, ((struct lyd_node_leaf_list *)elem)->value.bit,
1232 type->info.bits.count * sizeof *new_leaf->value.bit);
1233 }
1234 break;
1235 case LYS_ANYXML:
1236 new_axml = malloc(sizeof *new_axml);
1237 new_node = (struct lyd_node *)new_axml;
Michal Vasko253035f2015-12-17 16:58:13 +01001238 if (!new_node) {
1239 LOGMEM;
1240 return NULL;
1241 }
Michal Vaskoc0797f82015-10-14 15:51:25 +02001242
1243 new_axml->value = lyxml_dup_elem(elem->schema->module->ctx, ((struct lyd_node_anyxml *)elem)->value,
1244 NULL, 1);
1245 break;
1246 case LYS_CONTAINER:
1247 case LYS_LIST:
1248 case LYS_NOTIF:
1249 case LYS_RPC:
1250 new_node = malloc(sizeof *new_node);
Michal Vasko253035f2015-12-17 16:58:13 +01001251 if (!new_node) {
1252 LOGMEM;
1253 return NULL;
1254 }
Michal Vaskoc0797f82015-10-14 15:51:25 +02001255 new_node->child = NULL;
1256 break;
1257 default:
Michal Vaskoc0797f82015-10-14 15:51:25 +02001258 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +02001259 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +02001260 return NULL;
1261 }
1262
1263 /* fill common part */
1264 new_node->schema = elem->schema;
1265 new_node->attr = NULL;
1266 LY_TREE_FOR(elem->attr, attr) {
1267 lyd_dup_attr(elem->schema->module->ctx, new_node, attr);
1268 }
1269 new_node->next = NULL;
1270 new_node->prev = new_node;
1271 new_node->parent = NULL;
Radek Krejcica7efb72016-01-18 13:06:01 +01001272 new_node->validity = LYD_VAL_NOT;
Michal Vaskoc0797f82015-10-14 15:51:25 +02001273
1274 if (!ret) {
1275 ret = new_node;
1276 }
1277 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +02001278 if (lyd_insert(parent, new_node)) {
Michal Vaskoc0797f82015-10-14 15:51:25 +02001279 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +02001280 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +02001281 return NULL;
1282 }
1283 }
1284
1285 if (!recursive) {
1286 break;
1287 }
1288
1289 /* LY_TREE_DFS_END */
1290 /* select element for the next run - children first */
1291 next = elem->child;
1292 /* child exception for lyd_node_leaf and lyd_node_leaflist */
1293 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1294 next = NULL;
1295 }
1296 if (!next) {
1297 /* no children, so try siblings */
1298 next = elem->next;
1299 } else {
1300 parent = new_node;
1301 }
1302 while (!next) {
1303 /* no siblings, go back through parents */
1304 elem = elem->parent;
1305 if (elem->parent == node->parent) {
1306 break;
1307 }
Michal Vasko785b2ad2015-10-15 09:37:15 +02001308 if (!parent) {
Michal Vaskoc8f5d802015-10-23 10:14:39 +02001309 lyd_free(ret);
Michal Vasko785b2ad2015-10-15 09:37:15 +02001310 LOGINT;
Michal Vaskoc8f5d802015-10-23 10:14:39 +02001311 return NULL;
Michal Vasko785b2ad2015-10-15 09:37:15 +02001312 }
Michal Vaskoc0797f82015-10-14 15:51:25 +02001313 parent = parent->parent;
1314 /* parent is already processed, go to its sibling */
1315 next = elem->next;
1316 }
1317 }
1318
1319 return ret;
1320}
1321
Radek Krejci88f29302015-10-30 15:42:33 +01001322API void
1323lyd_free_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr, int recursive)
Michal Vasko2d162e12015-09-24 14:33:29 +02001324{
Radek Krejci88f29302015-10-30 15:42:33 +01001325 struct lyd_attr *iter;
1326
1327 if (!ctx || !attr) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001328 return;
1329 }
1330
Radek Krejci88f29302015-10-30 15:42:33 +01001331 if (parent) {
1332 if (parent->attr == attr) {
1333 if (recursive) {
1334 parent->attr = NULL;
1335 } else {
1336 parent->attr = attr->next;
1337 }
1338 } else {
1339 for (iter = parent->attr; iter->next != attr; iter = iter->next);
1340 if (iter->next) {
1341 if (recursive) {
1342 iter->next = NULL;
1343 } else {
1344 iter->next = attr->next;
1345 }
1346 }
1347 }
Michal Vasko2d162e12015-09-24 14:33:29 +02001348 }
Radek Krejci88f29302015-10-30 15:42:33 +01001349
1350 if (!recursive) {
1351 attr->next = NULL;
1352 }
1353
1354 for(iter = attr; iter; ) {
1355 attr = iter;
1356 iter = iter->next;
1357
1358 lydict_remove(ctx, attr->name);
1359 lydict_remove(ctx, attr->value);
1360 free(attr);
1361 }
Michal Vasko2d162e12015-09-24 14:33:29 +02001362}
1363
Michal Vaskofd76bd12015-09-24 15:49:57 +02001364struct lyd_node *
1365lyd_attr_parent(struct lyd_node *root, struct lyd_attr *attr)
1366{
1367 struct lyd_node *next, *elem;
1368 struct lyd_attr *node_attr;
1369
1370 LY_TREE_DFS_BEGIN(root, next, elem) {
1371 for (node_attr = elem->attr; node_attr; node_attr = node_attr->next) {
1372 if (node_attr == attr) {
1373 return elem;
1374 }
1375 }
1376 LY_TREE_DFS_END(root, next, elem)
1377 }
1378
1379 return NULL;
1380}
1381
Radek Krejci134610e2015-10-20 17:15:34 +02001382API struct lyd_attr *
1383lyd_insert_attr(struct lyd_node *parent, const char *name, const char *value)
1384{
Radek Krejci134610e2015-10-20 17:15:34 +02001385 struct lyd_attr *a, *iter;
1386 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01001387 const struct lys_module *module;
Radek Krejci134610e2015-10-20 17:15:34 +02001388 const char *p;
1389 char *aux;
1390
1391 if (!parent || !name || !value) {
1392 return NULL;
1393 }
1394 ctx = parent->schema->module->ctx;
1395
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001396 if ((p = strchr(name, ':'))) {
1397 /* search for the namespace */
1398 aux = strndup(name, p - name);
Michal Vasko253035f2015-12-17 16:58:13 +01001399 if (!aux) {
1400 LOGMEM;
1401 return NULL;
1402 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001403 module = ly_ctx_get_module(ctx, aux, NULL);
1404 free(aux);
1405 name = p + 1;
Radek Krejci134610e2015-10-20 17:15:34 +02001406
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001407 if (!module) {
1408 /* module not found */
Radek Krejcia008ca92015-10-30 15:52:05 +01001409 LOGERR(LY_EINVAL, "Attribute prefix does not match any schema in the context.");
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001410 return NULL;
Radek Krejci134610e2015-10-20 17:15:34 +02001411 }
1412 } else {
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001413 /* no prefix -> module is the same as for the parent */
1414 module = parent->schema->module;
Radek Krejci134610e2015-10-20 17:15:34 +02001415 }
1416
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001417 a = malloc(sizeof *a);
Michal Vasko253035f2015-12-17 16:58:13 +01001418 if (!a) {
1419 LOGMEM;
1420 return NULL;
1421 }
Michal Vasko1e62a092015-12-01 12:27:20 +01001422 a->module = (struct lys_module *)module;
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001423 a->next = NULL;
1424 a->name = lydict_insert(ctx, name, 0);
Radek Krejci134610e2015-10-20 17:15:34 +02001425 a->value = lydict_insert(ctx, value, 0);
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001426
Radek Krejci134610e2015-10-20 17:15:34 +02001427 if (!parent->attr) {
1428 parent->attr = a;
1429 } else {
1430 for (iter = parent->attr; iter->next; iter = iter->next);
1431 iter->next = a;
1432 }
1433
1434 return a;
1435}
1436
Michal Vasko2d162e12015-09-24 14:33:29 +02001437API void
1438lyd_free(struct lyd_node *node)
1439{
Radek Krejci46c4cd72016-01-21 15:13:52 +01001440 struct lyd_node *next, *iter;
Michal Vasko2d162e12015-09-24 14:33:29 +02001441
1442 if (!node) {
1443 return;
1444 }
1445
1446 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
1447 /* free children */
Radek Krejci46c4cd72016-01-21 15:13:52 +01001448 LY_TREE_FOR_SAFE(node->child, next, iter) {
1449 lyd_free(iter);
Michal Vasko2d162e12015-09-24 14:33:29 +02001450 }
1451 } else if (node->schema->nodetype == LYS_ANYXML) {
Michal Vasko345da0a2015-12-02 10:35:55 +01001452 lyxml_free(node->schema->module->ctx, ((struct lyd_node_anyxml *)node)->value);
Radek Krejci46c4cd72016-01-21 15:13:52 +01001453 } else { /* LYS_LEAF | LYS_LEAFLIST */
Michal Vasko2d162e12015-09-24 14:33:29 +02001454 /* free value */
Radek Krejci46c4cd72016-01-21 15:13:52 +01001455 switch (((struct lyd_node_leaf_list *)node)->value_type) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001456 case LY_TYPE_BINARY:
1457 case LY_TYPE_STRING:
Michal Vasko4c183312015-09-25 10:41:47 +02001458 lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value.string);
Michal Vasko2d162e12015-09-24 14:33:29 +02001459 break;
1460 case LY_TYPE_BITS:
Michal Vasko4c183312015-09-25 10:41:47 +02001461 if (((struct lyd_node_leaf_list *)node)->value.bit) {
1462 free(((struct lyd_node_leaf_list *)node)->value.bit);
Michal Vasko2d162e12015-09-24 14:33:29 +02001463 }
1464 break;
1465 default:
Radek Krejci225376f2016-02-16 17:36:22 +01001466 lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value_str);
Michal Vasko2d162e12015-09-24 14:33:29 +02001467 break;
1468 }
1469 }
1470
1471 lyd_unlink(node);
Radek Krejci88f29302015-10-30 15:42:33 +01001472 lyd_free_attr(node->schema->module->ctx, node, node->attr, 1);
Michal Vasko2d162e12015-09-24 14:33:29 +02001473 free(node);
1474}
1475
Radek Krejci81468402016-01-07 13:52:40 +01001476API void
1477lyd_free_withsiblings(struct lyd_node *node)
1478{
1479 struct lyd_node *iter, *aux;
1480
1481 if (!node) {
1482 return;
1483 }
1484
1485 /* optimization - avoid freeing (unlinking) the last node of the siblings list */
1486 /* so, first, free the node's predecessors to the beginning of the list ... */
1487 for(iter = node->prev; iter->next; iter = aux) {
1488 aux = iter->prev;
1489 lyd_free(iter);
1490 }
1491 /* ... then, the node is the first in the siblings list, so free them all */
1492 LY_TREE_FOR_SAFE(node, aux, iter) {
1493 lyd_free(iter);
1494 }
1495}
1496
Michal Vasko2d162e12015-09-24 14:33:29 +02001497int
1498lyd_compare(struct lyd_node *first, struct lyd_node *second, int unique)
1499{
1500 struct lys_node_list *slist;
Michal Vasko1e62a092015-12-01 12:27:20 +01001501 const struct lys_node *snode = NULL;
Michal Vasko2d162e12015-09-24 14:33:29 +02001502 struct lyd_node *diter;
1503 const char *val1, *val2;
1504 int i, j;
1505
1506 assert(first);
1507 assert(second);
1508
1509 if (first->schema != second->schema) {
1510 return 1;
1511 }
1512
1513 switch (first->schema->nodetype) {
1514 case LYS_LEAFLIST:
1515 /* compare values */
Radek Krejciedaaa082016-02-17 10:21:54 +01001516 if (ly_strequal(((struct lyd_node_leaf_list *)first)->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +01001517 ((struct lyd_node_leaf_list *)second)->value_str, 1)) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001518 return 0;
1519 }
1520 return 1;
1521 case LYS_LIST:
Michal Vasko4c183312015-09-25 10:41:47 +02001522 slist = (struct lys_node_list *)first->schema;
Michal Vasko2d162e12015-09-24 14:33:29 +02001523
1524 if (unique) {
1525 /* compare unique leafs */
1526 for (i = 0; i < slist->unique_size; i++) {
Radek Krejci581ce772015-11-10 17:22:40 +01001527 for (j = 0; j < slist->unique[i].expr_size; j++) {
1528 /* first */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001529 diter = resolve_data_descendant_schema_nodeid(slist->unique[i].expr[j], first->child);
Radek Krejci581ce772015-11-10 17:22:40 +01001530 if (diter) {
1531 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
1532 } else {
1533 /* use default value */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001534 if (resolve_descendant_schema_nodeid(slist->unique[i].expr[j], first->schema->child, LYS_LEAF, &snode)) {
Radek Krejci3eb09b62015-12-16 15:22:19 +01001535 /* error, but unique expression was checked when the schema was parsed */
1536 return -1;
1537 }
Radek Krejci581ce772015-11-10 17:22:40 +01001538 val1 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +02001539 }
Radek Krejci581ce772015-11-10 17:22:40 +01001540
1541 /* second */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001542 diter = resolve_data_descendant_schema_nodeid(slist->unique[i].expr[j], second->child);
Radek Krejci581ce772015-11-10 17:22:40 +01001543 if (diter) {
1544 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
1545 } else {
1546 /* use default value */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001547 if (resolve_descendant_schema_nodeid(slist->unique[i].expr[j], second->schema->child, LYS_LEAF, &snode)) {
Radek Krejci3eb09b62015-12-16 15:22:19 +01001548 /* error, but unique expression was checked when the schema was parsed */
1549 return -1;
1550 }
Radek Krejci581ce772015-11-10 17:22:40 +01001551 val2 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +02001552 }
Radek Krejci581ce772015-11-10 17:22:40 +01001553
Radek Krejci749190d2016-02-18 16:26:25 +01001554 if (!ly_strequal(val1, val2, 1)) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001555 break;
1556 }
1557 }
Radek Krejci581ce772015-11-10 17:22:40 +01001558 if (j && j == slist->unique[i].expr_size) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001559 /* all unique leafs are the same in this set */
1560 return 0;
1561 }
1562 }
1563 }
1564
Radek Krejcica7efb72016-01-18 13:06:01 +01001565 if (second->validity == LYD_VAL_UNIQUE) {
1566 /* only unique part changed somewhere, so it is no need to check keys */
1567 return 0;
1568 }
1569
Michal Vasko2d162e12015-09-24 14:33:29 +02001570 /* compare keys */
1571 for (i = 0; i < slist->keys_size; i++) {
1572 snode = (struct lys_node *)slist->keys[i];
1573 val1 = val2 = NULL;
1574 LY_TREE_FOR(first->child, diter) {
1575 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +02001576 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +02001577 break;
1578 }
1579 }
1580 LY_TREE_FOR(second->child, diter) {
1581 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +02001582 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +02001583 break;
1584 }
1585 }
Radek Krejci749190d2016-02-18 16:26:25 +01001586 if (!ly_strequal(val1, val2, 1)) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001587 return 1;
1588 }
1589 }
1590
1591 return 0;
1592 default:
1593 /* no additional check is needed */
1594 return 0;
1595 }
1596}
1597
Radek Krejcidc154432016-01-21 11:10:59 +01001598API struct ly_set *
Michal Vasko105cef12016-02-04 12:06:26 +01001599lyd_get_node(const struct lyd_node *data, const char *expr)
1600{
1601 struct lyxp_set xp_set;
1602 struct ly_set *set;
1603 uint16_t i;
1604
1605 if (!data || !expr) {
1606 ly_errno = LY_EINVAL;
1607 return NULL;
1608 }
1609
1610 memset(&xp_set, 0, sizeof xp_set);
1611
1612 if (lyxp_eval(expr, data, &xp_set, 0, 0) != EXIT_SUCCESS) {
1613 return NULL;
1614 }
1615
1616 set = ly_set_new();
1617 if (!set) {
1618 LOGMEM;
1619 return NULL;
1620 }
1621
1622 if (xp_set.type == LYXP_SET_NODE_SET) {
1623 for (i = 0; i < xp_set.used; ++i) {
1624 if ((xp_set.node_type[i] == LYXP_NODE_ELEM) || (xp_set.node_type[i] == LYXP_NODE_TEXT)) {
1625 if (ly_set_add(set, xp_set.value.nodes[i])) {
1626 ly_set_free(set);
1627 set = NULL;
1628 break;
1629 }
1630 }
1631 }
1632 }
1633 lyxp_set_cast(&xp_set, LYXP_SET_EMPTY, data, 0);
1634
1635 return set;
1636}
1637
1638API struct ly_set *
1639lyd_get_node2(const struct lyd_node *data, const struct lys_node *schema)
Radek Krejcic5b6b912016-01-18 16:35:35 +01001640{
Radek Krejcidc154432016-01-21 11:10:59 +01001641 struct ly_set *ret, *ret_aux, *spath;
Radek Krejcic5b6b912016-01-18 16:35:35 +01001642 const struct lys_node *siter;
1643 struct lyd_node *iter;
1644 unsigned int i, j;
1645
1646 if (!data || !schema ||
1647 !(schema->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC))) {
1648 ly_errno = LY_EINVAL;
1649 return NULL;
1650 }
1651
Radek Krejcidc154432016-01-21 11:10:59 +01001652 ret = ly_set_new();
1653 spath = ly_set_new();
Radek Krejcic5b6b912016-01-18 16:35:35 +01001654 if (!ret || !spath) {
1655 LOGMEM;
1656 goto error;
1657 }
1658
1659 /* find data root */
1660 while (data->parent) {
1661 /* vertical move (up) */
1662 data = data->parent;
1663 }
1664 while (data->prev->next) {
1665 /* horizontal move (left) */
1666 data = data->prev;
1667 }
1668
1669 /* build schema path */
1670 for (siter = schema; siter; ) {
1671 if (siter->nodetype == LYS_AUGMENT) {
1672 siter = ((struct lys_node_augment *)siter)->target;
1673 continue;
1674 } else if (siter->nodetype == LYS_OUTPUT) {
1675 /* done for RPC reply */
1676 break;
1677 } else if (siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
1678 /* standard data node */
Radek Krejcidc154432016-01-21 11:10:59 +01001679 ly_set_add(spath, (void*)siter);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001680
1681 } /* else skip the rest node types */
1682 siter = siter->parent;
1683 }
1684 if (!spath->number) {
1685 /* no valid path */
1686 goto error;
1687 }
1688
1689 /* start searching */
1690 LY_TREE_FOR((struct lyd_node *)data, iter) {
Radek Krejcidc154432016-01-21 11:10:59 +01001691 if (iter->schema == spath->sset[spath->number - 1]) {
1692 ly_set_add(ret, iter);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001693 }
1694 }
1695 for (i = spath->number - 1; i; i--) {
1696 if (!ret->number) {
1697 /* nothing found */
Radek Krejci6c0993c2016-01-19 09:40:16 +01001698 break;
Radek Krejcic5b6b912016-01-18 16:35:35 +01001699 }
1700
Radek Krejcidc154432016-01-21 11:10:59 +01001701 ret_aux = ly_set_new();
Radek Krejcic5b6b912016-01-18 16:35:35 +01001702 if (!ret_aux) {
1703 LOGMEM;
1704 goto error;
1705 }
1706 for (j = 0; j < ret->number; j++) {
Radek Krejcidc154432016-01-21 11:10:59 +01001707 LY_TREE_FOR(ret->dset[j]->child, iter) {
1708 if (iter->schema == spath->sset[i - 1]) {
1709 ly_set_add(ret_aux, iter);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001710 }
1711 }
1712 }
Radek Krejcidc154432016-01-21 11:10:59 +01001713 ly_set_free(ret);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001714 ret = ret_aux;
1715 }
1716
Radek Krejcidc154432016-01-21 11:10:59 +01001717 ly_set_free(spath);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001718 return ret;
1719
1720error:
Radek Krejcidc154432016-01-21 11:10:59 +01001721 ly_set_free(ret);
1722 ly_set_free(spath);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001723
1724 return NULL;
1725}
1726
Radek Krejcidc154432016-01-21 11:10:59 +01001727API struct ly_set *
Michal Vasko6a1ab6f2016-02-04 12:08:11 +01001728lyd_get_list_keys(const struct lyd_node *list)
1729{
1730 struct lyd_node *key;
1731 struct lys_node_list *slist;
1732 struct ly_set *set;
1733 unsigned int i;
1734
1735 if (!list || (list->schema->nodetype != LYS_LIST)) {
1736 ly_errno = LY_EINVAL;
1737 return NULL;
1738 }
1739
1740 slist = (struct lys_node_list *)list->schema;
1741
1742 set = ly_set_new();
1743 if (!set) {
1744 LOGMEM;
1745 return NULL;
1746 }
1747
1748 for (i = 0; i < slist->keys_size; ++i) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001749 key = resolve_data_descendant_schema_nodeid(slist->keys[i]->name, list->child);
Michal Vasko6a1ab6f2016-02-04 12:08:11 +01001750 if (key) {
1751 ly_set_add(set, key);
1752 }
1753 }
1754
1755 return set;
1756}
1757
1758API struct ly_set *
Radek Krejcidc154432016-01-21 11:10:59 +01001759ly_set_new(void)
Michal Vasko2d162e12015-09-24 14:33:29 +02001760{
Radek Krejcidc154432016-01-21 11:10:59 +01001761 return calloc(1, sizeof(struct ly_set));
Michal Vasko2d162e12015-09-24 14:33:29 +02001762}
1763
1764API void
Radek Krejcidc154432016-01-21 11:10:59 +01001765ly_set_free(struct ly_set *set)
Michal Vasko2d162e12015-09-24 14:33:29 +02001766{
1767 if (!set) {
1768 return;
1769 }
1770
1771 free(set->set);
1772 free(set);
1773}
1774
1775API int
Radek Krejcidc154432016-01-21 11:10:59 +01001776ly_set_add(struct ly_set *set, void *node)
Michal Vasko2d162e12015-09-24 14:33:29 +02001777{
Radek Krejci87fd4df2016-01-18 14:44:20 +01001778 unsigned int i;
Radek Krejcidc154432016-01-21 11:10:59 +01001779 void **new;
Michal Vasko2d162e12015-09-24 14:33:29 +02001780
Radek Krejci87fd4df2016-01-18 14:44:20 +01001781 if (!set || !node) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001782 ly_errno = LY_EINVAL;
1783 return EXIT_FAILURE;
1784 }
1785
Radek Krejci87fd4df2016-01-18 14:44:20 +01001786 /* search for duplication */
1787 for (i = 0; i < set->number; i++) {
1788 if (set->set[i] == node) {
1789 /* already in set */
1790 return EXIT_SUCCESS;
1791 }
1792 }
1793
Michal Vasko2d162e12015-09-24 14:33:29 +02001794 if (set->size == set->number) {
Radek Krejcic5c45982016-01-07 12:50:44 +01001795 new = realloc(set->set, (set->size + 8) * sizeof *(set->set));
Michal Vasko2d162e12015-09-24 14:33:29 +02001796 if (!new) {
1797 LOGMEM;
1798 return EXIT_FAILURE;
1799 }
1800 set->size += 8;
1801 set->set = new;
1802 }
1803
1804 set->set[set->number++] = node;
1805
1806 return EXIT_SUCCESS;
1807}
Radek Krejci8cc31e52016-01-18 14:45:33 +01001808
1809API int
Radek Krejcidc154432016-01-21 11:10:59 +01001810ly_set_rm_index(struct ly_set *set, unsigned int index)
Radek Krejci8cc31e52016-01-18 14:45:33 +01001811{
1812 if (!set || (index + 1) > set->number) {
1813 ly_errno = LY_EINVAL;
1814 return EXIT_FAILURE;
1815 }
1816
1817 if (index == set->number - 1) {
1818 /* removing last item in set */
1819 set->set[index] = NULL;
1820 } else {
1821 /* removing item somewhere in a middle, so put there the last item */
1822 set->set[index] = set->set[set->number - 1];
1823 set->set[set->number - 1] = NULL;
1824 }
1825 set->number--;
1826
1827 return EXIT_SUCCESS;
1828}
1829
1830API int
Radek Krejcidc154432016-01-21 11:10:59 +01001831ly_set_rm(struct ly_set *set, void *node)
Radek Krejci8cc31e52016-01-18 14:45:33 +01001832{
1833 unsigned int i;
1834
1835 if (!set || !node) {
1836 ly_errno = LY_EINVAL;
1837 return EXIT_FAILURE;
1838 }
1839
1840 /* get index */
1841 for (i = 0; i < set->number; i++) {
1842 if (set->set[i] == node) {
1843 break;
1844 }
1845 }
1846 if (i == set->number) {
1847 /* node is not in set */
1848 ly_errno = LY_EINVAL;
1849 return EXIT_FAILURE;
1850 }
1851
Radek Krejcidc154432016-01-21 11:10:59 +01001852 return ly_set_rm_index(set, i);
Radek Krejci8cc31e52016-01-18 14:45:33 +01001853}