efl/legacy/ecore/src/lib/ecore_desktop/ecore_desktop_tree.c

363 lines
9.8 KiB
C

#include <sys/types.h>
#include "Ecore_Desktop.h"
#include "ecore_desktop_private.h"
static void ecore_desktop_tree_dump_each_hash_node(void *value,
void *user_data);
/* Just a quick and dirty tree implemtation that will likely get replaced by
* something much saner at a later date. I wrote most of this while falling
* asleep. It will probably scare me when I wake up. B-)
*
* Devilhorns said to make it portable, so we can't rely on any external tree
* implementation. So this tree is designed specifically for this task. Then
* we finally found a place for the genmenu code, and Ecore was back on the
* menu. However, speed could be an issue later, so it might be worth it to
* stick with a custom tree implementation, so that we can optimize it for this
* task.
*
* The trees will be tiny.
* They only store strings.
* There is no insertion or deletion, only append.
* Append order must be maintained.
* The trees will only ever be accessed sequentially, from begining to end.
* The tree data will come in two ways, all in one big string, or a bunch of
* seperate strings, one per element. Any particular tree might have both.
*
* No duplicates in the tree,
* This is the nasty part of this tree implementation.
* Insertions involve a linear search for dupes, most of the
* time there won't be any dupes, so the tree is searched in
* it's entirety. These trees will be really small, and only created at
* the begining, so no big drama there.
* The tree may allow duplicates.
*/
Ecore_Desktop_Tree *
ecore_desktop_tree_new(char *buffer)
{
Ecore_Desktop_Tree *tree;
tree = E_NEW(Ecore_Desktop_Tree, 1);
if ((tree) && (buffer))
{
tree->buffers =
(char **)realloc(tree->buffers,
(tree->buffers_size + 1) * sizeof(char *));
tree->buffers[tree->buffers_size++] = strdup(buffer);
}
return tree;
}
Ecore_Desktop_Tree *
ecore_desktop_tree_add(Ecore_Desktop_Tree * tree, const char *element)
{
tree->elements =
(Ecore_Desktop_Tree_Element *) realloc(tree->elements,
(tree->size +
1) *
sizeof
(Ecore_Desktop_Tree_Element));
tree->elements[tree->size].element = (char*)element;
tree->elements[tree->size++].type = ECORE_DESKTOP_TREE_ELEMENT_TYPE_STRING;
return tree;
}
Ecore_Desktop_Tree *
ecore_desktop_tree_extend(Ecore_Desktop_Tree * tree, const char *element)
{
tree->buffers =
(char **)realloc(tree->buffers,
(tree->buffers_size + 1) * sizeof(char *));
tree->buffers[tree->buffers_size++] = strdup(element);
tree = ecore_desktop_tree_add(tree, tree->buffers[tree->buffers_size - 1]);
return tree;
}
void
ecore_desktop_tree_track(Ecore_Desktop_Tree * tree, void *element)
{
tree->buffers =
(char **)realloc(tree->buffers,
(tree->buffers_size + 1) * sizeof(char *));
tree->buffers[tree->buffers_size++] = element;
}
/* OK, so we need an insert after all, and it falls into the dumb category. */
Ecore_Desktop_Tree *
ecore_desktop_tree_insert(Ecore_Desktop_Tree * tree, int before, void *element,
Ecore_Desktop_Tree_Element_Type type)
{
int i;
tree->elements =
(Ecore_Desktop_Tree_Element *) realloc(tree->elements,
(tree->size +
1) *
sizeof
(Ecore_Desktop_Tree_Element));
tree->size++;
for (i = tree->size - 1; i > before; i--)
{
tree->elements[i].element = tree->elements[i - 1].element;
tree->elements[i].type = tree->elements[i - 1].type;
}
tree->elements[before].element = element;
tree->elements[before].type = type;
return tree;
}
/* OK, so we need a tree merge after all, and it falls into the dumb category. */
Ecore_Desktop_Tree *
ecore_desktop_tree_merge(Ecore_Desktop_Tree * tree, int before,
Ecore_Desktop_Tree * element)
{
int i, size;
size = element->size;
if (size)
{
tree->elements =
(Ecore_Desktop_Tree_Element *) realloc(tree->elements,
(tree->size +
size) *
sizeof
(Ecore_Desktop_Tree_Element));
tree->size += size;
for (i = tree->size - 1; (i > before) && ((i - size) > 0); i--)
{
tree->elements[i].element = tree->elements[i - size].element;
tree->elements[i].type = tree->elements[i - size].type;
}
for (i = 0; i < size; i++)
{
tree->elements[before + i].element = element->elements[i].element;
tree->elements[before + i].type = element->elements[i].type;
}
}
/* Careful, this might screw up the freeing order if that is important. */
size = element->buffers_size;
if (size)
{
/*
tree->buffers = (char **) realloc(tree->buffers, (tree->buffers_size + size) * sizeof(char *));
tree->buffers_size += size;
for (i = 0; i < size; i++)
{
tree->buffers[tree->buffers_size + i] = element->buffers[i];
element->buffers[i] = NULL;
}
*/
}
return tree;
}
Ecore_Desktop_Tree *
ecore_desktop_tree_add_child(Ecore_Desktop_Tree * tree,
Ecore_Desktop_Tree * element)
{
tree->elements =
(Ecore_Desktop_Tree_Element *) realloc(tree->elements,
(tree->size +
1) *
sizeof
(Ecore_Desktop_Tree_Element));
tree->elements[tree->size].element = element;
tree->elements[tree->size++].type = ECORE_DESKTOP_TREE_ELEMENT_TYPE_TREE;
element->parent = tree;
return tree;
}
Ecore_Desktop_Tree *
ecore_desktop_tree_add_hash(Ecore_Desktop_Tree * tree, Ecore_Hash * element)
{
tree->elements =
(Ecore_Desktop_Tree_Element *) realloc(tree->elements,
(tree->size +
1) *
sizeof
(Ecore_Desktop_Tree_Element));
tree->elements[tree->size].element = element;
tree->elements[tree->size++].type = ECORE_DESKTOP_TREE_ELEMENT_TYPE_HASH;
return tree;
}
void
ecore_desktop_tree_remove(Ecore_Desktop_Tree * tree, int element)
{
if (tree->size > element)
{
tree->elements[element].type = ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL;
tree->elements[element].element = NULL;
}
}
int
ecore_desktop_tree_exist(Ecore_Desktop_Tree * tree, char *element)
{
int exist = 0;
int i;
/* This is the dumb part of the tree, a linear search. */
for (i = 0; i < tree->size; i++)
{
if ((tree->elements[i].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_STRING)
&& (strcmp((char *)tree->elements[i].element, element) == 0))
{
exist = 1;
break;
}
}
return exist;
}
int
ecore_desktop_tree_foreach(Ecore_Desktop_Tree * tree, int level,
int (*func) (const void *data,
Ecore_Desktop_Tree * tree, int element,
int level), const void *data)
{
int result = 0;
int i;
for (i = 0; i < tree->size; i++)
{
if (tree->elements[i].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_TREE)
{
if (ecore_desktop_tree_foreach
((Ecore_Desktop_Tree *) tree->elements[i].element, level + 1,
func, data))
result = 1;
}
else if (tree->elements[i].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL)
{
/* This falls into the dumb category. */
int j = i;
int k = i;
int moved = 0;
/* Find the next non NULL element. */
while ((j < tree->size)
&& (tree->elements[j].type ==
ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL))
j++;
/* Move the next batch of non NULL up. */
while ((j < tree->size)
&& (tree->elements[j].type !=
ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL))
{
moved = 1;
tree->elements[k].type = tree->elements[j].type;
tree->elements[k].element = tree->elements[j].element;
tree->elements[j].type = ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL;
tree->elements[j].element = NULL;
j++;
k++;
}
if (moved)
i--;
else
tree->size = i;
}
else
{
if (func(data, tree, i, level))
result = 1;
}
}
return result;
}
void
ecore_desktop_tree_dump(Ecore_Desktop_Tree * tree, int level)
{
int i;
for (i = 0; i < tree->size; i++)
{
int j;
for (j = 0; j < level; j++)
printf(".");
switch (tree->elements[i].type)
{
case ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL:
{
printf("NULL\n");
}
break;
case ECORE_DESKTOP_TREE_ELEMENT_TYPE_STRING:
{
printf("%s\n", (char *)tree->elements[i].element);
}
break;
case ECORE_DESKTOP_TREE_ELEMENT_TYPE_TREE:
{
printf("TREE ELEMENT TYPE\n");
ecore_desktop_tree_dump((Ecore_Desktop_Tree *) tree->
elements[i].element, level + 1);
}
break;
case ECORE_DESKTOP_TREE_ELEMENT_TYPE_HASH:
{
int lev;
lev = level + 1;
printf("HASH ELEMENT TYPE\n");
ecore_hash_for_each_node((Ecore_Hash *) tree->elements[i].
element,
ecore_desktop_tree_dump_each_hash_node,
&lev);
}
break;
default:
{
printf("UNKNOWN ELEMENT TYPE!\n");
}
break;
}
}
}
static void
ecore_desktop_tree_dump_each_hash_node(void *value, void *user_data)
{
Ecore_Hash_Node *node;
int level;
int j;
node = (Ecore_Hash_Node *) value;
level = *((int *)user_data);
for (j = 0; j < level; j++)
printf(".");
printf("%s = %s\n", (char *)node->key, (char *)node->value);
}
void
ecore_desktop_tree_del(Ecore_Desktop_Tree * tree)
{
int i;
for (i = tree->size - 1; i >= 0; i--)
{
if (tree->elements[i].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_TREE)
ecore_desktop_tree_del((Ecore_Desktop_Tree *) tree->elements[i].
element);
else if (tree->elements[i].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_HASH)
ecore_hash_destroy((Ecore_Hash *) tree->elements[i].element);
}
E_FREE(tree->elements);
for (i = tree->buffers_size - 1; i >= 0; i--)
E_FREE(tree->buffers[i]);
E_FREE(tree);
}