From 051538b5c20966173724ae18c5a8270b36059646 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 1 Dec 2007 02:22:00 +0100 Subject: [PATCH] Add functions to iterate over directory children. --- src/libisofs.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/node.c | 54 ++++++++++++++++++++++++++++++++++++++++++ src/node.h | 10 ++++++++ 3 files changed, 128 insertions(+) diff --git a/src/libisofs.h b/src/libisofs.h index 365fead..e190ae3 100644 --- a/src/libisofs.h +++ b/src/libisofs.h @@ -13,6 +13,7 @@ typedef struct Iso_Node IsoNode; typedef struct Iso_Dir IsoDir; typedef struct Iso_Symlink IsoSymlink; +typedef struct Iso_Dir_Iter IsoDirIter; /** * Increments the reference counting of the given node. @@ -134,4 +135,67 @@ int iso_dir_get_node(IsoDir *dir, const char *name, IsoNode **node); */ int iso_dir_get_nchildren(IsoDir *dir); +/** + * Get an iterator for the children of the given dir. + * + * You can iterate over the children with iso_dir_iter_next. When finished, + * you should free the iterator with iso_dir_iter_free. + * You musn't delete a child of the same dir, using iso_node_take() or + * iso_node_remove(), while you're using the iterator. You can use + * iso_node_take_iter() or iso_node_remove_iter() instead. + * + * You can use the iterator in the way like this + * + * IsoDirIter *iter; + * IsoNode *node; + * if ( iso_dir_get_children(dir, &iter) != 1 ) { + * // handle error + * } + * while ( iso_dir_iter_next(iter, &node) == 1 ) { + * // do something with the child + * } + * iso_dir_iter_free(iter); + * + * An iterator is intended to be used in a single iteration over the + * children of a dir. Thus, it should be treated as a temporary object, + * and free as soon as possible. + * + * @return + * 1 success, < 0 error + * Possible errors: + * ISO_NULL_POINTER, if dir or iter are NULL + * ISO_OUT_OF_MEM + */ +int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter); + +/** + * Get the next child. + * Take care that the node is owned by its parent, and will be unref() when + * the parent is freed. If you want your own ref to it, call iso_node_ref() + * on it. + * + * @return + * 1 success, 0 if dir has no more elements, < 0 error + * Possible errors: + * ISO_NULL_POINTER, if node or iter are NULL + * ISO_ERROR, on wrong iter usage, usual caused by modiying the + * dir during iteration + */ +int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node); + +/** + * Check if there're more children. + * + * @return + * 1 dir has more elements, 0 no, < 0 error + * Possible errors: + * ISO_NULL_POINTER, if iter is NULL + */ +int iso_dir_iter_has_next(IsoDirIter *iter); + +/** + * Free a dir iterator. + */ +void iso_dir_iter_free(IsoDirIter *iter); + #endif /*LIBISO_LIBISOFS_H_*/ diff --git a/src/node.c b/src/node.c index 2458dd9..0efb1e7 100644 --- a/src/node.c +++ b/src/node.c @@ -214,3 +214,57 @@ int iso_dir_get_nchildren(IsoDir *dir) } return dir->nchildren; } + +int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) +{ + 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 = dir; + it->pos = dir->children; + + *iter = it; + return ISO_SUCCESS; +} + +int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node) +{ + IsoNode *n; + if (iter == NULL || node == NULL) { + return ISO_NULL_POINTER; + } + n = iter->pos; + if (n == NULL) { + return 0; + } + if (n->parent != iter->dir) { + /* this can happen if the node has been moved to another dir */ + return ISO_ERROR; + } + *node = n; + iter->pos = n->next; + return ISO_SUCCESS; +} + +/** + * Check if there're more children. + * + * @return + * 1 dir has more elements, 0 no, < 0 error + * Possible errors: + * ISO_NULL_POINTER, if iter is NULL + */ +int iso_dir_iter_has_next(IsoDirIter *iter) +{ + if (iter == NULL) { + return ISO_NULL_POINTER; + } + return iter->pos == NULL ? 0 : 1; +} diff --git a/src/node.h b/src/node.h index d8af7e5..deff24e 100644 --- a/src/node.h +++ b/src/node.h @@ -107,4 +107,14 @@ struct Iso_Symlink char *dest; }; + +/** + * An iterator for directory children. + */ +struct Iso_Dir_Iter +{ + const IsoDir *dir; + IsoNode *pos; +}; + #endif /*LIBISO_NODE_H_*/