/**
* mds — A micro-display server
* Copyright © 2014 Mattias Andrée (maandree@member.fsf.org)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tree.h"
#include <stdlib.h>
#include <string.h>
/**
* Initialise a tree node
*
* @param this The memory slot for the tree node
* @param type The type of the node
*/
void mds_kbdc_tree_initialise(mds_kbdc_tree_t* restrict this, int type)
{
memset(this, 0, sizeof(mds_kbdc_tree_t));
this->type = type;
}
/**
* Create a tree node
*
* @param type The type of the node
* @return The tree node, `NULL` on error
*/
mds_kbdc_tree_t* mds_kbdc_tree_create(int type)
{
mds_kbdc_tree_t* this = malloc(sizeof(mds_kbdc_tree_t));
if (this == NULL)
return NULL;
mds_kbdc_tree_initialise(this, type);
return this;
}
/**
* Common procedure for `mds_kbdc_tree_destroy` and `mds_kbdc_tree_destroy_nonrecursive`
*
* @param this The tree node
* @param recursive Whether subtree should be destroyed and freed
*/
static void mds_kbdc_tree_destroy_(mds_kbdc_tree_t* restrict this, int recursive)
{
#define V(type, var) (((type)this)->var)
#define xfree(t, v) (free(V(t, v)), V(t, v) = NULL)
#define xdestroy(t, v) (recursive ? (mds_kbdc_tree_destroy_(V(t, v), 1), xfree(t, v)) : (V(t, v) = NULL))
mds_kbdc_tree_t* prev = NULL;
mds_kbdc_tree_t* first = this;
again:
if (this == NULL)
return;
switch (this->type)
{
case MDS_KBDC_TREE_TYPE_INFORMATION:
case MDS_KBDC_TREE_TYPE_ASSUMPTION:
case MDS_KBDC_TREE_TYPE_ALTERNATION:
case MDS_KBDC_TREE_TYPE_UNORDERED:
xdestroy(struct mds_kbdc_tree_nesting*, inner);
break;
case MDS_KBDC_TREE_TYPE_INFORMATION_LANGUAGE:
case MDS_KBDC_TREE_TYPE_INFORMATION_COUNTRY:
case MDS_KBDC_TREE_TYPE_INFORMATION_VARIANT:
xfree(struct mds_kbdc_tree_information_data*, data);
break;
case MDS_KBDC_TREE_TYPE_FUNCTION:
case MDS_KBDC_TREE_TYPE_MACRO:
xfree(struct mds_kbdc_tree_callable*, name);
xdestroy(struct mds_kbdc_tree_callable*, inner);
break;
case MDS_KBDC_TREE_TYPE_INCLUDE:
xfree(mds_kbdc_tree_include_t*, filename);
break;
case MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE:
xdestroy(mds_kbdc_tree_assumption_have_t*, data);
break;
case MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_CHARS:
xfree(mds_kbdc_tree_assumption_have_chars_t*, chars);
break;
case MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_RANGE:
xfree(mds_kbdc_tree_assumption_have_range_t*, first);
xfree(mds_kbdc_tree_assumption_have_range_t*, last);
break;
case MDS_KBDC_TREE_TYPE_FOR:
xfree(mds_kbdc_tree_for_t*, first);
xfree(mds_kbdc_tree_for_t*, last);
xfree(mds_kbdc_tree_for_t*, variable);
xdestroy(mds_kbdc_tree_for_t*, inner);
break;
case MDS_KBDC_TREE_TYPE_IF:
xfree(mds_kbdc_tree_if_t*, condition);
xdestroy(mds_kbdc_tree_if_t*, inner);
xdestroy(mds_kbdc_tree_if_t*, otherwise);
break;
case MDS_KBDC_TREE_TYPE_LET:
xfree(mds_kbdc_tree_let_t*, variable);
xdestroy(mds_kbdc_tree_let_t*, value);
break;
case MDS_KBDC_TREE_TYPE_MAP:
xdestroy(mds_kbdc_tree_map_t*, sequence);
xdestroy(mds_kbdc_tree_map_t*, result);
break;
case MDS_KBDC_TREE_TYPE_ARRAY:
xdestroy(mds_kbdc_tree_array_t*, elements);
break;
case MDS_KBDC_TREE_TYPE_KEYS:
xfree(mds_kbdc_tree_keys_t*, keys);
break;
case MDS_KBDC_TREE_TYPE_STRING:
xfree(mds_kbdc_tree_string_t*, string);
break;
case MDS_KBDC_TREE_TYPE_MACRO_CALL:
xfree(mds_kbdc_tree_macro_call_t*, name);
xdestroy(mds_kbdc_tree_macro_call_t*, arguments);
break;
default:
break;
}
prev = this;
this = this->next;
if (prev != first)
free(prev);
goto again;
#undef xdestroy
#undef xfree
#undef V
}
/**
* Release all resources stored in a tree node,
* without freeing the node itself or freeing
* or destroying inner `mds_kbdc_tree_t*`:s
*
* @param this The tree node
*/
void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t* restrict this)
{
mds_kbdc_tree_destroy_(this, 0);
}
/**
* Release all resources stored in a tree node,
* without freeing or destroying inner
* `mds_kbdc_tree_t*`:s, but free this node's
* allocation
*
* @param this The tree node
*/
void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t* restrict this)
{
mds_kbdc_tree_destroy_nonrecursive(this);
free(this);
}
/**
* Release all resources stored in a tree node
* recursively, but do not free the allocation
* of the tree node
*
* @param this The tree node
*/
void mds_kbdc_tree_destroy(mds_kbdc_tree_t* restrict this)
{
mds_kbdc_tree_destroy_(this, 1);
}
/**
* Release all resources stored in a tree node
* recursively, and free the allocation
* of the tree node
*
* @param this The tree node
*/
void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this)
{
mds_kbdc_tree_destroy(this);
free(this);
}