Convert IsoDirIter in an interface.

This commit is contained in:
Vreixo Formoso 2008-03-03 21:18:54 +01:00
parent c75f1a430e
commit dd02d1d976
2 changed files with 158 additions and 60 deletions

View File

@ -15,6 +15,17 @@
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
struct dir_iter_data
{
/* points to the last visited child, to NULL before start */
IsoNode *pos;
/* Some control flags.
* bit 0 -> 1 if next called, 0 reseted at start or on deletion
*/
int flag;
};
/** /**
* Increments the reference counting of the given node. * Increments the reference counting of the given node.
*/ */
@ -354,69 +365,53 @@ int iso_dir_get_children_count(IsoDir *dir)
return dir->nchildren; return dir->nchildren;
} }
int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) static
{ int iter_next(IsoDirIter *iter, IsoNode **node)
IsoDirIter *it;
if (dir == NULL || iter == NULL) {
return ISO_NULL_POINTER;
}
it = malloc(sizeof(IsoDirIter));
if (it == NULL) {
return ISO_OUT_OF_MEM;
}
it->dir = (IsoDir*)dir;
it->pos = NULL;
it->flag = 0x00;
*iter = it;
return ISO_SUCCESS;
}
int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node)
{ {
struct dir_iter_data *data;
if (iter == NULL || node == NULL) { if (iter == NULL || node == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
/* clear next flag */ data = iter->data;
iter->flag &= ~0x01;
if (iter->pos == NULL) { /* clear next flag */
data->flag &= ~0x01;
if (data->pos == NULL) {
/* we are at the beginning */ /* we are at the beginning */
iter->pos = iter->dir->children; data->pos = iter->dir->children;
if (iter->pos == NULL) { if (data->pos == NULL) {
/* empty dir */ /* empty dir */
*node = NULL; *node = NULL;
return 0; return 0;
} }
} else { } else {
if (iter->pos->parent != iter->dir) { if (data->pos->parent != iter->dir) {
/* this can happen if the node has been moved to another dir */ /* this can happen if the node has been moved to another dir */
/* TODO specific error */ /* TODO specific error */
return ISO_ERROR; return ISO_ERROR;
} }
if (iter->pos->next == NULL) { if (data->pos->next == NULL) {
/* no more children */ /* no more children */
*node = NULL; *node = NULL;
return 0; return 0;
} else { } else {
/* free reference to current position */ /* free reference to current position */
iso_node_unref(iter->pos); /* it is never last ref!! */ iso_node_unref(data->pos); /* it is never last ref!! */
/* advance a position */ /* advance a position */
iter->pos = iter->pos->next; data->pos = data->pos->next;
} }
} }
/* ok, take a ref to the current position, to prevent internal errors /* ok, take a ref to the current position, to prevent internal errors
* if deleted somewhere */ * if deleted somewhere */
iso_node_ref(iter->pos); iso_node_ref(data->pos);
iter->flag |= 0x01; /* set next flag */ data->flag |= 0x01; /* set next flag */
/* return pointed node */ /* return pointed node */
*node = iter->pos; *node = data->pos;
return ISO_SUCCESS; return ISO_SUCCESS;
} }
@ -428,24 +423,30 @@ int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node)
* Possible errors: * Possible errors:
* ISO_NULL_POINTER, if iter is NULL * ISO_NULL_POINTER, if iter is NULL
*/ */
int iso_dir_iter_has_next(IsoDirIter *iter) static
int iter_has_next(IsoDirIter *iter)
{ {
struct dir_iter_data *data;
if (iter == NULL) { if (iter == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
if (iter->pos == NULL) { data = iter->data;
if (data->pos == NULL) {
return iter->dir->children == NULL ? 0 : 1; return iter->dir->children == NULL ? 0 : 1;
} else { } else {
return iter->pos->next == NULL ? 0 : 1; return data->pos->next == NULL ? 0 : 1;
} }
} }
void iso_dir_iter_free(IsoDirIter *iter) static
void iter_free(IsoDirIter *iter)
{ {
if (iter->pos != NULL) { struct dir_iter_data *data;
iso_node_unref(iter->pos); data = iter->data;
if (data->pos != NULL) {
iso_node_unref(data->pos);
} }
free(iter); free(data);
} }
static IsoNode** iso_dir_find_node(IsoDir *dir, IsoNode *node) static IsoNode** iso_dir_find_node(IsoDir *dir, IsoNode *node)
@ -526,27 +527,31 @@ IsoDir *iso_node_get_parent(IsoNode *node)
} }
/* TODO #00005 optimize iso_dir_iter_take */ /* TODO #00005 optimize iso_dir_iter_take */
int iso_dir_iter_take(IsoDirIter *iter) static
int iter_take(IsoDirIter *iter)
{ {
struct dir_iter_data *data;
IsoNode *pos, *pre; IsoNode *pos, *pre;
if (iter == NULL) { if (iter == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
if (!(iter->flag & 0x01)) { data = iter->data;
if (!(data->flag & 0x01)) {
return ISO_ERROR; /* next not called or end of dir */ return ISO_ERROR; /* next not called or end of dir */
} }
if (iter->pos == NULL) { if (data->pos == NULL) {
return ISO_ASSERT_FAILURE; return ISO_ASSERT_FAILURE;
} }
/* clear next flag */ /* clear next flag */
iter->flag &= ~0x01; data->flag &= ~0x01;
pos = iter->dir->children; pos = iter->dir->children;
pre = NULL; pre = NULL;
while (pos != NULL && pos != iter->pos) { while (pos != NULL && pos != data->pos) {
pre = pos; pre = pos;
pos = pos->next; pos = pos->next;
} }
@ -554,20 +559,20 @@ int iso_dir_iter_take(IsoDirIter *iter)
return ISO_ERROR; /* node not in dir */ return ISO_ERROR; /* node not in dir */
} }
if (pos != iter->pos) { if (pos != data->pos) {
return ISO_ASSERT_FAILURE; return ISO_ASSERT_FAILURE;
} }
/* dispose iterator reference */ /* dispose iterator reference */
iso_node_unref(iter->pos); iso_node_unref(data->pos);
if (pre == NULL) { if (pre == NULL) {
/* node is a first position */ /* node is a first position */
iter->dir->children = pos->next; iter->dir->children = pos->next;
iter->pos = NULL; data->pos = NULL;
} else { } else {
pre->next = pos->next; pre->next = pos->next;
iter->pos = pre; data->pos = pre;
iso_node_ref(pre); /* take iter ref */ iso_node_ref(pre); /* take iter ref */
} }
@ -578,27 +583,108 @@ int iso_dir_iter_take(IsoDirIter *iter)
return ISO_SUCCESS; return ISO_SUCCESS;
} }
int iso_dir_iter_remove(IsoDirIter *iter) static
int iter_remove(IsoDirIter *iter)
{ {
int ret; int ret;
IsoNode *pos; IsoNode *pos;
struct dir_iter_data *data;
if (iter == NULL) { if (iter == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
pos = iter->pos; data = iter->data;
pos = data->pos;
ret = iso_dir_iter_take(iter); ret = iter_take(iter);
if (ret == ISO_SUCCESS) { if (ret == ISO_SUCCESS) {
/* remove node */ /* remove node */
iso_node_unref(pos); iso_node_unref(pos);
} }
if (iter->pos == pos) { if (data->pos == pos) {
return ISO_ERROR; return ISO_ERROR;
} }
return ret; return ret;
} }
static
struct iso_dir_iter_iface iter_class = {
iter_next,
iter_has_next,
iter_free,
iter_take,
iter_remove
};
int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter)
{
IsoDirIter *it;
struct dir_iter_data *data;
if (dir == NULL || iter == NULL) {
return ISO_NULL_POINTER;
}
it = malloc(sizeof(IsoDirIter));
if (it == NULL) {
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(struct dir_iter_data));
if (data == NULL) {
free(it);
return ISO_OUT_OF_MEM;
}
it->class = &iter_class;
it->dir = (IsoDir*)dir;
data->pos = NULL;
data->flag = 0x00;
it->data = data;
*iter = it;
return ISO_SUCCESS;
}
int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node)
{
if (iter == NULL || node == NULL) {
return ISO_NULL_POINTER;
}
return iter->class->next(iter, node);
}
int iso_dir_iter_has_next(IsoDirIter *iter)
{
if (iter == NULL) {
return ISO_NULL_POINTER;
}
return iter->class->has_next(iter);
}
void iso_dir_iter_free(IsoDirIter *iter)
{
if (iter != NULL) {
iter->class->free(iter);
free(iter);
}
}
int iso_dir_iter_take(IsoDirIter *iter)
{
if (iter == NULL) {
return ISO_NULL_POINTER;
}
return iter->class->take(iter);
}
int iso_dir_iter_remove(IsoDirIter *iter)
{
if (iter == NULL) {
return ISO_NULL_POINTER;
}
return iter->class->remove(iter);
}
/** /**
* Get the destination of a node. * Get the destination of a node.
* The returned string belongs to the node and should not be modified nor * The returned string belongs to the node and should not be modified nor

View File

@ -148,20 +148,32 @@ struct Iso_Special
dev_t dev; dev_t dev;
}; };
struct iso_dir_iter_iface
{
int (*next)(IsoDirIter *iter, IsoNode **node);
int (*has_next)(IsoDirIter *iter);
void (*free)(IsoDirIter *iter);
int (*take)(IsoDirIter *iter);
int (*remove)(IsoDirIter *iter);
};
/** /**
* An iterator for directory children. * An iterator for directory children.
*/ */
struct Iso_Dir_Iter struct Iso_Dir_Iter
{ {
struct iso_dir_iter_iface *class;
/* the directory this iterator iterates over */
IsoDir *dir; IsoDir *dir;
/* points to the last visited child, to NULL before start */ void *data;
IsoNode *pos;
/* Some control flags.
* bit 0 -> 1 if next called, 0 reseted at start or on deletion
*/
int flag;
}; };
int iso_node_new_root(IsoDir **root); int iso_node_new_root(IsoDir **root);