blob: 1337abfcf053ea982fd55b765b910b6a2231d721 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file tree_data_free.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Freeing functions for data tree structures
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#include "common.h"
16
17#include <assert.h>
18#include <stdlib.h>
19
20#include "hash_table.h"
21#include "log.h"
22#include "tree.h"
23#include "tree_data.h"
24#include "tree_schema.h"
25#include "tree_data_internal.h"
26
27API LY_ERR
28lyd_unlink_tree(struct lyd_node *node)
29{
30 struct lyd_node *iter;
31 struct lyd_node **first_sibling;
32
33 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
34
35 if (node->parent) {
36 first_sibling = lyd_node_children_p((struct lyd_node*)node->parent);
37 }
38
39 /* unlink from siblings */
40 if (node->prev->next) {
41 node->prev->next = node->next;
42 }
43 if (node->next) {
44 node->next->prev = node->prev;
45 } else {
46 /* unlinking the last node */
47 if (node->parent) {
48 iter = *first_sibling;
49 } else {
50 iter = node->prev;
51 while (iter->prev != node) {
52 iter = iter->prev;
53 }
54 }
55 /* update the "last" pointer from the first node */
56 iter->prev = node->prev;
57 }
58
59 /* unlink from parent */
60 if (node->parent) {
61 if (*first_sibling == node) {
62 /* the node is the first child */
63 *first_sibling = node->next;
64 }
65 lyd_unlink_hash(node);
66 node->parent = NULL;
67 }
68
69 node->next = NULL;
70 node->prev = node;
71
72 return EXIT_SUCCESS;
73}
74
75/**
76 * @brief Free the YANG data value content.
77 * @param[in] ctx libyang context
78 * @param[in] value Data value structure to clean - since it is mostly part of other structure, only content is freed.
79 */
80static void
81lyd_free_value(struct ly_ctx *ctx, struct lyd_value *value)
82{
83 FREE_STRING(ctx, value->canonized);
84}
85
86API void
87lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive)
88{
89 struct lyd_attr *iter;
90
91 LY_CHECK_ARG_RET(NULL, ctx, );
92 if (!attr) {
93 return;
94 }
95
96 if (attr->parent) {
97 if (attr->parent->attr == attr) {
98 if (recursive) {
99 attr->parent->attr = NULL;
100 } else {
101 attr->parent->attr = attr->next;
102 }
103 } else {
104 for (iter = attr->parent->attr; iter->next != attr; iter = iter->next);
105 if (iter->next) {
106 if (recursive) {
107 iter->next = NULL;
108 } else {
109 iter->next = attr->next;
110 }
111 }
112 }
113 }
114
115 if (!recursive) {
116 attr->next = NULL;
117 }
118
119 for(iter = attr; iter; ) {
120 attr = iter;
121 iter = iter->next;
122
123 FREE_STRING(ctx, attr->name);
124 lyd_free_value(ctx, &attr->value);
125 free(attr);
126 }
127}
128
129/**
130 * @brief Free Data (sub)tree.
131 * @param[in] ctx libyang context.
132 * @param[in] node Data node to be freed.
133 * @param[in] top Recursion flag to unlink the root of the subtree being freed.
134 */
135static void
136lyd_free_subtree(struct ly_ctx *ctx, struct lyd_node *node, int top)
137{
138 struct lyd_node *iter, *next;
139 struct lyd_node *children;
140
141 assert(node);
142
143 /* remove children hash table in case of inner data node */
144 if (node->schema->nodetype & LYD_NODE_INNER) {
145 lyht_free(((struct lyd_node_inner*)node)->children_ht);
146 ((struct lyd_node_inner*)node)->children_ht = NULL;
147
148 /* free the children */
149 children = (struct lyd_node*)lyd_node_children(node);
150 LY_LIST_FOR_SAFE(children, next, iter) {
151 lyd_free_subtree(ctx, iter, 0);
152 }
153 } else if (node->schema->nodetype & LYD_NODE_ANY) {
154 /* TODO anydata */
155#if 0
156 switch (((struct lyd_node_anydata *)node)->value_type) {
157 case LYD_ANYDATA_CONSTSTRING:
158 case LYD_ANYDATA_SXML:
159 case LYD_ANYDATA_JSON:
160 FREE_STRING(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.str);
161 break;
162 case LYD_ANYDATA_DATATREE:
163 lyd_free_withsiblings(((struct lyd_node_anydata *)node)->value.tree);
164 break;
165 case LYD_ANYDATA_XML:
166 lyxml_free_withsiblings(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.xml);
167 break;
168 case LYD_ANYDATA_LYB:
169 free(((struct lyd_node_anydata *)node)->value.mem);
170 break;
171 case LYD_ANYDATA_STRING:
172 case LYD_ANYDATA_SXMLD:
173 case LYD_ANYDATA_JSOND:
174 case LYD_ANYDATA_LYBD:
175 /* dynamic strings are used only as input parameters */
176 assert(0);
177 break;
178 }
179#endif
180 } else if (node->schema->nodetype & LYD_NODE_TERM) {
181 lyd_free_value(ctx, &((struct lyd_node_term*)node)->value);
182 }
183
184 /* free the node's attributes */
185 lyd_free_attr(ctx, node->attr, 1);
186
187 /* unlink only the nodes from the first level, nodes in subtree are freed all, so no unlink is needed */
188 if (top) {
189 lyd_unlink_tree(node);
190 }
191
192 free(node);
193}
194
195API void
196lyd_free_tree(struct lyd_node *node)
197{
198 if (!node) {
199 return;
200 }
201
202 lyd_free_subtree(node->schema->module->ctx, node, 1);
203}
204
205API void
206lyd_free_all(struct lyd_node *node)
207{
208 struct lyd_node *iter, *next;
209
210 if (!node) {
211 return;
212 }
213
214 /* get the first top-level sibling */
215 for (; node->parent; node = (struct lyd_node*)node->parent);
216 while (node->prev->next) {
217 node = node->prev;
218 }
219
220 LY_LIST_FOR_SAFE(node, next, iter) {
221 /* in case of the top-level nodes (node->parent is NULL), no unlinking needed */
222 lyd_free_subtree(node->schema->module->ctx, node, node->parent ? 1 : 0);
223 }
224}