blob: c2488aea87c926168dc76d40c2cbdb79b3362d5b [file] [log] [blame]
Michal Vasko2d162e12015-09-24 14:33:29 +02001/**
2 * @file tree_data.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Manipulation with libyang data structures
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21#define _GNU_SOURCE
22
23#include <assert.h>
24#include <ctype.h>
25#include <stdlib.h>
26#include <sys/mman.h>
27#include <sys/stat.h>
28#include <string.h>
29
30#include "common.h"
31#include "context.h"
32#include "parser.h"
33#include "resolve.h"
34#include "xml.h"
35#include "tree_internal.h"
36#include "validation.h"
37
38API struct lyd_node *
39lyd_parse(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options)
40{
41 if (!ctx || !data) {
42 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
43 return NULL;
44 }
45
46 switch (format) {
47 case LYD_XML:
48 return xml_read_data(ctx, data, options);
49 case LYD_JSON:
50 default:
51 /* TODO */
52 return NULL;
53 }
54
55 return NULL;
56}
57
58API int
59lyd_insert(struct lyd_node *parent, struct lyd_node *node, int options)
60{
61 struct lys_node *sparent;
62 struct lyd_node *iter, *next, *last;
63
64 if (!node || !parent) {
65 ly_errno = LY_EINVAL;
66 return EXIT_FAILURE;
67 }
68
69 if (node->parent || node->prev->next) {
70 lyd_unlink(node);
71 }
72
73 /* check placing the node to the appropriate place according to the schema */
74 sparent = node->schema->parent;
75 while (!(sparent->nodetype & (LYS_CONTAINER | LYS_LIST))) {
76 sparent = sparent->parent;
77 }
78 if (sparent != parent->schema) {
79 ly_errno = LY_EINVAL;
80 return EXIT_FAILURE;
81 }
82
83 if (!parent->child) {
84 /* add as the only child of the parent */
85 parent->child = node;
86 } else {
87 /* add as the last child of the parent */
88 parent->child->prev->next = node;
89 node->prev = parent->child->prev;
90 for (iter = node; iter->next; iter = iter->next);
91 parent->child->prev = iter;
92 }
93 LY_TREE_FOR(node, iter) {
94 iter->parent = parent;
95 last = iter; /* remember the last of the inserted nodes */
96 }
97
98 ly_errno = 0;
99 LY_TREE_FOR_SAFE(node, next, iter) {
100 /* various validation checks */
101 if (lyv_data_content(iter, 0, options)) {
102 if (ly_errno) {
103 return EXIT_FAILURE;
104 } else {
105 lyd_free(iter);
106 }
107 }
108
109 if (iter == last) {
110 /* we are done - checking only the inserted nodes */
111 break;
112 }
113 }
114
115 return EXIT_SUCCESS;
116}
117
118API int
119lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node, int options)
120{
121 struct lys_node *par1, *par2;
122 struct lyd_node *iter, *next, *last;
123
124 if (!node || !sibling) {
125 ly_errno = LY_EINVAL;
126 return EXIT_FAILURE;
127 }
128
129 if (node->parent || node->prev->next) {
130 lyd_unlink(node);
131 }
132
133 /* check placing the node to the appropriate place according to the schema */
134 for (par1 = sibling->schema->parent; par1 && (par1->nodetype & (LYS_CONTAINER | LYS_LIST)); par1 = par1->parent);
135 for (par2 = node->schema->parent; par2 && (par2->nodetype & (LYS_CONTAINER | LYS_LIST)); par2 = par2->parent);
136 if (par1 != par2) {
137 ly_errno = LY_EINVAL;
138 return EXIT_FAILURE;
139 }
140
141 LY_TREE_FOR(node, iter) {
142 iter->parent = sibling->parent;
143 last = iter; /* remember the last of the inserted nodes */
144 }
145
146 if (sibling->next) {
147 /* adding into a middle - fix the prev pointer of the node after inserted nodes */
148 last->next = sibling->next;
149 sibling->next->prev = last;
150 } else {
151 /* at the end - fix the prev pointer of the first node */
152 if (sibling->parent) {
153 sibling->parent->child->prev = last;
154 } else {
155 for (iter = sibling; iter->prev->next; iter = iter->prev);
156 iter->prev = last;
157 }
158 }
159 sibling->next = node;
160 node->prev = sibling;
161
162 ly_errno = 0;
163 LY_TREE_FOR_SAFE(node, next, iter) {
164 /* various validation checks */
165 if (lyv_data_content(iter, 0, options)) {
166 if (ly_errno) {
167 return EXIT_FAILURE;
168 } else {
169 lyd_free(iter);
170 }
171 }
172
173 if (iter == last) {
174 /* we are done - checking only the inserted nodes */
175 break;
176 }
177 }
178
179 return EXIT_SUCCESS;
180}
181
182API int
183lyd_unlink(struct lyd_node *node)
184{
185 struct lyd_node *iter;
186
187 if (!node) {
188 ly_errno = LY_EINVAL;
189 return EXIT_FAILURE;
190 }
191
192 /* unlink from siblings */
193 if (node->prev->next) {
194 node->prev->next = node->next;
195 }
196 if (node->next) {
197 node->next->prev = node->prev;
198 } else {
199 /* unlinking the last node */
200 iter = node->prev;
201 while (iter->prev != node) {
202 iter = iter->prev;
203 }
204 /* update the "last" pointer from the first node */
205 iter->prev = node->prev;
206 }
207
208 /* unlink from parent */
209 if (node->parent) {
210 if (node->parent->child == node) {
211 /* the node is the first child */
212 node->parent->child = node->next;
213 }
214 node->parent = NULL;
215 }
216
217 node->next = NULL;
218 node->prev = node;
219
220 return EXIT_SUCCESS;
221}
222
223static void
224lyd_attr_free(struct ly_ctx *ctx, struct lyd_attr *attr)
225{
226 if (!attr) {
227 return;
228 }
229
230 if (attr->next) {
231 lyd_attr_free(ctx, attr->next);
232 }
233 lydict_remove(ctx, attr->name);
234 lydict_remove(ctx, attr->value);
235 free(attr);
236}
237
238API void
239lyd_free(struct lyd_node *node)
240{
241 struct lyd_node *next, *child;
242
243 if (!node) {
244 return;
245 }
246
247 if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
248 /* free children */
249 LY_TREE_FOR_SAFE(node->child, next, child) {
250 lyd_free(child);
251 }
252 } else if (node->schema->nodetype == LYS_ANYXML) {
253 lyxml_free_elem(node->schema->module->ctx, ((struct lyd_node_anyxml *)node)->value);
254 } else {
255 /* free value */
256 switch(((struct lyd_node_leaf *)node)->value_type) {
257 case LY_TYPE_BINARY:
258 case LY_TYPE_STRING:
259 lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf *)node)->value.string);
260 break;
261 case LY_TYPE_BITS:
262 if (((struct lyd_node_leaf *)node)->value.bit) {
263 free(((struct lyd_node_leaf *)node)->value.bit);
264 }
265 break;
266 default:
267 /* TODO nothing needed : LY_TYPE_BOOL, LY_TYPE_DEC64*/
268 break;
269 }
270 }
271
272 lyd_unlink(node);
273 lyd_attr_free(node->schema->module->ctx, node->attr);
274 free(node);
275}
276
277int
278lyd_compare(struct lyd_node *first, struct lyd_node *second, int unique)
279{
280 struct lys_node_list *slist;
281 struct lys_node *snode;
282 struct lyd_node *diter;
283 const char *val1, *val2;
284 int i, j;
285
286 assert(first);
287 assert(second);
288
289 if (first->schema != second->schema) {
290 return 1;
291 }
292
293 switch (first->schema->nodetype) {
294 case LYS_LEAFLIST:
295 /* compare values */
296 if (((struct lyd_node_leaflist *)first)->value_str == ((struct lyd_node_leaflist *)second)->value_str) {
297 return 0;
298 }
299 return 1;
300 case LYS_LIST:
301 slist = (struct lys_node_list*)first->schema;
302
303 if (unique) {
304 /* compare unique leafs */
305 for (i = 0; i < slist->unique_size; i++) {
306 for (j = 0; j < slist->unique[i].leafs_size; j++) {
307 snode = (struct lys_node *)slist->unique[i].leafs[j];
308 /* use default values if the instances of unique leafs are not present */
309 val1 = val2 = ((struct lys_node_leaf *)snode)->dflt;
310 LY_TREE_FOR(first->child, diter) {
311 if (diter->schema == snode) {
312 val1 = ((struct lyd_node_leaf *)diter)->value_str;
313 break;
314 }
315 }
316 LY_TREE_FOR(second->child, diter) {
317 if (diter->schema == snode) {
318 val2 = ((struct lyd_node_leaf *)diter)->value_str;
319 break;
320 }
321 }
322 if (val1 != val2) {
323 break;
324 }
325 }
326 if (j && j == slist->unique[i].leafs_size) {
327 /* all unique leafs are the same in this set */
328 return 0;
329 }
330 }
331 }
332
333 /* compare keys */
334 for (i = 0; i < slist->keys_size; i++) {
335 snode = (struct lys_node *)slist->keys[i];
336 val1 = val2 = NULL;
337 LY_TREE_FOR(first->child, diter) {
338 if (diter->schema == snode) {
339 val1 = ((struct lyd_node_leaf *)diter)->value_str;
340 break;
341 }
342 }
343 LY_TREE_FOR(second->child, diter) {
344 if (diter->schema == snode) {
345 val2 = ((struct lyd_node_leaf *)diter)->value_str;
346 break;
347 }
348 }
349 if (val1 != val2) {
350 return 1;
351 }
352 }
353
354 return 0;
355 default:
356 /* no additional check is needed */
357 return 0;
358 }
359}
360
361API struct lyd_set *
362lyd_set_new(void)
363{
364 return calloc(1, sizeof(struct lyd_set));
365}
366
367API void
368lyd_set_free(struct lyd_set *set)
369{
370 if (!set) {
371 return;
372 }
373
374 free(set->set);
375 free(set);
376}
377
378API int
379lyd_set_add(struct lyd_set *set, struct lyd_node *node)
380{
381 struct lyd_node **new;
382
383 if (!set) {
384 ly_errno = LY_EINVAL;
385 return EXIT_FAILURE;
386 }
387
388 if (set->size == set->number) {
389 new = realloc(set->set, (set->size + 8) * sizeof *(set->set));
390 if (!new) {
391 LOGMEM;
392 return EXIT_FAILURE;
393 }
394 set->size += 8;
395 set->set = new;
396 }
397
398 set->set[set->number++] = node;
399
400 return EXIT_SUCCESS;
401}