blob: d1221ed507dadcbb998248510bee236363ac66de [file] [log] [blame]
Radek Krejcic6704c82015-10-06 11:12:45 +02001
Michal Vasko2d162e12015-09-24 14:33:29 +02002/**
3 * @file tree_data.c
4 * @author Radek Krejci <rkrejci@cesnet.cz>
5 * @brief Manipulation with libyang data structures
6 *
7 * Copyright (c) 2015 CESNET, z.s.p.o.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name of the Company nor the names of its contributors
19 * may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 */
22#define _GNU_SOURCE
Michal Vaskoff4c2832015-10-15 13:30:50 +020023#define _XOPEN_SOURCE 700
Michal Vasko2d162e12015-09-24 14:33:29 +020024
25#include <assert.h>
26#include <ctype.h>
Michal Vasko3e671b52015-10-23 16:23:15 +020027#include <limits.h>
Radek Krejci4a49bdf2016-01-12 17:17:01 +010028#include <stdarg.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020029#include <stdlib.h>
Michal Vasko662610a2015-12-07 11:25:45 +010030#include <sys/types.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020031#include <sys/mman.h>
32#include <sys/stat.h>
Michal Vasko662610a2015-12-07 11:25:45 +010033#include <fcntl.h>
34#include <unistd.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020035#include <string.h>
Michal Vasko662610a2015-12-07 11:25:45 +010036#include <errno.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020037
Michal Vasko662610a2015-12-07 11:25:45 +010038#include "libyang.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020039#include "common.h"
40#include "context.h"
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020041#include "tree_data.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020042#include "parser.h"
43#include "resolve.h"
Michal Vaskofc5744d2015-10-22 12:09:34 +020044#include "xml_internal.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020045#include "tree_internal.h"
46#include "validation.h"
47
Michal Vasko36ef6932015-12-01 14:30:17 +010048static struct lyd_node *
49lyd_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 +020050{
Radek Krejci5974c1f2015-10-09 09:53:24 +020051 struct lyxml_elem *xml;
52 struct lyd_node *result = NULL;
Radek Krejci86538212015-12-17 15:59:01 +010053 int xmlopt = LYXML_READ_MULTIROOT;
Radek Krejci5974c1f2015-10-09 09:53:24 +020054
Michal Vasko2d162e12015-09-24 14:33:29 +020055 if (!ctx || !data) {
56 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
57 return NULL;
58 }
59
Radek Krejci86538212015-12-17 15:59:01 +010060 if (options & LYD_OPT_NOSIBLINGS) {
61 xmlopt = 0;
62 }
63
Michal Vasko2d162e12015-09-24 14:33:29 +020064 switch (format) {
65 case LYD_XML:
Radek Krejci452fb952015-10-02 16:07:46 +020066 case LYD_XML_FORMAT:
Radek Krejci86538212015-12-17 15:59:01 +010067 xml = lyxml_read_data(ctx, data, xmlopt);
Radek Krejci4a49bdf2016-01-12 17:17:01 +010068 result = lyd_parse_xml(ctx, &xml, options, parent);
Michal Vasko345da0a2015-12-02 10:35:55 +010069 lyxml_free(ctx, xml);
Radek Krejci5974c1f2015-10-09 09:53:24 +020070 break;
Michal Vasko2d162e12015-09-24 14:33:29 +020071 case LYD_JSON:
Michal Vasko36ef6932015-12-01 14:30:17 +010072 result = lyd_parse_json(ctx, parent, data, options);
Radek Krejci5449d472015-10-26 14:35:56 +010073 break;
Michal Vasko2d162e12015-09-24 14:33:29 +020074 default:
Radek Krejci5449d472015-10-26 14:35:56 +010075 /* error */
Michal Vasko2d162e12015-09-24 14:33:29 +020076 return NULL;
77 }
78
Radek Krejci5974c1f2015-10-09 09:53:24 +020079 return result;
Michal Vasko2d162e12015-09-24 14:33:29 +020080}
81
Radek Krejci4a49bdf2016-01-12 17:17:01 +010082static struct lyd_node *
83lyd_parse_data_(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, va_list ap)
Michal Vasko36ef6932015-12-01 14:30:17 +010084{
Radek Krejci4a49bdf2016-01-12 17:17:01 +010085 const struct lys_node *rpc = NULL;
86
87 if (lyp_check_options(options)) {
88 LOGERR(LY_EINVAL, "%s: Invalid options (multiple data type flags set).", __func__);
89 return NULL;
90 }
91
92 if (options & LYD_OPT_RPCREPLY) {
93 rpc = va_arg(ap, struct lys_node*);
94 if (!rpc || (rpc->nodetype != LYS_RPC)) {
95 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
96 return NULL;
97 }
98 }
99
100 return lyd_parse_(ctx, rpc, data, format, options);
Michal Vasko36ef6932015-12-01 14:30:17 +0100101}
102
103API struct lyd_node *
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100104lyd_parse_data(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, ...)
105{
106 va_list ap;
107 struct lyd_node *result;
108
109 va_start(ap, options);
110 result = lyd_parse_data_(ctx, data, format, options, ap);
111 va_end(ap);
112
113 return result;
114}
115
116API struct lyd_node *
117lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, ...)
Michal Vasko662610a2015-12-07 11:25:45 +0100118{
119 struct lyd_node *ret;
120 struct stat sb;
121 char *data;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100122 va_list ap;
Michal Vasko662610a2015-12-07 11:25:45 +0100123
124 if (!ctx || (fd == -1)) {
125 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
126 return NULL;
127 }
128
129 if (fstat(fd, &sb) == -1) {
130 LOGERR(LY_ESYS, "Failed to stat the file descriptor (%s).", strerror(errno));
131 return NULL;
132 }
133
Radek Krejci3006be02015-12-17 11:24:33 +0100134 data = mmap(NULL, sb.st_size + 1, PROT_READ, MAP_PRIVATE, fd, 0);
Michal Vasko662610a2015-12-07 11:25:45 +0100135 if (data == MAP_FAILED) {
136 LOGERR(LY_ESYS, "Mapping file descriptor into memory failed.");
137 return NULL;
138 }
139
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100140 va_start(ap, options);
141 ret = lyd_parse_data_(ctx, data, format, options, ap);
142
143 va_end(ap);
Michal Vasko662610a2015-12-07 11:25:45 +0100144 munmap(data, sb.st_size);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100145
Michal Vasko662610a2015-12-07 11:25:45 +0100146 return ret;
147}
148
149API struct lyd_node *
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100150lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options, ...)
Michal Vasko662610a2015-12-07 11:25:45 +0100151{
152 int fd;
153 struct lyd_node *ret;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100154 va_list ap;
Michal Vasko662610a2015-12-07 11:25:45 +0100155
156 if (!ctx || !path) {
157 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
158 return NULL;
159 }
160
161 fd = open(path, O_RDONLY);
162 if (fd == -1) {
163 LOGERR(LY_ESYS, "Failed to open data file \"%s\" (%s).", path, strerror(errno));
164 return NULL;
165 }
166
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100167 va_start(ap, options);
Michal Vasko662610a2015-12-07 11:25:45 +0100168 ret = lyd_parse_fd(ctx, fd, format, options);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100169
170 va_end(ap);
Michal Vasko662610a2015-12-07 11:25:45 +0100171 close(fd);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100172
Michal Vasko662610a2015-12-07 11:25:45 +0100173 return ret;
174}
175
176API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100177lyd_new(struct lyd_node *parent, const struct lys_module *module, const char *name)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200178{
179 struct lyd_node *ret;
Michal Vasko1e62a092015-12-01 12:27:20 +0100180 const struct lys_node *snode = NULL, *siblings;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200181
182 if ((!parent && !module) || !name) {
183 ly_errno = LY_EINVAL;
184 return NULL;
185 }
186
187 if (!parent) {
188 siblings = module->data;
189 } else {
Michal Vaskoa5ef4d72015-09-29 16:05:21 +0200190 if (!parent->schema) {
191 return NULL;
192 }
193 siblings = parent->schema->child;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200194 }
195
Michal Vaskoa45cf2b2015-10-23 09:45:36 +0200196 if (lys_get_data_sibling(module, siblings, name, LYS_CONTAINER | LYS_LIST | LYS_NOTIF | LYS_RPC, &snode)
197 || !snode) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200198 return NULL;
199 }
200
201 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100202 if (!ret) {
203 LOGMEM;
204 return NULL;
205 }
Michal Vasko1e62a092015-12-01 12:27:20 +0100206 ret->schema = (struct lys_node *)snode;
Radek Krejcica7efb72016-01-18 13:06:01 +0100207 ret->validity = LYD_VAL_NOT;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200208 ret->prev = ret;
209 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200210 if (lyd_insert(parent, ret)) {
211 lyd_free(ret);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200212 return NULL;
213 }
214 }
215
216 return ret;
217}
218
Michal Vasko50c0a872016-01-13 14:34:11 +0100219static struct lyd_node *
220lyd_create_leaf(const struct lys_node *schema, const char *val_str)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200221{
Michal Vasko50c0a872016-01-13 14:34:11 +0100222 struct lyd_node_leaf_list *ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200223
Michal Vasko3e671b52015-10-23 16:23:15 +0200224 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100225 if (!ret) {
226 LOGMEM;
227 return NULL;
228 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100229 ret->schema = (struct lys_node *)schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100230 ret->validity = LYD_VAL_NOT;
Michal Vasko3e671b52015-10-23 16:23:15 +0200231 ret->prev = (struct lyd_node *)ret;
Radek Krejci37b756f2016-01-18 10:15:03 +0100232 ret->value_type = ((struct lys_node_leaf *)schema)->type.base;
Michal Vasko50c0a872016-01-13 14:34:11 +0100233 ret->value_str = lydict_insert(schema->module->ctx, val_str, 0);
Michal Vasko3e671b52015-10-23 16:23:15 +0200234
235 /* resolve the type correctly */
Radek Krejci37b756f2016-01-18 10:15:03 +0100236 if (lyp_parse_value(ret, NULL, 1, NULL, 0)) {
237 lyd_free((struct lyd_node *)ret);
238 ly_errno = LY_EINVAL;
239 return NULL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200240 }
241
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200242 return (struct lyd_node *)ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200243}
244
245API struct lyd_node *
Michal Vasko50c0a872016-01-13 14:34:11 +0100246lyd_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 +0200247{
Michal Vasko50c0a872016-01-13 14:34:11 +0100248 struct lyd_node *ret;
249 const struct lys_node *snode = NULL, *siblings;
Michal Vasko587998f2015-09-29 16:07:53 +0200250
Michal Vasko14d88772015-12-03 10:54:59 +0100251 if ((!parent && !module) || !name) {
Michal Vasko587998f2015-09-29 16:07:53 +0200252 ly_errno = LY_EINVAL;
253 return NULL;
254 }
255
256 if (!parent) {
257 siblings = module->data;
Michal Vasko587998f2015-09-29 16:07:53 +0200258 } else {
259 if (!parent->schema) {
Michal Vasko50c0a872016-01-13 14:34:11 +0100260 ly_errno = LY_EINVAL;
Michal Vasko587998f2015-09-29 16:07:53 +0200261 return NULL;
262 }
263 siblings = parent->schema->child;
Michal Vasko587998f2015-09-29 16:07:53 +0200264 }
265
Michal Vasko50c0a872016-01-13 14:34:11 +0100266 if (lys_get_data_sibling(module, siblings, name, LYS_LEAFLIST | LYS_LEAF, &snode) || !snode) {
267 ly_errno = LY_EINVAL;
Michal Vasko587998f2015-09-29 16:07:53 +0200268 return NULL;
269 }
270
Michal Vasko50c0a872016-01-13 14:34:11 +0100271 ret = lyd_create_leaf(snode, val_str);
272 if (!ret) {
273 return NULL;
274 }
275
276 /* connect to parent */
277 if (parent) {
278 if (lyd_insert(parent, ret)) {
279 lyd_free(ret);
280 return NULL;
281 }
282 }
283
Radek Krejcica7efb72016-01-18 13:06:01 +0100284 if (ret->schema->flags & LYS_UNIQUE) {
285 /* locate the first parent list */
286 for (parent = ret->parent; parent && parent->schema->nodetype != LYS_LIST; parent = parent->parent);
287
288 /* set flag for future validation */
289 if (parent) {
290 parent->validity |= LYD_VAL_UNIQUE;
291 }
292 }
293
Michal Vasko50c0a872016-01-13 14:34:11 +0100294 return ret;
295
296}
297
Radek Krejcib9b4d002016-01-18 13:08:51 +0100298int
299lyd_change_leaf(struct lyd_node_leaf_list *leaf, const char *val_str)
300{
301 const char *backup;
302 struct lyd_node *parent;
303
304 if (!leaf) {
305 ly_errno = LY_EINVAL;
306 return EXIT_FAILURE;
307 }
308
309 backup = leaf->value_str;
310 leaf->value_str = val_str;
311
312 /* resolve the type correctly */
313 if (lyp_parse_value(leaf, NULL, 1, NULL, 0)) {
314 leaf->value_str = backup;
315 ly_errno = LY_EINVAL;
316 return EXIT_FAILURE;
317 }
318
319 /* value is correct, finish the changes in leaf */
320 lydict_remove(leaf->schema->module->ctx, backup);
321 leaf->value_str = lydict_insert(leaf->schema->module->ctx, val_str, 0);
322
323 if (leaf->schema->flags & LYS_UNIQUE) {
324 /* locate the first parent list */
325 for (parent = leaf->parent; parent && parent->schema->nodetype != LYS_LIST; parent = parent->parent);
326
327 /* set flag for future validation */
328 if (parent) {
329 parent->validity |= LYD_VAL_UNIQUE;
330 }
331 }
332
333 return EXIT_SUCCESS;
334}
335
Michal Vasko50c0a872016-01-13 14:34:11 +0100336static struct lyd_node *
337lyd_create_anyxml(const struct lys_node *schema, const char *val_xml)
338{
339 struct lyd_node_anyxml *ret;
340 struct lyxml_elem *root;
341 char *xml;
342
Michal Vasko587998f2015-09-29 16:07:53 +0200343 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100344 if (!ret) {
345 LOGMEM;
346 return NULL;
347 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100348 ret->schema = (struct lys_node *)schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100349 ret->validity = LYD_VAL_NOT;
Michal Vasko587998f2015-09-29 16:07:53 +0200350 ret->prev = (struct lyd_node *)ret;
Michal Vasko587998f2015-09-29 16:07:53 +0200351
Radek Krejci86538212015-12-17 15:59:01 +0100352 /* store the anyxml data together with the anyxml element */
Michal Vasko50c0a872016-01-13 14:34:11 +0100353 asprintf(&xml, "<%s>%s</%s>", schema->name, (val_xml ? val_xml : ""), schema->name);
354 root = lyxml_read_data(schema->module->ctx, xml, 0);
Michal Vasko17cc7062015-12-10 14:31:48 +0100355 free(xml);
356 if (!root) {
357 lyd_free((struct lyd_node *)ret);
358 return NULL;
Michal Vasko14d88772015-12-03 10:54:59 +0100359 }
Michal Vasko587998f2015-09-29 16:07:53 +0200360
Michal Vasko17cc7062015-12-10 14:31:48 +0100361 /* remove the root */
362 ret->value = root->child;
Michal Vasko50c0a872016-01-13 14:34:11 +0100363 lyxml_unlink_elem(schema->module->ctx, root->child, 1);
364 lyxml_free(schema->module->ctx, root);
Michal Vasko17cc7062015-12-10 14:31:48 +0100365
Michal Vasko587998f2015-09-29 16:07:53 +0200366 return (struct lyd_node *)ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200367}
368
Michal Vasko0df122f2015-12-14 13:38:21 +0100369API struct lyd_node *
Michal Vasko50c0a872016-01-13 14:34:11 +0100370lyd_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 +0100371{
372 struct lyd_node *ret;
Michal Vasko50c0a872016-01-13 14:34:11 +0100373 const struct lys_node *siblings, *snode;
Michal Vasko0df122f2015-12-14 13:38:21 +0100374
Michal Vasko50c0a872016-01-13 14:34:11 +0100375 if ((!parent && !module) || !name) {
Michal Vasko0df122f2015-12-14 13:38:21 +0100376 ly_errno = LY_EINVAL;
377 return NULL;
378 }
379
Michal Vasko50c0a872016-01-13 14:34:11 +0100380 if (!parent) {
381 siblings = module->data;
Michal Vasko0df122f2015-12-14 13:38:21 +0100382 } else {
Michal Vasko50c0a872016-01-13 14:34:11 +0100383 if (!parent->schema) {
384 return NULL;
385 }
386 siblings = parent->schema->child;
387 }
388
389 if (lys_get_data_sibling(module, siblings, name, LYS_ANYXML, &snode) || !snode) {
390 return NULL;
391 }
392
393 ret = lyd_create_anyxml(snode, val_xml);
394 if (!ret) {
395 return NULL;
396 }
397
398 /* connect to parent */
399 if (parent) {
400 if (lyd_insert(parent, ret)) {
401 lyd_free(ret);
402 return NULL;
403 }
404 }
405
406 return ret;
407}
408
409API struct lyd_node *
410lyd_output_new(const struct lys_node *schema)
411{
412 struct lyd_node *ret;
413
414 if (!schema || !(schema->nodetype & (LYS_CONTAINER | LYS_LIST))
415 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
Michal Vasko0df122f2015-12-14 13:38:21 +0100416 ly_errno = LY_EINVAL;
417 return NULL;
418 }
419
420 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100421 if (!ret) {
422 LOGMEM;
423 return NULL;
424 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100425 ret->schema = (struct lys_node *)schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100426 ret->validity = LYD_VAL_NOT;
Michal Vasko0df122f2015-12-14 13:38:21 +0100427 ret->prev = ret;
428
Michal Vasko50c0a872016-01-13 14:34:11 +0100429 return ret;
430}
431
432API struct lyd_node *
433lyd_output_new_leaf(const struct lys_node *schema, const char *val_str)
434{
435 if (!schema || (schema->nodetype != LYS_LEAF)
436 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
437 ly_errno = LY_EINVAL;
438 return NULL;
439 }
440
441 return lyd_create_leaf(schema, val_str);
442}
443
444API struct lyd_node *
445lyd_output_new_anyxml(const struct lys_node *schema, const char *val_xml)
446{
447 if (!schema || (schema->nodetype != LYS_ANYXML)
448 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
449 ly_errno = LY_EINVAL;
450 return NULL;
451 }
452
453 return lyd_create_anyxml(schema, val_xml);
Michal Vasko0df122f2015-12-14 13:38:21 +0100454}
455
Radek Krejcica7efb72016-01-18 13:06:01 +0100456static void
457lyd_insert_setinvalid(struct lyd_node *node)
458{
459 struct lyd_node *next, *elem, *parent_list;
460
461 assert(node);
462
463 /* overall validity of the node itself */
464 node->validity = LYD_VAL_NOT;
465
466 /* explore changed unique leafs */
467 /* first, get know if there is a list in parents chain */
468 for (parent_list = node->parent;
469 parent_list && parent_list->schema->nodetype != LYS_LIST;
470 parent_list = parent_list->parent);
471 if (parent_list && !(parent_list->validity & LYD_VAL_UNIQUE)) {
472 /* there is a list, so check if we inserted a leaf supposed to be unique */
473 for (elem = node; elem; elem = next) {
474 if (elem->schema->nodetype == LYS_LIST) {
475 /* stop searching to the depth, children would be unique to a list in subtree */
476 goto nextsibling;
477 }
478
479 if (elem->schema->nodetype == LYS_LEAF && (elem->schema->flags & LYS_UNIQUE)) {
480 /* set flag to list for future validation */
481 parent_list->validity |= LYD_VAL_UNIQUE;
482 break;
483 }
484
485 /* select next elem to process */
486 /* go into children */
487 next = elem->child;
488 /* got through siblings */
489 if (!next) {
490nextsibling:
491 next = elem->next;
492 if (!next) {
493 /* no children */
494 if (elem == node) {
495 /* we are done, back in start node */
496 break;
497 }
498 /* try siblings */
499 next = elem->next;
500 }
501 }
502 /* go back to parents */
503 while (!next) {
504 if (elem->parent == node) {
505 /* we are done, back in start node */
506 break;
507 }
508 /* parent was actually already processed, so go to the parent's sibling */
509 next = elem->parent->next;
510 }
511 }
512 }
513}
514
Michal Vasko24337392015-10-16 09:58:16 +0200515API int
516lyd_insert(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko2d162e12015-09-24 14:33:29 +0200517{
518 struct lys_node *sparent;
Michal Vasko24337392015-10-16 09:58:16 +0200519 struct lyd_node *iter;
Radek Krejcica7efb72016-01-18 13:06:01 +0100520 int invalid = 0;
Michal Vasko2d162e12015-09-24 14:33:29 +0200521
Michal Vasko24337392015-10-16 09:58:16 +0200522 if (!node || !parent) {
523 ly_errno = LY_EINVAL;
524 return EXIT_FAILURE;
Michal Vasko2d162e12015-09-24 14:33:29 +0200525 }
526
Radek Krejcica7efb72016-01-18 13:06:01 +0100527 /* check placing the node to the appropriate place according to the schema */
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100528 for (sparent = lys_parent(node->schema);
Michal Vasko72d65c92015-12-07 14:02:35 +0100529 sparent && !(sparent->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100530 sparent = lys_parent(sparent));
Michal Vasko2d162e12015-09-24 14:33:29 +0200531 if (sparent != parent->schema) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200532 return EXIT_FAILURE;
533 }
534
Radek Krejcica7efb72016-01-18 13:06:01 +0100535 if (node->parent != parent || lyp_is_rpc(node->schema)) {
536 /* it is not just moving under a parent node or it is in an RPC where
537 * nodes order matters, so the validation will be necessary */
538 invalid = 1;
539 }
540
Michal Vasko24337392015-10-16 09:58:16 +0200541 if (node->parent || node->prev->next) {
542 lyd_unlink(node);
543 }
544
Michal Vasko2d162e12015-09-24 14:33:29 +0200545 if (!parent->child) {
546 /* add as the only child of the parent */
547 parent->child = node;
548 } else {
549 /* add as the last child of the parent */
550 parent->child->prev->next = node;
551 node->prev = parent->child->prev;
552 for (iter = node; iter->next; iter = iter->next);
553 parent->child->prev = iter;
554 }
Michal Vasko9cc2d0a2015-10-14 15:49:07 +0200555
Michal Vasko2d162e12015-09-24 14:33:29 +0200556 LY_TREE_FOR(node, iter) {
557 iter->parent = parent;
Radek Krejcica7efb72016-01-18 13:06:01 +0100558 if (invalid) {
559 lyd_insert_setinvalid(iter);
560 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200561 }
562
563 return EXIT_SUCCESS;
564}
565
Michal Vasko02592902015-10-15 12:14:40 +0200566static int
Michal Vasko24337392015-10-16 09:58:16 +0200567lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, int before)
Michal Vasko2d162e12015-09-24 14:33:29 +0200568{
569 struct lys_node *par1, *par2;
Michal Vasko24337392015-10-16 09:58:16 +0200570 struct lyd_node *iter, *last;
Radek Krejcica7efb72016-01-18 13:06:01 +0100571 int invalid = 0;
Michal Vasko3f7dba12015-10-15 13:09:27 +0200572
573 if (sibling == node) {
574 return EXIT_SUCCESS;
575 }
576
Michal Vasko2d162e12015-09-24 14:33:29 +0200577 /* check placing the node to the appropriate place according to the schema */
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100578 for (par1 = lys_parent(sibling->schema);
Radek Krejci2b7bb492015-12-02 15:46:29 +0100579 par1 && !(par1->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100580 par1 = lys_parent(par1));
581 for (par2 = lys_parent(node->schema);
Radek Krejci2b7bb492015-12-02 15:46:29 +0100582 par2 && !(par2->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100583 par2 = lys_parent(par2));
Michal Vasko2d162e12015-09-24 14:33:29 +0200584 if (par1 != par2) {
585 ly_errno = LY_EINVAL;
586 return EXIT_FAILURE;
587 }
588
Radek Krejcica7efb72016-01-18 13:06:01 +0100589 if (node->parent != sibling->parent || lyp_is_rpc(node->schema)) {
590 /* it is not just moving under a parent node or it is in an RPC where
591 * nodes order matters, so the validation will be necessary */
592 invalid = 1;
593 }
594
Michal Vasko24337392015-10-16 09:58:16 +0200595 if (node->parent || node->prev->next) {
596 lyd_unlink(node);
597 }
598
Michal Vasko2d162e12015-09-24 14:33:29 +0200599 LY_TREE_FOR(node, iter) {
600 iter->parent = sibling->parent;
Michal Vasko24337392015-10-16 09:58:16 +0200601 last = iter;
Radek Krejcica7efb72016-01-18 13:06:01 +0100602
603 if (invalid) {
604 lyd_insert_setinvalid(iter);
605 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200606 }
607
Michal Vasko02592902015-10-15 12:14:40 +0200608 if (before) {
609 if (sibling->prev->next) {
610 /* adding into the list */
611 sibling->prev->next = node;
612 } else if (sibling->parent) {
613 /* at the beginning */
614 sibling->parent->child = node;
Michal Vasko2d162e12015-09-24 14:33:29 +0200615 }
Michal Vasko02592902015-10-15 12:14:40 +0200616 node->prev = sibling->prev;
617 sibling->prev = last;
618 last->next = sibling;
619 } else {
620 if (sibling->next) {
621 /* adding into a middle - fix the prev pointer of the node after inserted nodes */
622 last->next = sibling->next;
623 sibling->next->prev = last;
624 } else {
625 /* at the end - fix the prev pointer of the first node */
626 if (sibling->parent) {
627 sibling->parent->child->prev = last;
628 } else {
629 for (iter = sibling; iter->prev->next; iter = iter->prev);
630 iter->prev = last;
631 }
632 }
633 sibling->next = node;
634 node->prev = sibling;
Michal Vasko2d162e12015-09-24 14:33:29 +0200635 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200636
Michal Vasko24337392015-10-16 09:58:16 +0200637 return EXIT_SUCCESS;
638}
Michal Vasko2d162e12015-09-24 14:33:29 +0200639
Michal Vasko24337392015-10-16 09:58:16 +0200640API int
641lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
642{
643 if (!node || !sibling || lyd_insert_sibling(sibling, node, 1)) {
644 ly_errno = LY_EINVAL;
645 return EXIT_FAILURE;
646 }
647
648 return EXIT_SUCCESS;
649}
650
651API int
652lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
653{
654 if (!node || !sibling || lyd_insert_sibling(sibling, node, 0)) {
655 ly_errno = LY_EINVAL;
656 return EXIT_FAILURE;
657 }
658
659 return EXIT_SUCCESS;
660}
661
662API int
663lyd_validate(struct lyd_node *node, int options)
664{
665 struct lyd_node *next, *iter, *to_free = NULL;
666
667 ly_errno = 0;
668 LY_TREE_DFS_BEGIN(node, next, iter) {
669 if (to_free) {
670 lyd_free(to_free);
671 to_free = NULL;
672 }
673
Radek Krejcif03ec152015-12-03 13:18:37 +0100674 if (lyv_data_context(iter, options, 0, NULL)) {
675 return EXIT_FAILURE;
676 }
677 if (lyv_data_content(iter, options, 0, NULL)) {
Michal Vasko24337392015-10-16 09:58:16 +0200678 if (ly_errno) {
679 return EXIT_FAILURE;
680 } else {
681 /* safe deferred removal */
682 to_free = iter;
Radek Krejciefe6a142015-12-03 14:01:00 +0100683 if (iter == node) {
684 /* removing the whole subtree */
685 break;
686 }
Michal Vasko3f7dba12015-10-15 13:09:27 +0200687 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200688 }
Michal Vasko24337392015-10-16 09:58:16 +0200689
Radek Krejcica7efb72016-01-18 13:06:01 +0100690 /* validation successful */
691 iter->validity = LYD_VAL_OK;
692
Michal Vasko24337392015-10-16 09:58:16 +0200693 LY_TREE_DFS_END(node, next, iter);
Michal Vasko2d162e12015-09-24 14:33:29 +0200694 }
695
Michal Vasko24337392015-10-16 09:58:16 +0200696 if (to_free) {
697 lyd_free(to_free);
698 to_free = NULL;
Michal Vasko02592902015-10-15 12:14:40 +0200699 }
700
701 return EXIT_SUCCESS;
702}
703
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100704/* create an attribute copy */
Michal Vasko55f60be2015-10-14 13:12:58 +0200705static struct lyd_attr *
706lyd_dup_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr)
707{
708 struct lyd_attr *ret;
709
710 /* allocate new attr */
711 if (!parent->attr) {
712 parent->attr = malloc(sizeof *parent->attr);
713 ret = parent->attr;
714 } else {
715 for (ret = parent->attr; ret->next; ret = ret->next);
716 ret->next = malloc(sizeof *ret);
717 ret = ret->next;
718 }
Michal Vasko253035f2015-12-17 16:58:13 +0100719 if (!ret) {
720 LOGMEM;
721 return NULL;
722 }
Michal Vasko55f60be2015-10-14 13:12:58 +0200723
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100724 /* fill new attr except */
Michal Vasko55f60be2015-10-14 13:12:58 +0200725 ret->next = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100726 ret->module = attr->module;
Michal Vasko55f60be2015-10-14 13:12:58 +0200727 ret->name = lydict_insert(ctx, attr->name, 0);
728 ret->value = lydict_insert(ctx, attr->value, 0);
729
Michal Vasko55f60be2015-10-14 13:12:58 +0200730 return ret;
731}
732
Michal Vasko2d162e12015-09-24 14:33:29 +0200733API int
734lyd_unlink(struct lyd_node *node)
735{
736 struct lyd_node *iter;
737
738 if (!node) {
739 ly_errno = LY_EINVAL;
740 return EXIT_FAILURE;
741 }
742
743 /* unlink from siblings */
744 if (node->prev->next) {
745 node->prev->next = node->next;
746 }
747 if (node->next) {
748 node->next->prev = node->prev;
749 } else {
750 /* unlinking the last node */
Radek Krejci32636312016-01-07 13:49:48 +0100751 if (node->parent) {
752 iter = node->parent->child;
753 } else {
754 iter = node->prev;
755 while (iter->prev != node) {
756 iter = iter->prev;
757 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200758 }
759 /* update the "last" pointer from the first node */
760 iter->prev = node->prev;
761 }
762
763 /* unlink from parent */
764 if (node->parent) {
765 if (node->parent->child == node) {
766 /* the node is the first child */
767 node->parent->child = node->next;
768 }
769 node->parent = NULL;
770 }
771
772 node->next = NULL;
773 node->prev = node;
774
775 return EXIT_SUCCESS;
776}
777
Michal Vaskoc0797f82015-10-14 15:51:25 +0200778API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100779lyd_dup(const struct lyd_node *node, int recursive)
Michal Vaskoc0797f82015-10-14 15:51:25 +0200780{
Michal Vasko1e62a092015-12-01 12:27:20 +0100781 const struct lyd_node *next, *elem;
782 struct lyd_node *ret, *parent, *new_node;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200783 struct lyd_attr *attr;
784 struct lyd_node_leaf_list *new_leaf;
785 struct lyd_node_anyxml *new_axml;
786 struct lys_type *type;
787
788 if (!node) {
789 ly_errno = LY_EINVAL;
790 return NULL;
791 }
792
793 ret = NULL;
794 parent = NULL;
795
796 /* LY_TREE_DFS */
797 for (elem = next = node; elem; elem = next) {
798
799 /* fill specific part */
800 switch (elem->schema->nodetype) {
801 case LYS_LEAF:
802 case LYS_LEAFLIST:
803 new_leaf = malloc(sizeof *new_leaf);
804 new_node = (struct lyd_node *)new_leaf;
Michal Vasko253035f2015-12-17 16:58:13 +0100805 if (!new_node) {
806 LOGMEM;
807 return NULL;
808 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200809
810 new_leaf->value = ((struct lyd_node_leaf_list *)elem)->value;
811 new_leaf->value_str = lydict_insert(elem->schema->module->ctx,
812 ((struct lyd_node_leaf_list *)elem)->value_str, 0);
813 new_leaf->value_type = ((struct lyd_node_leaf_list *)elem)->value_type;
814 /* bits type must be treated specially */
815 if (new_leaf->value_type == LY_TYPE_BITS) {
816 for (type = &((struct lys_node_leaf *)elem->schema)->type; type->der->module; type = &type->der->type) {
817 if (type->base != LY_TYPE_BITS) {
818 LOGINT;
Michal Vaskod80e6c72015-10-15 09:37:01 +0200819 lyd_free(new_node);
Michal Vaskoc0797f82015-10-14 15:51:25 +0200820 lyd_free(ret);
821 return NULL;
822 }
823 }
824
825 new_leaf->value.bit = malloc(type->info.bits.count * sizeof *new_leaf->value.bit);
Michal Vasko253035f2015-12-17 16:58:13 +0100826 if (!new_leaf->value.bit) {
827 LOGMEM;
828 lyd_free(new_node);
829 lyd_free(ret);
830 return NULL;
831 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200832 memcpy(new_leaf->value.bit, ((struct lyd_node_leaf_list *)elem)->value.bit,
833 type->info.bits.count * sizeof *new_leaf->value.bit);
834 }
835 break;
836 case LYS_ANYXML:
837 new_axml = malloc(sizeof *new_axml);
838 new_node = (struct lyd_node *)new_axml;
Michal Vasko253035f2015-12-17 16:58:13 +0100839 if (!new_node) {
840 LOGMEM;
841 return NULL;
842 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200843
844 new_axml->value = lyxml_dup_elem(elem->schema->module->ctx, ((struct lyd_node_anyxml *)elem)->value,
845 NULL, 1);
846 break;
847 case LYS_CONTAINER:
848 case LYS_LIST:
849 case LYS_NOTIF:
850 case LYS_RPC:
851 new_node = malloc(sizeof *new_node);
Michal Vasko253035f2015-12-17 16:58:13 +0100852 if (!new_node) {
853 LOGMEM;
854 return NULL;
855 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200856 new_node->child = NULL;
857 break;
858 default:
Michal Vaskoc0797f82015-10-14 15:51:25 +0200859 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +0200860 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200861 return NULL;
862 }
863
864 /* fill common part */
865 new_node->schema = elem->schema;
866 new_node->attr = NULL;
867 LY_TREE_FOR(elem->attr, attr) {
868 lyd_dup_attr(elem->schema->module->ctx, new_node, attr);
869 }
870 new_node->next = NULL;
871 new_node->prev = new_node;
872 new_node->parent = NULL;
Radek Krejcica7efb72016-01-18 13:06:01 +0100873 new_node->validity = LYD_VAL_NOT;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200874
875 if (!ret) {
876 ret = new_node;
877 }
878 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200879 if (lyd_insert(parent, new_node)) {
Michal Vaskoc0797f82015-10-14 15:51:25 +0200880 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +0200881 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200882 return NULL;
883 }
884 }
885
886 if (!recursive) {
887 break;
888 }
889
890 /* LY_TREE_DFS_END */
891 /* select element for the next run - children first */
892 next = elem->child;
893 /* child exception for lyd_node_leaf and lyd_node_leaflist */
894 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
895 next = NULL;
896 }
897 if (!next) {
898 /* no children, so try siblings */
899 next = elem->next;
900 } else {
901 parent = new_node;
902 }
903 while (!next) {
904 /* no siblings, go back through parents */
905 elem = elem->parent;
906 if (elem->parent == node->parent) {
907 break;
908 }
Michal Vasko785b2ad2015-10-15 09:37:15 +0200909 if (!parent) {
Michal Vaskoc8f5d802015-10-23 10:14:39 +0200910 lyd_free(ret);
Michal Vasko785b2ad2015-10-15 09:37:15 +0200911 LOGINT;
Michal Vaskoc8f5d802015-10-23 10:14:39 +0200912 return NULL;
Michal Vasko785b2ad2015-10-15 09:37:15 +0200913 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200914 parent = parent->parent;
915 /* parent is already processed, go to its sibling */
916 next = elem->next;
917 }
918 }
919
920 return ret;
921}
922
Radek Krejci88f29302015-10-30 15:42:33 +0100923API void
924lyd_free_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr, int recursive)
Michal Vasko2d162e12015-09-24 14:33:29 +0200925{
Radek Krejci88f29302015-10-30 15:42:33 +0100926 struct lyd_attr *iter;
927
928 if (!ctx || !attr) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200929 return;
930 }
931
Radek Krejci88f29302015-10-30 15:42:33 +0100932 if (parent) {
933 if (parent->attr == attr) {
934 if (recursive) {
935 parent->attr = NULL;
936 } else {
937 parent->attr = attr->next;
938 }
939 } else {
940 for (iter = parent->attr; iter->next != attr; iter = iter->next);
941 if (iter->next) {
942 if (recursive) {
943 iter->next = NULL;
944 } else {
945 iter->next = attr->next;
946 }
947 }
948 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200949 }
Radek Krejci88f29302015-10-30 15:42:33 +0100950
951 if (!recursive) {
952 attr->next = NULL;
953 }
954
955 for(iter = attr; iter; ) {
956 attr = iter;
957 iter = iter->next;
958
959 lydict_remove(ctx, attr->name);
960 lydict_remove(ctx, attr->value);
961 free(attr);
962 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200963}
964
Michal Vaskofd76bd12015-09-24 15:49:57 +0200965struct lyd_node *
966lyd_attr_parent(struct lyd_node *root, struct lyd_attr *attr)
967{
968 struct lyd_node *next, *elem;
969 struct lyd_attr *node_attr;
970
971 LY_TREE_DFS_BEGIN(root, next, elem) {
972 for (node_attr = elem->attr; node_attr; node_attr = node_attr->next) {
973 if (node_attr == attr) {
974 return elem;
975 }
976 }
977 LY_TREE_DFS_END(root, next, elem)
978 }
979
980 return NULL;
981}
982
Radek Krejci134610e2015-10-20 17:15:34 +0200983API struct lyd_attr *
984lyd_insert_attr(struct lyd_node *parent, const char *name, const char *value)
985{
Radek Krejci134610e2015-10-20 17:15:34 +0200986 struct lyd_attr *a, *iter;
987 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +0100988 const struct lys_module *module;
Radek Krejci134610e2015-10-20 17:15:34 +0200989 const char *p;
990 char *aux;
991
992 if (!parent || !name || !value) {
993 return NULL;
994 }
995 ctx = parent->schema->module->ctx;
996
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100997 if ((p = strchr(name, ':'))) {
998 /* search for the namespace */
999 aux = strndup(name, p - name);
Michal Vasko253035f2015-12-17 16:58:13 +01001000 if (!aux) {
1001 LOGMEM;
1002 return NULL;
1003 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001004 module = ly_ctx_get_module(ctx, aux, NULL);
1005 free(aux);
1006 name = p + 1;
Radek Krejci134610e2015-10-20 17:15:34 +02001007
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001008 if (!module) {
1009 /* module not found */
Radek Krejcia008ca92015-10-30 15:52:05 +01001010 LOGERR(LY_EINVAL, "Attribute prefix does not match any schema in the context.");
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001011 return NULL;
Radek Krejci134610e2015-10-20 17:15:34 +02001012 }
1013 } else {
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001014 /* no prefix -> module is the same as for the parent */
1015 module = parent->schema->module;
Radek Krejci134610e2015-10-20 17:15:34 +02001016 }
1017
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001018 a = malloc(sizeof *a);
Michal Vasko253035f2015-12-17 16:58:13 +01001019 if (!a) {
1020 LOGMEM;
1021 return NULL;
1022 }
Michal Vasko1e62a092015-12-01 12:27:20 +01001023 a->module = (struct lys_module *)module;
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001024 a->next = NULL;
1025 a->name = lydict_insert(ctx, name, 0);
Radek Krejci134610e2015-10-20 17:15:34 +02001026 a->value = lydict_insert(ctx, value, 0);
Radek Krejci5f9e8c92015-10-30 10:01:06 +01001027
Radek Krejci134610e2015-10-20 17:15:34 +02001028 if (!parent->attr) {
1029 parent->attr = a;
1030 } else {
1031 for (iter = parent->attr; iter->next; iter = iter->next);
1032 iter->next = a;
1033 }
1034
1035 return a;
1036}
1037
Michal Vasko2d162e12015-09-24 14:33:29 +02001038API void
1039lyd_free(struct lyd_node *node)
1040{
1041 struct lyd_node *next, *child;
1042
1043 if (!node) {
1044 return;
1045 }
1046
1047 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
1048 /* free children */
1049 LY_TREE_FOR_SAFE(node->child, next, child) {
1050 lyd_free(child);
1051 }
1052 } else if (node->schema->nodetype == LYS_ANYXML) {
Michal Vasko345da0a2015-12-02 10:35:55 +01001053 lyxml_free(node->schema->module->ctx, ((struct lyd_node_anyxml *)node)->value);
Michal Vasko2d162e12015-09-24 14:33:29 +02001054 } else {
1055 /* free value */
Michal Vasko4c183312015-09-25 10:41:47 +02001056 switch(((struct lyd_node_leaf_list *)node)->value_type) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001057 case LY_TYPE_BINARY:
1058 case LY_TYPE_STRING:
Michal Vasko4c183312015-09-25 10:41:47 +02001059 lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value.string);
Michal Vasko2d162e12015-09-24 14:33:29 +02001060 break;
1061 case LY_TYPE_BITS:
Michal Vasko4c183312015-09-25 10:41:47 +02001062 if (((struct lyd_node_leaf_list *)node)->value.bit) {
1063 free(((struct lyd_node_leaf_list *)node)->value.bit);
Michal Vasko2d162e12015-09-24 14:33:29 +02001064 }
1065 break;
1066 default:
1067 /* TODO nothing needed : LY_TYPE_BOOL, LY_TYPE_DEC64*/
1068 break;
1069 }
1070 }
1071
1072 lyd_unlink(node);
Radek Krejci88f29302015-10-30 15:42:33 +01001073 lyd_free_attr(node->schema->module->ctx, node, node->attr, 1);
Michal Vasko2d162e12015-09-24 14:33:29 +02001074 free(node);
1075}
1076
Radek Krejci81468402016-01-07 13:52:40 +01001077API void
1078lyd_free_withsiblings(struct lyd_node *node)
1079{
1080 struct lyd_node *iter, *aux;
1081
1082 if (!node) {
1083 return;
1084 }
1085
1086 /* optimization - avoid freeing (unlinking) the last node of the siblings list */
1087 /* so, first, free the node's predecessors to the beginning of the list ... */
1088 for(iter = node->prev; iter->next; iter = aux) {
1089 aux = iter->prev;
1090 lyd_free(iter);
1091 }
1092 /* ... then, the node is the first in the siblings list, so free them all */
1093 LY_TREE_FOR_SAFE(node, aux, iter) {
1094 lyd_free(iter);
1095 }
1096}
1097
Michal Vaskoff4c2832015-10-15 13:30:50 +02001098API char *
Michal Vasko1e62a092015-12-01 12:27:20 +01001099lyxml_serialize(const struct lyxml_elem *anyxml)
Michal Vaskoff4c2832015-10-15 13:30:50 +02001100{
1101 FILE *stream;
1102 char *buf;
1103 size_t buf_size;
1104
1105 if (!anyxml) {
1106 ly_errno = LY_EINVAL;
1107 return NULL;
1108 }
1109
1110 stream = open_memstream(&buf, &buf_size);
1111 if (!stream) {
1112 ly_errno = LY_ESYS;
1113 return NULL;
1114 }
Michal Vasko70f92c32015-12-10 09:57:24 +01001115 if (lyxml_dump_file(stream, anyxml, 0) == 0) {
Michal Vaskoff4c2832015-10-15 13:30:50 +02001116 free(buf);
1117 buf = NULL;
1118 ly_errno = LY_EINVAL;
1119 }
1120 fclose(stream);
1121
1122 return buf;
1123}
1124
Michal Vasko2d162e12015-09-24 14:33:29 +02001125int
1126lyd_compare(struct lyd_node *first, struct lyd_node *second, int unique)
1127{
1128 struct lys_node_list *slist;
Michal Vasko1e62a092015-12-01 12:27:20 +01001129 const struct lys_node *snode = NULL;
Michal Vasko2d162e12015-09-24 14:33:29 +02001130 struct lyd_node *diter;
1131 const char *val1, *val2;
1132 int i, j;
1133
1134 assert(first);
1135 assert(second);
1136
1137 if (first->schema != second->schema) {
1138 return 1;
1139 }
1140
1141 switch (first->schema->nodetype) {
1142 case LYS_LEAFLIST:
1143 /* compare values */
Michal Vasko4c183312015-09-25 10:41:47 +02001144 if (((struct lyd_node_leaf_list *)first)->value_str == ((struct lyd_node_leaf_list *)second)->value_str) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001145 return 0;
1146 }
1147 return 1;
1148 case LYS_LIST:
Michal Vasko4c183312015-09-25 10:41:47 +02001149 slist = (struct lys_node_list *)first->schema;
Michal Vasko2d162e12015-09-24 14:33:29 +02001150
1151 if (unique) {
1152 /* compare unique leafs */
1153 for (i = 0; i < slist->unique_size; i++) {
Radek Krejci581ce772015-11-10 17:22:40 +01001154 for (j = 0; j < slist->unique[i].expr_size; j++) {
1155 /* first */
1156 diter = resolve_data_nodeid(slist->unique[i].expr[j], first->child);
1157 if (diter) {
1158 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
1159 } else {
1160 /* use default value */
Radek Krejci3eb09b62015-12-16 15:22:19 +01001161 if (resolve_schema_nodeid(slist->unique[i].expr[j], first->schema->child, first->schema->module, LYS_LEAF, &snode)) {
1162 /* error, but unique expression was checked when the schema was parsed */
1163 return -1;
1164 }
Radek Krejci581ce772015-11-10 17:22:40 +01001165 val1 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +02001166 }
Radek Krejci581ce772015-11-10 17:22:40 +01001167
1168 /* second */
1169 diter = resolve_data_nodeid(slist->unique[i].expr[j], second->child);
1170 if (diter) {
1171 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
1172 } else {
1173 /* use default value */
Radek Krejci3eb09b62015-12-16 15:22:19 +01001174 if (resolve_schema_nodeid(slist->unique[i].expr[j], second->schema->child, second->schema->module, LYS_LEAF, &snode)) {
1175 /* error, but unique expression was checked when the schema was parsed */
1176 return -1;
1177 }
Radek Krejci581ce772015-11-10 17:22:40 +01001178 val2 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +02001179 }
Radek Krejci581ce772015-11-10 17:22:40 +01001180
Michal Vasko2d162e12015-09-24 14:33:29 +02001181 if (val1 != val2) {
1182 break;
1183 }
1184 }
Radek Krejci581ce772015-11-10 17:22:40 +01001185 if (j && j == slist->unique[i].expr_size) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001186 /* all unique leafs are the same in this set */
1187 return 0;
1188 }
1189 }
1190 }
1191
Radek Krejcica7efb72016-01-18 13:06:01 +01001192 if (second->validity == LYD_VAL_UNIQUE) {
1193 /* only unique part changed somewhere, so it is no need to check keys */
1194 return 0;
1195 }
1196
Michal Vasko2d162e12015-09-24 14:33:29 +02001197 /* compare keys */
1198 for (i = 0; i < slist->keys_size; i++) {
1199 snode = (struct lys_node *)slist->keys[i];
1200 val1 = val2 = NULL;
1201 LY_TREE_FOR(first->child, diter) {
1202 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +02001203 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +02001204 break;
1205 }
1206 }
1207 LY_TREE_FOR(second->child, diter) {
1208 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +02001209 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +02001210 break;
1211 }
1212 }
1213 if (val1 != val2) {
1214 return 1;
1215 }
1216 }
1217
1218 return 0;
1219 default:
1220 /* no additional check is needed */
1221 return 0;
1222 }
1223}
1224
1225API struct lyd_set *
1226lyd_set_new(void)
1227{
1228 return calloc(1, sizeof(struct lyd_set));
1229}
1230
1231API void
1232lyd_set_free(struct lyd_set *set)
1233{
1234 if (!set) {
1235 return;
1236 }
1237
1238 free(set->set);
1239 free(set);
1240}
1241
1242API int
1243lyd_set_add(struct lyd_set *set, struct lyd_node *node)
1244{
Radek Krejci87fd4df2016-01-18 14:44:20 +01001245 unsigned int i;
Michal Vasko2d162e12015-09-24 14:33:29 +02001246 struct lyd_node **new;
1247
Radek Krejci87fd4df2016-01-18 14:44:20 +01001248 if (!set || !node) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001249 ly_errno = LY_EINVAL;
1250 return EXIT_FAILURE;
1251 }
1252
Radek Krejci87fd4df2016-01-18 14:44:20 +01001253 /* search for duplication */
1254 for (i = 0; i < set->number; i++) {
1255 if (set->set[i] == node) {
1256 /* already in set */
1257 return EXIT_SUCCESS;
1258 }
1259 }
1260
Michal Vasko2d162e12015-09-24 14:33:29 +02001261 if (set->size == set->number) {
Radek Krejcic5c45982016-01-07 12:50:44 +01001262 new = realloc(set->set, (set->size + 8) * sizeof *(set->set));
Michal Vasko2d162e12015-09-24 14:33:29 +02001263 if (!new) {
1264 LOGMEM;
1265 return EXIT_FAILURE;
1266 }
1267 set->size += 8;
1268 set->set = new;
1269 }
1270
1271 set->set[set->number++] = node;
1272
1273 return EXIT_SUCCESS;
1274}
Radek Krejci8cc31e52016-01-18 14:45:33 +01001275
1276API int
1277lyd_set_rm_index(struct lyd_set *set, unsigned int index)
1278{
1279 if (!set || (index + 1) > set->number) {
1280 ly_errno = LY_EINVAL;
1281 return EXIT_FAILURE;
1282 }
1283
1284 if (index == set->number - 1) {
1285 /* removing last item in set */
1286 set->set[index] = NULL;
1287 } else {
1288 /* removing item somewhere in a middle, so put there the last item */
1289 set->set[index] = set->set[set->number - 1];
1290 set->set[set->number - 1] = NULL;
1291 }
1292 set->number--;
1293
1294 return EXIT_SUCCESS;
1295}
1296
1297API int
1298lyd_set_rm(struct lyd_set *set, struct lyd_node *node)
1299{
1300 unsigned int i;
1301
1302 if (!set || !node) {
1303 ly_errno = LY_EINVAL;
1304 return EXIT_FAILURE;
1305 }
1306
1307 /* get index */
1308 for (i = 0; i < set->number; i++) {
1309 if (set->set[i] == node) {
1310 break;
1311 }
1312 }
1313 if (i == set->number) {
1314 /* node is not in set */
1315 ly_errno = LY_EINVAL;
1316 return EXIT_FAILURE;
1317 }
1318
1319 return lyd_set_rm_index(set, i);
1320}