blob: 9d2d7a03ac1a1f45dff35a9598c7390c1455ed88 [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"
Radek Krejci849a62a2019-05-22 15:29:05 +020026#include "plugins_types.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020027
Radek Krejci084289f2019-07-09 17:35:30 +020028void
29lyd_value_free_path(struct ly_ctx *ctx, struct lyd_value_path *path)
30{
31 unsigned int u, v;
32
33 LY_ARRAY_FOR(path, u) {
34 LY_ARRAY_FOR(path[u].predicates, v) {
35 if (path[u].predicates[v].type > 0) {
Radek Krejci62903c32019-07-15 14:42:05 +020036 ((struct lysc_node_leaf*)path[u].predicates[v].key)->type->plugin->free(ctx, path[u].predicates[v].value);
Radek Krejci084289f2019-07-09 17:35:30 +020037 free(path[u].predicates[v].value);
38 }
39 }
40 LY_ARRAY_FREE(path[u].predicates);
41 }
42 LY_ARRAY_FREE(path);
43}
44
Radek Krejcie7b95092019-05-15 11:03:07 +020045API LY_ERR
46lyd_unlink_tree(struct lyd_node *node)
47{
48 struct lyd_node *iter;
49 struct lyd_node **first_sibling;
50
51 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
52
53 if (node->parent) {
54 first_sibling = lyd_node_children_p((struct lyd_node*)node->parent);
55 }
56
57 /* unlink from siblings */
58 if (node->prev->next) {
59 node->prev->next = node->next;
60 }
61 if (node->next) {
62 node->next->prev = node->prev;
63 } else {
64 /* unlinking the last node */
65 if (node->parent) {
66 iter = *first_sibling;
67 } else {
68 iter = node->prev;
69 while (iter->prev != node) {
70 iter = iter->prev;
71 }
72 }
73 /* update the "last" pointer from the first node */
74 iter->prev = node->prev;
75 }
76
77 /* unlink from parent */
78 if (node->parent) {
79 if (*first_sibling == node) {
80 /* the node is the first child */
81 *first_sibling = node->next;
82 }
83 lyd_unlink_hash(node);
84 node->parent = NULL;
85 }
86
87 node->next = NULL;
88 node->prev = node;
89
90 return EXIT_SUCCESS;
91}
92
Radek Krejcie7b95092019-05-15 11:03:07 +020093API void
94lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive)
95{
96 struct lyd_attr *iter;
97
98 LY_CHECK_ARG_RET(NULL, ctx, );
99 if (!attr) {
100 return;
101 }
102
103 if (attr->parent) {
104 if (attr->parent->attr == attr) {
105 if (recursive) {
106 attr->parent->attr = NULL;
107 } else {
108 attr->parent->attr = attr->next;
109 }
110 } else {
111 for (iter = attr->parent->attr; iter->next != attr; iter = iter->next);
112 if (iter->next) {
113 if (recursive) {
114 iter->next = NULL;
115 } else {
116 iter->next = attr->next;
117 }
118 }
119 }
120 }
121
122 if (!recursive) {
123 attr->next = NULL;
124 }
125
126 for(iter = attr; iter; ) {
127 attr = iter;
128 iter = iter->next;
129
130 FREE_STRING(ctx, attr->name);
Radek Krejci73dead22019-07-11 16:46:16 +0200131 /* TODO type->plugin->free(ctx, type, &attr->value); */
Radek Krejcie7b95092019-05-15 11:03:07 +0200132 free(attr);
133 }
134}
135
136/**
137 * @brief Free Data (sub)tree.
138 * @param[in] ctx libyang context.
139 * @param[in] node Data node to be freed.
140 * @param[in] top Recursion flag to unlink the root of the subtree being freed.
141 */
142static void
143lyd_free_subtree(struct ly_ctx *ctx, struct lyd_node *node, int top)
144{
145 struct lyd_node *iter, *next;
146 struct lyd_node *children;
147
148 assert(node);
149
150 /* remove children hash table in case of inner data node */
151 if (node->schema->nodetype & LYD_NODE_INNER) {
152 lyht_free(((struct lyd_node_inner*)node)->children_ht);
153 ((struct lyd_node_inner*)node)->children_ht = NULL;
154
155 /* free the children */
156 children = (struct lyd_node*)lyd_node_children(node);
157 LY_LIST_FOR_SAFE(children, next, iter) {
158 lyd_free_subtree(ctx, iter, 0);
159 }
160 } else if (node->schema->nodetype & LYD_NODE_ANY) {
Radek Krejciee4cab22019-07-17 17:07:47 +0200161 switch (((struct lyd_node_any*)node)->value_type) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200162 case LYD_ANYDATA_DATATREE:
Radek Krejciee4cab22019-07-17 17:07:47 +0200163 lyd_free_all(((struct lyd_node_any*)node)->value.tree);
Radek Krejcie7b95092019-05-15 11:03:07 +0200164 break;
165 case LYD_ANYDATA_STRING:
Radek Krejciee4cab22019-07-17 17:07:47 +0200166 case LYD_ANYDATA_XML:
167 case LYD_ANYDATA_JSON:
168 FREE_STRING(node->schema->module->ctx, ((struct lyd_node_any*)node)->value.str);
169 break;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200170#if 0 /* TODO LYB format */
Radek Krejciee4cab22019-07-17 17:07:47 +0200171 case LYD_ANYDATA_LYB:
172 free(((struct lyd_node_any*)node)->value.mem);
Radek Krejcie7b95092019-05-15 11:03:07 +0200173 break;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200174#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200175 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200176 } else if (node->schema->nodetype & LYD_NODE_TERM) {
Radek Krejci62903c32019-07-15 14:42:05 +0200177 ((struct lysc_node_leaf*)node->schema)->type->plugin->free(ctx, &((struct lyd_node_term*)node)->value);
Radek Krejcie7b95092019-05-15 11:03:07 +0200178 }
179
180 /* free the node's attributes */
181 lyd_free_attr(ctx, node->attr, 1);
182
183 /* unlink only the nodes from the first level, nodes in subtree are freed all, so no unlink is needed */
184 if (top) {
185 lyd_unlink_tree(node);
186 }
187
188 free(node);
189}
190
191API void
192lyd_free_tree(struct lyd_node *node)
193{
194 if (!node) {
195 return;
196 }
197
198 lyd_free_subtree(node->schema->module->ctx, node, 1);
199}
200
201API void
202lyd_free_all(struct lyd_node *node)
203{
204 struct lyd_node *iter, *next;
205
206 if (!node) {
207 return;
208 }
209
210 /* get the first top-level sibling */
211 for (; node->parent; node = (struct lyd_node*)node->parent);
212 while (node->prev->next) {
213 node = node->prev;
214 }
215
216 LY_LIST_FOR_SAFE(node, next, iter) {
217 /* in case of the top-level nodes (node->parent is NULL), no unlinking needed */
Radek Krejci35676302019-05-17 10:50:57 +0200218 lyd_free_subtree(iter->schema->module->ctx, iter, iter->parent ? 1 : 0);
Radek Krejcie7b95092019-05-15 11:03:07 +0200219 }
220}