blob: e14959025cc31d33301068fefb3eb4aebcc202c0 [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>
Michal Vasko2d162e12015-09-24 14:33:29 +020028#include <stdlib.h>
Michal Vasko662610a2015-12-07 11:25:45 +010029#include <sys/types.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020030#include <sys/mman.h>
31#include <sys/stat.h>
Michal Vasko662610a2015-12-07 11:25:45 +010032#include <fcntl.h>
33#include <unistd.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020034#include <string.h>
Michal Vasko662610a2015-12-07 11:25:45 +010035#include <errno.h>
Michal Vasko2d162e12015-09-24 14:33:29 +020036
Michal Vasko662610a2015-12-07 11:25:45 +010037#include "libyang.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020038#include "common.h"
39#include "context.h"
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020040#include "tree_data.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020041#include "parser.h"
42#include "resolve.h"
Michal Vaskofc5744d2015-10-22 12:09:34 +020043#include "xml_internal.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020044#include "tree_internal.h"
45#include "validation.h"
46
Michal Vasko36ef6932015-12-01 14:30:17 +010047static struct lyd_node *
48lyd_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 +020049{
Radek Krejci5974c1f2015-10-09 09:53:24 +020050 struct lyxml_elem *xml;
51 struct lyd_node *result = NULL;
52
Michal Vasko2d162e12015-09-24 14:33:29 +020053 if (!ctx || !data) {
54 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
55 return NULL;
56 }
57
58 switch (format) {
59 case LYD_XML:
Radek Krejci452fb952015-10-02 16:07:46 +020060 case LYD_XML_FORMAT:
Michal Vasko70f92c32015-12-10 09:57:24 +010061 xml = lyxml_read_data(ctx, data, 0);
Michal Vasko36ef6932015-12-01 14:30:17 +010062 if (parent) {
63 result = lyd_parse_output_xml(parent, xml, options);
64 } else {
65 result = lyd_parse_xml(ctx, xml, options);
66 }
Michal Vasko345da0a2015-12-02 10:35:55 +010067 lyxml_free(ctx, xml);
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 Krejci5974c1f2015-10-09 09:53:24 +020077 return result;
Michal Vasko2d162e12015-09-24 14:33:29 +020078}
79
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020080API struct lyd_node *
Michal Vasko662610a2015-12-07 11:25:45 +010081lyd_parse_data(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options)
Michal Vasko36ef6932015-12-01 14:30:17 +010082{
83 return lyd_parse_(ctx, NULL, data, format, options);
84}
85
86API struct lyd_node *
Michal Vasko662610a2015-12-07 11:25:45 +010087lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options)
88{
89 struct lyd_node *ret;
90 struct stat sb;
91 char *data;
92
93 if (!ctx || (fd == -1)) {
94 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
95 return NULL;
96 }
97
98 if (fstat(fd, &sb) == -1) {
99 LOGERR(LY_ESYS, "Failed to stat the file descriptor (%s).", strerror(errno));
100 return NULL;
101 }
102
103 data = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
104 if (data == MAP_FAILED) {
105 LOGERR(LY_ESYS, "Mapping file descriptor into memory failed.");
106 return NULL;
107 }
108
109 ret = lyd_parse_data(ctx, data, format, options);
110 munmap(data, sb.st_size);
111 return ret;
112}
113
114API struct lyd_node *
115lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options)
116{
117 int fd;
118 struct lyd_node *ret;
119
120 if (!ctx || !path) {
121 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
122 return NULL;
123 }
124
125 fd = open(path, O_RDONLY);
126 if (fd == -1) {
127 LOGERR(LY_ESYS, "Failed to open data file \"%s\" (%s).", path, strerror(errno));
128 return NULL;
129 }
130
131 ret = lyd_parse_fd(ctx, fd, format, options);
132 close(fd);
133 return ret;
134}
135
136API struct lyd_node *
137lyd_parse_output_data(const struct lys_node *rpc, const char *data, LYD_FORMAT format, int options)
Michal Vasko36ef6932015-12-01 14:30:17 +0100138{
139 if (!rpc || (rpc->nodetype != LYS_RPC)) {
140 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
141 return NULL;
142 }
143
144 return lyd_parse_(rpc->module->ctx, rpc, data, format, options);
145}
146
147API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100148lyd_new(struct lyd_node *parent, const struct lys_module *module, const char *name)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200149{
150 struct lyd_node *ret;
Michal Vasko1e62a092015-12-01 12:27:20 +0100151 const struct lys_node *snode = NULL, *siblings;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200152
153 if ((!parent && !module) || !name) {
154 ly_errno = LY_EINVAL;
155 return NULL;
156 }
157
158 if (!parent) {
159 siblings = module->data;
160 } else {
Michal Vaskoa5ef4d72015-09-29 16:05:21 +0200161 if (!parent->schema) {
162 return NULL;
163 }
164 siblings = parent->schema->child;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200165 }
166
Michal Vaskoa45cf2b2015-10-23 09:45:36 +0200167 if (lys_get_data_sibling(module, siblings, name, LYS_CONTAINER | LYS_LIST | LYS_NOTIF | LYS_RPC, &snode)
168 || !snode) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200169 return NULL;
170 }
171
172 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100173 if (!ret) {
174 LOGMEM;
175 return NULL;
176 }
Michal Vasko1e62a092015-12-01 12:27:20 +0100177 ret->schema = (struct lys_node *)snode;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200178 ret->prev = ret;
179 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200180 if (lyd_insert(parent, ret)) {
181 lyd_free(ret);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200182 return NULL;
183 }
184 }
185
186 return ret;
187}
188
189API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100190lyd_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 +0200191{
192 struct lyd_node_leaf_list *ret;
Michal Vasko1e62a092015-12-01 12:27:20 +0100193 const struct lys_node *snode = NULL, *siblings;
Michal Vasko3e671b52015-10-23 16:23:15 +0200194 struct lys_type *stype, *type;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200195 int found;
196
197 if ((!parent && !module) || !name) {
198 ly_errno = LY_EINVAL;
199 return NULL;
200 }
201
202 if (!parent) {
203 siblings = module->data;
204 } else {
Michal Vaskoa5ef4d72015-09-29 16:05:21 +0200205 if (!parent->schema) {
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200206 ly_errno = LY_EINVAL;
Michal Vaskoa5ef4d72015-09-29 16:05:21 +0200207 return NULL;
208 }
209 siblings = parent->schema->child;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200210 }
211
Michal Vaskoa45cf2b2015-10-23 09:45:36 +0200212 if (lys_get_data_sibling(module, siblings, name, LYS_LEAFLIST | LYS_LEAF, &snode) || !snode) {
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200213 ly_errno = LY_EINVAL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200214 return NULL;
215 }
216
Michal Vasko3e671b52015-10-23 16:23:15 +0200217 /* create the new leaf */
218 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100219 if (!ret) {
220 LOGMEM;
221 return NULL;
222 }
Michal Vasko1e62a092015-12-01 12:27:20 +0100223 ret->schema = (struct lys_node *)snode;
Michal Vasko3e671b52015-10-23 16:23:15 +0200224 ret->prev = (struct lyd_node *)ret;
225 ret->value_str = lydict_insert((module ? module->ctx : parent->schema->module->ctx), val_str, 0);
226
227 /* resolve the type correctly */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200228 stype = &((struct lys_node_leaf *)snode)->type;
229 if (stype->base == LY_TYPE_UNION) {
230 found = 0;
Radek Krejcif7388492015-10-30 16:12:53 +0100231 type = NULL;
232 while ((type = lyp_get_next_union_type(stype, type, &found))) {
Michal Vasko3e671b52015-10-23 16:23:15 +0200233 ret->value_type = type->base;
234 if (!lyp_parse_value(ret, type, 1, NULL, UINT_MAX)) {
235 /* success! */
236 break;
237 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200238 found = 0;
Radek Krejcif7388492015-10-30 16:12:53 +0100239 }
Michal Vasko3e671b52015-10-23 16:23:15 +0200240
241 if (!type) {
242 /* fail */
243 ly_errno = LY_EINVAL;
244 lyd_free((struct lyd_node *)ret);
245 return NULL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200246 }
Michal Vasko3e671b52015-10-23 16:23:15 +0200247 } else {
248 ret->value_type = stype->base;
249 if (lyp_parse_value(ret, stype, 1, NULL, 0)) {
250 lyd_free((struct lyd_node *)ret);
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200251 ly_errno = LY_EINVAL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200252 return NULL;
253 }
254 }
255
Michal Vasko3e671b52015-10-23 16:23:15 +0200256 /* connect to parent */
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200257 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200258 if (lyd_insert(parent, (struct lyd_node *)ret)) {
259 lyd_free((struct lyd_node *)ret);
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200260 return NULL;
261 }
262 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200263
264 return (struct lyd_node *)ret;
265
266}
267
268API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100269lyd_new_anyxml(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_xml)
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200270{
Michal Vasko587998f2015-09-29 16:07:53 +0200271 struct lyd_node_anyxml *ret;
Michal Vasko1e62a092015-12-01 12:27:20 +0100272 const struct lys_node *siblings, *snode;
Michal Vasko17cc7062015-12-10 14:31:48 +0100273 struct lyxml_elem *root;
Michal Vasko587998f2015-09-29 16:07:53 +0200274 struct ly_ctx *ctx;
275 char *xml;
276
Michal Vasko14d88772015-12-03 10:54:59 +0100277 if ((!parent && !module) || !name) {
Michal Vasko587998f2015-09-29 16:07:53 +0200278 ly_errno = LY_EINVAL;
279 return NULL;
280 }
281
282 if (!parent) {
283 siblings = module->data;
284 ctx = module->ctx;
285 } else {
286 if (!parent->schema) {
287 return NULL;
288 }
289 siblings = parent->schema->child;
290 ctx = parent->schema->module->ctx;
291 }
292
Michal Vaskoa45cf2b2015-10-23 09:45:36 +0200293 if (lys_get_data_sibling(module, siblings, name, LYS_ANYXML, &snode) || !snode) {
Michal Vasko587998f2015-09-29 16:07:53 +0200294 return NULL;
295 }
296
297 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100298 if (!ret) {
299 LOGMEM;
300 return NULL;
301 }
Michal Vasko1e62a092015-12-01 12:27:20 +0100302 ret->schema = (struct lys_node *)snode;
Michal Vasko587998f2015-09-29 16:07:53 +0200303 ret->prev = (struct lyd_node *)ret;
304 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200305 if (lyd_insert(parent, (struct lyd_node *)ret)) {
306 lyd_free((struct lyd_node *)ret);
Michal Vasko587998f2015-09-29 16:07:53 +0200307 return NULL;
308 }
309 }
310
Michal Vasko17cc7062015-12-10 14:31:48 +0100311 /* add fake root and top-level and parse the data */
312 asprintf(&xml, "<root><%s>%s</%s></root>", name, (val_xml ? val_xml : ""), name);
313 root = lyxml_read_data(ctx, xml, 0);
314 free(xml);
315 if (!root) {
316 lyd_free((struct lyd_node *)ret);
317 return NULL;
Michal Vasko14d88772015-12-03 10:54:59 +0100318 }
Michal Vasko587998f2015-09-29 16:07:53 +0200319
Michal Vasko17cc7062015-12-10 14:31:48 +0100320 /* remove the root */
321 ret->value = root->child;
322 lyxml_unlink_elem(ctx, root->child, 1);
323
324 lyxml_free(ctx, root);
325
Michal Vasko587998f2015-09-29 16:07:53 +0200326 return (struct lyd_node *)ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200327}
328
Michal Vasko0df122f2015-12-14 13:38:21 +0100329API struct lyd_node *
330lyd_new_output(const struct lys_node *rpc_schema)
331{
332 struct lyd_node *ret;
333 struct lys_node *output;
334
335 if (!rpc_schema || (rpc_schema->nodetype != LYS_RPC)) {
336 ly_errno = LY_EINVAL;
337 return NULL;
338 }
339
340 if (rpc_schema->child->nodetype == LYS_OUTPUT) {
341 output = rpc_schema->child;
342 } else if (rpc_schema->child->next->nodetype == LYS_OUTPUT) {
343 output = rpc_schema->child->next;
344 } else {
345 ly_errno = LY_EINVAL;
346 return NULL;
347 }
348
349 ret = calloc(1, sizeof *ret);
Michal Vasko253035f2015-12-17 16:58:13 +0100350 if (!ret) {
351 LOGMEM;
352 return NULL;
353 }
Michal Vasko0df122f2015-12-14 13:38:21 +0100354 ret->schema = output;
355 ret->prev = ret;
356
357 return (struct lyd_node *)ret;
358}
359
Michal Vasko24337392015-10-16 09:58:16 +0200360API int
361lyd_insert(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko2d162e12015-09-24 14:33:29 +0200362{
363 struct lys_node *sparent;
Michal Vasko24337392015-10-16 09:58:16 +0200364 struct lyd_node *iter;
Michal Vasko2d162e12015-09-24 14:33:29 +0200365
Michal Vasko24337392015-10-16 09:58:16 +0200366 if (!node || !parent) {
367 ly_errno = LY_EINVAL;
368 return EXIT_FAILURE;
Michal Vasko2d162e12015-09-24 14:33:29 +0200369 }
370
Michal Vasko72d65c92015-12-07 14:02:35 +0100371 /* check placing the node to the appropriate place according to the schema (if LYS_OUTPUT is returned,
372 * the parent's schema will never match and it fails as it should) */
373 for (sparent = node->schema->parent;
374 sparent && !(sparent->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_OUTPUT | LYS_NOTIF));
375 sparent = sparent->parent);
Michal Vasko2d162e12015-09-24 14:33:29 +0200376 if (sparent != parent->schema) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200377 return EXIT_FAILURE;
378 }
379
Michal Vasko24337392015-10-16 09:58:16 +0200380 if (node->parent || node->prev->next) {
381 lyd_unlink(node);
382 }
383
Michal Vasko2d162e12015-09-24 14:33:29 +0200384 if (!parent->child) {
385 /* add as the only child of the parent */
386 parent->child = node;
387 } else {
388 /* add as the last child of the parent */
389 parent->child->prev->next = node;
390 node->prev = parent->child->prev;
391 for (iter = node; iter->next; iter = iter->next);
392 parent->child->prev = iter;
393 }
Michal Vasko9cc2d0a2015-10-14 15:49:07 +0200394
Michal Vasko2d162e12015-09-24 14:33:29 +0200395 LY_TREE_FOR(node, iter) {
396 iter->parent = parent;
Michal Vasko2d162e12015-09-24 14:33:29 +0200397 }
398
399 return EXIT_SUCCESS;
400}
401
Michal Vasko02592902015-10-15 12:14:40 +0200402static int
Michal Vasko24337392015-10-16 09:58:16 +0200403lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, int before)
Michal Vasko2d162e12015-09-24 14:33:29 +0200404{
405 struct lys_node *par1, *par2;
Michal Vasko24337392015-10-16 09:58:16 +0200406 struct lyd_node *iter, *last;
Michal Vasko3f7dba12015-10-15 13:09:27 +0200407
408 if (sibling == node) {
409 return EXIT_SUCCESS;
410 }
411
Michal Vasko2d162e12015-09-24 14:33:29 +0200412 /* check placing the node to the appropriate place according to the schema */
Radek Krejci2b7bb492015-12-02 15:46:29 +0100413 for (par1 = sibling->schema->parent;
414 par1 && !(par1->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
415 par1 = par1->parent);
416 for (par2 = node->schema->parent;
417 par2 && !(par2->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
418 par2 = par2->parent);
Michal Vasko2d162e12015-09-24 14:33:29 +0200419 if (par1 != par2) {
420 ly_errno = LY_EINVAL;
421 return EXIT_FAILURE;
422 }
423
Michal Vasko24337392015-10-16 09:58:16 +0200424 if (node->parent || node->prev->next) {
425 lyd_unlink(node);
426 }
427
Michal Vasko2d162e12015-09-24 14:33:29 +0200428 LY_TREE_FOR(node, iter) {
429 iter->parent = sibling->parent;
Michal Vasko24337392015-10-16 09:58:16 +0200430 last = iter;
Michal Vasko2d162e12015-09-24 14:33:29 +0200431 }
432
Michal Vasko02592902015-10-15 12:14:40 +0200433 if (before) {
434 if (sibling->prev->next) {
435 /* adding into the list */
436 sibling->prev->next = node;
437 } else if (sibling->parent) {
438 /* at the beginning */
439 sibling->parent->child = node;
Michal Vasko2d162e12015-09-24 14:33:29 +0200440 }
Michal Vasko02592902015-10-15 12:14:40 +0200441 node->prev = sibling->prev;
442 sibling->prev = last;
443 last->next = sibling;
444 } else {
445 if (sibling->next) {
446 /* adding into a middle - fix the prev pointer of the node after inserted nodes */
447 last->next = sibling->next;
448 sibling->next->prev = last;
449 } else {
450 /* at the end - fix the prev pointer of the first node */
451 if (sibling->parent) {
452 sibling->parent->child->prev = last;
453 } else {
454 for (iter = sibling; iter->prev->next; iter = iter->prev);
455 iter->prev = last;
456 }
457 }
458 sibling->next = node;
459 node->prev = sibling;
Michal Vasko2d162e12015-09-24 14:33:29 +0200460 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200461
Michal Vasko24337392015-10-16 09:58:16 +0200462 return EXIT_SUCCESS;
463}
Michal Vasko2d162e12015-09-24 14:33:29 +0200464
Michal Vasko24337392015-10-16 09:58:16 +0200465API int
466lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
467{
468 if (!node || !sibling || lyd_insert_sibling(sibling, node, 1)) {
469 ly_errno = LY_EINVAL;
470 return EXIT_FAILURE;
471 }
472
473 return EXIT_SUCCESS;
474}
475
476API int
477lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
478{
479 if (!node || !sibling || lyd_insert_sibling(sibling, node, 0)) {
480 ly_errno = LY_EINVAL;
481 return EXIT_FAILURE;
482 }
483
484 return EXIT_SUCCESS;
485}
486
487API int
488lyd_validate(struct lyd_node *node, int options)
489{
490 struct lyd_node *next, *iter, *to_free = NULL;
491
492 ly_errno = 0;
493 LY_TREE_DFS_BEGIN(node, next, iter) {
494 if (to_free) {
495 lyd_free(to_free);
496 to_free = NULL;
497 }
498
Radek Krejcif03ec152015-12-03 13:18:37 +0100499 if (lyv_data_context(iter, options, 0, NULL)) {
500 return EXIT_FAILURE;
501 }
502 if (lyv_data_content(iter, options, 0, NULL)) {
Michal Vasko24337392015-10-16 09:58:16 +0200503 if (ly_errno) {
504 return EXIT_FAILURE;
505 } else {
506 /* safe deferred removal */
507 to_free = iter;
Radek Krejciefe6a142015-12-03 14:01:00 +0100508 if (iter == node) {
509 /* removing the whole subtree */
510 break;
511 }
Michal Vasko3f7dba12015-10-15 13:09:27 +0200512 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200513 }
Michal Vasko24337392015-10-16 09:58:16 +0200514
515 LY_TREE_DFS_END(node, next, iter);
Michal Vasko2d162e12015-09-24 14:33:29 +0200516 }
517
Michal Vasko24337392015-10-16 09:58:16 +0200518 if (to_free) {
519 lyd_free(to_free);
520 to_free = NULL;
Michal Vasko02592902015-10-15 12:14:40 +0200521 }
522
523 return EXIT_SUCCESS;
524}
525
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100526/* create an attribute copy */
Michal Vasko55f60be2015-10-14 13:12:58 +0200527static struct lyd_attr *
528lyd_dup_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr)
529{
530 struct lyd_attr *ret;
531
532 /* allocate new attr */
533 if (!parent->attr) {
534 parent->attr = malloc(sizeof *parent->attr);
535 ret = parent->attr;
536 } else {
537 for (ret = parent->attr; ret->next; ret = ret->next);
538 ret->next = malloc(sizeof *ret);
539 ret = ret->next;
540 }
Michal Vasko253035f2015-12-17 16:58:13 +0100541 if (!ret) {
542 LOGMEM;
543 return NULL;
544 }
Michal Vasko55f60be2015-10-14 13:12:58 +0200545
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100546 /* fill new attr except */
Michal Vasko55f60be2015-10-14 13:12:58 +0200547 ret->next = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100548 ret->module = attr->module;
Michal Vasko55f60be2015-10-14 13:12:58 +0200549 ret->name = lydict_insert(ctx, attr->name, 0);
550 ret->value = lydict_insert(ctx, attr->value, 0);
551
Michal Vasko55f60be2015-10-14 13:12:58 +0200552 return ret;
553}
554
Michal Vasko2d162e12015-09-24 14:33:29 +0200555API int
556lyd_unlink(struct lyd_node *node)
557{
558 struct lyd_node *iter;
559
560 if (!node) {
561 ly_errno = LY_EINVAL;
562 return EXIT_FAILURE;
563 }
564
565 /* unlink from siblings */
566 if (node->prev->next) {
567 node->prev->next = node->next;
568 }
569 if (node->next) {
570 node->next->prev = node->prev;
571 } else {
572 /* unlinking the last node */
573 iter = node->prev;
574 while (iter->prev != node) {
575 iter = iter->prev;
576 }
577 /* update the "last" pointer from the first node */
578 iter->prev = node->prev;
579 }
580
581 /* unlink from parent */
582 if (node->parent) {
583 if (node->parent->child == node) {
584 /* the node is the first child */
585 node->parent->child = node->next;
586 }
587 node->parent = NULL;
588 }
589
590 node->next = NULL;
591 node->prev = node;
592
593 return EXIT_SUCCESS;
594}
595
Michal Vaskoc0797f82015-10-14 15:51:25 +0200596API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100597lyd_dup(const struct lyd_node *node, int recursive)
Michal Vaskoc0797f82015-10-14 15:51:25 +0200598{
Michal Vasko1e62a092015-12-01 12:27:20 +0100599 const struct lyd_node *next, *elem;
600 struct lyd_node *ret, *parent, *new_node;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200601 struct lyd_attr *attr;
602 struct lyd_node_leaf_list *new_leaf;
603 struct lyd_node_anyxml *new_axml;
604 struct lys_type *type;
605
606 if (!node) {
607 ly_errno = LY_EINVAL;
608 return NULL;
609 }
610
611 ret = NULL;
612 parent = NULL;
613
614 /* LY_TREE_DFS */
615 for (elem = next = node; elem; elem = next) {
616
617 /* fill specific part */
618 switch (elem->schema->nodetype) {
619 case LYS_LEAF:
620 case LYS_LEAFLIST:
621 new_leaf = malloc(sizeof *new_leaf);
622 new_node = (struct lyd_node *)new_leaf;
Michal Vasko253035f2015-12-17 16:58:13 +0100623 if (!new_node) {
624 LOGMEM;
625 return NULL;
626 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200627
628 new_leaf->value = ((struct lyd_node_leaf_list *)elem)->value;
629 new_leaf->value_str = lydict_insert(elem->schema->module->ctx,
630 ((struct lyd_node_leaf_list *)elem)->value_str, 0);
631 new_leaf->value_type = ((struct lyd_node_leaf_list *)elem)->value_type;
632 /* bits type must be treated specially */
633 if (new_leaf->value_type == LY_TYPE_BITS) {
634 for (type = &((struct lys_node_leaf *)elem->schema)->type; type->der->module; type = &type->der->type) {
635 if (type->base != LY_TYPE_BITS) {
636 LOGINT;
Michal Vaskod80e6c72015-10-15 09:37:01 +0200637 lyd_free(new_node);
Michal Vaskoc0797f82015-10-14 15:51:25 +0200638 lyd_free(ret);
639 return NULL;
640 }
641 }
642
643 new_leaf->value.bit = malloc(type->info.bits.count * sizeof *new_leaf->value.bit);
Michal Vasko253035f2015-12-17 16:58:13 +0100644 if (!new_leaf->value.bit) {
645 LOGMEM;
646 lyd_free(new_node);
647 lyd_free(ret);
648 return NULL;
649 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200650 memcpy(new_leaf->value.bit, ((struct lyd_node_leaf_list *)elem)->value.bit,
651 type->info.bits.count * sizeof *new_leaf->value.bit);
652 }
653 break;
654 case LYS_ANYXML:
655 new_axml = malloc(sizeof *new_axml);
656 new_node = (struct lyd_node *)new_axml;
Michal Vasko253035f2015-12-17 16:58:13 +0100657 if (!new_node) {
658 LOGMEM;
659 return NULL;
660 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200661
662 new_axml->value = lyxml_dup_elem(elem->schema->module->ctx, ((struct lyd_node_anyxml *)elem)->value,
663 NULL, 1);
664 break;
665 case LYS_CONTAINER:
666 case LYS_LIST:
667 case LYS_NOTIF:
668 case LYS_RPC:
669 new_node = malloc(sizeof *new_node);
Michal Vasko253035f2015-12-17 16:58:13 +0100670 if (!new_node) {
671 LOGMEM;
672 return NULL;
673 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200674 new_node->child = NULL;
675 break;
676 default:
Michal Vaskoc0797f82015-10-14 15:51:25 +0200677 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +0200678 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200679 return NULL;
680 }
681
682 /* fill common part */
683 new_node->schema = elem->schema;
684 new_node->attr = NULL;
685 LY_TREE_FOR(elem->attr, attr) {
686 lyd_dup_attr(elem->schema->module->ctx, new_node, attr);
687 }
688 new_node->next = NULL;
689 new_node->prev = new_node;
690 new_node->parent = NULL;
691
692 if (!ret) {
693 ret = new_node;
694 }
695 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200696 if (lyd_insert(parent, new_node)) {
Michal Vaskoc0797f82015-10-14 15:51:25 +0200697 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +0200698 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200699 return NULL;
700 }
701 }
702
703 if (!recursive) {
704 break;
705 }
706
707 /* LY_TREE_DFS_END */
708 /* select element for the next run - children first */
709 next = elem->child;
710 /* child exception for lyd_node_leaf and lyd_node_leaflist */
711 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
712 next = NULL;
713 }
714 if (!next) {
715 /* no children, so try siblings */
716 next = elem->next;
717 } else {
718 parent = new_node;
719 }
720 while (!next) {
721 /* no siblings, go back through parents */
722 elem = elem->parent;
723 if (elem->parent == node->parent) {
724 break;
725 }
Michal Vasko785b2ad2015-10-15 09:37:15 +0200726 if (!parent) {
Michal Vaskoc8f5d802015-10-23 10:14:39 +0200727 lyd_free(ret);
Michal Vasko785b2ad2015-10-15 09:37:15 +0200728 LOGINT;
Michal Vaskoc8f5d802015-10-23 10:14:39 +0200729 return NULL;
Michal Vasko785b2ad2015-10-15 09:37:15 +0200730 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200731 parent = parent->parent;
732 /* parent is already processed, go to its sibling */
733 next = elem->next;
734 }
735 }
736
737 return ret;
738}
739
Radek Krejci88f29302015-10-30 15:42:33 +0100740API void
741lyd_free_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr, int recursive)
Michal Vasko2d162e12015-09-24 14:33:29 +0200742{
Radek Krejci88f29302015-10-30 15:42:33 +0100743 struct lyd_attr *iter;
744
745 if (!ctx || !attr) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200746 return;
747 }
748
Radek Krejci88f29302015-10-30 15:42:33 +0100749 if (parent) {
750 if (parent->attr == attr) {
751 if (recursive) {
752 parent->attr = NULL;
753 } else {
754 parent->attr = attr->next;
755 }
756 } else {
757 for (iter = parent->attr; iter->next != attr; iter = iter->next);
758 if (iter->next) {
759 if (recursive) {
760 iter->next = NULL;
761 } else {
762 iter->next = attr->next;
763 }
764 }
765 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200766 }
Radek Krejci88f29302015-10-30 15:42:33 +0100767
768 if (!recursive) {
769 attr->next = NULL;
770 }
771
772 for(iter = attr; iter; ) {
773 attr = iter;
774 iter = iter->next;
775
776 lydict_remove(ctx, attr->name);
777 lydict_remove(ctx, attr->value);
778 free(attr);
779 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200780}
781
Michal Vaskofd76bd12015-09-24 15:49:57 +0200782struct lyd_node *
783lyd_attr_parent(struct lyd_node *root, struct lyd_attr *attr)
784{
785 struct lyd_node *next, *elem;
786 struct lyd_attr *node_attr;
787
788 LY_TREE_DFS_BEGIN(root, next, elem) {
789 for (node_attr = elem->attr; node_attr; node_attr = node_attr->next) {
790 if (node_attr == attr) {
791 return elem;
792 }
793 }
794 LY_TREE_DFS_END(root, next, elem)
795 }
796
797 return NULL;
798}
799
Radek Krejci134610e2015-10-20 17:15:34 +0200800API struct lyd_attr *
801lyd_insert_attr(struct lyd_node *parent, const char *name, const char *value)
802{
Radek Krejci134610e2015-10-20 17:15:34 +0200803 struct lyd_attr *a, *iter;
804 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +0100805 const struct lys_module *module;
Radek Krejci134610e2015-10-20 17:15:34 +0200806 const char *p;
807 char *aux;
808
809 if (!parent || !name || !value) {
810 return NULL;
811 }
812 ctx = parent->schema->module->ctx;
813
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100814 if ((p = strchr(name, ':'))) {
815 /* search for the namespace */
816 aux = strndup(name, p - name);
Michal Vasko253035f2015-12-17 16:58:13 +0100817 if (!aux) {
818 LOGMEM;
819 return NULL;
820 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100821 module = ly_ctx_get_module(ctx, aux, NULL);
822 free(aux);
823 name = p + 1;
Radek Krejci134610e2015-10-20 17:15:34 +0200824
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100825 if (!module) {
826 /* module not found */
Radek Krejcia008ca92015-10-30 15:52:05 +0100827 LOGERR(LY_EINVAL, "Attribute prefix does not match any schema in the context.");
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100828 return NULL;
Radek Krejci134610e2015-10-20 17:15:34 +0200829 }
830 } else {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100831 /* no prefix -> module is the same as for the parent */
832 module = parent->schema->module;
Radek Krejci134610e2015-10-20 17:15:34 +0200833 }
834
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100835 a = malloc(sizeof *a);
Michal Vasko253035f2015-12-17 16:58:13 +0100836 if (!a) {
837 LOGMEM;
838 return NULL;
839 }
Michal Vasko1e62a092015-12-01 12:27:20 +0100840 a->module = (struct lys_module *)module;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100841 a->next = NULL;
842 a->name = lydict_insert(ctx, name, 0);
Radek Krejci134610e2015-10-20 17:15:34 +0200843 a->value = lydict_insert(ctx, value, 0);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100844
Radek Krejci134610e2015-10-20 17:15:34 +0200845 if (!parent->attr) {
846 parent->attr = a;
847 } else {
848 for (iter = parent->attr; iter->next; iter = iter->next);
849 iter->next = a;
850 }
851
852 return a;
853}
854
Michal Vasko2d162e12015-09-24 14:33:29 +0200855API void
856lyd_free(struct lyd_node *node)
857{
858 struct lyd_node *next, *child;
859
860 if (!node) {
861 return;
862 }
863
864 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
865 /* free children */
866 LY_TREE_FOR_SAFE(node->child, next, child) {
867 lyd_free(child);
868 }
869 } else if (node->schema->nodetype == LYS_ANYXML) {
Michal Vasko345da0a2015-12-02 10:35:55 +0100870 lyxml_free(node->schema->module->ctx, ((struct lyd_node_anyxml *)node)->value);
Michal Vasko2d162e12015-09-24 14:33:29 +0200871 } else {
872 /* free value */
Michal Vasko4c183312015-09-25 10:41:47 +0200873 switch(((struct lyd_node_leaf_list *)node)->value_type) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200874 case LY_TYPE_BINARY:
875 case LY_TYPE_STRING:
Michal Vasko4c183312015-09-25 10:41:47 +0200876 lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value.string);
Michal Vasko2d162e12015-09-24 14:33:29 +0200877 break;
878 case LY_TYPE_BITS:
Michal Vasko4c183312015-09-25 10:41:47 +0200879 if (((struct lyd_node_leaf_list *)node)->value.bit) {
880 free(((struct lyd_node_leaf_list *)node)->value.bit);
Michal Vasko2d162e12015-09-24 14:33:29 +0200881 }
882 break;
883 default:
884 /* TODO nothing needed : LY_TYPE_BOOL, LY_TYPE_DEC64*/
885 break;
886 }
887 }
888
889 lyd_unlink(node);
Radek Krejci88f29302015-10-30 15:42:33 +0100890 lyd_free_attr(node->schema->module->ctx, node, node->attr, 1);
Michal Vasko2d162e12015-09-24 14:33:29 +0200891 free(node);
892}
893
Michal Vaskoff4c2832015-10-15 13:30:50 +0200894API char *
Michal Vasko1e62a092015-12-01 12:27:20 +0100895lyxml_serialize(const struct lyxml_elem *anyxml)
Michal Vaskoff4c2832015-10-15 13:30:50 +0200896{
897 FILE *stream;
898 char *buf;
899 size_t buf_size;
900
901 if (!anyxml) {
902 ly_errno = LY_EINVAL;
903 return NULL;
904 }
905
906 stream = open_memstream(&buf, &buf_size);
907 if (!stream) {
908 ly_errno = LY_ESYS;
909 return NULL;
910 }
Michal Vasko70f92c32015-12-10 09:57:24 +0100911 if (lyxml_dump_file(stream, anyxml, 0) == 0) {
Michal Vaskoff4c2832015-10-15 13:30:50 +0200912 free(buf);
913 buf = NULL;
914 ly_errno = LY_EINVAL;
915 }
916 fclose(stream);
917
918 return buf;
919}
920
Michal Vasko2d162e12015-09-24 14:33:29 +0200921int
922lyd_compare(struct lyd_node *first, struct lyd_node *second, int unique)
923{
924 struct lys_node_list *slist;
Michal Vasko1e62a092015-12-01 12:27:20 +0100925 const struct lys_node *snode = NULL;
Michal Vasko2d162e12015-09-24 14:33:29 +0200926 struct lyd_node *diter;
927 const char *val1, *val2;
928 int i, j;
929
930 assert(first);
931 assert(second);
932
933 if (first->schema != second->schema) {
934 return 1;
935 }
936
937 switch (first->schema->nodetype) {
938 case LYS_LEAFLIST:
939 /* compare values */
Michal Vasko4c183312015-09-25 10:41:47 +0200940 if (((struct lyd_node_leaf_list *)first)->value_str == ((struct lyd_node_leaf_list *)second)->value_str) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200941 return 0;
942 }
943 return 1;
944 case LYS_LIST:
Michal Vasko4c183312015-09-25 10:41:47 +0200945 slist = (struct lys_node_list *)first->schema;
Michal Vasko2d162e12015-09-24 14:33:29 +0200946
947 if (unique) {
948 /* compare unique leafs */
949 for (i = 0; i < slist->unique_size; i++) {
Radek Krejci581ce772015-11-10 17:22:40 +0100950 for (j = 0; j < slist->unique[i].expr_size; j++) {
951 /* first */
952 diter = resolve_data_nodeid(slist->unique[i].expr[j], first->child);
953 if (diter) {
954 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
955 } else {
956 /* use default value */
Radek Krejci3eb09b62015-12-16 15:22:19 +0100957 if (resolve_schema_nodeid(slist->unique[i].expr[j], first->schema->child, first->schema->module, LYS_LEAF, &snode)) {
958 /* error, but unique expression was checked when the schema was parsed */
959 return -1;
960 }
Radek Krejci581ce772015-11-10 17:22:40 +0100961 val1 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +0200962 }
Radek Krejci581ce772015-11-10 17:22:40 +0100963
964 /* second */
965 diter = resolve_data_nodeid(slist->unique[i].expr[j], second->child);
966 if (diter) {
967 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
968 } else {
969 /* use default value */
Radek Krejci3eb09b62015-12-16 15:22:19 +0100970 if (resolve_schema_nodeid(slist->unique[i].expr[j], second->schema->child, second->schema->module, LYS_LEAF, &snode)) {
971 /* error, but unique expression was checked when the schema was parsed */
972 return -1;
973 }
Radek Krejci581ce772015-11-10 17:22:40 +0100974 val2 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +0200975 }
Radek Krejci581ce772015-11-10 17:22:40 +0100976
Michal Vasko2d162e12015-09-24 14:33:29 +0200977 if (val1 != val2) {
978 break;
979 }
980 }
Radek Krejci581ce772015-11-10 17:22:40 +0100981 if (j && j == slist->unique[i].expr_size) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200982 /* all unique leafs are the same in this set */
983 return 0;
984 }
985 }
986 }
987
988 /* compare keys */
989 for (i = 0; i < slist->keys_size; i++) {
990 snode = (struct lys_node *)slist->keys[i];
991 val1 = val2 = NULL;
992 LY_TREE_FOR(first->child, diter) {
993 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +0200994 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +0200995 break;
996 }
997 }
998 LY_TREE_FOR(second->child, diter) {
999 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +02001000 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +02001001 break;
1002 }
1003 }
1004 if (val1 != val2) {
1005 return 1;
1006 }
1007 }
1008
1009 return 0;
1010 default:
1011 /* no additional check is needed */
1012 return 0;
1013 }
1014}
1015
1016API struct lyd_set *
1017lyd_set_new(void)
1018{
1019 return calloc(1, sizeof(struct lyd_set));
1020}
1021
1022API void
1023lyd_set_free(struct lyd_set *set)
1024{
1025 if (!set) {
1026 return;
1027 }
1028
1029 free(set->set);
1030 free(set);
1031}
1032
1033API int
1034lyd_set_add(struct lyd_set *set, struct lyd_node *node)
1035{
1036 struct lyd_node **new;
1037
1038 if (!set) {
1039 ly_errno = LY_EINVAL;
1040 return EXIT_FAILURE;
1041 }
1042
1043 if (set->size == set->number) {
Michal Vasko253035f2015-12-17 16:58:13 +01001044 new = ly_realloc(set->set, (set->size + 8) * sizeof *(set->set));
Michal Vasko2d162e12015-09-24 14:33:29 +02001045 if (!new) {
1046 LOGMEM;
1047 return EXIT_FAILURE;
1048 }
1049 set->size += 8;
1050 set->set = new;
1051 }
1052
1053 set->set[set->number++] = node;
1054
1055 return EXIT_SUCCESS;
1056}