data tree FEATURE initial implementation of YANG data support
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
new file mode 100644
index 0000000..1337abf
--- /dev/null
+++ b/src/tree_data_free.c
@@ -0,0 +1,224 @@
+/**
+ * @file tree_data_free.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Freeing functions for data tree structures
+ *
+ * Copyright (c) 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "common.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "hash_table.h"
+#include "log.h"
+#include "tree.h"
+#include "tree_data.h"
+#include "tree_schema.h"
+#include "tree_data_internal.h"
+
+API LY_ERR
+lyd_unlink_tree(struct lyd_node *node)
+{
+    struct lyd_node *iter;
+    struct lyd_node **first_sibling;
+
+    LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
+
+    if (node->parent) {
+        first_sibling = lyd_node_children_p((struct lyd_node*)node->parent);
+    }
+
+    /* unlink from siblings */
+    if (node->prev->next) {
+        node->prev->next = node->next;
+    }
+    if (node->next) {
+        node->next->prev = node->prev;
+    } else {
+        /* unlinking the last node */
+        if (node->parent) {
+            iter = *first_sibling;
+        } else {
+            iter = node->prev;
+            while (iter->prev != node) {
+                iter = iter->prev;
+            }
+        }
+        /* update the "last" pointer from the first node */
+        iter->prev = node->prev;
+    }
+
+    /* unlink from parent */
+    if (node->parent) {
+        if (*first_sibling == node) {
+            /* the node is the first child */
+            *first_sibling = node->next;
+        }
+        lyd_unlink_hash(node);
+        node->parent = NULL;
+    }
+
+    node->next = NULL;
+    node->prev = node;
+
+    return EXIT_SUCCESS;
+}
+
+/**
+ * @brief Free the YANG data value content.
+ * @param[in] ctx libyang context
+ * @param[in] value Data value structure to clean - since it is mostly part of other structure, only content is freed.
+ */
+static void
+lyd_free_value(struct ly_ctx *ctx, struct lyd_value *value)
+{
+    FREE_STRING(ctx, value->canonized);
+}
+
+API void
+lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive)
+{
+    struct lyd_attr *iter;
+
+    LY_CHECK_ARG_RET(NULL, ctx, );
+    if (!attr) {
+        return;
+    }
+
+    if (attr->parent) {
+        if (attr->parent->attr == attr) {
+            if (recursive) {
+                attr->parent->attr = NULL;
+            } else {
+                attr->parent->attr = attr->next;
+            }
+        } else {
+            for (iter = attr->parent->attr; iter->next != attr; iter = iter->next);
+            if (iter->next) {
+                if (recursive) {
+                    iter->next = NULL;
+                } else {
+                    iter->next = attr->next;
+                }
+            }
+        }
+    }
+
+    if (!recursive) {
+        attr->next = NULL;
+    }
+
+    for(iter = attr; iter; ) {
+        attr = iter;
+        iter = iter->next;
+
+        FREE_STRING(ctx, attr->name);
+        lyd_free_value(ctx, &attr->value);
+        free(attr);
+    }
+}
+
+/**
+ * @brief Free Data (sub)tree.
+ * @param[in] ctx libyang context.
+ * @param[in] node Data node to be freed.
+ * @param[in] top Recursion flag to unlink the root of the subtree being freed.
+ */
+static void
+lyd_free_subtree(struct ly_ctx *ctx, struct lyd_node *node, int top)
+{
+    struct lyd_node *iter, *next;
+    struct lyd_node *children;
+
+    assert(node);
+
+    /* remove children hash table in case of inner data node */
+    if (node->schema->nodetype & LYD_NODE_INNER) {
+        lyht_free(((struct lyd_node_inner*)node)->children_ht);
+        ((struct lyd_node_inner*)node)->children_ht = NULL;
+
+        /* free the children */
+        children = (struct lyd_node*)lyd_node_children(node);
+        LY_LIST_FOR_SAFE(children, next, iter) {
+            lyd_free_subtree(ctx, iter, 0);
+        }
+    } else if (node->schema->nodetype & LYD_NODE_ANY) {
+        /* TODO anydata */
+#if 0
+        switch (((struct lyd_node_anydata *)node)->value_type) {
+        case LYD_ANYDATA_CONSTSTRING:
+        case LYD_ANYDATA_SXML:
+        case LYD_ANYDATA_JSON:
+            FREE_STRING(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.str);
+            break;
+        case LYD_ANYDATA_DATATREE:
+            lyd_free_withsiblings(((struct lyd_node_anydata *)node)->value.tree);
+            break;
+        case LYD_ANYDATA_XML:
+            lyxml_free_withsiblings(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.xml);
+            break;
+        case LYD_ANYDATA_LYB:
+            free(((struct lyd_node_anydata *)node)->value.mem);
+            break;
+        case LYD_ANYDATA_STRING:
+        case LYD_ANYDATA_SXMLD:
+        case LYD_ANYDATA_JSOND:
+        case LYD_ANYDATA_LYBD:
+            /* dynamic strings are used only as input parameters */
+            assert(0);
+            break;
+        }
+#endif
+    } else if (node->schema->nodetype & LYD_NODE_TERM) {
+        lyd_free_value(ctx, &((struct lyd_node_term*)node)->value);
+    }
+
+    /* free the node's attributes */
+    lyd_free_attr(ctx, node->attr, 1);
+
+    /* unlink only the nodes from the first level, nodes in subtree are freed all, so no unlink is needed */
+    if (top) {
+        lyd_unlink_tree(node);
+    }
+
+    free(node);
+}
+
+API void
+lyd_free_tree(struct lyd_node *node)
+{
+    if (!node) {
+        return;
+    }
+
+    lyd_free_subtree(node->schema->module->ctx, node, 1);
+}
+
+API void
+lyd_free_all(struct lyd_node *node)
+{
+    struct lyd_node *iter, *next;
+
+    if (!node) {
+        return;
+    }
+
+    /* get the first top-level sibling */
+    for (; node->parent; node = (struct lyd_node*)node->parent);
+    while (node->prev->next) {
+        node = node->prev;
+    }
+
+    LY_LIST_FOR_SAFE(node, next, iter) {
+        /* in case of the top-level nodes (node->parent is NULL), no unlinking needed */
+        lyd_free_subtree(node->schema->module->ctx, node, node->parent ? 1 : 0);
+    }
+}