blob: 9fc66ec84c3963dba7b2aaa3f0c5ffbc69a071e2 [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
22#include <stdlib.h>
23#include <sys/mman.h>
24#include <sys/stat.h>
25
26#include "common.h"
27#include "context.h"
28
29void ly_mnode_unlink(struct ly_mnode *node)
30{
31 struct ly_mnode *parent, *first;
32
33 if (!node) {
34 return;
35 }
36
37 /* unlink from data model if necessary */
38 if (node->module) {
39 if (node->module->data == node) {
40 node->module->data = node->next;
41 }
42 }
43
44 /* store pointers to important nodes */
45 parent = node->parent;
46
47 /* unlink from parent */
48 if (parent) {
49 if (parent->child == node) {
50 parent->child = node->next;
51 }
52 node->parent = NULL;
53 }
54
55 /* unlink from siblings */
56 if (node->prev == node) {
57 /* there are no more siblings */
58 node->parent = NULL;
59 return;
60 }
61 if (node->next) {
62 node->next->prev = node->prev;
63 } else {
64 /* unlinking the last element */
65 if (parent) {
66 first = parent->child;
67 } else {
68 first = node;
69 while (node->prev->next) {
70 first = node->prev;
71 }
72 }
73 first->prev = node->prev;
74 }
75 if (node->prev->next) {
76 node->prev->next = node->next;
77 }
78
79 /* clean up the unlinked element */
80 node->next = NULL;
81 node->prev = node;
82 node->parent = NULL;
83}
84
85/*
86 * Add child model node at the end of the parent's child list.
87 * If the child is connected somewhere (has a parent), it is completely
88 * unlinked and none of the following conditions applies.
89 * If the child has prev sibling(s), they are ignored (child is added at the
90 * end of the child list).
91 * If the child has next sibling(s), all of them are connected with the parent.
92 */
93int ly_mnode_addchild(struct ly_mnode *parent, struct ly_mnode *child)
94{
95 struct ly_mnode *last;
96
97 if (!parent || !child) {
98 ly_errno = LY_EINVAL;
99 return EXIT_FAILURE;
100 }
101
102 if (child->parent) {
103 ly_mnode_unlink(child);
104 }
105
106 if (!parent->child) {
107 /* the only/first child of the parent */
108 parent->child = child;
109 child->parent = parent;
110 return EXIT_SUCCESS;
111 }
112
113 /* add a new child at the end of parent's child list */
114 last = parent->child->prev;
115 last->next = child;
116 child->prev = last;
117 while (last->next) {
118 last = last->next;
119 last->parent = parent;
120 }
121 parent->child->prev = last;
122
123 return EXIT_SUCCESS;
124}
125
126API struct ly_module *ly_model_read(struct ly_ctx *ctx, const char *data,
127 LY_MFORMAT format)
128{
129 if (!ctx || !data) {
130 ly_errno = LY_EINVAL;
131 return NULL;
132 }
133
134 switch (format) {
135 case LY_YIN:
136 return ly_read_yin(ctx, data);
137 case LY_YANG:
Radek Krejci5a065542015-05-22 15:02:07 +0200138 default:
Radek Krejcida04f4a2015-05-21 12:54:09 +0200139 /* TODO */
140 return NULL;
141 }
142
143 return NULL;
144}
145
146API struct ly_module *ly_model_read_fd(struct ly_ctx *ctx, int fd,
147 LY_MFORMAT format)
148{
149 struct ly_module *module;
150 struct stat sb;
151 char *addr;
152
153 if (!ctx || fd < 0) {
154 ly_errno = LY_EINVAL;
155 return NULL;
156 }
157
158 /*
159 * TODO
160 * This is just a temporary solution to make working automatic search for
161 * imported modules. This doesn't work e.g. for streams (stdin)
162 */
163 fstat(fd, &sb);
164 addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
165 module = ly_model_read(ctx, addr, format);
166 munmap(addr, sb.st_size);
167
168 return module;
169}
170
Radek Krejci5a065542015-05-22 15:02:07 +0200171void ly_type_free(struct ly_ctx *ctx, struct ly_type *type)
172{
173 int i;
174
175 lydict_remove(ctx, type->prefix);
176
177 switch(type->base) {
178 case LY_TYPE_ENUM:
179 for (i = 0; i < type->info.enums.count; i++) {
180 lydict_remove(ctx, type->info.enums.list[i].name);
181 lydict_remove(ctx, type->info.enums.list[i].dsc);
182 lydict_remove(ctx, type->info.enums.list[i].ref);
183 }
184 free(type->info.enums.list);
185 break;
186 default:
187 /* TODO */
188 break;
189 }
190}
191
Radek Krejcida04f4a2015-05-21 12:54:09 +0200192void ly_tpdf_free(struct ly_ctx *ctx, struct ly_tpdf *tpdf)
193{
194 lydict_remove(ctx, tpdf->name);
195 lydict_remove(ctx, tpdf->dsc);
196 lydict_remove(ctx, tpdf->ref);
197
Radek Krejci5a065542015-05-22 15:02:07 +0200198 ly_type_free(ctx, &tpdf->type);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200199}
200
Radek Krejci6793db02015-05-22 17:49:54 +0200201void ly_ident_free(struct ly_ctx *ctx, struct ly_ident *ident)
202{
203 struct ly_ident_der *der;
204
205 /*
206 * TODO
207 * if caller free only a single data model which is used (its identity is
208 * reference from identity in another module), this silly freeing can lead
209 * to segmentation fault. But without noting if the module is used by some
210 * other, it cannot be solved.
211 */
212 while(ident->der) {
213 der = ident->der;
214 ident->der = der->next;
215 free(der);
216 }
217
218 lydict_remove(ctx, ident->name);
219 lydict_remove(ctx, ident->dsc);
220 lydict_remove(ctx, ident->ref);
221
222}
223
Radek Krejcida04f4a2015-05-21 12:54:09 +0200224void ly_grp_free(struct ly_ctx *ctx, struct ly_mnode_grp *grp)
225{
226 int i;
227
228 /* handle only specific parts for LY_NODE_GROUPING */
229 if (grp->tpdf_size) {
230 for (i = 0; i < grp->tpdf_size; i++) {
231 ly_tpdf_free(ctx, &grp->tpdf[i]);
232 }
233 free(grp->tpdf);
234 }
235}
236
Radek Krejci5a065542015-05-22 15:02:07 +0200237void ly_leaf_free(struct ly_ctx *ctx, struct ly_mnode_leaf *leaf)
238{
239 ly_type_free(ctx, &leaf->type);
240}
241
242void ly_leaflist_free(struct ly_ctx *ctx, struct ly_mnode_leaflist *llist)
243{
244 ly_type_free(ctx, &llist->type);
245}
246
Radek Krejcida04f4a2015-05-21 12:54:09 +0200247void ly_list_free(struct ly_ctx *ctx, struct ly_mnode_list *list)
248{
249 int i;
250
251 /* handle only specific parts for LY_NODE_LIST */
252 if (list->tpdf_size) {
253 for (i = 0; i < list->tpdf_size; i++) {
254 ly_tpdf_free(ctx, &list->tpdf[i]);
255 }
256 free(list->tpdf);
257 }
258}
259
260void ly_container_free(struct ly_ctx *ctx, struct ly_mnode_container *cont)
261{
262 int i;
263
264 /* handle only specific parts for LY_NODE_CONTAINER */
265 if (cont->tpdf_size) {
266 for (i = 0; i < cont->tpdf_size; i++) {
267 ly_tpdf_free(ctx, &cont->tpdf[i]);
268 }
269 free(cont->tpdf);
270 }
271}
272
273void ly_mnode_free(struct ly_mnode *node)
274{
275 struct ly_ctx *ctx;
276 struct ly_mnode *sub, *next;
277
278 if (!node) {
279 return;
280 }
281
282 ctx = node->module->ctx;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200283
284 /* common part */
285 LY_TREE_FOR_SAFE(node->child, next, sub) {
286 ly_mnode_free(sub);
287 }
288
289 lydict_remove(ctx, node->name);
290 lydict_remove(ctx, node->dsc);
291 lydict_remove(ctx, node->ref);
292
293 /* specific part */
294 switch(node->nodetype) {
295 case LY_NODE_CONTAINER:
296 ly_container_free(ctx, (struct ly_mnode_container *)node);
297 break;
298 case LY_NODE_CHOICE:
299 break;
300 case LY_NODE_LEAF:
Radek Krejci5a065542015-05-22 15:02:07 +0200301 ly_leaf_free(ctx, (struct ly_mnode_leaf *)node);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200302 break;
303 case LY_NODE_LEAFLIST:
Radek Krejci5a065542015-05-22 15:02:07 +0200304 ly_leaflist_free(ctx, (struct ly_mnode_leaflist *)node);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200305 break;
306 case LY_NODE_LIST:
307 ly_list_free(ctx, (struct ly_mnode_list *)node);
308 break;
309 case LY_NODE_ANYXML:
310 break;
311 case LY_NODE_USES:
312 break;
313 case LY_NODE_GROUPING:
314 ly_grp_free(ctx, (struct ly_mnode_grp *)node);
315 break;
316 }
Radek Krejci5a065542015-05-22 15:02:07 +0200317
318 /* again common part */
319 ly_mnode_unlink(node);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200320 free(node);
321}
322
323API void ly_model_free(struct ly_module *module)
324{
325 struct ly_ctx *ctx;
326 struct ly_mnode *mnode;
327 int i;
328
329 if (!module) {
330 return;
331 }
332
333 ctx = module->ctx;
334
Radek Krejci5a065542015-05-22 15:02:07 +0200335 while(module->data) {
336 mnode = module->data;
337 module->data = mnode;
338 ly_mnode_free(mnode);
339 }
340
Radek Krejcida04f4a2015-05-21 12:54:09 +0200341 lydict_remove(ctx, module->dsc);
342 lydict_remove(ctx, module->ref);
343 lydict_remove(ctx, module->org);
344 lydict_remove(ctx, module->contact);
345
346 if (module->rev_size) {
347 for (i = 0; i < module->rev_size; i++) {
348 lydict_remove(ctx, module->rev[i].dsc);
349 lydict_remove(ctx, module->rev[i].ref);
350 }
351 free(module->rev);
352 }
353
Radek Krejci6793db02015-05-22 17:49:54 +0200354 if (module->ident_size) {
355 for (i = 0; i < module->ident_size; i++) {
356 ly_ident_free(ctx, &module->ident[i]);
357 }
358 free(module->ident);
359 module->ident_size = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200360 }
361
362 if (module->tpdf_size) {
363 for (i = 0; i < module->tpdf_size; i++) {
364 ly_tpdf_free(ctx, &module->tpdf[i]);
365 }
366 free(module->tpdf);
367 }
368
Radek Krejci6793db02015-05-22 17:49:54 +0200369 if (module->imp_size) {
370 free(module->imp);
371 }
372
373 lydict_remove(ctx, module->name);
374 lydict_remove(ctx, module->ns);
375 lydict_remove(ctx, module->prefix);
376
Radek Krejcida04f4a2015-05-21 12:54:09 +0200377 free(module);
378}
379
380