blob: 7d6d40283369abd1714665fe0f6c99468ffe44a5 [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 Vasko1e62a092015-12-01 12:27:20 +0100173 ret->schema = (struct lys_node *)snode;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200174 ret->prev = ret;
175 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200176 if (lyd_insert(parent, ret)) {
177 lyd_free(ret);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200178 return NULL;
179 }
180 }
181
182 return ret;
183}
184
185API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100186lyd_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 +0200187{
188 struct lyd_node_leaf_list *ret;
Michal Vasko1e62a092015-12-01 12:27:20 +0100189 const struct lys_node *snode = NULL, *siblings;
Michal Vasko3e671b52015-10-23 16:23:15 +0200190 struct lys_type *stype, *type;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200191 int found;
192
193 if ((!parent && !module) || !name) {
194 ly_errno = LY_EINVAL;
195 return NULL;
196 }
197
198 if (!parent) {
199 siblings = module->data;
200 } else {
Michal Vaskoa5ef4d72015-09-29 16:05:21 +0200201 if (!parent->schema) {
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200202 ly_errno = LY_EINVAL;
Michal Vaskoa5ef4d72015-09-29 16:05:21 +0200203 return NULL;
204 }
205 siblings = parent->schema->child;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200206 }
207
Michal Vaskoa45cf2b2015-10-23 09:45:36 +0200208 if (lys_get_data_sibling(module, siblings, name, LYS_LEAFLIST | LYS_LEAF, &snode) || !snode) {
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200209 ly_errno = LY_EINVAL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200210 return NULL;
211 }
212
Michal Vasko3e671b52015-10-23 16:23:15 +0200213 /* create the new leaf */
214 ret = calloc(1, sizeof *ret);
Michal Vasko1e62a092015-12-01 12:27:20 +0100215 ret->schema = (struct lys_node *)snode;
Michal Vasko3e671b52015-10-23 16:23:15 +0200216 ret->prev = (struct lyd_node *)ret;
217 ret->value_str = lydict_insert((module ? module->ctx : parent->schema->module->ctx), val_str, 0);
218
219 /* resolve the type correctly */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200220 stype = &((struct lys_node_leaf *)snode)->type;
221 if (stype->base == LY_TYPE_UNION) {
222 found = 0;
Radek Krejcif7388492015-10-30 16:12:53 +0100223 type = NULL;
224 while ((type = lyp_get_next_union_type(stype, type, &found))) {
Michal Vasko3e671b52015-10-23 16:23:15 +0200225 ret->value_type = type->base;
226 if (!lyp_parse_value(ret, type, 1, NULL, UINT_MAX)) {
227 /* success! */
228 break;
229 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200230 found = 0;
Radek Krejcif7388492015-10-30 16:12:53 +0100231 }
Michal Vasko3e671b52015-10-23 16:23:15 +0200232
233 if (!type) {
234 /* fail */
235 ly_errno = LY_EINVAL;
236 lyd_free((struct lyd_node *)ret);
237 return NULL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200238 }
Michal Vasko3e671b52015-10-23 16:23:15 +0200239 } else {
240 ret->value_type = stype->base;
241 if (lyp_parse_value(ret, stype, 1, NULL, 0)) {
242 lyd_free((struct lyd_node *)ret);
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200243 ly_errno = LY_EINVAL;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200244 return NULL;
245 }
246 }
247
Michal Vasko3e671b52015-10-23 16:23:15 +0200248 /* connect to parent */
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200249 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200250 if (lyd_insert(parent, (struct lyd_node *)ret)) {
251 lyd_free((struct lyd_node *)ret);
Michal Vasko6a9dd1f2015-10-15 15:09:11 +0200252 return NULL;
253 }
254 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200255
256 return (struct lyd_node *)ret;
257
258}
259
260API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100261lyd_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 +0200262{
Michal Vasko587998f2015-09-29 16:07:53 +0200263 struct lyd_node_anyxml *ret;
Michal Vasko1e62a092015-12-01 12:27:20 +0100264 const struct lys_node *siblings, *snode;
Michal Vasko17cc7062015-12-10 14:31:48 +0100265 struct lyxml_elem *root;
Michal Vasko587998f2015-09-29 16:07:53 +0200266 struct ly_ctx *ctx;
267 char *xml;
268
Michal Vasko14d88772015-12-03 10:54:59 +0100269 if ((!parent && !module) || !name) {
Michal Vasko587998f2015-09-29 16:07:53 +0200270 ly_errno = LY_EINVAL;
271 return NULL;
272 }
273
274 if (!parent) {
275 siblings = module->data;
276 ctx = module->ctx;
277 } else {
278 if (!parent->schema) {
279 return NULL;
280 }
281 siblings = parent->schema->child;
282 ctx = parent->schema->module->ctx;
283 }
284
Michal Vaskoa45cf2b2015-10-23 09:45:36 +0200285 if (lys_get_data_sibling(module, siblings, name, LYS_ANYXML, &snode) || !snode) {
Michal Vasko587998f2015-09-29 16:07:53 +0200286 return NULL;
287 }
288
289 ret = calloc(1, sizeof *ret);
Michal Vasko1e62a092015-12-01 12:27:20 +0100290 ret->schema = (struct lys_node *)snode;
Michal Vasko587998f2015-09-29 16:07:53 +0200291 ret->prev = (struct lyd_node *)ret;
292 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200293 if (lyd_insert(parent, (struct lyd_node *)ret)) {
294 lyd_free((struct lyd_node *)ret);
Michal Vasko587998f2015-09-29 16:07:53 +0200295 return NULL;
296 }
297 }
298
Michal Vasko17cc7062015-12-10 14:31:48 +0100299 /* add fake root and top-level and parse the data */
300 asprintf(&xml, "<root><%s>%s</%s></root>", name, (val_xml ? val_xml : ""), name);
301 root = lyxml_read_data(ctx, xml, 0);
302 free(xml);
303 if (!root) {
304 lyd_free((struct lyd_node *)ret);
305 return NULL;
Michal Vasko14d88772015-12-03 10:54:59 +0100306 }
Michal Vasko587998f2015-09-29 16:07:53 +0200307
Michal Vasko17cc7062015-12-10 14:31:48 +0100308 /* remove the root */
309 ret->value = root->child;
310 lyxml_unlink_elem(ctx, root->child, 1);
311
312 lyxml_free(ctx, root);
313
Michal Vasko587998f2015-09-29 16:07:53 +0200314 return (struct lyd_node *)ret;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200315}
316
Michal Vasko0df122f2015-12-14 13:38:21 +0100317API struct lyd_node *
318lyd_new_output(const struct lys_node *rpc_schema)
319{
320 struct lyd_node *ret;
321 struct lys_node *output;
322
323 if (!rpc_schema || (rpc_schema->nodetype != LYS_RPC)) {
324 ly_errno = LY_EINVAL;
325 return NULL;
326 }
327
328 if (rpc_schema->child->nodetype == LYS_OUTPUT) {
329 output = rpc_schema->child;
330 } else if (rpc_schema->child->next->nodetype == LYS_OUTPUT) {
331 output = rpc_schema->child->next;
332 } else {
333 ly_errno = LY_EINVAL;
334 return NULL;
335 }
336
337 ret = calloc(1, sizeof *ret);
338 ret->schema = output;
339 ret->prev = ret;
340
341 return (struct lyd_node *)ret;
342}
343
Michal Vasko24337392015-10-16 09:58:16 +0200344API int
345lyd_insert(struct lyd_node *parent, struct lyd_node *node)
Michal Vasko2d162e12015-09-24 14:33:29 +0200346{
347 struct lys_node *sparent;
Michal Vasko24337392015-10-16 09:58:16 +0200348 struct lyd_node *iter;
Michal Vasko2d162e12015-09-24 14:33:29 +0200349
Michal Vasko24337392015-10-16 09:58:16 +0200350 if (!node || !parent) {
351 ly_errno = LY_EINVAL;
352 return EXIT_FAILURE;
Michal Vasko2d162e12015-09-24 14:33:29 +0200353 }
354
Michal Vasko72d65c92015-12-07 14:02:35 +0100355 /* check placing the node to the appropriate place according to the schema (if LYS_OUTPUT is returned,
356 * the parent's schema will never match and it fails as it should) */
357 for (sparent = node->schema->parent;
358 sparent && !(sparent->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_OUTPUT | LYS_NOTIF));
359 sparent = sparent->parent);
Michal Vasko2d162e12015-09-24 14:33:29 +0200360 if (sparent != parent->schema) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200361 return EXIT_FAILURE;
362 }
363
Michal Vasko24337392015-10-16 09:58:16 +0200364 if (node->parent || node->prev->next) {
365 lyd_unlink(node);
366 }
367
Michal Vasko2d162e12015-09-24 14:33:29 +0200368 if (!parent->child) {
369 /* add as the only child of the parent */
370 parent->child = node;
371 } else {
372 /* add as the last child of the parent */
373 parent->child->prev->next = node;
374 node->prev = parent->child->prev;
375 for (iter = node; iter->next; iter = iter->next);
376 parent->child->prev = iter;
377 }
Michal Vasko9cc2d0a2015-10-14 15:49:07 +0200378
Michal Vasko2d162e12015-09-24 14:33:29 +0200379 LY_TREE_FOR(node, iter) {
380 iter->parent = parent;
Michal Vasko2d162e12015-09-24 14:33:29 +0200381 }
382
383 return EXIT_SUCCESS;
384}
385
Michal Vasko02592902015-10-15 12:14:40 +0200386static int
Michal Vasko24337392015-10-16 09:58:16 +0200387lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, int before)
Michal Vasko2d162e12015-09-24 14:33:29 +0200388{
389 struct lys_node *par1, *par2;
Michal Vasko24337392015-10-16 09:58:16 +0200390 struct lyd_node *iter, *last;
Michal Vasko3f7dba12015-10-15 13:09:27 +0200391
392 if (sibling == node) {
393 return EXIT_SUCCESS;
394 }
395
Michal Vasko2d162e12015-09-24 14:33:29 +0200396 /* check placing the node to the appropriate place according to the schema */
Radek Krejci2b7bb492015-12-02 15:46:29 +0100397 for (par1 = sibling->schema->parent;
398 par1 && !(par1->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
399 par1 = par1->parent);
400 for (par2 = node->schema->parent;
401 par2 && !(par2->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
402 par2 = par2->parent);
Michal Vasko2d162e12015-09-24 14:33:29 +0200403 if (par1 != par2) {
404 ly_errno = LY_EINVAL;
405 return EXIT_FAILURE;
406 }
407
Michal Vasko24337392015-10-16 09:58:16 +0200408 if (node->parent || node->prev->next) {
409 lyd_unlink(node);
410 }
411
Michal Vasko2d162e12015-09-24 14:33:29 +0200412 LY_TREE_FOR(node, iter) {
413 iter->parent = sibling->parent;
Michal Vasko24337392015-10-16 09:58:16 +0200414 last = iter;
Michal Vasko2d162e12015-09-24 14:33:29 +0200415 }
416
Michal Vasko02592902015-10-15 12:14:40 +0200417 if (before) {
418 if (sibling->prev->next) {
419 /* adding into the list */
420 sibling->prev->next = node;
421 } else if (sibling->parent) {
422 /* at the beginning */
423 sibling->parent->child = node;
Michal Vasko2d162e12015-09-24 14:33:29 +0200424 }
Michal Vasko02592902015-10-15 12:14:40 +0200425 node->prev = sibling->prev;
426 sibling->prev = last;
427 last->next = sibling;
428 } else {
429 if (sibling->next) {
430 /* adding into a middle - fix the prev pointer of the node after inserted nodes */
431 last->next = sibling->next;
432 sibling->next->prev = last;
433 } else {
434 /* at the end - fix the prev pointer of the first node */
435 if (sibling->parent) {
436 sibling->parent->child->prev = last;
437 } else {
438 for (iter = sibling; iter->prev->next; iter = iter->prev);
439 iter->prev = last;
440 }
441 }
442 sibling->next = node;
443 node->prev = sibling;
Michal Vasko2d162e12015-09-24 14:33:29 +0200444 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200445
Michal Vasko24337392015-10-16 09:58:16 +0200446 return EXIT_SUCCESS;
447}
Michal Vasko2d162e12015-09-24 14:33:29 +0200448
Michal Vasko24337392015-10-16 09:58:16 +0200449API int
450lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
451{
452 if (!node || !sibling || lyd_insert_sibling(sibling, node, 1)) {
453 ly_errno = LY_EINVAL;
454 return EXIT_FAILURE;
455 }
456
457 return EXIT_SUCCESS;
458}
459
460API int
461lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
462{
463 if (!node || !sibling || lyd_insert_sibling(sibling, node, 0)) {
464 ly_errno = LY_EINVAL;
465 return EXIT_FAILURE;
466 }
467
468 return EXIT_SUCCESS;
469}
470
471API int
472lyd_validate(struct lyd_node *node, int options)
473{
474 struct lyd_node *next, *iter, *to_free = NULL;
475
476 ly_errno = 0;
477 LY_TREE_DFS_BEGIN(node, next, iter) {
478 if (to_free) {
479 lyd_free(to_free);
480 to_free = NULL;
481 }
482
Radek Krejcif03ec152015-12-03 13:18:37 +0100483 if (lyv_data_context(iter, options, 0, NULL)) {
484 return EXIT_FAILURE;
485 }
486 if (lyv_data_content(iter, options, 0, NULL)) {
Michal Vasko24337392015-10-16 09:58:16 +0200487 if (ly_errno) {
488 return EXIT_FAILURE;
489 } else {
490 /* safe deferred removal */
491 to_free = iter;
Radek Krejciefe6a142015-12-03 14:01:00 +0100492 if (iter == node) {
493 /* removing the whole subtree */
494 break;
495 }
Michal Vasko3f7dba12015-10-15 13:09:27 +0200496 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200497 }
Michal Vasko24337392015-10-16 09:58:16 +0200498
499 LY_TREE_DFS_END(node, next, iter);
Michal Vasko2d162e12015-09-24 14:33:29 +0200500 }
501
Michal Vasko24337392015-10-16 09:58:16 +0200502 if (to_free) {
503 lyd_free(to_free);
504 to_free = NULL;
Michal Vasko02592902015-10-15 12:14:40 +0200505 }
506
507 return EXIT_SUCCESS;
508}
509
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100510/* create an attribute copy */
Michal Vasko55f60be2015-10-14 13:12:58 +0200511static struct lyd_attr *
512lyd_dup_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr)
513{
514 struct lyd_attr *ret;
515
516 /* allocate new attr */
517 if (!parent->attr) {
518 parent->attr = malloc(sizeof *parent->attr);
519 ret = parent->attr;
520 } else {
521 for (ret = parent->attr; ret->next; ret = ret->next);
522 ret->next = malloc(sizeof *ret);
523 ret = ret->next;
524 }
525
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100526 /* fill new attr except */
Michal Vasko55f60be2015-10-14 13:12:58 +0200527 ret->next = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100528 ret->module = attr->module;
Michal Vasko55f60be2015-10-14 13:12:58 +0200529 ret->name = lydict_insert(ctx, attr->name, 0);
530 ret->value = lydict_insert(ctx, attr->value, 0);
531
Michal Vasko55f60be2015-10-14 13:12:58 +0200532 return ret;
533}
534
Michal Vasko2d162e12015-09-24 14:33:29 +0200535API int
536lyd_unlink(struct lyd_node *node)
537{
538 struct lyd_node *iter;
539
540 if (!node) {
541 ly_errno = LY_EINVAL;
542 return EXIT_FAILURE;
543 }
544
545 /* unlink from siblings */
546 if (node->prev->next) {
547 node->prev->next = node->next;
548 }
549 if (node->next) {
550 node->next->prev = node->prev;
551 } else {
552 /* unlinking the last node */
553 iter = node->prev;
554 while (iter->prev != node) {
555 iter = iter->prev;
556 }
557 /* update the "last" pointer from the first node */
558 iter->prev = node->prev;
559 }
560
561 /* unlink from parent */
562 if (node->parent) {
563 if (node->parent->child == node) {
564 /* the node is the first child */
565 node->parent->child = node->next;
566 }
567 node->parent = NULL;
568 }
569
570 node->next = NULL;
571 node->prev = node;
572
573 return EXIT_SUCCESS;
574}
575
Michal Vaskoc0797f82015-10-14 15:51:25 +0200576API struct lyd_node *
Michal Vasko1e62a092015-12-01 12:27:20 +0100577lyd_dup(const struct lyd_node *node, int recursive)
Michal Vaskoc0797f82015-10-14 15:51:25 +0200578{
Michal Vasko1e62a092015-12-01 12:27:20 +0100579 const struct lyd_node *next, *elem;
580 struct lyd_node *ret, *parent, *new_node;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200581 struct lyd_attr *attr;
582 struct lyd_node_leaf_list *new_leaf;
583 struct lyd_node_anyxml *new_axml;
584 struct lys_type *type;
585
586 if (!node) {
587 ly_errno = LY_EINVAL;
588 return NULL;
589 }
590
591 ret = NULL;
592 parent = NULL;
593
594 /* LY_TREE_DFS */
595 for (elem = next = node; elem; elem = next) {
596
597 /* fill specific part */
598 switch (elem->schema->nodetype) {
599 case LYS_LEAF:
600 case LYS_LEAFLIST:
601 new_leaf = malloc(sizeof *new_leaf);
602 new_node = (struct lyd_node *)new_leaf;
603
604 new_leaf->value = ((struct lyd_node_leaf_list *)elem)->value;
605 new_leaf->value_str = lydict_insert(elem->schema->module->ctx,
606 ((struct lyd_node_leaf_list *)elem)->value_str, 0);
607 new_leaf->value_type = ((struct lyd_node_leaf_list *)elem)->value_type;
608 /* bits type must be treated specially */
609 if (new_leaf->value_type == LY_TYPE_BITS) {
610 for (type = &((struct lys_node_leaf *)elem->schema)->type; type->der->module; type = &type->der->type) {
611 if (type->base != LY_TYPE_BITS) {
612 LOGINT;
Michal Vaskod80e6c72015-10-15 09:37:01 +0200613 lyd_free(new_node);
Michal Vaskoc0797f82015-10-14 15:51:25 +0200614 lyd_free(ret);
615 return NULL;
616 }
617 }
618
619 new_leaf->value.bit = malloc(type->info.bits.count * sizeof *new_leaf->value.bit);
620 memcpy(new_leaf->value.bit, ((struct lyd_node_leaf_list *)elem)->value.bit,
621 type->info.bits.count * sizeof *new_leaf->value.bit);
622 }
623 break;
624 case LYS_ANYXML:
625 new_axml = malloc(sizeof *new_axml);
626 new_node = (struct lyd_node *)new_axml;
627
628 new_axml->value = lyxml_dup_elem(elem->schema->module->ctx, ((struct lyd_node_anyxml *)elem)->value,
629 NULL, 1);
630 break;
631 case LYS_CONTAINER:
632 case LYS_LIST:
633 case LYS_NOTIF:
634 case LYS_RPC:
635 new_node = malloc(sizeof *new_node);
636 new_node->child = NULL;
637 break;
638 default:
Michal Vaskoc0797f82015-10-14 15:51:25 +0200639 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +0200640 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200641 return NULL;
642 }
643
644 /* fill common part */
645 new_node->schema = elem->schema;
646 new_node->attr = NULL;
647 LY_TREE_FOR(elem->attr, attr) {
648 lyd_dup_attr(elem->schema->module->ctx, new_node, attr);
649 }
650 new_node->next = NULL;
651 new_node->prev = new_node;
652 new_node->parent = NULL;
653
654 if (!ret) {
655 ret = new_node;
656 }
657 if (parent) {
Michal Vasko24337392015-10-16 09:58:16 +0200658 if (lyd_insert(parent, new_node)) {
Michal Vaskoc0797f82015-10-14 15:51:25 +0200659 lyd_free(ret);
Michal Vasko24337392015-10-16 09:58:16 +0200660 LOGINT;
Michal Vaskoc0797f82015-10-14 15:51:25 +0200661 return NULL;
662 }
663 }
664
665 if (!recursive) {
666 break;
667 }
668
669 /* LY_TREE_DFS_END */
670 /* select element for the next run - children first */
671 next = elem->child;
672 /* child exception for lyd_node_leaf and lyd_node_leaflist */
673 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
674 next = NULL;
675 }
676 if (!next) {
677 /* no children, so try siblings */
678 next = elem->next;
679 } else {
680 parent = new_node;
681 }
682 while (!next) {
683 /* no siblings, go back through parents */
684 elem = elem->parent;
685 if (elem->parent == node->parent) {
686 break;
687 }
Michal Vasko785b2ad2015-10-15 09:37:15 +0200688 if (!parent) {
Michal Vaskoc8f5d802015-10-23 10:14:39 +0200689 lyd_free(ret);
Michal Vasko785b2ad2015-10-15 09:37:15 +0200690 LOGINT;
Michal Vaskoc8f5d802015-10-23 10:14:39 +0200691 return NULL;
Michal Vasko785b2ad2015-10-15 09:37:15 +0200692 }
Michal Vaskoc0797f82015-10-14 15:51:25 +0200693 parent = parent->parent;
694 /* parent is already processed, go to its sibling */
695 next = elem->next;
696 }
697 }
698
699 return ret;
700}
701
Radek Krejci88f29302015-10-30 15:42:33 +0100702API void
703lyd_free_attr(struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_attr *attr, int recursive)
Michal Vasko2d162e12015-09-24 14:33:29 +0200704{
Radek Krejci88f29302015-10-30 15:42:33 +0100705 struct lyd_attr *iter;
706
707 if (!ctx || !attr) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200708 return;
709 }
710
Radek Krejci88f29302015-10-30 15:42:33 +0100711 if (parent) {
712 if (parent->attr == attr) {
713 if (recursive) {
714 parent->attr = NULL;
715 } else {
716 parent->attr = attr->next;
717 }
718 } else {
719 for (iter = parent->attr; iter->next != attr; iter = iter->next);
720 if (iter->next) {
721 if (recursive) {
722 iter->next = NULL;
723 } else {
724 iter->next = attr->next;
725 }
726 }
727 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200728 }
Radek Krejci88f29302015-10-30 15:42:33 +0100729
730 if (!recursive) {
731 attr->next = NULL;
732 }
733
734 for(iter = attr; iter; ) {
735 attr = iter;
736 iter = iter->next;
737
738 lydict_remove(ctx, attr->name);
739 lydict_remove(ctx, attr->value);
740 free(attr);
741 }
Michal Vasko2d162e12015-09-24 14:33:29 +0200742}
743
Michal Vaskofd76bd12015-09-24 15:49:57 +0200744struct lyd_node *
745lyd_attr_parent(struct lyd_node *root, struct lyd_attr *attr)
746{
747 struct lyd_node *next, *elem;
748 struct lyd_attr *node_attr;
749
750 LY_TREE_DFS_BEGIN(root, next, elem) {
751 for (node_attr = elem->attr; node_attr; node_attr = node_attr->next) {
752 if (node_attr == attr) {
753 return elem;
754 }
755 }
756 LY_TREE_DFS_END(root, next, elem)
757 }
758
759 return NULL;
760}
761
Radek Krejci134610e2015-10-20 17:15:34 +0200762API struct lyd_attr *
763lyd_insert_attr(struct lyd_node *parent, const char *name, const char *value)
764{
Radek Krejci134610e2015-10-20 17:15:34 +0200765 struct lyd_attr *a, *iter;
766 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +0100767 const struct lys_module *module;
Radek Krejci134610e2015-10-20 17:15:34 +0200768 const char *p;
769 char *aux;
770
771 if (!parent || !name || !value) {
772 return NULL;
773 }
774 ctx = parent->schema->module->ctx;
775
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100776 if ((p = strchr(name, ':'))) {
777 /* search for the namespace */
778 aux = strndup(name, p - name);
779 module = ly_ctx_get_module(ctx, aux, NULL);
780 free(aux);
781 name = p + 1;
Radek Krejci134610e2015-10-20 17:15:34 +0200782
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100783 if (!module) {
784 /* module not found */
Radek Krejcia008ca92015-10-30 15:52:05 +0100785 LOGERR(LY_EINVAL, "Attribute prefix does not match any schema in the context.");
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100786 return NULL;
Radek Krejci134610e2015-10-20 17:15:34 +0200787 }
788 } else {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100789 /* no prefix -> module is the same as for the parent */
790 module = parent->schema->module;
Radek Krejci134610e2015-10-20 17:15:34 +0200791 }
792
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100793 a = malloc(sizeof *a);
Michal Vasko1e62a092015-12-01 12:27:20 +0100794 a->module = (struct lys_module *)module;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100795 a->next = NULL;
796 a->name = lydict_insert(ctx, name, 0);
Radek Krejci134610e2015-10-20 17:15:34 +0200797 a->value = lydict_insert(ctx, value, 0);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100798
Radek Krejci134610e2015-10-20 17:15:34 +0200799 if (!parent->attr) {
800 parent->attr = a;
801 } else {
802 for (iter = parent->attr; iter->next; iter = iter->next);
803 iter->next = a;
804 }
805
806 return a;
807}
808
Michal Vasko2d162e12015-09-24 14:33:29 +0200809API void
810lyd_free(struct lyd_node *node)
811{
812 struct lyd_node *next, *child;
813
814 if (!node) {
815 return;
816 }
817
818 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
819 /* free children */
820 LY_TREE_FOR_SAFE(node->child, next, child) {
821 lyd_free(child);
822 }
823 } else if (node->schema->nodetype == LYS_ANYXML) {
Michal Vasko345da0a2015-12-02 10:35:55 +0100824 lyxml_free(node->schema->module->ctx, ((struct lyd_node_anyxml *)node)->value);
Michal Vasko2d162e12015-09-24 14:33:29 +0200825 } else {
826 /* free value */
Michal Vasko4c183312015-09-25 10:41:47 +0200827 switch(((struct lyd_node_leaf_list *)node)->value_type) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200828 case LY_TYPE_BINARY:
829 case LY_TYPE_STRING:
Michal Vasko4c183312015-09-25 10:41:47 +0200830 lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value.string);
Michal Vasko2d162e12015-09-24 14:33:29 +0200831 break;
832 case LY_TYPE_BITS:
Michal Vasko4c183312015-09-25 10:41:47 +0200833 if (((struct lyd_node_leaf_list *)node)->value.bit) {
834 free(((struct lyd_node_leaf_list *)node)->value.bit);
Michal Vasko2d162e12015-09-24 14:33:29 +0200835 }
836 break;
837 default:
838 /* TODO nothing needed : LY_TYPE_BOOL, LY_TYPE_DEC64*/
839 break;
840 }
841 }
842
843 lyd_unlink(node);
Radek Krejci88f29302015-10-30 15:42:33 +0100844 lyd_free_attr(node->schema->module->ctx, node, node->attr, 1);
Michal Vasko2d162e12015-09-24 14:33:29 +0200845 free(node);
846}
847
Michal Vaskoff4c2832015-10-15 13:30:50 +0200848API char *
Michal Vasko1e62a092015-12-01 12:27:20 +0100849lyxml_serialize(const struct lyxml_elem *anyxml)
Michal Vaskoff4c2832015-10-15 13:30:50 +0200850{
851 FILE *stream;
852 char *buf;
853 size_t buf_size;
854
855 if (!anyxml) {
856 ly_errno = LY_EINVAL;
857 return NULL;
858 }
859
860 stream = open_memstream(&buf, &buf_size);
861 if (!stream) {
862 ly_errno = LY_ESYS;
863 return NULL;
864 }
Michal Vasko70f92c32015-12-10 09:57:24 +0100865 if (lyxml_dump_file(stream, anyxml, 0) == 0) {
Michal Vaskoff4c2832015-10-15 13:30:50 +0200866 free(buf);
867 buf = NULL;
868 ly_errno = LY_EINVAL;
869 }
870 fclose(stream);
871
872 return buf;
873}
874
Michal Vasko2d162e12015-09-24 14:33:29 +0200875int
876lyd_compare(struct lyd_node *first, struct lyd_node *second, int unique)
877{
878 struct lys_node_list *slist;
Michal Vasko1e62a092015-12-01 12:27:20 +0100879 const struct lys_node *snode = NULL;
Michal Vasko2d162e12015-09-24 14:33:29 +0200880 struct lyd_node *diter;
881 const char *val1, *val2;
882 int i, j;
883
884 assert(first);
885 assert(second);
886
887 if (first->schema != second->schema) {
888 return 1;
889 }
890
891 switch (first->schema->nodetype) {
892 case LYS_LEAFLIST:
893 /* compare values */
Michal Vasko4c183312015-09-25 10:41:47 +0200894 if (((struct lyd_node_leaf_list *)first)->value_str == ((struct lyd_node_leaf_list *)second)->value_str) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200895 return 0;
896 }
897 return 1;
898 case LYS_LIST:
Michal Vasko4c183312015-09-25 10:41:47 +0200899 slist = (struct lys_node_list *)first->schema;
Michal Vasko2d162e12015-09-24 14:33:29 +0200900
901 if (unique) {
902 /* compare unique leafs */
903 for (i = 0; i < slist->unique_size; i++) {
Radek Krejci581ce772015-11-10 17:22:40 +0100904 for (j = 0; j < slist->unique[i].expr_size; j++) {
905 /* first */
906 diter = resolve_data_nodeid(slist->unique[i].expr[j], first->child);
907 if (diter) {
908 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
909 } else {
910 /* use default value */
Radek Krejci3eb09b62015-12-16 15:22:19 +0100911 if (resolve_schema_nodeid(slist->unique[i].expr[j], first->schema->child, first->schema->module, LYS_LEAF, &snode)) {
912 /* error, but unique expression was checked when the schema was parsed */
913 return -1;
914 }
Radek Krejci581ce772015-11-10 17:22:40 +0100915 val1 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +0200916 }
Radek Krejci581ce772015-11-10 17:22:40 +0100917
918 /* second */
919 diter = resolve_data_nodeid(slist->unique[i].expr[j], second->child);
920 if (diter) {
921 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
922 } else {
923 /* use default value */
Radek Krejci3eb09b62015-12-16 15:22:19 +0100924 if (resolve_schema_nodeid(slist->unique[i].expr[j], second->schema->child, second->schema->module, LYS_LEAF, &snode)) {
925 /* error, but unique expression was checked when the schema was parsed */
926 return -1;
927 }
Radek Krejci581ce772015-11-10 17:22:40 +0100928 val2 = ((struct lys_node_leaf *)snode)->dflt;
Michal Vasko2d162e12015-09-24 14:33:29 +0200929 }
Radek Krejci581ce772015-11-10 17:22:40 +0100930
Michal Vasko2d162e12015-09-24 14:33:29 +0200931 if (val1 != val2) {
932 break;
933 }
934 }
Radek Krejci581ce772015-11-10 17:22:40 +0100935 if (j && j == slist->unique[i].expr_size) {
Michal Vasko2d162e12015-09-24 14:33:29 +0200936 /* all unique leafs are the same in this set */
937 return 0;
938 }
939 }
940 }
941
942 /* compare keys */
943 for (i = 0; i < slist->keys_size; i++) {
944 snode = (struct lys_node *)slist->keys[i];
945 val1 = val2 = NULL;
946 LY_TREE_FOR(first->child, diter) {
947 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +0200948 val1 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +0200949 break;
950 }
951 }
952 LY_TREE_FOR(second->child, diter) {
953 if (diter->schema == snode) {
Michal Vasko4c183312015-09-25 10:41:47 +0200954 val2 = ((struct lyd_node_leaf_list *)diter)->value_str;
Michal Vasko2d162e12015-09-24 14:33:29 +0200955 break;
956 }
957 }
958 if (val1 != val2) {
959 return 1;
960 }
961 }
962
963 return 0;
964 default:
965 /* no additional check is needed */
966 return 0;
967 }
968}
969
970API struct lyd_set *
971lyd_set_new(void)
972{
973 return calloc(1, sizeof(struct lyd_set));
974}
975
976API void
977lyd_set_free(struct lyd_set *set)
978{
979 if (!set) {
980 return;
981 }
982
983 free(set->set);
984 free(set);
985}
986
987API int
988lyd_set_add(struct lyd_set *set, struct lyd_node *node)
989{
990 struct lyd_node **new;
991
992 if (!set) {
993 ly_errno = LY_EINVAL;
994 return EXIT_FAILURE;
995 }
996
997 if (set->size == set->number) {
998 new = realloc(set->set, (set->size + 8) * sizeof *(set->set));
999 if (!new) {
1000 LOGMEM;
1001 return EXIT_FAILURE;
1002 }
1003 set->size += 8;
1004 set->set = new;
1005 }
1006
1007 set->set[set->number++] = node;
1008
1009 return EXIT_SUCCESS;
1010}