blob: a3ea03e3ffd5590644def8155f38b75e55c7bcf1 [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file tree.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
Radek Krejci812b10a2015-05-28 16:48:25 +020022#include <assert.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020023#include <stdlib.h>
24#include <sys/mman.h>
25#include <sys/stat.h>
26
27#include "common.h"
28#include "context.h"
Radek Krejci3045cf32015-05-28 10:58:52 +020029#include "parser.h"
Radek Krejciefaeba32015-05-27 14:30:57 +020030
31void ly_submodule_free(struct ly_submodule *submodule);
32
Radek Krejcida04f4a2015-05-21 12:54:09 +020033
34void ly_mnode_unlink(struct ly_mnode *node)
35{
36 struct ly_mnode *parent, *first;
37
38 if (!node) {
39 return;
40 }
41
42 /* unlink from data model if necessary */
43 if (node->module) {
44 if (node->module->data == node) {
45 node->module->data = node->next;
46 }
47 }
48
49 /* store pointers to important nodes */
50 parent = node->parent;
51
52 /* unlink from parent */
53 if (parent) {
54 if (parent->child == node) {
55 parent->child = node->next;
56 }
57 node->parent = NULL;
58 }
59
60 /* unlink from siblings */
61 if (node->prev == node) {
62 /* there are no more siblings */
Radek Krejcida04f4a2015-05-21 12:54:09 +020063 return;
64 }
65 if (node->next) {
66 node->next->prev = node->prev;
67 } else {
68 /* unlinking the last element */
69 if (parent) {
70 first = parent->child;
71 } else {
72 first = node;
73 while (node->prev->next) {
74 first = node->prev;
75 }
76 }
77 first->prev = node->prev;
78 }
79 if (node->prev->next) {
80 node->prev->next = node->next;
81 }
82
83 /* clean up the unlinked element */
84 node->next = NULL;
85 node->prev = node;
Radek Krejcida04f4a2015-05-21 12:54:09 +020086}
87
88/*
89 * Add child model node at the end of the parent's child list.
90 * If the child is connected somewhere (has a parent), it is completely
91 * unlinked and none of the following conditions applies.
92 * If the child has prev sibling(s), they are ignored (child is added at the
93 * end of the child list).
94 * If the child has next sibling(s), all of them are connected with the parent.
95 */
96int ly_mnode_addchild(struct ly_mnode *parent, struct ly_mnode *child)
97{
98 struct ly_mnode *last;
99
Radek Krejci812b10a2015-05-28 16:48:25 +0200100 assert(parent);
101 assert(child);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200102
103 if (child->parent) {
104 ly_mnode_unlink(child);
105 }
106
107 if (!parent->child) {
108 /* the only/first child of the parent */
109 parent->child = child;
110 child->parent = parent;
111 return EXIT_SUCCESS;
112 }
113
114 /* add a new child at the end of parent's child list */
115 last = parent->child->prev;
116 last->next = child;
117 child->prev = last;
118 while (last->next) {
119 last = last->next;
120 last->parent = parent;
121 }
122 parent->child->prev = last;
123
124 return EXIT_SUCCESS;
125}
126
Radek Krejciefaeba32015-05-27 14:30:57 +0200127API struct ly_module *ly_module_read(struct ly_ctx *ctx, const char *data,
Radek Krejcida04f4a2015-05-21 12:54:09 +0200128 LY_MFORMAT format)
129{
130 if (!ctx || !data) {
Radek Krejci812b10a2015-05-28 16:48:25 +0200131 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200132 return NULL;
133 }
134
135 switch (format) {
136 case LY_YIN:
Radek Krejciefaeba32015-05-27 14:30:57 +0200137 return yin_read_module(ctx, data);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200138 case LY_YANG:
Radek Krejci5a065542015-05-22 15:02:07 +0200139 default:
Radek Krejcida04f4a2015-05-21 12:54:09 +0200140 /* TODO */
141 return NULL;
142 }
143
144 return NULL;
145}
146
Radek Krejciefaeba32015-05-27 14:30:57 +0200147struct ly_submodule *ly_submodule_read(struct ly_module *module,
148 const char *data, LY_MFORMAT format)
149{
Radek Krejci812b10a2015-05-28 16:48:25 +0200150 assert(module);
151 assert(data);
Radek Krejciefaeba32015-05-27 14:30:57 +0200152
153 switch (format) {
154 case LY_YIN:
155 return yin_read_submodule(module, data);
156 case LY_YANG:
157 default:
158 /* TODO */
159 return NULL;
160 }
161
162 return NULL;
163}
164
165API struct ly_module *ly_module_read_fd(struct ly_ctx *ctx, int fd,
Radek Krejcida04f4a2015-05-21 12:54:09 +0200166 LY_MFORMAT format)
167{
168 struct ly_module *module;
169 struct stat sb;
170 char *addr;
171
172 if (!ctx || fd < 0) {
Radek Krejci812b10a2015-05-28 16:48:25 +0200173 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200174 return NULL;
175 }
176
177 /*
178 * TODO
179 * This is just a temporary solution to make working automatic search for
180 * imported modules. This doesn't work e.g. for streams (stdin)
181 */
182 fstat(fd, &sb);
183 addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
Radek Krejciefaeba32015-05-27 14:30:57 +0200184 module = ly_module_read(ctx, addr, format);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200185 munmap(addr, sb.st_size);
186
187 return module;
188}
189
Radek Krejciefaeba32015-05-27 14:30:57 +0200190struct ly_submodule *ly_submodule_read_fd(struct ly_module *module, int fd,
191 LY_MFORMAT format)
192{
193 struct ly_submodule *submodule;
194 struct stat sb;
195 char *addr;
196
Radek Krejci812b10a2015-05-28 16:48:25 +0200197 assert(module);
198 assert(fd >= 0);
Radek Krejciefaeba32015-05-27 14:30:57 +0200199
200 /*
201 * TODO
202 * This is just a temporary solution to make working automatic search for
203 * imported modules. This doesn't work e.g. for streams (stdin)
204 */
205 fstat(fd, &sb);
206 addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
Radek Krejci812b10a2015-05-28 16:48:25 +0200207 /* TODO addr error check */
Radek Krejciefaeba32015-05-27 14:30:57 +0200208 submodule = ly_submodule_read(module, addr, format);
209 munmap(addr, sb.st_size);
210
211 return submodule;
212
213}
214
Radek Krejci5a065542015-05-22 15:02:07 +0200215void ly_type_free(struct ly_ctx *ctx, struct ly_type *type)
216{
217 int i;
218
Radek Krejci812b10a2015-05-28 16:48:25 +0200219 assert(ctx);
220 if (!type) {
221 return;
222 }
223
Radek Krejci5a065542015-05-22 15:02:07 +0200224 lydict_remove(ctx, type->prefix);
225
226 switch(type->base) {
227 case LY_TYPE_ENUM:
228 for (i = 0; i < type->info.enums.count; i++) {
229 lydict_remove(ctx, type->info.enums.list[i].name);
230 lydict_remove(ctx, type->info.enums.list[i].dsc);
231 lydict_remove(ctx, type->info.enums.list[i].ref);
232 }
233 free(type->info.enums.list);
234 break;
235 default:
236 /* TODO */
237 break;
238 }
239}
240
Radek Krejcida04f4a2015-05-21 12:54:09 +0200241void ly_tpdf_free(struct ly_ctx *ctx, struct ly_tpdf *tpdf)
242{
Radek Krejci812b10a2015-05-28 16:48:25 +0200243 assert(ctx);
244 if (!tpdf) {
245 return;
246 }
247
Radek Krejcida04f4a2015-05-21 12:54:09 +0200248 lydict_remove(ctx, tpdf->name);
249 lydict_remove(ctx, tpdf->dsc);
250 lydict_remove(ctx, tpdf->ref);
251
Radek Krejci5a065542015-05-22 15:02:07 +0200252 ly_type_free(ctx, &tpdf->type);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200253}
254
Radek Krejci800af702015-06-02 13:46:01 +0200255void ly_must_free(struct ly_ctx *ctx, struct ly_must *must)
256{
257 assert(ctx);
258 if (!must) {
259 return;
260 }
261
262 lydict_remove(ctx, must->cond);
263 lydict_remove(ctx, must->dsc);
264 lydict_remove(ctx, must->ref);
265 lydict_remove(ctx, must->eapptag);
266 lydict_remove(ctx, must->emsg);
267}
268
Radek Krejci6793db02015-05-22 17:49:54 +0200269void ly_ident_free(struct ly_ctx *ctx, struct ly_ident *ident)
270{
271 struct ly_ident_der *der;
272
Radek Krejci812b10a2015-05-28 16:48:25 +0200273 assert(ctx);
274 if (!ident) {
275 return;
276 }
277
Radek Krejci6793db02015-05-22 17:49:54 +0200278 /*
279 * TODO
280 * if caller free only a single data model which is used (its identity is
281 * reference from identity in another module), this silly freeing can lead
282 * to segmentation fault. But without noting if the module is used by some
283 * other, it cannot be solved.
284 */
285 while(ident->der) {
286 der = ident->der;
287 ident->der = der->next;
288 free(der);
289 }
290
291 lydict_remove(ctx, ident->name);
292 lydict_remove(ctx, ident->dsc);
293 lydict_remove(ctx, ident->ref);
294
295}
296
Radek Krejcida04f4a2015-05-21 12:54:09 +0200297void ly_grp_free(struct ly_ctx *ctx, struct ly_mnode_grp *grp)
298{
299 int i;
300
301 /* handle only specific parts for LY_NODE_GROUPING */
302 if (grp->tpdf_size) {
303 for (i = 0; i < grp->tpdf_size; i++) {
304 ly_tpdf_free(ctx, &grp->tpdf[i]);
305 }
306 free(grp->tpdf);
307 }
308}
309
Radek Krejci5a065542015-05-22 15:02:07 +0200310void ly_leaf_free(struct ly_ctx *ctx, struct ly_mnode_leaf *leaf)
311{
312 ly_type_free(ctx, &leaf->type);
313}
314
315void ly_leaflist_free(struct ly_ctx *ctx, struct ly_mnode_leaflist *llist)
316{
317 ly_type_free(ctx, &llist->type);
318}
319
Radek Krejcida04f4a2015-05-21 12:54:09 +0200320void ly_list_free(struct ly_ctx *ctx, struct ly_mnode_list *list)
321{
322 int i;
323
324 /* handle only specific parts for LY_NODE_LIST */
325 if (list->tpdf_size) {
326 for (i = 0; i < list->tpdf_size; i++) {
327 ly_tpdf_free(ctx, &list->tpdf[i]);
328 }
329 free(list->tpdf);
330 }
Radek Krejcid7f0d012015-05-25 15:04:52 +0200331
332 free(list->keys);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200333}
334
335void ly_container_free(struct ly_ctx *ctx, struct ly_mnode_container *cont)
336{
337 int i;
338
339 /* handle only specific parts for LY_NODE_CONTAINER */
Radek Krejci800af702015-06-02 13:46:01 +0200340 lydict_remove(ctx, cont->presence);
341
Radek Krejcida04f4a2015-05-21 12:54:09 +0200342 if (cont->tpdf_size) {
343 for (i = 0; i < cont->tpdf_size; i++) {
344 ly_tpdf_free(ctx, &cont->tpdf[i]);
345 }
346 free(cont->tpdf);
347 }
Radek Krejci800af702015-06-02 13:46:01 +0200348
349 if (cont->must_size) {
350 for (i = 0; i < cont->must_size; i++) {
351 ly_must_free(ctx, &cont->must[i]);
352 }
353 free(cont->tpdf);
354 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200355}
356
357void ly_mnode_free(struct ly_mnode *node)
358{
359 struct ly_ctx *ctx;
360 struct ly_mnode *sub, *next;
361
362 if (!node) {
363 return;
364 }
365
Radek Krejci812b10a2015-05-28 16:48:25 +0200366 assert(node->module);
367 assert(node->module->ctx);
368
Radek Krejcida04f4a2015-05-21 12:54:09 +0200369 ctx = node->module->ctx;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200370
371 /* common part */
372 LY_TREE_FOR_SAFE(node->child, next, sub) {
373 ly_mnode_free(sub);
374 }
375
376 lydict_remove(ctx, node->name);
377 lydict_remove(ctx, node->dsc);
378 lydict_remove(ctx, node->ref);
379
380 /* specific part */
381 switch(node->nodetype) {
382 case LY_NODE_CONTAINER:
383 ly_container_free(ctx, (struct ly_mnode_container *)node);
384 break;
385 case LY_NODE_CHOICE:
386 break;
387 case LY_NODE_LEAF:
Radek Krejci5a065542015-05-22 15:02:07 +0200388 ly_leaf_free(ctx, (struct ly_mnode_leaf *)node);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200389 break;
390 case LY_NODE_LEAFLIST:
Radek Krejci5a065542015-05-22 15:02:07 +0200391 ly_leaflist_free(ctx, (struct ly_mnode_leaflist *)node);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200392 break;
393 case LY_NODE_LIST:
394 ly_list_free(ctx, (struct ly_mnode_list *)node);
395 break;
396 case LY_NODE_ANYXML:
397 break;
398 case LY_NODE_USES:
399 break;
400 case LY_NODE_GROUPING:
401 ly_grp_free(ctx, (struct ly_mnode_grp *)node);
402 break;
Radek Krejcib4cf2022015-06-03 14:40:05 +0200403 case LY_NODE_CASE:
404 break;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200405 }
Radek Krejci5a065542015-05-22 15:02:07 +0200406
407 /* again common part */
408 ly_mnode_unlink(node);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200409 free(node);
410}
411
Radek Krejciefaeba32015-05-27 14:30:57 +0200412static void module_free_common(struct ly_module *module)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200413{
414 struct ly_ctx *ctx;
415 struct ly_mnode *mnode;
Radek Krejcice7fb782015-05-29 16:52:34 +0200416 unsigned int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200417
Radek Krejci812b10a2015-05-28 16:48:25 +0200418 assert(module->ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200419 ctx = module->ctx;
420
Radek Krejciefaeba32015-05-27 14:30:57 +0200421 while (module->data) {
Radek Krejci5a065542015-05-22 15:02:07 +0200422 mnode = module->data;
423 module->data = mnode;
424 ly_mnode_free(mnode);
425 }
426
Radek Krejcida04f4a2015-05-21 12:54:09 +0200427 lydict_remove(ctx, module->dsc);
428 lydict_remove(ctx, module->ref);
429 lydict_remove(ctx, module->org);
430 lydict_remove(ctx, module->contact);
431
Radek Krejcice7fb782015-05-29 16:52:34 +0200432 for (i = 0; i < module->rev_size; i++) {
433 lydict_remove(ctx, module->rev[i].dsc);
434 lydict_remove(ctx, module->rev[i].ref);
435 }
436 if (module->rev) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200437 free(module->rev);
438 }
439
Radek Krejcice7fb782015-05-29 16:52:34 +0200440 for (i = 0; i < module->ident_size; i++) {
441 ly_ident_free(ctx, &module->ident[i]);
442 }
443 module->ident_size = 0;
444 if (module->ident) {
Radek Krejci6793db02015-05-22 17:49:54 +0200445 free(module->ident);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200446 }
447
Radek Krejcice7fb782015-05-29 16:52:34 +0200448 for (i = 0; i < module->tpdf_size; i++) {
449 ly_tpdf_free(ctx, &module->tpdf[i]);
450 }
451 if (module->tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200452 free(module->tpdf);
453 }
454
Radek Krejcice7fb782015-05-29 16:52:34 +0200455 if (module->imp) {
Radek Krejci6793db02015-05-22 17:49:54 +0200456 free(module->imp);
457 }
458
Radek Krejcice7fb782015-05-29 16:52:34 +0200459 for (i = 0; i < module->inc_size; i++) {
460 ly_submodule_free(module->inc[i].submodule);
461 }
462 if (module->inc) {
Radek Krejciefaeba32015-05-27 14:30:57 +0200463 free(module->inc);
464 }
465
Radek Krejci6793db02015-05-22 17:49:54 +0200466 lydict_remove(ctx, module->name);
Radek Krejciefaeba32015-05-27 14:30:57 +0200467}
468
469void ly_submodule_free(struct ly_submodule *submodule)
470{
471 if (!submodule) {
472 return;
473 }
474
475 /* common part with struct ly_module */
476 module_free_common((struct ly_module *)submodule);
477
478 /* no specific items to free */
479
480 free(submodule);
481}
482
483API void ly_module_free(struct ly_module *module)
484{
485 if (!module) {
486 return;
487 }
488
489 /* common part with struct ly_submodule */
490 module_free_common(module);
491
492 /* specific items to free */
493 lydict_remove(module->ctx, module->ns);
494 lydict_remove(module->ctx, module->prefix);
Radek Krejci6793db02015-05-22 17:49:54 +0200495
Radek Krejcida04f4a2015-05-21 12:54:09 +0200496 free(module);
497}
498
499