tree REFACTOR tree split into tree_schema and tree_data
diff --git a/src/tree_data.c b/src/tree_data.c
new file mode 100644
index 0000000..c2488ae
--- /dev/null
+++ b/src/tree_data.c
@@ -0,0 +1,401 @@
+/**
+ * @file tree_data.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Manipulation with libyang data structures
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of the Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ */
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include "common.h"
+#include "context.h"
+#include "parser.h"
+#include "resolve.h"
+#include "xml.h"
+#include "tree_internal.h"
+#include "validation.h"
+
+API struct lyd_node *
+lyd_parse(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options)
+{
+ if (!ctx || !data) {
+ LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
+ return NULL;
+ }
+
+ switch (format) {
+ case LYD_XML:
+ return xml_read_data(ctx, data, options);
+ case LYD_JSON:
+ default:
+ /* TODO */
+ return NULL;
+ }
+
+ return NULL;
+}
+
+API int
+lyd_insert(struct lyd_node *parent, struct lyd_node *node, int options)
+{
+ struct lys_node *sparent;
+ struct lyd_node *iter, *next, *last;
+
+ if (!node || !parent) {
+ ly_errno = LY_EINVAL;
+ return EXIT_FAILURE;
+ }
+
+ if (node->parent || node->prev->next) {
+ lyd_unlink(node);
+ }
+
+ /* check placing the node to the appropriate place according to the schema */
+ sparent = node->schema->parent;
+ while (!(sparent->nodetype & (LYS_CONTAINER | LYS_LIST))) {
+ sparent = sparent->parent;
+ }
+ if (sparent != parent->schema) {
+ ly_errno = LY_EINVAL;
+ return EXIT_FAILURE;
+ }
+
+ if (!parent->child) {
+ /* add as the only child of the parent */
+ parent->child = node;
+ } else {
+ /* add as the last child of the parent */
+ parent->child->prev->next = node;
+ node->prev = parent->child->prev;
+ for (iter = node; iter->next; iter = iter->next);
+ parent->child->prev = iter;
+ }
+ LY_TREE_FOR(node, iter) {
+ iter->parent = parent;
+ last = iter; /* remember the last of the inserted nodes */
+ }
+
+ ly_errno = 0;
+ LY_TREE_FOR_SAFE(node, next, iter) {
+ /* various validation checks */
+ if (lyv_data_content(iter, 0, options)) {
+ if (ly_errno) {
+ return EXIT_FAILURE;
+ } else {
+ lyd_free(iter);
+ }
+ }
+
+ if (iter == last) {
+ /* we are done - checking only the inserted nodes */
+ break;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+API int
+lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node, int options)
+{
+ struct lys_node *par1, *par2;
+ struct lyd_node *iter, *next, *last;
+
+ if (!node || !sibling) {
+ ly_errno = LY_EINVAL;
+ return EXIT_FAILURE;
+ }
+
+ if (node->parent || node->prev->next) {
+ lyd_unlink(node);
+ }
+
+ /* check placing the node to the appropriate place according to the schema */
+ for (par1 = sibling->schema->parent; par1 && (par1->nodetype & (LYS_CONTAINER | LYS_LIST)); par1 = par1->parent);
+ for (par2 = node->schema->parent; par2 && (par2->nodetype & (LYS_CONTAINER | LYS_LIST)); par2 = par2->parent);
+ if (par1 != par2) {
+ ly_errno = LY_EINVAL;
+ return EXIT_FAILURE;
+ }
+
+ LY_TREE_FOR(node, iter) {
+ iter->parent = sibling->parent;
+ last = iter; /* remember the last of the inserted nodes */
+ }
+
+ if (sibling->next) {
+ /* adding into a middle - fix the prev pointer of the node after inserted nodes */
+ last->next = sibling->next;
+ sibling->next->prev = last;
+ } else {
+ /* at the end - fix the prev pointer of the first node */
+ if (sibling->parent) {
+ sibling->parent->child->prev = last;
+ } else {
+ for (iter = sibling; iter->prev->next; iter = iter->prev);
+ iter->prev = last;
+ }
+ }
+ sibling->next = node;
+ node->prev = sibling;
+
+ ly_errno = 0;
+ LY_TREE_FOR_SAFE(node, next, iter) {
+ /* various validation checks */
+ if (lyv_data_content(iter, 0, options)) {
+ if (ly_errno) {
+ return EXIT_FAILURE;
+ } else {
+ lyd_free(iter);
+ }
+ }
+
+ if (iter == last) {
+ /* we are done - checking only the inserted nodes */
+ break;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+API int
+lyd_unlink(struct lyd_node *node)
+{
+ struct lyd_node *iter;
+
+ if (!node) {
+ ly_errno = LY_EINVAL;
+ return EXIT_FAILURE;
+ }
+
+ /* 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 */
+ 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 (node->parent->child == node) {
+ /* the node is the first child */
+ node->parent->child = node->next;
+ }
+ node->parent = NULL;
+ }
+
+ node->next = NULL;
+ node->prev = node;
+
+ return EXIT_SUCCESS;
+}
+
+static void
+lyd_attr_free(struct ly_ctx *ctx, struct lyd_attr *attr)
+{
+ if (!attr) {
+ return;
+ }
+
+ if (attr->next) {
+ lyd_attr_free(ctx, attr->next);
+ }
+ lydict_remove(ctx, attr->name);
+ lydict_remove(ctx, attr->value);
+ free(attr);
+}
+
+API void
+lyd_free(struct lyd_node *node)
+{
+ struct lyd_node *next, *child;
+
+ if (!node) {
+ return;
+ }
+
+ if (!(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
+ /* free children */
+ LY_TREE_FOR_SAFE(node->child, next, child) {
+ lyd_free(child);
+ }
+ } else if (node->schema->nodetype == LYS_ANYXML) {
+ lyxml_free_elem(node->schema->module->ctx, ((struct lyd_node_anyxml *)node)->value);
+ } else {
+ /* free value */
+ switch(((struct lyd_node_leaf *)node)->value_type) {
+ case LY_TYPE_BINARY:
+ case LY_TYPE_STRING:
+ lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf *)node)->value.string);
+ break;
+ case LY_TYPE_BITS:
+ if (((struct lyd_node_leaf *)node)->value.bit) {
+ free(((struct lyd_node_leaf *)node)->value.bit);
+ }
+ break;
+ default:
+ /* TODO nothing needed : LY_TYPE_BOOL, LY_TYPE_DEC64*/
+ break;
+ }
+ }
+
+ lyd_unlink(node);
+ lyd_attr_free(node->schema->module->ctx, node->attr);
+ free(node);
+}
+
+int
+lyd_compare(struct lyd_node *first, struct lyd_node *second, int unique)
+{
+ struct lys_node_list *slist;
+ struct lys_node *snode;
+ struct lyd_node *diter;
+ const char *val1, *val2;
+ int i, j;
+
+ assert(first);
+ assert(second);
+
+ if (first->schema != second->schema) {
+ return 1;
+ }
+
+ switch (first->schema->nodetype) {
+ case LYS_LEAFLIST:
+ /* compare values */
+ if (((struct lyd_node_leaflist *)first)->value_str == ((struct lyd_node_leaflist *)second)->value_str) {
+ return 0;
+ }
+ return 1;
+ case LYS_LIST:
+ slist = (struct lys_node_list*)first->schema;
+
+ if (unique) {
+ /* compare unique leafs */
+ for (i = 0; i < slist->unique_size; i++) {
+ for (j = 0; j < slist->unique[i].leafs_size; j++) {
+ snode = (struct lys_node *)slist->unique[i].leafs[j];
+ /* use default values if the instances of unique leafs are not present */
+ val1 = val2 = ((struct lys_node_leaf *)snode)->dflt;
+ LY_TREE_FOR(first->child, diter) {
+ if (diter->schema == snode) {
+ val1 = ((struct lyd_node_leaf *)diter)->value_str;
+ break;
+ }
+ }
+ LY_TREE_FOR(second->child, diter) {
+ if (diter->schema == snode) {
+ val2 = ((struct lyd_node_leaf *)diter)->value_str;
+ break;
+ }
+ }
+ if (val1 != val2) {
+ break;
+ }
+ }
+ if (j && j == slist->unique[i].leafs_size) {
+ /* all unique leafs are the same in this set */
+ return 0;
+ }
+ }
+ }
+
+ /* compare keys */
+ for (i = 0; i < slist->keys_size; i++) {
+ snode = (struct lys_node *)slist->keys[i];
+ val1 = val2 = NULL;
+ LY_TREE_FOR(first->child, diter) {
+ if (diter->schema == snode) {
+ val1 = ((struct lyd_node_leaf *)diter)->value_str;
+ break;
+ }
+ }
+ LY_TREE_FOR(second->child, diter) {
+ if (diter->schema == snode) {
+ val2 = ((struct lyd_node_leaf *)diter)->value_str;
+ break;
+ }
+ }
+ if (val1 != val2) {
+ return 1;
+ }
+ }
+
+ return 0;
+ default:
+ /* no additional check is needed */
+ return 0;
+ }
+}
+
+API struct lyd_set *
+lyd_set_new(void)
+{
+ return calloc(1, sizeof(struct lyd_set));
+}
+
+API void
+lyd_set_free(struct lyd_set *set)
+{
+ if (!set) {
+ return;
+ }
+
+ free(set->set);
+ free(set);
+}
+
+API int
+lyd_set_add(struct lyd_set *set, struct lyd_node *node)
+{
+ struct lyd_node **new;
+
+ if (!set) {
+ ly_errno = LY_EINVAL;
+ return EXIT_FAILURE;
+ }
+
+ if (set->size == set->number) {
+ new = realloc(set->set, (set->size + 8) * sizeof *(set->set));
+ if (!new) {
+ LOGMEM;
+ return EXIT_FAILURE;
+ }
+ set->size += 8;
+ set->set = new;
+ }
+
+ set->set[set->number++] = node;
+
+ return EXIT_SUCCESS;
+}