blob: 5a5ee58c531c2df89667659b4f9c15a9548c7c84 [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;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200207 ret->prev = ret;
208 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200209 if (lyd_insert(parent, ret)) {
210 lyd_free(ret);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200211 return NULL;
212 }
213 }
214
215 return ret;
216}
217
Michal Vasko50c0a872016-01-13 14:34:11 +0100218static struct lyd_node *
219lyd_create_leaf(const struct lys_node *schema, const char *val_str)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200220{
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200221 int found;
Michal Vasko50c0a872016-01-13 14:34:11 +0100222 struct lyd_node_leaf_list *ret;
223 struct lys_type *stype, *type;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200224
Michal Vasko3e671b52015-10-23 16:23:15 +0200225 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100226 if (!ret) {
227 LOGMEM;
228 return NULL;
229 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100230 ret->schema = (struct lys_node *)schema;
Michal Vasko3e671b52015-10-23 16:23:15 +0200231 ret->prev = (struct lyd_node *)ret;
Michal Vasko50c0a872016-01-13 14:34:11 +0100232 ret->value_str = lydict_insert(schema->module->ctx, val_str, 0);
Michal Vasko3e671b52015-10-23 16:23:15 +0200233
234 /* resolve the type correctly */
Michal Vasko50c0a872016-01-13 14:34:11 +0100235 stype = &((struct lys_node_leaf *)schema)->type;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200236 if (stype->base == LY_TYPE_UNION) {
237 found = 0;
Radek Krejcif7388492015-10-30 16:12:53 +0100238 type = NULL;
239 while ((type = lyp_get_next_union_type(stype, type, &found))) {
Michal Vasko3e671b52015-10-23 16:23:15 +0200240 ret->value_type = type->base;
241 if (!lyp_parse_value(ret, type, 1, NULL, UINT_MAX)) {
242 /* success! */
243 break;
244 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200245 found = 0;
Radek Krejcif7388492015-10-30 16:12:53 +0100246 }
Michal Vasko3e671b52015-10-23 16:23:15 +0200247
248 if (!type) {
249 /* fail */
250 ly_errno = LY_EINVAL;
251 lyd_free((struct lyd_node *)ret);
252 return NULL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200253 }
Michal Vasko3e671b52015-10-23 16:23:15 +0200254 } else {
255 ret->value_type = stype->base;
256 if (lyp_parse_value(ret, stype, 1, NULL, 0)) {
257 lyd_free((struct lyd_node *)ret);
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200258 ly_errno = LY_EINVAL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200259 return NULL;
260 }
261 }
262
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200263 return (struct lyd_node *)ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200264}
265
266API struct lyd_node *
Michal Vasko50c0a872016-01-13 14:34:11 +0100267lyd_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 +0200268{
Michal Vasko50c0a872016-01-13 14:34:11 +0100269 struct lyd_node *ret;
270 const struct lys_node *snode = NULL, *siblings;
Michal Vasko587998f2015-09-29 16:07:53 +0200271
Michal Vasko14d88772015-12-03 10:54:59 +0100272 if ((!parent && !module) || !name) {
Michal Vasko587998f2015-09-29 16:07:53 +0200273 ly_errno = LY_EINVAL;
274 return NULL;
275 }
276
277 if (!parent) {
278 siblings = module->data;
Michal Vasko587998f2015-09-29 16:07:53 +0200279 } else {
280 if (!parent->schema) {
Michal Vasko50c0a872016-01-13 14:34:11 +0100281 ly_errno = LY_EINVAL;
Michal Vasko587998f2015-09-29 16:07:53 +0200282 return NULL;
283 }
284 siblings = parent->schema->child;
Michal Vasko587998f2015-09-29 16:07:53 +0200285 }
286
Michal Vasko50c0a872016-01-13 14:34:11 +0100287 if (lys_get_data_sibling(module, siblings, name, LYS_LEAFLIST | LYS_LEAF, &snode) || !snode) {
288 ly_errno = LY_EINVAL;
Michal Vasko587998f2015-09-29 16:07:53 +0200289 return NULL;
290 }
291
Michal Vasko50c0a872016-01-13 14:34:11 +0100292 ret = lyd_create_leaf(snode, val_str);
293 if (!ret) {
294 return NULL;
295 }
296
297 /* connect to parent */
298 if (parent) {
299 if (lyd_insert(parent, ret)) {
300 lyd_free(ret);
301 return NULL;
302 }
303 }
304
305 return ret;
306
307}
308
309static struct lyd_node *
310lyd_create_anyxml(const struct lys_node *schema, const char *val_xml)
311{
312 struct lyd_node_anyxml *ret;
313 struct lyxml_elem *root;
314 char *xml;
315
Michal Vasko587998f2015-09-29 16:07:53 +0200316 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100317 if (!ret) {
318 LOGMEM;
319 return NULL;
320 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100321 ret->schema = (struct lys_node *)schema;
Michal Vasko587998f2015-09-29 16:07:53 +0200322 ret->prev = (struct lyd_node *)ret;
Michal Vasko587998f2015-09-29 16:07:53 +0200323
Radek Krejci86538212015-12-17 15:59:01 +0100324 /* store the anyxml data together with the anyxml element */
Michal Vasko50c0a872016-01-13 14:34:11 +0100325 asprintf(&xml, "<%s>%s</%s>", schema->name, (val_xml ? val_xml : ""), schema->name);
326 root = lyxml_read_data(schema->module->ctx, xml, 0);
Michal Vasko17cc7062015-12-10 14:31:48 +0100327 free(xml);
328 if (!root) {
329 lyd_free((struct lyd_node *)ret);
330 return NULL;
Michal Vasko14d88772015-12-03 10:54:59 +0100331 }
Michal Vasko587998f2015-09-29 16:07:53 +0200332
Michal Vasko17cc7062015-12-10 14:31:48 +0100333 /* remove the root */
334 ret->value = root->child;
Michal Vasko50c0a872016-01-13 14:34:11 +0100335 lyxml_unlink_elem(schema->module->ctx, root->child, 1);
336 lyxml_free(schema->module->ctx, root);
Michal Vasko17cc7062015-12-10 14:31:48 +0100337
Michal Vasko587998f2015-09-29 16:07:53 +0200338 return (struct lyd_node *)ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200339}
340
Michal Vasko0df122f2015-12-14 13:38:21 +0100341API struct lyd_node *
Michal Vasko50c0a872016-01-13 14:34:11 +0100342lyd_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 +0100343{
344 struct lyd_node *ret;
Michal Vasko50c0a872016-01-13 14:34:11 +0100345 const struct lys_node *siblings, *snode;
Michal Vasko0df122f2015-12-14 13:38:21 +0100346
Michal Vasko50c0a872016-01-13 14:34:11 +0100347 if ((!parent && !module) || !name) {
Michal Vasko0df122f2015-12-14 13:38:21 +0100348 ly_errno = LY_EINVAL;
349 return NULL;
350 }
351
Michal Vasko50c0a872016-01-13 14:34:11 +0100352 if (!parent) {
353 siblings = module->data;
Michal Vasko0df122f2015-12-14 13:38:21 +0100354 } else {
Michal Vasko50c0a872016-01-13 14:34:11 +0100355 if (!parent->schema) {
356 return NULL;
357 }
358 siblings = parent->schema->child;
359 }
360
361 if (lys_get_data_sibling(module, siblings, name, LYS_ANYXML, &snode) || !snode) {
362 return NULL;
363 }
364
365 ret = lyd_create_anyxml(snode, val_xml);
366 if (!ret) {
367 return NULL;
368 }
369
370 /* connect to parent */
371 if (parent) {
372 if (lyd_insert(parent, ret)) {
373 lyd_free(ret);
374 return NULL;
375 }
376 }
377
378 return ret;
379}
380
381API struct lyd_node *
382lyd_output_new(const struct lys_node *schema)
383{
384 struct lyd_node *ret;
385
386 if (!schema || !(schema->nodetype & (LYS_CONTAINER | LYS_LIST))
387 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
Michal Vasko0df122f2015-12-14 13:38:21 +0100388 ly_errno = LY_EINVAL;
389 return NULL;
390 }
391
392 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100393 if (!ret) {
394 LOGMEM;
395 return NULL;
396 }
Michal Vasko50c0a872016-01-13 14:34:11 +0100397 ret->schema = (struct lys_node *)schema;
Michal Vasko0df122f2015-12-14 13:38:21 +0100398 ret->prev = ret;
399
Michal Vasko50c0a872016-01-13 14:34:11 +0100400 return ret;
401}
402
403API struct lyd_node *
404lyd_output_new_leaf(const struct lys_node *schema, const char *val_str)
405{
406 if (!schema || (schema->nodetype != LYS_LEAF)
407 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
408 ly_errno = LY_EINVAL;
409 return NULL;
410 }
411
412 return lyd_create_leaf(schema, val_str);
413}
414
415API struct lyd_node *
416lyd_output_new_anyxml(const struct lys_node *schema, const char *val_xml)
417{
418 if (!schema || (schema->nodetype != LYS_ANYXML)
419 || !lys_parent(schema) || (lys_parent(schema)->nodetype != LYS_OUTPUT)) {
420 ly_errno = LY_EINVAL;
421 return NULL;
422 }
423
424 return lyd_create_anyxml(schema, val_xml);
Michal Vasko0df122f2015-12-14 13:38:21 +0100425}
426
Michal Vasko24337392015-10-16 09:58:16 +0200427API int
428lyd_insert(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko2d162e12015-09-24 14:33:29 +0200429{
430 struct lys_node *sparent;
Michal Vasko24337392015-10-16 09:58:16 +0200431 struct lyd_node *iter;
Michal Vasko2d162e12015-09-24 14:33:29 +0200432
Michal Vasko24337392015-10-16 09:58:16 +0200433 if (!node || !parent) {
434 ly_errno = LY_EINVAL;
435 return EXIT_FAILURE;
Michal Vasko2d162e12015-09-24 14:33:29 +0200436 }
437
Michal Vasko72d65c92015-12-07 14:02:35 +0100438 /* check placing the node to the appropriate place according to the schema (if LYS_OUTPUT is returned,
439 * the parent's schema will never match and it fails as it should) */
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100440 for (sparent = lys_parent(node->schema);
Michal Vasko72d65c92015-12-07 14:02:35 +0100441 sparent && !(sparent->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100442 sparent = lys_parent(sparent));
Michal Vasko2d162e12015-09-24 14:33:29 +0200443 if (sparent != parent->schema) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200444 return EXIT_FAILURE;
445 }
446
Michal Vasko24337392015-10-16 09:58:16 +0200447 if (node->parent || node->prev->next) {
448 lyd_unlink(node);
449 }
450
Michal Vasko2d162e12015-09-24 14:33:29 +0200451 if (!parent->child) {
452 /* add as the only child of the parent */
453 parent->child = node;
454 } else {
455 /* add as the last child of the parent */
456 parent->child->prev->next = node;
457 node->prev = parent->child->prev;
458 for (iter = node; iter->next; iter = iter->next);
459 parent->child->prev = iter;
460 }
Michal Vasko9cc2d0a2015-10-14 15:49:07 +0200461
Michal Vasko2d162e12015-09-24 14:33:29 +0200462 LY_TREE_FOR(node, iter) {
463 iter->parent = parent;
Michal Vasko2d162e12015-09-24 14:33:29 +0200464 }
465
466 return EXIT_SUCCESS;
467}
468
Michal Vasko02592902015-10-15 12:14:40 +0200469static int
Michal Vasko24337392015-10-16 09:58:16 +0200470lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, int before)
Michal Vasko2d162e12015-09-24 14:33:29 +0200471{
472 struct lys_node *par1, *par2;
Michal Vasko24337392015-10-16 09:58:16 +0200473 struct lyd_node *iter, *last;
Michal Vasko3f7dba12015-10-15 13:09:27 +0200474
475 if (sibling == node) {
476 return EXIT_SUCCESS;
477 }
478
Michal Vasko2d162e12015-09-24 14:33:29 +0200479 /* check placing the node to the appropriate place according to the schema */
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100480 for (par1 = lys_parent(sibling->schema);
Radek Krejci2b7bb492015-12-02 15:46:29 +0100481 par1 && !(par1->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100482 par1 = lys_parent(par1));
483 for (par2 = lys_parent(node->schema);
Radek Krejci2b7bb492015-12-02 15:46:29 +0100484 par2 && !(par2->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
Michal Vaskob9f6a6c2016-01-04 15:41:58 +0100485 par2 = lys_parent(par2));
Michal Vasko2d162e12015-09-24 14:33:29 +0200486 if (par1 != par2) {
487 ly_errno = LY_EINVAL;
488 return EXIT_FAILURE;
489 }
490
Michal Vasko24337392015-10-16 09:58:16 +0200491 if (node->parent || node->prev->next) {
492 lyd_unlink(node);
493 }
494
Michal Vasko2d162e12015-09-24 14:33:29 +0200495 LY_TREE_FOR(node, iter) {
496 iter->parent = sibling->parent;
Michal Vasko24337392015-10-16 09:58:16 +0200497 last = iter;
Michal Vasko2d162e12015-09-24 14:33:29 +0200498 }
499
Michal Vasko02592902015-10-15 12:14:40 +0200500 if (before) {
501 if (sibling->prev->next) {
502 /* adding into the list */
503 sibling->prev->next = node;
504 } else if (sibling->parent) {
505 /* at the beginning */
506 sibling->parent->child = node;
Michal Vasko2d162e12015-09-24 14:33:29 +0200507 }
Michal Vasko02592902015-10-15 12:14:40 +0200508 node->prev = sibling->prev;
509 sibling->prev = last;
510 last->next = sibling;
511 } else {
512 if (sibling->next) {
513 /* adding into a middle - fix the prev pointer of the node after inserted nodes */
514 last->next = sibling->next;
515 sibling->next->prev = last;
516 } else {
517 /* at the end - fix the prev pointer of the first node */
518 if (sibling->parent) {
519 sibling->parent->child->prev = last;
520 } else {
521 for (iter = sibling; iter->prev->next; iter = iter->prev);
522 iter->prev = last;
523 }
524 }
525 sibling->next = node;
526 node->prev = sibling;
Michal Vasko2d162e12015-09-24 14:33:29 +0200527 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200528
Michal Vasko24337392015-10-16 09:58:16 +0200529 return EXIT_SUCCESS;
530}
Michal Vasko2d162e12015-09-24 14:33:29 +0200531
Michal Vasko24337392015-10-16 09:58:16 +0200532API int
533lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
534{
535 if (!node || !sibling || lyd_insert_sibling(sibling, node, 1)) {
536 ly_errno = LY_EINVAL;
537 return EXIT_FAILURE;
538 }
539
540 return EXIT_SUCCESS;
541}
542
543API int
544lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
545{
546 if (!node || !sibling || lyd_insert_sibling(sibling, node, 0)) {
547 ly_errno = LY_EINVAL;
548 return EXIT_FAILURE;
549 }
550
551 return EXIT_SUCCESS;
552}
553
554API int
555lyd_validate(struct lyd_node *node, int options)
556{
557 struct lyd_node *next, *iter, *to_free = NULL;
558
559 ly_errno = 0;
560 LY_TREE_DFS_BEGIN(node, next, iter) {
561 if (to_free) {
562 lyd_free(to_free);
563 to_free = NULL;
564 }
565
Radek Krejcif03ec152015-12-03 13:18:37 +0100566 if (lyv_data_context(iter, options, 0, NULL)) {
567 return EXIT_FAILURE;
568 }
569 if (lyv_data_content(iter, options, 0, NULL)) {
Michal Vasko24337392015-10-16 09:58:16 +0200570 if (ly_errno) {
571 return EXIT_FAILURE;
572 } else {
573 /* safe deferred removal */
574 to_free = iter;
Radek Krejciefe6a142015-12-03 14:01:00 +0100575 if (iter == node) {
576 /* removing the whole subtree */
577 break;
578 }
Michal Vasko3f7dba12015-10-15 13:09:27 +0200579 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200580 }
Michal Vasko24337392015-10-16 09:58:16 +0200581
582 LY_TREE_DFS_END(node, next, iter);
Michal Vasko2d162e12015-09-24 14:33:29 +0200583 }
584
Michal Vasko24337392015-10-16 09:58:16 +0200585 if (to_free) {
586 lyd_free(to_free);
587 to_free = NULL;
Michal Vasko02592902015-10-15 12:14:40 +0200588 }
589
590 return EXIT_SUCCESS;
591}
592
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100593/* create an attribute copy */
Michal Vasko55f60be2015-10-14 13:12:58 +0200594static struct lyd_attr *
595lyd_dup_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr)
596{
597 struct lyd_attr *ret;
598
599 /* allocate new attr */
600 if (!parent->attr) {
601 parent->attr = malloc(sizeof *parent->attr);
602 ret = parent->attr;
603 } else {
604 for (ret = parent->attr; ret->next; ret = ret->next);
605 ret->next = malloc(sizeof *ret);
606 ret = ret->next;
607 }
Michal Vasko253035f2015-12-17 16:58:13 +0100608 if (!ret) {
609 LOGMEM;
610 return NULL;
611 }
Michal Vasko55f60be2015-10-14 13:12:58 +0200612
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100613 /* fill new attr except */
Michal Vasko55f60be2015-10-14 13:12:58 +0200614 ret->next = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100615 ret->module = attr->module;
Michal Vasko55f60be2015-10-14 13:12:58 +0200616 ret->name = lydict_insert(ctx, attr->name, 0);
617 ret->value = lydict_insert(ctx, attr->value, 0);
618
Michal Vasko55f60be2015-10-14 13:12:58 +0200619 return ret;
620}
621
Michal Vasko2d162e12015-09-24 14:33:29 +0200622API int
623lyd_unlink(struct lyd_node *node)
624{
625 struct lyd_node *iter;
626
627 if (!node) {
628 ly_errno = LY_EINVAL;
629 return EXIT_FAILURE;
630 }
631
632 /* unlink from siblings */
633 if (node->prev->next) {
634 node->prev->next = node->next;
635 }
636 if (node->next) {
637 node->next->prev = node->prev;
638 } else {
639 /* unlinking the last node */
Radek Krejci32636312016-01-07 13:49:48 +0100640 if (node->parent) {
641 iter = node->parent->child;
642 } else {
643 iter = node->prev;
644 while (iter->prev != node) {
645 iter = iter->prev;
646 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200647 }
648 /* update the "last" pointer from the first node */
649 iter->prev = node->prev;
650 }
651
652 /* unlink from parent */
653 if (node->parent) {
654 if (node->parent->child == node) {
655 /* the node is the first child */
656 node->parent->child = node->next;
657 }
658 node->parent = NULL;
659 }
660
661 node->next = NULL;
662 node->prev = node;
663
664 return EXIT_SUCCESS;
665}
666
Michal Vaskoc0797f82015-10-14 15:51:25 +0200667API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100668lyd_dup(const struct lyd_node *node, int recursive)
Michal Vaskoc0797f82015-10-14 15:51:25 +0200669{
Michal Vasko1e62a092015-12-01 12:27:20 +0100670 const struct lyd_node *next, *elem;
671 struct lyd_node *ret, *parent, *new_node;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200672 struct lyd_attr *attr;
673 struct lyd_node_leaf_list *new_leaf;
674 struct lyd_node_anyxml *new_axml;
675 struct lys_type *type;
676
677 if (!node) {
678 ly_errno = LY_EINVAL;
679 return NULL;
680 }
681
682 ret = NULL;
683 parent = NULL;
684
685 /* LY_TREE_DFS */
686 for (elem = next = node; elem; elem = next) {
687
688 /* fill specific part */
689 switch (elem->schema->nodetype) {
690 case LYS_LEAF:
691 case LYS_LEAFLIST:
692 new_leaf = malloc(sizeof *new_leaf);
693 new_node = (struct lyd_node *)new_leaf;
Michal Vasko253035f2015-12-17 16:58:13 +0100694 if (!new_node) {
695 LOGMEM;
696 return NULL;
697 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200698
699 new_leaf->value = ((struct lyd_node_leaf_list *)elem)->value;
700 new_leaf->value_str = lydict_insert(elem->schema->module->ctx,
701 ((struct lyd_node_leaf_list *)elem)->value_str, 0);
702 new_leaf->value_type = ((struct lyd_node_leaf_list *)elem)->value_type;
703 /* bits type must be treated specially */
704 if (new_leaf->value_type == LY_TYPE_BITS) {
705 for (type = &((struct lys_node_leaf *)elem->schema)->type; type->der->module; type = &type->der->type) {
706 if (type->base != LY_TYPE_BITS) {
707 LOGINT;
Michal Vaskod80e6c72015-10-15 09:37:01 +0200708 lyd_free(new_node);
Michal Vaskoc0797f82015-10-14 15:51:25 +0200709 lyd_free(ret);
710 return NULL;
711 }
712 }
713
714 new_leaf->value.bit = malloc(type->info.bits.count * sizeof *new_leaf->value.bit);
Michal Vasko253035f2015-12-17 16:58:13 +0100715 if (!new_leaf->value.bit) {
716 LOGMEM;
717 lyd_free(new_node);
718 lyd_free(ret);
719 return NULL;
720 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200721 memcpy(new_leaf->value.bit, ((struct lyd_node_leaf_list *)elem)->value.bit,
722 type->info.bits.count * sizeof *new_leaf->value.bit);
723 }
724 break;
725 case LYS_ANYXML:
726 new_axml = malloc(sizeof *new_axml);
727 new_node = (struct lyd_node *)new_axml;
Michal Vasko253035f2015-12-17 16:58:13 +0100728 if (!new_node) {
729 LOGMEM;
730 return NULL;
731 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200732
733 new_axml->value = lyxml_dup_elem(elem->schema->module->ctx, ((struct lyd_node_anyxml *)elem)->value,
734 NULL, 1);
735 break;
736 case LYS_CONTAINER:
737 case LYS_LIST:
738 case LYS_NOTIF:
739 case LYS_RPC:
740 new_node = malloc(sizeof *new_node);
Michal Vasko253035f2015-12-17 16:58:13 +0100741 if (!new_node) {
742 LOGMEM;
743 return NULL;
744 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200745 new_node->child = NULL;
746 break;
747 default:
Michal Vaskoc0797f82015-10-14 15:51:25 +0200748 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +0200749 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200750 return NULL;
751 }
752
753 /* fill common part */
754 new_node->schema = elem->schema;
755 new_node->attr = NULL;
756 LY_TREE_FOR(elem->attr, attr) {
757 lyd_dup_attr(elem->schema->module->ctx, new_node, attr);
758 }
759 new_node->next = NULL;
760 new_node->prev = new_node;
761 new_node->parent = NULL;
762
763 if (!ret) {
764 ret = new_node;
765 }
766 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200767 if (lyd_insert(parent, new_node)) {
Michal Vaskoc0797f82015-10-14 15:51:25 +0200768 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +0200769 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200770 return NULL;
771 }
772 }
773
774 if (!recursive) {
775 break;
776 }
777
778 /* LY_TREE_DFS_END */
779 /* select element for the next run - children first */
780 next = elem->child;
781 /* child exception for lyd_node_leaf and lyd_node_leaflist */
782 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
783 next = NULL;
784 }
785 if (!next) {
786 /* no children, so try siblings */
787 next = elem->next;
788 } else {
789 parent = new_node;
790 }
791 while (!next) {
792 /* no siblings, go back through parents */
793 elem = elem->parent;
794 if (elem->parent == node->parent) {
795 break;
796 }
Michal Vasko785b2ad2015-10-15 09:37:15 +0200797 if (!parent) {
Michal Vaskoc8f5d802015-10-23 10:14:39 +0200798 lyd_free(ret);
Michal Vasko785b2ad2015-10-15 09:37:15 +0200799 LOGINT;
Michal Vaskoc8f5d802015-10-23 10:14:39 +0200800 return NULL;
Michal Vasko785b2ad2015-10-15 09:37:15 +0200801 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200802 parent = parent->parent;
803 /* parent is already processed, go to its sibling */
804 next = elem->next;
805 }
806 }
807
808 return ret;
809}
810
Radek Krejci88f29302015-10-30 15:42:33 +0100811API void
812lyd_free_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr, int recursive)
Michal Vasko2d162e12015-09-24 14:33:29 +0200813{
Radek Krejci88f29302015-10-30 15:42:33 +0100814 struct lyd_attr *iter;
815
816 if (!ctx || !attr) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200817 return;
818 }
819
Radek Krejci88f29302015-10-30 15:42:33 +0100820 if (parent) {
821 if (parent->attr == attr) {
822 if (recursive) {
823 parent->attr = NULL;
824 } else {
825 parent->attr = attr->next;
826 }
827 } else {
828 for (iter = parent->attr; iter->next != attr; iter = iter->next);
829 if (iter->next) {
830 if (recursive) {
831 iter->next = NULL;
832 } else {
833 iter->next = attr->next;
834 }
835 }
836 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200837 }
Radek Krejci88f29302015-10-30 15:42:33 +0100838
839 if (!recursive) {
840 attr->next = NULL;
841 }
842
843 for(iter = attr; iter; ) {
844 attr = iter;
845 iter = iter->next;
846
847 lydict_remove(ctx, attr->name);
848 lydict_remove(ctx, attr->value);
849 free(attr);
850 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200851}
852
Michal Vaskofd76bd12015-09-24 15:49:57 +0200853struct lyd_node *
854lyd_attr_parent(struct lyd_node *root, struct lyd_attr *attr)
855{
856 struct lyd_node *next, *elem;
857 struct lyd_attr *node_attr;
858
859 LY_TREE_DFS_BEGIN(root, next, elem) {
860 for (node_attr = elem->attr; node_attr; node_attr = node_attr->next) {
861 if (node_attr == attr) {
862 return elem;
863 }
864 }
865 LY_TREE_DFS_END(root, next, elem)
866 }
867
868 return NULL;
869}
870
Radek Krejci134610e2015-10-20 17:15:34 +0200871API struct lyd_attr *
872lyd_insert_attr(struct lyd_node *parent, const char *name, const char *value)
873{
Radek Krejci134610e2015-10-20 17:15:34 +0200874 struct lyd_attr *a, *iter;
875 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +0100876 const struct lys_module *module;
Radek Krejci134610e2015-10-20 17:15:34 +0200877 const char *p;
878 char *aux;
879
880 if (!parent || !name || !value) {
881 return NULL;
882 }
883 ctx = parent->schema->module->ctx;
884
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100885 if ((p = strchr(name, ':'))) {
886 /* search for the namespace */
887 aux = strndup(name, p - name);
Michal Vasko253035f2015-12-17 16:58:13 +0100888 if (!aux) {
889 LOGMEM;
890 return NULL;
891 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100892 module = ly_ctx_get_module(ctx, aux, NULL);
893 free(aux);
894 name = p + 1;
Radek Krejci134610e2015-10-20 17:15:34 +0200895
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100896 if (!module) {
897 /* module not found */
Radek Krejcia008ca92015-10-30 15:52:05 +0100898 LOGERR(LY_EINVAL, "Attribute prefix does not match any schema in the context.");
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100899 return NULL;
Radek Krejci134610e2015-10-20 17:15:34 +0200900 }
901 } else {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100902 /* no prefix -> module is the same as for the parent */
903 module = parent->schema->module;
Radek Krejci134610e2015-10-20 17:15:34 +0200904 }
905
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100906 a = malloc(sizeof *a);
Michal Vasko253035f2015-12-17 16:58:13 +0100907 if (!a) {
908 LOGMEM;
909 return NULL;
910 }
Michal Vasko1e62a092015-12-01 12:27:20 +0100911 a->module = (struct lys_module *)module;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100912 a->next = NULL;
913 a->name = lydict_insert(ctx, name, 0);
Radek Krejci134610e2015-10-20 17:15:34 +0200914 a->value = lydict_insert(ctx, value, 0);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100915
Radek Krejci134610e2015-10-20 17:15:34 +0200916 if (!parent->attr) {
917 parent->attr = a;
918 } else {
919 for (iter = parent->attr; iter->next; iter = iter->next);
920 iter->next = a;
921 }
922
923 return a;
924}
925
Michal Vasko2d162e12015-09-24 14:33:29 +0200926API void
927lyd_free(struct lyd_node *node)
928{
929 struct lyd_node *next, *child;
930
931 if (!node) {
932 return;
933 }
934
935 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
936 /* free children */
937 LY_TREE_FOR_SAFE(node->child, next, child) {
938 lyd_free(child);
939 }
940 } else if (node->schema->nodetype == LYS_ANYXML) {
Michal Vasko345da0a2015-12-02 10:35:55 +0100941 lyxml_free(node->schema->module->ctx, ((struct lyd_node_anyxml *)node)->value);
Michal Vasko2d162e12015-09-24 14:33:29 +0200942 } else {
943 /* free value */
Michal Vasko4c183312015-09-25 10:41:47 +0200944 switch(((struct lyd_node_leaf_list *)node)->value_type) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200945 case LY_TYPE_BINARY:
946 case LY_TYPE_STRING:
Michal Vasko4c183312015-09-25 10:41:47 +0200947 lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value.string);
Michal Vasko2d162e12015-09-24 14:33:29 +0200948 break;
949 case LY_TYPE_BITS:
Michal Vasko4c183312015-09-25 10:41:47 +0200950 if (((struct lyd_node_leaf_list *)node)->value.bit) {
951 free(((struct lyd_node_leaf_list *)node)->value.bit);
Michal Vasko2d162e12015-09-24 14:33:29 +0200952 }
953 break;
954 default:
955 /* TODO nothing needed : LY_TYPE_BOOL, LY_TYPE_DEC64*/
956 break;
957 }
958 }
959
960 lyd_unlink(node);
Radek Krejci88f29302015-10-30 15:42:33 +0100961 lyd_free_attr(node->schema->module->ctx, node, node->attr, 1);
Michal Vasko2d162e12015-09-24 14:33:29 +0200962 free(node);
963}
964
Radek Krejci81468402016-01-07 13:52:40 +0100965API void
966lyd_free_withsiblings(struct lyd_node *node)
967{
968 struct lyd_node *iter, *aux;
969
970 if (!node) {
971 return;
972 }
973
974 /* optimization - avoid freeing (unlinking) the last node of the siblings list */
975 /* so, first, free the node's predecessors to the beginning of the list ... */
976 for(iter = node->prev; iter->next; iter = aux) {
977 aux = iter->prev;
978 lyd_free(iter);
979 }
980 /* ... then, the node is the first in the siblings list, so free them all */
981 LY_TREE_FOR_SAFE(node, aux, iter) {
982 lyd_free(iter);
983 }
984}
985
Michal Vaskoff4c2832015-10-15 13:30:50 +0200986API char *
Michal Vasko1e62a092015-12-01 12:27:20 +0100987lyxml_serialize(const struct lyxml_elem *anyxml)
Michal Vaskoff4c2832015-10-15 13:30:50 +0200988{
989 FILE *stream;
990 char *buf;
991 size_t buf_size;
992
993 if (!anyxml) {
994 ly_errno = LY_EINVAL;
995 return NULL;
996 }
997
998 stream = open_memstream(&buf, &buf_size);
999 if (!stream) {
1000 ly_errno = LY_ESYS;
1001 return NULL;
1002 }
Michal Vasko70f92c32015-12-10 09:57:24 +01001003 if (lyxml_dump_file(stream, anyxml, 0) == 0) {
Michal Vaskoff4c2832015-10-15 13:30:50 +02001004 free(buf);
1005 buf = NULL;
1006 ly_errno = LY_EINVAL;
1007 }
1008 fclose(stream);
1009
1010 return buf;
1011}
1012
Michal Vasko2d162e12015-09-24 14:33:29 +02001013int
1014lyd_compare(struct lyd_node *first, struct lyd_node *second, int unique)
1015{
1016 struct lys_node_list *slist;
Michal Vasko1e62a092015-12-01 12:27:20 +01001017 const struct lys_node *snode = NULL;
Michal Vasko2d162e12015-09-24 14:33:29 +02001018 struct lyd_node *diter;
1019 const char *val1, *val2;
1020 int i, j;
1021
1022 assert(first);
1023 assert(second);
1024
1025 if (first->schema != second->schema) {
1026 return 1;
1027 }
1028
1029 switch (first->schema->nodetype) {
1030 case LYS_LEAFLIST:
1031 /* compare values */
Michal Vasko4c183312015-09-25 10:41:47 +02001032 if (((struct lyd_node_leaf_list *)first)->value_str == ((struct lyd_node_leaf_list *)second)->value_str) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001033 return 0;
1034 }
1035 return 1;
1036 case LYS_LIST:
Michal Vasko4c183312015-09-25 10:41:47 +02001037 slist = (struct lys_node_list *)first->schema;
Michal Vasko2d162e12015-09-24 14:33:29 +02001038
1039 if (unique) {
1040 /* compare unique leafs */
1041 for (i = 0; i < slist->unique_size; i++) {
Radek Krejci581ce772015-11-10 17:22:40 +01001042 for (j = 0; j < slist->unique[i].expr_size; j++) {
1043 /* first */
1044 diter = resolve_data_nodeid(slist->unique[i].expr[j], first->child);
1045 if (diter) {
1046 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
1047 } else {
1048 /* use default value */
Radek Krejci3eb09b62015-12-16 15:22:19 +01001049 if (resolve_schema_nodeid(slist->unique[i].expr[j], first->schema->child, first->schema->module, LYS_LEAF, &snode)) {
1050 /* error, but unique expression was checked when the schema was parsed */
1051 return -1;
1052 }
Radek Krejci581ce772015-11-10 17:22:40 +01001053 val1 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +02001054 }
Radek Krejci581ce772015-11-10 17:22:40 +01001055
1056 /* second */
1057 diter = resolve_data_nodeid(slist->unique[i].expr[j], second->child);
1058 if (diter) {
1059 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
1060 } else {
1061 /* use default value */
Radek Krejci3eb09b62015-12-16 15:22:19 +01001062 if (resolve_schema_nodeid(slist->unique[i].expr[j], second->schema->child, second->schema->module, LYS_LEAF, &snode)) {
1063 /* error, but unique expression was checked when the schema was parsed */
1064 return -1;
1065 }
Radek Krejci581ce772015-11-10 17:22:40 +01001066 val2 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +02001067 }
Radek Krejci581ce772015-11-10 17:22:40 +01001068
Michal Vasko2d162e12015-09-24 14:33:29 +02001069 if (val1 != val2) {
1070 break;
1071 }
1072 }
Radek Krejci581ce772015-11-10 17:22:40 +01001073 if (j && j == slist->unique[i].expr_size) {
Michal Vasko2d162e12015-09-24 14:33:29 +02001074 /* all unique leafs are the same in this set */
1075 return 0;
1076 }
1077 }
1078 }
1079
1080 /* compare keys */
1081 for (i = 0; i < slist->keys_size; i++) {
1082 snode = (struct lys_node *)slist->keys[i];
1083 val1 = val2 = NULL;
1084 LY_TREE_FOR(first->child, diter) {
1085 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +02001086 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +02001087 break;
1088 }
1089 }
1090 LY_TREE_FOR(second->child, diter) {
1091 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +02001092 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +02001093 break;
1094 }
1095 }
1096 if (val1 != val2) {
1097 return 1;
1098 }
1099 }
1100
1101 return 0;
1102 default:
1103 /* no additional check is needed */
1104 return 0;
1105 }
1106}
1107
1108API struct lyd_set *
1109lyd_set_new(void)
1110{
1111 return calloc(1, sizeof(struct lyd_set));
1112}
1113
1114API void
1115lyd_set_free(struct lyd_set *set)
1116{
1117 if (!set) {
1118 return;
1119 }
1120
1121 free(set->set);
1122 free(set);
1123}
1124
1125API int
1126lyd_set_add(struct lyd_set *set, struct lyd_node *node)
1127{
1128 struct lyd_node **new;
1129
1130 if (!set) {
1131 ly_errno = LY_EINVAL;
1132 return EXIT_FAILURE;
1133 }
1134
1135 if (set->size == set->number) {
Radek Krejcic5c45982016-01-07 12:50:44 +01001136 new = realloc(set->set, (set->size + 8) * sizeof *(set->set));
Michal Vasko2d162e12015-09-24 14:33:29 +02001137 if (!new) {
1138 LOGMEM;
1139 return EXIT_FAILURE;
1140 }
1141 set->size += 8;
1142 set->set = new;
1143 }
1144
1145 set->set[set->number++] = node;
1146
1147 return EXIT_SUCCESS;
1148}