blob: 1b580e5ee2111407ba4a47f57554593b081260c4 [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
178API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100179lyd_new(struct lyd_node *parent, const struct lys_module *module, const char *name)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200180{
181 struct lyd_node *ret;
Michal Vasko1e62a092015-12-01 12:27:20 +0100182 const struct lys_node *snode = NULL, *siblings;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200183
184 if ((!parent && !module) || !name) {
185 ly_errno = LY_EINVAL;
186 return NULL;
187 }
188
189 if (!parent) {
190 siblings = module->data;
191 } else {
Michal Vaskoa5ef4d72015-09-29 16:05:21 +0200192 if (!parent->schema) {
193 return NULL;
194 }
195 siblings = parent->schema->child;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200196 }
197
Michal Vaskoa45cf2b2015-10-23 09:45:36 +0200198 if (lys_get_data_sibling(module, siblings, name, LYS_CONTAINER | LYS_LIST | LYS_NOTIF | LYS_RPC, &snode)
199 || !snode) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200200 return NULL;
201 }
202
203 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100204 if (!ret) {
205 LOGMEM;
206 return NULL;
207 }
Michal Vasko1e62a092015-12-01 12:27:20 +0100208 ret->schema = (struct lys_node *)snode;
Radek Krejcica7efb72016-01-18 13:06:01 +0100209 ret->validity = LYD_VAL_NOT;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200210 ret->prev = ret;
211 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200212 if (lyd_insert(parent, ret)) {
213 lyd_free(ret);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200214 return NULL;
215 }
216 }
217
218 return ret;
219}
220
Michal Vasko50c0a872016-01-13 14:34:11 +0100221static struct lyd_node *
222lyd_create_leaf(const struct lys_node *schema, const char *val_str)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200223{
Michal Vasko50c0a872016-01-13 14:34:11 +0100224 struct lyd_node_leaf_list *ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200225
Michal Vasko3e671b52015-10-23 16:23:15 +0200226 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100227 if (!ret) {
228 LOGMEM;
229 return NULL;
230 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100231 ret->schema = (struct lys_node *)schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100232 ret->validity = LYD_VAL_NOT;
Michal Vasko3e671b52015-10-23 16:23:15 +0200233 ret->prev = (struct lyd_node *)ret;
Radek Krejci37b756f2016-01-18 10:15:03 +0100234 ret->value_type = ((struct lys_node_leaf *)schema)->type.base;
Michal Vasko50c0a872016-01-13 14:34:11 +0100235 ret->value_str = lydict_insert(schema->module->ctx, val_str, 0);
Michal Vasko3e671b52015-10-23 16:23:15 +0200236
237 /* resolve the type correctly */
Radek Krejci37b756f2016-01-18 10:15:03 +0100238 if (lyp_parse_value(ret, NULL, 1, NULL, 0)) {
239 lyd_free((struct lyd_node *)ret);
240 ly_errno = LY_EINVAL;
241 return NULL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200242 }
243
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200244 return (struct lyd_node *)ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200245}
246
247API struct lyd_node *
Michal Vasko50c0a872016-01-13 14:34:11 +0100248lyd_new_leaf(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200249{
Michal Vasko50c0a872016-01-13 14:34:11 +0100250 struct lyd_node *ret;
251 const struct lys_node *snode = NULL, *siblings;
Michal Vasko587998f2015-09-29 16:07:53 +0200252
Michal Vasko14d88772015-12-03 10:54:59 +0100253 if ((!parent && !module) || !name) {
Michal Vasko587998f2015-09-29 16:07:53 +0200254 ly_errno = LY_EINVAL;
255 return NULL;
256 }
257
258 if (!parent) {
259 siblings = module->data;
Michal Vasko587998f2015-09-29 16:07:53 +0200260 } else {
261 if (!parent->schema) {
Michal Vasko50c0a872016-01-13 14:34:11 +0100262 ly_errno = LY_EINVAL;
Michal Vasko587998f2015-09-29 16:07:53 +0200263 return NULL;
264 }
265 siblings = parent->schema->child;
Michal Vasko587998f2015-09-29 16:07:53 +0200266 }
267
Michal Vasko50c0a872016-01-13 14:34:11 +0100268 if (lys_get_data_sibling(module, siblings, name, LYS_LEAFLIST | LYS_LEAF, &snode) || !snode) {
269 ly_errno = LY_EINVAL;
Michal Vasko587998f2015-09-29 16:07:53 +0200270 return NULL;
271 }
272
Michal Vasko50c0a872016-01-13 14:34:11 +0100273 ret = lyd_create_leaf(snode, val_str);
274 if (!ret) {
275 return NULL;
276 }
277
278 /* connect to parent */
279 if (parent) {
280 if (lyd_insert(parent, ret)) {
281 lyd_free(ret);
282 return NULL;
283 }
284 }
285
Radek Krejcica7efb72016-01-18 13:06:01 +0100286 if (ret->schema->flags & LYS_UNIQUE) {
287 /* locate the first parent list */
288 for (parent = ret->parent; parent && parent->schema->nodetype != LYS_LIST; parent = parent->parent);
289
290 /* set flag for future validation */
291 if (parent) {
292 parent->validity |= LYD_VAL_UNIQUE;
293 }
294 }
295
Michal Vasko50c0a872016-01-13 14:34:11 +0100296 return ret;
297
298}
299
Radek Krejcib9b4d002016-01-18 13:08:51 +0100300int
301lyd_change_leaf(struct lyd_node_leaf_list *leaf, const char *val_str)
302{
303 const char *backup;
304 struct lyd_node *parent;
305
306 if (!leaf) {
307 ly_errno = LY_EINVAL;
308 return EXIT_FAILURE;
309 }
310
311 backup = leaf->value_str;
312 leaf->value_str = val_str;
313
314 /* resolve the type correctly */
315 if (lyp_parse_value(leaf, NULL, 1, NULL, 0)) {
316 leaf->value_str = backup;
317 ly_errno = LY_EINVAL;
318 return EXIT_FAILURE;
319 }
320
321 /* value is correct, finish the changes in leaf */
322 lydict_remove(leaf->schema->module->ctx, backup);
323 leaf->value_str = lydict_insert(leaf->schema->module->ctx, val_str, 0);
324
325 if (leaf->schema->flags & LYS_UNIQUE) {
326 /* locate the first parent list */
327 for (parent = leaf->parent; parent && parent->schema->nodetype != LYS_LIST; parent = parent->parent);
328
329 /* set flag for future validation */
330 if (parent) {
331 parent->validity |= LYD_VAL_UNIQUE;
332 }
333 }
334
335 return EXIT_SUCCESS;
336}
337
Michal Vasko50c0a872016-01-13 14:34:11 +0100338static struct lyd_node *
339lyd_create_anyxml(const struct lys_node *schema, const char *val_xml)
340{
341 struct lyd_node_anyxml *ret;
342 struct lyxml_elem *root;
343 char *xml;
344
Michal Vasko587998f2015-09-29 16:07:53 +0200345 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100346 if (!ret) {
347 LOGMEM;
348 return NULL;
349 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100350 ret->schema = (struct lys_node *)schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100351 ret->validity = LYD_VAL_NOT;
Michal Vasko587998f2015-09-29 16:07:53 +0200352 ret->prev = (struct lyd_node *)ret;
Michal Vasko587998f2015-09-29 16:07:53 +0200353
Radek Krejci86538212015-12-17 15:59:01 +0100354 /* store the anyxml data together with the anyxml element */
Radek Krejci15412ca2016-03-03 11:16:52 +0100355 if (asprintf(&xml, "<%s>%s</%s>", schema->name, (val_xml ? val_xml : ""), schema->name) == -1) {
356 LOGMEM;
357 lyd_free((struct lyd_node *)ret);
358 return NULL;
359 }
Radek Krejci722b0072016-02-01 17:09:45 +0100360 root = lyxml_parse_mem(schema->module->ctx, xml, 0);
Michal Vasko17cc7062015-12-10 14:31:48 +0100361 free(xml);
362 if (!root) {
363 lyd_free((struct lyd_node *)ret);
364 return NULL;
Michal Vasko14d88772015-12-03 10:54:59 +0100365 }
Michal Vasko334a07d2016-02-29 11:30:10 +0100366 ret->value = root;
Michal Vasko17cc7062015-12-10 14:31:48 +0100367
Michal Vasko587998f2015-09-29 16:07:53 +0200368 return (struct lyd_node *)ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200369}
370
Michal Vasko0df122f2015-12-14 13:38:21 +0100371API struct lyd_node *
Michal Vasko50c0a872016-01-13 14:34:11 +0100372lyd_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 +0100373{
374 struct lyd_node *ret;
Michal Vasko50c0a872016-01-13 14:34:11 +0100375 const struct lys_node *siblings, *snode;
Michal Vasko0df122f2015-12-14 13:38:21 +0100376
Michal Vasko50c0a872016-01-13 14:34:11 +0100377 if ((!parent && !module) || !name) {
Michal Vasko0df122f2015-12-14 13:38:21 +0100378 ly_errno = LY_EINVAL;
379 return NULL;
380 }
381
Michal Vasko50c0a872016-01-13 14:34:11 +0100382 if (!parent) {
383 siblings = module->data;
Michal Vasko0df122f2015-12-14 13:38:21 +0100384 } else {
Michal Vasko50c0a872016-01-13 14:34:11 +0100385 if (!parent->schema) {
386 return NULL;
387 }
388 siblings = parent->schema->child;
389 }
390
391 if (lys_get_data_sibling(module, siblings, name, LYS_ANYXML, &snode) || !snode) {
392 return NULL;
393 }
394
395 ret = lyd_create_anyxml(snode, val_xml);
396 if (!ret) {
397 return NULL;
398 }
399
400 /* connect to parent */
401 if (parent) {
402 if (lyd_insert(parent, ret)) {
403 lyd_free(ret);
404 return NULL;
405 }
406 }
407
408 return ret;
409}
410
411API struct lyd_node *
412lyd_output_new(const struct lys_node *schema)
413{
414 struct lyd_node *ret;
415
416 if (!schema || !(schema->nodetype & (LYS_CONTAINER | LYS_LIST))
417 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
Michal Vasko0df122f2015-12-14 13:38:21 +0100418 ly_errno = LY_EINVAL;
419 return NULL;
420 }
421
422 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100423 if (!ret) {
424 LOGMEM;
425 return NULL;
426 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100427 ret->schema = (struct lys_node *)schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100428 ret->validity = LYD_VAL_NOT;
Michal Vasko0df122f2015-12-14 13:38:21 +0100429 ret->prev = ret;
430
Michal Vasko50c0a872016-01-13 14:34:11 +0100431 return ret;
432}
433
434API struct lyd_node *
435lyd_output_new_leaf(const struct lys_node *schema, const char *val_str)
436{
437 if (!schema || (schema->nodetype != LYS_LEAF)
438 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
439 ly_errno = LY_EINVAL;
440 return NULL;
441 }
442
443 return lyd_create_leaf(schema, val_str);
444}
445
446API struct lyd_node *
447lyd_output_new_anyxml(const struct lys_node *schema, const char *val_xml)
448{
449 if (!schema || (schema->nodetype != LYS_ANYXML)
450 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
451 ly_errno = LY_EINVAL;
452 return NULL;
453 }
454
455 return lyd_create_anyxml(schema, val_xml);
Michal Vasko0df122f2015-12-14 13:38:21 +0100456}
457
Radek Krejcica7efb72016-01-18 13:06:01 +0100458static void
459lyd_insert_setinvalid(struct lyd_node *node)
460{
461 struct lyd_node *next, *elem, *parent_list;
462
463 assert(node);
464
465 /* overall validity of the node itself */
466 node->validity = LYD_VAL_NOT;
467
468 /* explore changed unique leafs */
469 /* first, get know if there is a list in parents chain */
470 for (parent_list = node->parent;
471 parent_list && parent_list->schema->nodetype != LYS_LIST;
472 parent_list = parent_list->parent);
473 if (parent_list && !(parent_list->validity & LYD_VAL_UNIQUE)) {
474 /* there is a list, so check if we inserted a leaf supposed to be unique */
475 for (elem = node; elem; elem = next) {
476 if (elem->schema->nodetype == LYS_LIST) {
477 /* stop searching to the depth, children would be unique to a list in subtree */
478 goto nextsibling;
479 }
480
481 if (elem->schema->nodetype == LYS_LEAF && (elem->schema->flags & LYS_UNIQUE)) {
482 /* set flag to list for future validation */
483 parent_list->validity |= LYD_VAL_UNIQUE;
484 break;
485 }
486
Radek Krejci46c4cd72016-01-21 15:13:52 +0100487 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
488 goto nextsibling;
489 }
490
Radek Krejcica7efb72016-01-18 13:06:01 +0100491 /* select next elem to process */
492 /* go into children */
493 next = elem->child;
494 /* got through siblings */
495 if (!next) {
496nextsibling:
497 next = elem->next;
498 if (!next) {
499 /* no children */
500 if (elem == node) {
501 /* we are done, back in start node */
502 break;
503 }
504 /* try siblings */
505 next = elem->next;
506 }
507 }
508 /* go back to parents */
509 while (!next) {
510 if (elem->parent == node) {
511 /* we are done, back in start node */
512 break;
513 }
514 /* parent was actually already processed, so go to the parent's sibling */
515 next = elem->parent->next;
516 }
517 }
518 }
519}
520
Michal Vasko24337392015-10-16 09:58:16 +0200521API int
522lyd_insert(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko2d162e12015-09-24 14:33:29 +0200523{
524 struct lys_node *sparent;
Michal Vasko24337392015-10-16 09:58:16 +0200525 struct lyd_node *iter;
Radek Krejcica7efb72016-01-18 13:06:01 +0100526 int invalid = 0;
Michal Vasko2d162e12015-09-24 14:33:29 +0200527
Michal Vasko24337392015-10-16 09:58:16 +0200528 if (!node || !parent) {
529 ly_errno = LY_EINVAL;
530 return EXIT_FAILURE;
Michal Vasko2d162e12015-09-24 14:33:29 +0200531 }
532
Radek Krejcica7efb72016-01-18 13:06:01 +0100533 /* check placing the node to the appropriate place according to the schema */
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100534 for (sparent = lys_parent(node->schema);
Michal Vasko72d65c92015-12-07 14:02:35 +0100535 sparent && !(sparent->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100536 sparent = lys_parent(sparent));
Michal Vasko2d162e12015-09-24 14:33:29 +0200537 if (sparent != parent->schema) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200538 return EXIT_FAILURE;
539 }
540
Radek Krejcica7efb72016-01-18 13:06:01 +0100541 if (node->parent != parent || lyp_is_rpc(node->schema)) {
542 /* it is not just moving under a parent node or it is in an RPC where
543 * nodes order matters, so the validation will be necessary */
544 invalid = 1;
545 }
546
Michal Vasko24337392015-10-16 09:58:16 +0200547 if (node->parent || node->prev->next) {
548 lyd_unlink(node);
549 }
550
Michal Vasko2d162e12015-09-24 14:33:29 +0200551 if (!parent->child) {
552 /* add as the only child of the parent */
553 parent->child = node;
554 } else {
555 /* add as the last child of the parent */
556 parent->child->prev->next = node;
557 node->prev = parent->child->prev;
558 for (iter = node; iter->next; iter = iter->next);
559 parent->child->prev = iter;
560 }
Michal Vasko9cc2d0a2015-10-14 15:49:07 +0200561
Michal Vasko2d162e12015-09-24 14:33:29 +0200562 LY_TREE_FOR(node, iter) {
563 iter->parent = parent;
Radek Krejcica7efb72016-01-18 13:06:01 +0100564 if (invalid) {
565 lyd_insert_setinvalid(iter);
566 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200567 }
568
569 return EXIT_SUCCESS;
570}
571
Michal Vasko02592902015-10-15 12:14:40 +0200572static int
Michal Vasko24337392015-10-16 09:58:16 +0200573lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, int before)
Michal Vasko2d162e12015-09-24 14:33:29 +0200574{
575 struct lys_node *par1, *par2;
Radek Krejci20a5f292016-02-09 15:04:49 +0100576 struct lyd_node *iter;
Radek Krejcica7efb72016-01-18 13:06:01 +0100577 int invalid = 0;
Michal Vasko3f7dba12015-10-15 13:09:27 +0200578
579 if (sibling == node) {
580 return EXIT_SUCCESS;
581 }
582
Michal Vasko2d162e12015-09-24 14:33:29 +0200583 /* check placing the node to the appropriate place according to the schema */
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100584 for (par1 = lys_parent(sibling->schema);
Radek Krejci2b7bb492015-12-02 15:46:29 +0100585 par1 && !(par1->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100586 par1 = lys_parent(par1));
587 for (par2 = lys_parent(node->schema);
Radek Krejci2b7bb492015-12-02 15:46:29 +0100588 par2 && !(par2->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100589 par2 = lys_parent(par2));
Michal Vasko2d162e12015-09-24 14:33:29 +0200590 if (par1 != par2) {
591 ly_errno = LY_EINVAL;
592 return EXIT_FAILURE;
593 }
594
Radek Krejcic886a2a2016-02-09 15:07:16 +0100595 if (node->parent != sibling->parent || !node->parent || lyp_is_rpc(node->schema)) {
596 /* a) it is not just moving under a parent node or
597 * b) it is top-level where we don't know if it is the same tree, or
598 * c) it is in an RPC where nodes order matters,
599 * so the validation will be necessary */
600 if (!node->parent) {
601 /* b) search in siblings */
602 for (iter = node->prev; iter != node; iter = iter->prev) {
603 if (iter == sibling) {
604 break;
605 }
606 }
607 if (iter == node) {
608 /* node and siblings are not currently in the same data tree */
609 invalid = 1;
610 }
611 } else { /* a) and c) */
612 invalid = 1;
613 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100614 }
615
Radek Krejci20a5f292016-02-09 15:04:49 +0100616 if (node->parent || node->next || node->prev->next) {
Michal Vasko24337392015-10-16 09:58:16 +0200617 lyd_unlink(node);
618 }
619
Radek Krejci20a5f292016-02-09 15:04:49 +0100620 node->parent = sibling->parent;
621 if (invalid) {
622 lyd_insert_setinvalid(node);
Michal Vasko2d162e12015-09-24 14:33:29 +0200623 }
624
Michal Vasko02592902015-10-15 12:14:40 +0200625 if (before) {
626 if (sibling->prev->next) {
627 /* adding into the list */
628 sibling->prev->next = node;
629 } else if (sibling->parent) {
630 /* at the beginning */
631 sibling->parent->child = node;
Michal Vasko2d162e12015-09-24 14:33:29 +0200632 }
Michal Vasko02592902015-10-15 12:14:40 +0200633 node->prev = sibling->prev;
Radek Krejci20a5f292016-02-09 15:04:49 +0100634 sibling->prev = node;
635 node->next = sibling;
Michal Vasko02592902015-10-15 12:14:40 +0200636 } else {
637 if (sibling->next) {
638 /* adding into a middle - fix the prev pointer of the node after inserted nodes */
Radek Krejci20a5f292016-02-09 15:04:49 +0100639 node->next = sibling->next;
640 sibling->next->prev = node;
Michal Vasko02592902015-10-15 12:14:40 +0200641 } else {
642 /* at the end - fix the prev pointer of the first node */
643 if (sibling->parent) {
Radek Krejci20a5f292016-02-09 15:04:49 +0100644 sibling->parent->child->prev = node;
Michal Vasko02592902015-10-15 12:14:40 +0200645 } else {
646 for (iter = sibling; iter->prev->next; iter = iter->prev);
Radek Krejci20a5f292016-02-09 15:04:49 +0100647 iter->prev = node;
Michal Vasko02592902015-10-15 12:14:40 +0200648 }
649 }
650 sibling->next = node;
651 node->prev = sibling;
Michal Vasko2d162e12015-09-24 14:33:29 +0200652 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200653
Michal Vasko24337392015-10-16 09:58:16 +0200654 return EXIT_SUCCESS;
655}
Michal Vasko2d162e12015-09-24 14:33:29 +0200656
Michal Vasko24337392015-10-16 09:58:16 +0200657API int
658lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
659{
660 if (!node || !sibling || lyd_insert_sibling(sibling, node, 1)) {
661 ly_errno = LY_EINVAL;
662 return EXIT_FAILURE;
663 }
664
665 return EXIT_SUCCESS;
666}
667
668API int
669lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
670{
671 if (!node || !sibling || lyd_insert_sibling(sibling, node, 0)) {
672 ly_errno = LY_EINVAL;
673 return EXIT_FAILURE;
674 }
675
676 return EXIT_SUCCESS;
677}
678
679API int
Radek Krejci2342cf62016-01-29 16:48:23 +0100680lyd_validate(struct lyd_node *node, int options, ...)
Michal Vasko24337392015-10-16 09:58:16 +0200681{
Radek Krejci15c733d2016-01-27 16:31:17 +0100682 struct lyd_node *root, *next1, *next2, *iter, *to_free = NULL;
Radek Krejci2342cf62016-01-29 16:48:23 +0100683 const struct lys_node *schema;
684 struct ly_ctx *ctx;
685 int i;
686 va_list ap;
Michal Vasko24337392015-10-16 09:58:16 +0200687
688 ly_errno = 0;
Michal Vasko24337392015-10-16 09:58:16 +0200689
Radek Krejci2342cf62016-01-29 16:48:23 +0100690 if (!node) {
691 /* TODO what about LYD_OPT_NOTIF, LYD_OPT_RPC and LYD_OPT_RPCREPLY ? */
692 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
693 return EXIT_SUCCESS;
694 }
695 /* LYD_OPT_DATA || LYD_OPT_CONFIG */
696
697 /* get context with schemas from the variable arguments */
698 va_start(ap, options);
699 ctx = va_arg(ap, struct ly_ctx*);
700 if (!ctx) {
701 LOGERR(LY_EINVAL, "%s: Invalid variable argument.", __func__);
702 va_end(ap);
703 return EXIT_FAILURE;
704 }
705
706 /* check for missing mandatory elements according to schemas in context */
707 for (i = 0; i < ctx->models.used; i++) {
708 if (!ctx->models.list[i]->data) {
709 continue;
710 }
711 schema = ly_check_mandatory(NULL, ctx->models.list[i]->data);
712 if (schema) {
713 if (schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
Radek Krejciadb57612016-02-16 13:34:34 +0100714 LOGVAL(LYE_SPEC, 0, LY_VLOG_LYS, schema,
715 "Number of \"%s\" instances in \"%s\" does not follow min-elements constraint.",
Radek Krejci2342cf62016-01-29 16:48:23 +0100716 schema->name, schema->parent ? schema->parent->name : ctx->models.list[i]->name);
717 } else {
Radek Krejciadb57612016-02-16 13:34:34 +0100718 LOGVAL(LYE_MISSELEM, 0, LY_VLOG_LYS, schema,
719 schema->name, schema->parent ? schema->parent->name : ctx->models.list[i]->name);
Radek Krejci2342cf62016-01-29 16:48:23 +0100720 }
721 va_end(ap);
722 return EXIT_FAILURE;
723
724 }
725 }
726
727 va_end(ap);
728 return EXIT_SUCCESS;
729 }
730
Radek Krejci27e82262016-01-21 17:15:05 +0100731 if (!(options & LYD_OPT_NOSIBLINGS)) {
732 /* check that the node is the first sibling */
733 while(node->prev->next) {
734 node = node->prev;
Radek Krejcif03ec152015-12-03 13:18:37 +0100735 }
Radek Krejci27e82262016-01-21 17:15:05 +0100736 }
737
Radek Krejci15c733d2016-01-27 16:31:17 +0100738 LY_TREE_FOR_SAFE(node, next1, root) {
739 LY_TREE_DFS_BEGIN(root, next2, iter) {
Radek Krejci27e82262016-01-21 17:15:05 +0100740 if (to_free) {
741 lyd_free(to_free);
742 to_free = NULL;
743 }
744
745 if (lyv_data_context(iter, options, 0, NULL)) {
Michal Vasko24337392015-10-16 09:58:16 +0200746 return EXIT_FAILURE;
Radek Krejci27e82262016-01-21 17:15:05 +0100747 }
Radek Krejci15c733d2016-01-27 16:31:17 +0100748 if (lyv_data_value(iter, options)) {
749 return EXIT_FAILURE;
750 }
Radek Krejci27e82262016-01-21 17:15:05 +0100751 if (lyv_data_content(iter, options, 0, NULL)) {
752 if (ly_errno) {
753 return EXIT_FAILURE;
754 } else {
755 /* safe deferred removal */
756 to_free = iter;
Radek Krejci15c733d2016-01-27 16:31:17 +0100757 next2 = NULL;
758 goto nextsiblings;
Radek Krejciefe6a142015-12-03 14:01:00 +0100759 }
Michal Vasko3f7dba12015-10-15 13:09:27 +0200760 }
Michal Vasko24337392015-10-16 09:58:16 +0200761
Radek Krejci27e82262016-01-21 17:15:05 +0100762 /* validation successful */
763 iter->validity = LYD_VAL_OK;
Radek Krejcica7efb72016-01-18 13:06:01 +0100764
Radek Krejci15c733d2016-01-27 16:31:17 +0100765 /* where go next? - modified LY_TREE_DFS_END */
766 if (iter->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
767 next2 = NULL;
768 } else {
769 next2 = iter->child;
770 }
771nextsiblings:
772 if (!next2) {
773 /* no children */
774 if (iter == root) {
775 /* we are done */
776 break;
777 }
778 /* try siblings */
779 next2 = iter->next;
780 }
781 while (!next2) {
782 iter = iter->parent;
783 /* parent is already processed, go to its sibling */
784 if (iter->parent == root->parent) {
785 /* we are done */
786 break;
787 }
788 next2 = iter->next;
789 } /* end of modified LY_TREE_DFS_END */
790 }
791
792 if (to_free) {
793 if (node == to_free) {
794 /* we shouldn't be here */
795 assert(0);
796 }
797 lyd_free(to_free);
798 to_free = NULL;
799 }
Radek Krejci27e82262016-01-21 17:15:05 +0100800
801 if (options & LYD_OPT_NOSIBLINGS) {
802 break;
803 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200804 }
805
Michal Vasko02592902015-10-15 12:14:40 +0200806
807 return EXIT_SUCCESS;
808}
809
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100810/* create an attribute copy */
Michal Vasko55f60be2015-10-14 13:12:58 +0200811static struct lyd_attr *
812lyd_dup_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr)
813{
814 struct lyd_attr *ret;
815
816 /* allocate new attr */
817 if (!parent->attr) {
818 parent->attr = malloc(sizeof *parent->attr);
819 ret = parent->attr;
820 } else {
821 for (ret = parent->attr; ret->next; ret = ret->next);
822 ret->next = malloc(sizeof *ret);
823 ret = ret->next;
824 }
Michal Vasko253035f2015-12-17 16:58:13 +0100825 if (!ret) {
826 LOGMEM;
827 return NULL;
828 }
Michal Vasko55f60be2015-10-14 13:12:58 +0200829
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100830 /* fill new attr except */
Michal Vasko55f60be2015-10-14 13:12:58 +0200831 ret->next = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100832 ret->module = attr->module;
Michal Vasko55f60be2015-10-14 13:12:58 +0200833 ret->name = lydict_insert(ctx, attr->name, 0);
834 ret->value = lydict_insert(ctx, attr->value, 0);
835
Michal Vasko55f60be2015-10-14 13:12:58 +0200836 return ret;
837}
838
Michal Vasko2d162e12015-09-24 14:33:29 +0200839API int
840lyd_unlink(struct lyd_node *node)
841{
Radek Krejci46c4cd72016-01-21 15:13:52 +0100842 struct lyd_node *iter, *next;
843 struct ly_set *set, *data;
844 unsigned int i, j;
Michal Vasko2d162e12015-09-24 14:33:29 +0200845
846 if (!node) {
847 ly_errno = LY_EINVAL;
848 return EXIT_FAILURE;
849 }
850
Radek Krejci46c4cd72016-01-21 15:13:52 +0100851 /* fix leafrefs */
852 LY_TREE_DFS_BEGIN(node, next, iter) {
853 /* the node is target of a leafref */
854 if ((iter->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && iter->schema->child) {
855 set = (struct ly_set *)iter->schema->child;
856 for (i = 0; i < set->number; i++) {
Michal Vasko105cef12016-02-04 12:06:26 +0100857 data = lyd_get_node2(iter, set->sset[i]);
Radek Krejci46c4cd72016-01-21 15:13:52 +0100858 if (data) {
859 for (j = 0; j < data->number; j++) {
860 if (((struct lyd_node_leaf_list *)data->dset[j])->value.leafref == iter) {
861 /* remove reference to the node we are going to replace */
862 ((struct lyd_node_leaf_list *)data->dset[j])->value.leafref = NULL;
863 }
864 }
865 ly_set_free(data);
866 }
867 }
868 }
869 LY_TREE_DFS_END(node, next, iter)
870 }
871
Michal Vasko2d162e12015-09-24 14:33:29 +0200872 /* unlink from siblings */
873 if (node->prev->next) {
874 node->prev->next = node->next;
875 }
876 if (node->next) {
877 node->next->prev = node->prev;
878 } else {
879 /* unlinking the last node */
Radek Krejci32636312016-01-07 13:49:48 +0100880 if (node->parent) {
881 iter = node->parent->child;
882 } else {
883 iter = node->prev;
884 while (iter->prev != node) {
885 iter = iter->prev;
886 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200887 }
888 /* update the "last" pointer from the first node */
889 iter->prev = node->prev;
890 }
891
892 /* unlink from parent */
893 if (node->parent) {
894 if (node->parent->child == node) {
895 /* the node is the first child */
896 node->parent->child = node->next;
897 }
898 node->parent = NULL;
899 }
900
901 node->next = NULL;
902 node->prev = node;
903
904 return EXIT_SUCCESS;
905}
906
Michal Vaskoc0797f82015-10-14 15:51:25 +0200907API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100908lyd_dup(const struct lyd_node *node, int recursive)
Michal Vaskoc0797f82015-10-14 15:51:25 +0200909{
Michal Vasko1e62a092015-12-01 12:27:20 +0100910 const struct lyd_node *next, *elem;
911 struct lyd_node *ret, *parent, *new_node;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200912 struct lyd_attr *attr;
913 struct lyd_node_leaf_list *new_leaf;
914 struct lyd_node_anyxml *new_axml;
915 struct lys_type *type;
916
917 if (!node) {
918 ly_errno = LY_EINVAL;
919 return NULL;
920 }
921
922 ret = NULL;
923 parent = NULL;
924
925 /* LY_TREE_DFS */
926 for (elem = next = node; elem; elem = next) {
927
928 /* fill specific part */
929 switch (elem->schema->nodetype) {
930 case LYS_LEAF:
931 case LYS_LEAFLIST:
932 new_leaf = malloc(sizeof *new_leaf);
933 new_node = (struct lyd_node *)new_leaf;
Michal Vasko253035f2015-12-17 16:58:13 +0100934 if (!new_node) {
935 LOGMEM;
936 return NULL;
937 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200938
939 new_leaf->value = ((struct lyd_node_leaf_list *)elem)->value;
940 new_leaf->value_str = lydict_insert(elem->schema->module->ctx,
941 ((struct lyd_node_leaf_list *)elem)->value_str, 0);
942 new_leaf->value_type = ((struct lyd_node_leaf_list *)elem)->value_type;
943 /* bits type must be treated specially */
944 if (new_leaf->value_type == LY_TYPE_BITS) {
945 for (type = &((struct lys_node_leaf *)elem->schema)->type; type->der->module; type = &type->der->type) {
946 if (type->base != LY_TYPE_BITS) {
947 LOGINT;
Michal Vaskod80e6c72015-10-15 09:37:01 +0200948 lyd_free(new_node);
Michal Vaskoc0797f82015-10-14 15:51:25 +0200949 lyd_free(ret);
950 return NULL;
951 }
952 }
953
954 new_leaf->value.bit = malloc(type->info.bits.count * sizeof *new_leaf->value.bit);
Michal Vasko253035f2015-12-17 16:58:13 +0100955 if (!new_leaf->value.bit) {
956 LOGMEM;
957 lyd_free(new_node);
958 lyd_free(ret);
959 return NULL;
960 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200961 memcpy(new_leaf->value.bit, ((struct lyd_node_leaf_list *)elem)->value.bit,
962 type->info.bits.count * sizeof *new_leaf->value.bit);
963 }
964 break;
965 case LYS_ANYXML:
966 new_axml = malloc(sizeof *new_axml);
967 new_node = (struct lyd_node *)new_axml;
Michal Vasko253035f2015-12-17 16:58:13 +0100968 if (!new_node) {
969 LOGMEM;
970 return NULL;
971 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200972
973 new_axml->value = lyxml_dup_elem(elem->schema->module->ctx, ((struct lyd_node_anyxml *)elem)->value,
974 NULL, 1);
975 break;
976 case LYS_CONTAINER:
977 case LYS_LIST:
978 case LYS_NOTIF:
979 case LYS_RPC:
980 new_node = malloc(sizeof *new_node);
Michal Vasko253035f2015-12-17 16:58:13 +0100981 if (!new_node) {
982 LOGMEM;
983 return NULL;
984 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200985 new_node->child = NULL;
986 break;
987 default:
Michal Vaskoc0797f82015-10-14 15:51:25 +0200988 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +0200989 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200990 return NULL;
991 }
992
993 /* fill common part */
994 new_node->schema = elem->schema;
995 new_node->attr = NULL;
996 LY_TREE_FOR(elem->attr, attr) {
997 lyd_dup_attr(elem->schema->module->ctx, new_node, attr);
998 }
999 new_node->next = NULL;
1000 new_node->prev = new_node;
1001 new_node->parent = NULL;
Radek Krejcica7efb72016-01-18 13:06:01 +01001002 new_node->validity = LYD_VAL_NOT;
Michal Vaskoc0797f82015-10-14 15:51:25 +02001003
1004 if (!ret) {
1005 ret = new_node;
1006 }
1007 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +02001008 if (lyd_insert(parent, new_node)) {
Michal Vaskoc0797f82015-10-14 15:51:25 +02001009 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +02001010 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +02001011 return NULL;
1012 }
1013 }
1014
1015 if (!recursive) {
1016 break;
1017 }
1018
1019 /* LY_TREE_DFS_END */
1020 /* select element for the next run - children first */
1021 next = elem->child;
1022 /* child exception for lyd_node_leaf and lyd_node_leaflist */
1023 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1024 next = NULL;
1025 }
1026 if (!next) {
1027 /* no children, so try siblings */
1028 next = elem->next;
1029 } else {
1030 parent = new_node;
1031 }
1032 while (!next) {
1033 /* no siblings, go back through parents */
1034 elem = elem->parent;
1035 if (elem->parent == node->parent) {
1036 break;
1037 }
Michal Vasko785b2ad2015-10-15 09:37:15 +02001038 if (!parent) {
Michal Vaskoc8f5d802015-10-23 10:14:39 +02001039 lyd_free(ret);
Michal Vasko785b2ad2015-10-15 09:37:15 +02001040 LOGINT;
Michal Vaskoc8f5d802015-10-23 10:14:39 +02001041 return NULL;
Michal Vasko785b2ad2015-10-15 09:37:15 +02001042 }
Michal Vaskoc0797f82015-10-14 15:51:25 +02001043 parent = parent->parent;
1044 /* parent is already processed, go to its sibling */
1045 next = elem->next;
1046 }
1047 }
1048
1049 return ret;
1050}
1051
Radek Krejci88f29302015-10-30 15:42:33 +01001052API void
1053lyd_free_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr, int recursive)
Michal Vasko2d162e12015-09-24 14:33:29 +02001054{
Radek Krejci88f29302015-10-30 15:42:33 +01001055 struct lyd_attr *iter;
1056
1057 if (!ctx || !attr) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001058 return;
1059 }
1060
Radek Krejci88f29302015-10-30 15:42:33 +01001061 if (parent) {
1062 if (parent->attr == attr) {
1063 if (recursive) {
1064 parent->attr = NULL;
1065 } else {
1066 parent->attr = attr->next;
1067 }
1068 } else {
1069 for (iter = parent->attr; iter->next != attr; iter = iter->next);
1070 if (iter->next) {
1071 if (recursive) {
1072 iter->next = NULL;
1073 } else {
1074 iter->next = attr->next;
1075 }
1076 }
1077 }
Michal Vasko2d162e12015-09-24 14:33:29 +02001078 }
Radek Krejci88f29302015-10-30 15:42:33 +01001079
1080 if (!recursive) {
1081 attr->next = NULL;
1082 }
1083
1084 for(iter = attr; iter; ) {
1085 attr = iter;
1086 iter = iter->next;
1087
1088 lydict_remove(ctx, attr->name);
1089 lydict_remove(ctx, attr->value);
1090 free(attr);
1091 }
Michal Vasko2d162e12015-09-24 14:33:29 +02001092}
1093
Michal Vaskofd76bd12015-09-24 15:49:57 +02001094struct lyd_node *
1095lyd_attr_parent(struct lyd_node *root, struct lyd_attr *attr)
1096{
1097 struct lyd_node *next, *elem;
1098 struct lyd_attr *node_attr;
1099
1100 LY_TREE_DFS_BEGIN(root, next, elem) {
1101 for (node_attr = elem->attr; node_attr; node_attr = node_attr->next) {
1102 if (node_attr == attr) {
1103 return elem;
1104 }
1105 }
1106 LY_TREE_DFS_END(root, next, elem)
1107 }
1108
1109 return NULL;
1110}
1111
Radek Krejci134610e2015-10-20 17:15:34 +02001112API struct lyd_attr *
1113lyd_insert_attr(struct lyd_node *parent, const char *name, const char *value)
1114{
Radek Krejci134610e2015-10-20 17:15:34 +02001115 struct lyd_attr *a, *iter;
1116 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01001117 const struct lys_module *module;
Radek Krejci134610e2015-10-20 17:15:34 +02001118 const char *p;
1119 char *aux;
1120
1121 if (!parent || !name || !value) {
1122 return NULL;
1123 }
1124 ctx = parent->schema->module->ctx;
1125
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001126 if ((p = strchr(name, ':'))) {
1127 /* search for the namespace */
1128 aux = strndup(name, p - name);
Michal Vasko253035f2015-12-17 16:58:13 +01001129 if (!aux) {
1130 LOGMEM;
1131 return NULL;
1132 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001133 module = ly_ctx_get_module(ctx, aux, NULL);
1134 free(aux);
1135 name = p + 1;
Radek Krejci134610e2015-10-20 17:15:34 +02001136
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001137 if (!module) {
1138 /* module not found */
Radek Krejcia008ca92015-10-30 15:52:05 +01001139 LOGERR(LY_EINVAL, "Attribute prefix does not match any schema in the context.");
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001140 return NULL;
Radek Krejci134610e2015-10-20 17:15:34 +02001141 }
1142 } else {
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001143 /* no prefix -> module is the same as for the parent */
1144 module = parent->schema->module;
Radek Krejci134610e2015-10-20 17:15:34 +02001145 }
1146
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001147 a = malloc(sizeof *a);
Michal Vasko253035f2015-12-17 16:58:13 +01001148 if (!a) {
1149 LOGMEM;
1150 return NULL;
1151 }
Michal Vasko1e62a092015-12-01 12:27:20 +01001152 a->module = (struct lys_module *)module;
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001153 a->next = NULL;
1154 a->name = lydict_insert(ctx, name, 0);
Radek Krejci134610e2015-10-20 17:15:34 +02001155 a->value = lydict_insert(ctx, value, 0);
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001156
Radek Krejci134610e2015-10-20 17:15:34 +02001157 if (!parent->attr) {
1158 parent->attr = a;
1159 } else {
1160 for (iter = parent->attr; iter->next; iter = iter->next);
1161 iter->next = a;
1162 }
1163
1164 return a;
1165}
1166
Michal Vasko2d162e12015-09-24 14:33:29 +02001167API void
1168lyd_free(struct lyd_node *node)
1169{
Radek Krejci46c4cd72016-01-21 15:13:52 +01001170 struct lyd_node *next, *iter;
Michal Vasko2d162e12015-09-24 14:33:29 +02001171
1172 if (!node) {
1173 return;
1174 }
1175
1176 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
1177 /* free children */
Radek Krejci46c4cd72016-01-21 15:13:52 +01001178 LY_TREE_FOR_SAFE(node->child, next, iter) {
1179 lyd_free(iter);
Michal Vasko2d162e12015-09-24 14:33:29 +02001180 }
1181 } else if (node->schema->nodetype == LYS_ANYXML) {
Michal Vasko345da0a2015-12-02 10:35:55 +01001182 lyxml_free(node->schema->module->ctx, ((struct lyd_node_anyxml *)node)->value);
Radek Krejci46c4cd72016-01-21 15:13:52 +01001183 } else { /* LYS_LEAF | LYS_LEAFLIST */
Michal Vasko2d162e12015-09-24 14:33:29 +02001184 /* free value */
Radek Krejci46c4cd72016-01-21 15:13:52 +01001185 switch (((struct lyd_node_leaf_list *)node)->value_type) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001186 case LY_TYPE_BINARY:
1187 case LY_TYPE_STRING:
Michal Vasko4c183312015-09-25 10:41:47 +02001188 lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value.string);
Michal Vasko2d162e12015-09-24 14:33:29 +02001189 break;
1190 case LY_TYPE_BITS:
Michal Vasko4c183312015-09-25 10:41:47 +02001191 if (((struct lyd_node_leaf_list *)node)->value.bit) {
1192 free(((struct lyd_node_leaf_list *)node)->value.bit);
Michal Vasko2d162e12015-09-24 14:33:29 +02001193 }
1194 break;
1195 default:
Radek Krejci225376f2016-02-16 17:36:22 +01001196 lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value_str);
Michal Vasko2d162e12015-09-24 14:33:29 +02001197 break;
1198 }
1199 }
1200
1201 lyd_unlink(node);
Radek Krejci88f29302015-10-30 15:42:33 +01001202 lyd_free_attr(node->schema->module->ctx, node, node->attr, 1);
Michal Vasko2d162e12015-09-24 14:33:29 +02001203 free(node);
1204}
1205
Radek Krejci81468402016-01-07 13:52:40 +01001206API void
1207lyd_free_withsiblings(struct lyd_node *node)
1208{
1209 struct lyd_node *iter, *aux;
1210
1211 if (!node) {
1212 return;
1213 }
1214
1215 /* optimization - avoid freeing (unlinking) the last node of the siblings list */
1216 /* so, first, free the node's predecessors to the beginning of the list ... */
1217 for(iter = node->prev; iter->next; iter = aux) {
1218 aux = iter->prev;
1219 lyd_free(iter);
1220 }
1221 /* ... then, the node is the first in the siblings list, so free them all */
1222 LY_TREE_FOR_SAFE(node, aux, iter) {
1223 lyd_free(iter);
1224 }
1225}
1226
Michal Vasko2d162e12015-09-24 14:33:29 +02001227int
1228lyd_compare(struct lyd_node *first, struct lyd_node *second, int unique)
1229{
1230 struct lys_node_list *slist;
Michal Vasko1e62a092015-12-01 12:27:20 +01001231 const struct lys_node *snode = NULL;
Michal Vasko2d162e12015-09-24 14:33:29 +02001232 struct lyd_node *diter;
1233 const char *val1, *val2;
1234 int i, j;
1235
1236 assert(first);
1237 assert(second);
1238
1239 if (first->schema != second->schema) {
1240 return 1;
1241 }
1242
1243 switch (first->schema->nodetype) {
1244 case LYS_LEAFLIST:
1245 /* compare values */
Radek Krejciedaaa082016-02-17 10:21:54 +01001246 if (ly_strequal(((struct lyd_node_leaf_list *)first)->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +01001247 ((struct lyd_node_leaf_list *)second)->value_str, 1)) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001248 return 0;
1249 }
1250 return 1;
1251 case LYS_LIST:
Michal Vasko4c183312015-09-25 10:41:47 +02001252 slist = (struct lys_node_list *)first->schema;
Michal Vasko2d162e12015-09-24 14:33:29 +02001253
1254 if (unique) {
1255 /* compare unique leafs */
1256 for (i = 0; i < slist->unique_size; i++) {
Radek Krejci581ce772015-11-10 17:22:40 +01001257 for (j = 0; j < slist->unique[i].expr_size; j++) {
1258 /* first */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001259 diter = resolve_data_descendant_schema_nodeid(slist->unique[i].expr[j], first->child);
Radek Krejci581ce772015-11-10 17:22:40 +01001260 if (diter) {
1261 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
1262 } else {
1263 /* use default value */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001264 if (resolve_descendant_schema_nodeid(slist->unique[i].expr[j], first->schema->child, LYS_LEAF, &snode)) {
Radek Krejci3eb09b62015-12-16 15:22:19 +01001265 /* error, but unique expression was checked when the schema was parsed */
1266 return -1;
1267 }
Radek Krejci581ce772015-11-10 17:22:40 +01001268 val1 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +02001269 }
Radek Krejci581ce772015-11-10 17:22:40 +01001270
1271 /* second */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001272 diter = resolve_data_descendant_schema_nodeid(slist->unique[i].expr[j], second->child);
Radek Krejci581ce772015-11-10 17:22:40 +01001273 if (diter) {
1274 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
1275 } else {
1276 /* use default value */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001277 if (resolve_descendant_schema_nodeid(slist->unique[i].expr[j], second->schema->child, LYS_LEAF, &snode)) {
Radek Krejci3eb09b62015-12-16 15:22:19 +01001278 /* error, but unique expression was checked when the schema was parsed */
1279 return -1;
1280 }
Radek Krejci581ce772015-11-10 17:22:40 +01001281 val2 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +02001282 }
Radek Krejci581ce772015-11-10 17:22:40 +01001283
Radek Krejci749190d2016-02-18 16:26:25 +01001284 if (!ly_strequal(val1, val2, 1)) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001285 break;
1286 }
1287 }
Radek Krejci581ce772015-11-10 17:22:40 +01001288 if (j && j == slist->unique[i].expr_size) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001289 /* all unique leafs are the same in this set */
1290 return 0;
1291 }
1292 }
1293 }
1294
Radek Krejcica7efb72016-01-18 13:06:01 +01001295 if (second->validity == LYD_VAL_UNIQUE) {
1296 /* only unique part changed somewhere, so it is no need to check keys */
1297 return 0;
1298 }
1299
Michal Vasko2d162e12015-09-24 14:33:29 +02001300 /* compare keys */
1301 for (i = 0; i < slist->keys_size; i++) {
1302 snode = (struct lys_node *)slist->keys[i];
1303 val1 = val2 = NULL;
1304 LY_TREE_FOR(first->child, diter) {
1305 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +02001306 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +02001307 break;
1308 }
1309 }
1310 LY_TREE_FOR(second->child, diter) {
1311 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +02001312 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +02001313 break;
1314 }
1315 }
Radek Krejci749190d2016-02-18 16:26:25 +01001316 if (!ly_strequal(val1, val2, 1)) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001317 return 1;
1318 }
1319 }
1320
1321 return 0;
1322 default:
1323 /* no additional check is needed */
1324 return 0;
1325 }
1326}
1327
Radek Krejcidc154432016-01-21 11:10:59 +01001328API struct ly_set *
Michal Vasko105cef12016-02-04 12:06:26 +01001329lyd_get_node(const struct lyd_node *data, const char *expr)
1330{
1331 struct lyxp_set xp_set;
1332 struct ly_set *set;
1333 uint16_t i;
1334
1335 if (!data || !expr) {
1336 ly_errno = LY_EINVAL;
1337 return NULL;
1338 }
1339
1340 memset(&xp_set, 0, sizeof xp_set);
1341
1342 if (lyxp_eval(expr, data, &xp_set, 0, 0) != EXIT_SUCCESS) {
1343 return NULL;
1344 }
1345
1346 set = ly_set_new();
1347 if (!set) {
1348 LOGMEM;
1349 return NULL;
1350 }
1351
1352 if (xp_set.type == LYXP_SET_NODE_SET) {
1353 for (i = 0; i < xp_set.used; ++i) {
1354 if ((xp_set.node_type[i] == LYXP_NODE_ELEM) || (xp_set.node_type[i] == LYXP_NODE_TEXT)) {
1355 if (ly_set_add(set, xp_set.value.nodes[i])) {
1356 ly_set_free(set);
1357 set = NULL;
1358 break;
1359 }
1360 }
1361 }
1362 }
1363 lyxp_set_cast(&xp_set, LYXP_SET_EMPTY, data, 0);
1364
1365 return set;
1366}
1367
1368API struct ly_set *
1369lyd_get_node2(const struct lyd_node *data, const struct lys_node *schema)
Radek Krejcic5b6b912016-01-18 16:35:35 +01001370{
Radek Krejcidc154432016-01-21 11:10:59 +01001371 struct ly_set *ret, *ret_aux, *spath;
Radek Krejcic5b6b912016-01-18 16:35:35 +01001372 const struct lys_node *siter;
1373 struct lyd_node *iter;
1374 unsigned int i, j;
1375
1376 if (!data || !schema ||
1377 !(schema->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC))) {
1378 ly_errno = LY_EINVAL;
1379 return NULL;
1380 }
1381
Radek Krejcidc154432016-01-21 11:10:59 +01001382 ret = ly_set_new();
1383 spath = ly_set_new();
Radek Krejcic5b6b912016-01-18 16:35:35 +01001384 if (!ret || !spath) {
1385 LOGMEM;
1386 goto error;
1387 }
1388
1389 /* find data root */
1390 while (data->parent) {
1391 /* vertical move (up) */
1392 data = data->parent;
1393 }
1394 while (data->prev->next) {
1395 /* horizontal move (left) */
1396 data = data->prev;
1397 }
1398
1399 /* build schema path */
1400 for (siter = schema; siter; ) {
1401 if (siter->nodetype == LYS_AUGMENT) {
1402 siter = ((struct lys_node_augment *)siter)->target;
1403 continue;
1404 } else if (siter->nodetype == LYS_OUTPUT) {
1405 /* done for RPC reply */
1406 break;
1407 } else if (siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
1408 /* standard data node */
Radek Krejcidc154432016-01-21 11:10:59 +01001409 ly_set_add(spath, (void*)siter);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001410
1411 } /* else skip the rest node types */
1412 siter = siter->parent;
1413 }
1414 if (!spath->number) {
1415 /* no valid path */
1416 goto error;
1417 }
1418
1419 /* start searching */
1420 LY_TREE_FOR((struct lyd_node *)data, iter) {
Radek Krejcidc154432016-01-21 11:10:59 +01001421 if (iter->schema == spath->sset[spath->number - 1]) {
1422 ly_set_add(ret, iter);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001423 }
1424 }
1425 for (i = spath->number - 1; i; i--) {
1426 if (!ret->number) {
1427 /* nothing found */
Radek Krejci6c0993c2016-01-19 09:40:16 +01001428 break;
Radek Krejcic5b6b912016-01-18 16:35:35 +01001429 }
1430
Radek Krejcidc154432016-01-21 11:10:59 +01001431 ret_aux = ly_set_new();
Radek Krejcic5b6b912016-01-18 16:35:35 +01001432 if (!ret_aux) {
1433 LOGMEM;
1434 goto error;
1435 }
1436 for (j = 0; j < ret->number; j++) {
Radek Krejcidc154432016-01-21 11:10:59 +01001437 LY_TREE_FOR(ret->dset[j]->child, iter) {
1438 if (iter->schema == spath->sset[i - 1]) {
1439 ly_set_add(ret_aux, iter);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001440 }
1441 }
1442 }
Radek Krejcidc154432016-01-21 11:10:59 +01001443 ly_set_free(ret);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001444 ret = ret_aux;
1445 }
1446
Radek Krejcidc154432016-01-21 11:10:59 +01001447 ly_set_free(spath);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001448 return ret;
1449
1450error:
Radek Krejcidc154432016-01-21 11:10:59 +01001451 ly_set_free(ret);
1452 ly_set_free(spath);
Radek Krejcic5b6b912016-01-18 16:35:35 +01001453
1454 return NULL;
1455}
1456
Radek Krejcidc154432016-01-21 11:10:59 +01001457API struct ly_set *
Michal Vasko6a1ab6f2016-02-04 12:08:11 +01001458lyd_get_list_keys(const struct lyd_node *list)
1459{
1460 struct lyd_node *key;
1461 struct lys_node_list *slist;
1462 struct ly_set *set;
1463 unsigned int i;
1464
1465 if (!list || (list->schema->nodetype != LYS_LIST)) {
1466 ly_errno = LY_EINVAL;
1467 return NULL;
1468 }
1469
1470 slist = (struct lys_node_list *)list->schema;
1471
1472 set = ly_set_new();
1473 if (!set) {
1474 LOGMEM;
1475 return NULL;
1476 }
1477
1478 for (i = 0; i < slist->keys_size; ++i) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001479 key = resolve_data_descendant_schema_nodeid(slist->keys[i]->name, list->child);
Michal Vasko6a1ab6f2016-02-04 12:08:11 +01001480 if (key) {
1481 ly_set_add(set, key);
1482 }
1483 }
1484
1485 return set;
1486}
1487
1488API struct ly_set *
Radek Krejcidc154432016-01-21 11:10:59 +01001489ly_set_new(void)
Michal Vasko2d162e12015-09-24 14:33:29 +02001490{
Radek Krejcidc154432016-01-21 11:10:59 +01001491 return calloc(1, sizeof(struct ly_set));
Michal Vasko2d162e12015-09-24 14:33:29 +02001492}
1493
1494API void
Radek Krejcidc154432016-01-21 11:10:59 +01001495ly_set_free(struct ly_set *set)
Michal Vasko2d162e12015-09-24 14:33:29 +02001496{
1497 if (!set) {
1498 return;
1499 }
1500
1501 free(set->set);
1502 free(set);
1503}
1504
1505API int
Radek Krejcidc154432016-01-21 11:10:59 +01001506ly_set_add(struct ly_set *set, void *node)
Michal Vasko2d162e12015-09-24 14:33:29 +02001507{
Radek Krejci87fd4df2016-01-18 14:44:20 +01001508 unsigned int i;
Radek Krejcidc154432016-01-21 11:10:59 +01001509 void **new;
Michal Vasko2d162e12015-09-24 14:33:29 +02001510
Radek Krejci87fd4df2016-01-18 14:44:20 +01001511 if (!set || !node) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001512 ly_errno = LY_EINVAL;
1513 return EXIT_FAILURE;
1514 }
1515
Radek Krejci87fd4df2016-01-18 14:44:20 +01001516 /* search for duplication */
1517 for (i = 0; i < set->number; i++) {
1518 if (set->set[i] == node) {
1519 /* already in set */
1520 return EXIT_SUCCESS;
1521 }
1522 }
1523
Michal Vasko2d162e12015-09-24 14:33:29 +02001524 if (set->size == set->number) {
Radek Krejcic5c45982016-01-07 12:50:44 +01001525 new = realloc(set->set, (set->size + 8) * sizeof *(set->set));
Michal Vasko2d162e12015-09-24 14:33:29 +02001526 if (!new) {
1527 LOGMEM;
1528 return EXIT_FAILURE;
1529 }
1530 set->size += 8;
1531 set->set = new;
1532 }
1533
1534 set->set[set->number++] = node;
1535
1536 return EXIT_SUCCESS;
1537}
Radek Krejci8cc31e52016-01-18 14:45:33 +01001538
1539API int
Radek Krejcidc154432016-01-21 11:10:59 +01001540ly_set_rm_index(struct ly_set *set, unsigned int index)
Radek Krejci8cc31e52016-01-18 14:45:33 +01001541{
1542 if (!set || (index + 1) > set->number) {
1543 ly_errno = LY_EINVAL;
1544 return EXIT_FAILURE;
1545 }
1546
1547 if (index == set->number - 1) {
1548 /* removing last item in set */
1549 set->set[index] = NULL;
1550 } else {
1551 /* removing item somewhere in a middle, so put there the last item */
1552 set->set[index] = set->set[set->number - 1];
1553 set->set[set->number - 1] = NULL;
1554 }
1555 set->number--;
1556
1557 return EXIT_SUCCESS;
1558}
1559
1560API int
Radek Krejcidc154432016-01-21 11:10:59 +01001561ly_set_rm(struct ly_set *set, void *node)
Radek Krejci8cc31e52016-01-18 14:45:33 +01001562{
1563 unsigned int i;
1564
1565 if (!set || !node) {
1566 ly_errno = LY_EINVAL;
1567 return EXIT_FAILURE;
1568 }
1569
1570 /* get index */
1571 for (i = 0; i < set->number; i++) {
1572 if (set->set[i] == node) {
1573 break;
1574 }
1575 }
1576 if (i == set->number) {
1577 /* node is not in set */
1578 ly_errno = LY_EINVAL;
1579 return EXIT_FAILURE;
1580 }
1581
Radek Krejcidc154432016-01-21 11:10:59 +01001582 return ly_set_rm_index(set, i);
Radek Krejci8cc31e52016-01-18 14:45:33 +01001583}