From 5d3a987b0ea7dabeaa4b7171257646ff1cd631ca Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 1 Nov 2025 10:03:59 +0000 Subject: [PATCH] io: directory: implement new b_iterator interface --- io/include/blue/io/directory.h | 31 ++--- io/sys/darwin/directory.c | 237 +++++++++++++++++++-------------- 2 files changed, 145 insertions(+), 123 deletions(-) diff --git a/io/include/blue/io/directory.h b/io/include/blue/io/directory.h index 1ffda09..89c5e92 100644 --- a/io/include/blue/io/directory.h +++ b/io/include/blue/io/directory.h @@ -14,13 +14,18 @@ B_DECLS_BEGIN; struct b_directory_p; -#define B_TYPE_DIRECTORY (b_directory_get_type()) +#define B_TYPE_DIRECTORY (b_directory_get_type()) +#define B_TYPE_DIRECTORY_ITERATOR (b_directory_iterator_get_type()) B_DECLARE_TYPE(b_directory); +B_DECLARE_TYPE(b_directory_iterator); B_TYPE_CLASS_DECLARATION_BEGIN(b_directory) B_TYPE_CLASS_DECLARATION_END(b_directory) +B_TYPE_CLASS_DECLARATION_BEGIN(b_directory_iterator) +B_TYPE_CLASS_DECLARATION_END(b_directory_iterator) + struct z__b_directory_iterator; typedef enum b_directory_iterator_flags { @@ -34,24 +39,14 @@ typedef enum b_directory_open_flags { B_DIRECTORY_OPEN_DELETE_ON_CLOSE = 0x04u, } b_directory_open_flags; -typedef struct b_directory_iterator { - b_iterator _base; - struct z__b_directory_iterator *_z; - struct b_directory_p *_p; - - b_directory_iterator_flags flags; - b_directory *root; - +typedef struct b_directory_entry { const b_path *filepath; char *filename; b_file_info info; -} b_directory_iterator; - -#define b_directory_foreach(it, dir, flags) \ - for (int z__b_unique_name() = b_directory_iterator_begin(dir, it, flags); \ - b_directory_iterator_is_valid(it); b_directory_iterator_next(it)) +} b_directory_entry; BLUE_API b_type b_directory_get_type(void); +BLUE_API b_type b_directory_iterator_get_type(void); BLUE_API b_result b_directory_open( b_directory *root, const b_path *path, b_directory_open_flags flags, @@ -72,12 +67,8 @@ BLUE_API b_result b_directory_path_stat( BLUE_API b_result b_directory_path_unlink( const b_directory *root, const b_path *path); -BLUE_API int b_directory_iterator_begin( - b_directory *directory, b_directory_iterator *it, - b_directory_iterator_flags flags); -BLUE_API bool b_directory_iterator_next(b_directory_iterator *it); -BLUE_API b_status b_directory_iterator_erase(b_directory_iterator *it); -BLUE_API bool b_directory_iterator_is_valid(const b_directory_iterator *it); +BLUE_API b_iterator *b_directory_begin( + b_directory *dir, b_directory_iterator_flags flags); B_DECLS_END; diff --git a/io/sys/darwin/directory.c b/io/sys/darwin/directory.c index 1b40412..3873354 100644 --- a/io/sys/darwin/directory.c +++ b/io/sys/darwin/directory.c @@ -25,9 +25,16 @@ struct b_directory_p { b_path *d_path_abs; }; -struct z__b_directory_iterator { +struct b_directory_iterator_p { + struct b_directory_p *_p; + FTS *fts; FTSENT *ent; + + b_directory_iterator_flags flags; + b_directory *root; + + b_directory_entry entry; }; /*** PRIVATE FUNCTIONS ********************************************************/ @@ -55,13 +62,14 @@ static b_result directory_delete(b_directory *dir, struct b_directory_p *dir_p) { enum b_status status = B_SUCCESS; - struct b_directory_iterator it; - b_directory_iterator_begin(dir, &it, B_DIRECTORY_ITERATE_PARENT_LAST); - while (b_directory_iterator_is_valid(&it)) { - status = b_directory_iterator_erase(&it); - if (!B_OK(status)) { - return B_RESULT_STATUS(status); - } + b_iterator *it = b_directory_begin(dir, B_DIRECTORY_ITERATE_PARENT_LAST); + while (B_OK(b_iterator_get_status(it))) { + b_iterator_erase(it); + } + + status = b_iterator_get_status(it); + if (!B_OK(status) && status != B_ERR_NO_DATA) { + return B_RESULT_STATUS(status); } status = b_path_unlink(dir_p->d_path_abs); @@ -190,7 +198,7 @@ static b_result create_directory(struct b_directory_p *root, const char *path) static b_result create_directory_hierarchy( struct b_directory_p *root, const char *path) { - int root_fd = root->d_fd; + int root_fd = root ? root->d_fd : AT_FDCWD; char *path_buf = b_strdup(path); if (!path_buf) { @@ -417,22 +425,6 @@ static void directory_fini(b_object *obj, void *priv) b_path_unref(dir->d_path_abs); } -/*** CLASS DEFINITION *********************************************************/ - -B_TYPE_CLASS_DEFINITION_BEGIN(b_directory) - B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) - B_INTERFACE_ENTRY(to_string) = NULL; - B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) -B_TYPE_CLASS_DEFINITION_END(b_directory) - -B_TYPE_DEFINITION_BEGIN(b_directory) - B_TYPE_ID(0x10d36546, 0x7f96, 0x464b, 0xbc4d, 0xe504b283fa45); - B_TYPE_CLASS(b_directory_class); - B_TYPE_INSTANCE_PRIVATE(struct b_directory_p); - B_TYPE_INSTANCE_INIT(directory_init); - B_TYPE_INSTANCE_FINI(directory_fini); -B_TYPE_DEFINITION_END(b_directory) - /*** ITERATOR FUNCTIONS *******************************************************/ static int ftsent_compare(const FTSENT **one, const FTSENT **two) @@ -440,89 +432,71 @@ static int ftsent_compare(const FTSENT **one, const FTSENT **two) return (strcmp((*one)->fts_name, (*two)->fts_name)); } -static void update_iterator_data(struct b_directory_iterator *it) +static void update_iterator_data(struct b_directory_iterator_p *it) { - struct z__b_directory_iterator *it_data = it->_z; - - if (it->filepath) { - b_path_unref((b_path *)it->filepath); - it->filepath = NULL; + if (it->entry.filepath) { + b_path_unref((b_path *)it->entry.filepath); + it->entry.filepath = NULL; } - FTSENT *ent = it_data->ent; + FTSENT *ent = it->ent; b_path *path = b_path_create_from_cstr( ent->fts_path + b_path_length(it->_p->d_path_abs) + 1); - it->filename = ent->fts_name; - it->filepath = path; + it->entry.filename = ent->fts_name; + it->entry.filepath = path; - memset(&it->info, 0x0, sizeof it->info); + memset(&it->entry.info, 0x0, sizeof it->entry.info); - it->info.length = ent->fts_statp->st_size; + it->entry.info.length = ent->fts_statp->st_size; if (S_ISREG(ent->fts_statp->st_mode)) { - it->info.attrib |= B_FILE_ATTRIB_NORMAL; + it->entry.info.attrib |= B_FILE_ATTRIB_NORMAL; } if (S_ISDIR(ent->fts_statp->st_mode)) { - it->info.attrib |= B_FILE_ATTRIB_DIRECTORY; + it->entry.info.attrib |= B_FILE_ATTRIB_DIRECTORY; } if (S_ISBLK(ent->fts_statp->st_mode)) { - it->info.attrib |= B_FILE_ATTRIB_BLOCK_DEVICE; + it->entry.info.attrib |= B_FILE_ATTRIB_BLOCK_DEVICE; } if (S_ISCHR(ent->fts_statp->st_mode)) { - it->info.attrib |= B_FILE_ATTRIB_CHAR_DEVICE; + it->entry.info.attrib |= B_FILE_ATTRIB_CHAR_DEVICE; } if (S_ISLNK(ent->fts_statp->st_mode)) { - it->info.attrib |= B_FILE_ATTRIB_SYMLINK; + it->entry.info.attrib |= B_FILE_ATTRIB_SYMLINK; } } -static void cleanup_iterator(struct b_directory_iterator *it) +static void iterator_fini(b_object *obj, void *priv) { - if (it->filepath) { - b_path_unref((b_path *)it->filepath); - it->filepath = NULL; + struct b_directory_iterator_p *it = priv; + + if (it->entry.filepath) { + b_path_unref((b_path *)it->entry.filepath); + it->entry.filepath = NULL; } - struct z__b_directory_iterator *it_data = it->_z; - memset(it, 0x0, sizeof *it); - - if (!it_data) { - return; + if (it->fts) { + fts_close(it->fts); } - - if (it_data->fts) { - fts_close(it_data->fts); - } - - free(it_data); } -int b_directory_iterator_begin( - b_directory *directory, struct b_directory_iterator *it, - enum b_directory_iterator_flags flags) +b_iterator *b_directory_begin( + b_directory *directory, enum b_directory_iterator_flags flags) { - memset(it, 0x0, sizeof *it); + b_iterator *it_obj = b_object_create(B_TYPE_DIRECTORY_ITERATOR); + struct b_directory_iterator_p *it + = b_object_get_private(it_obj, B_TYPE_DIRECTORY_ITERATOR); it->flags = flags; it->root = directory; it->_p = b_object_get_private(directory, B_TYPE_DIRECTORY); - struct z__b_directory_iterator *it_data = malloc(sizeof *it_data); - - if (!it_data) { - return -1; - } - - memset(it_data, 0x0, sizeof *it_data); - - it->_z = it_data; - int fts_flags = FTS_COMFOLLOW | FTS_NOCHDIR; const char *path_list[] = { @@ -530,24 +504,23 @@ int b_directory_iterator_begin( NULL, }; - it_data->fts - = fts_open((char *const *)path_list, fts_flags, ftsent_compare); + it->fts = fts_open((char *const *)path_list, fts_flags, ftsent_compare); bool done = false; while (!done) { - it_data->ent = fts_read(it_data->fts); + it->ent = fts_read(it->fts); - if (!it_data->ent) { - cleanup_iterator(it); - return -1; + if (!it->ent) { + b_iterator_set_status(it_obj, B_ERR_NO_DATA); + return it_obj; } - if (it_data->ent->fts_level == 0) { + if (it->ent->fts_level == 0) { continue; } - switch (it_data->ent->fts_info) { + switch (it->ent->fts_info) { case FTS_DOT: continue; case FTS_F: @@ -573,31 +546,41 @@ int b_directory_iterator_begin( } update_iterator_data(it); - return 0; + return it_obj; } -bool b_directory_iterator_next(struct b_directory_iterator *it) +static b_iterator *iterator_begin(b_object *obj) { - struct z__b_directory_iterator *it_data = it->_z; - if (!it_data || !it_data->fts) { - return false; + return b_directory_begin(obj, B_DIRECTORY_ITERATE_PARENT_FIRST); +} + +static const b_iterator *iterator_cbegin(const b_object *obj) +{ + return b_directory_begin((b_object *)obj, B_DIRECTORY_ITERATE_PARENT_FIRST); +} + +static enum b_status iterator_move_next(const b_iterator *obj) +{ + struct b_directory_iterator_p *it + = b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR); + if (!it || !it->fts) { + return B_ERR_NO_DATA; } bool done = false; while (!done) { - it_data->ent = fts_read(it_data->fts); + it->ent = fts_read(it->fts); - if (!it_data->ent) { - cleanup_iterator(it); - return false; + if (!it->ent) { + return B_ERR_NO_DATA; } - if (it_data->ent->fts_level == 0) { + if (it->ent->fts_level == 0) { continue; } - switch (it_data->ent->fts_info) { + switch (it->ent->fts_info) { case FTS_DOT: continue; case FTS_F: @@ -622,31 +605,79 @@ bool b_directory_iterator_next(struct b_directory_iterator *it) } update_iterator_data(it); - return true; + return B_SUCCESS; } -enum b_status b_directory_iterator_erase(struct b_directory_iterator *it) +static enum b_status iterator_erase(b_iterator *obj) { - b_result result = b_directory_path_unlink(it->root, it->filepath); + struct b_directory_iterator_p *it + = b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR); + b_result result = b_directory_path_unlink(it->root, it->entry.filepath); if (b_result_is_error(result)) { enum b_status status = b_error_get_status_code(result); b_error_release(result); return status; } - b_directory_iterator_next(it); - return B_SUCCESS; + return iterator_move_next(obj); } -bool b_directory_iterator_is_valid(const struct b_directory_iterator *it) +static b_iterator_value iterator_get_value(b_iterator *obj) { - if (!it->_z) { - return false; - } + struct b_directory_iterator_p *it + = b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR); - if (!it->_z->ent) { - return false; - } - - return true; + return B_ITERATOR_VALUE_PTR(&it->entry); } + +static const b_iterator_value iterator_get_cvalue(const b_iterator *obj) +{ + struct b_directory_iterator_p *it + = b_object_get_private(obj, B_TYPE_DIRECTORY_ITERATOR); + + return B_ITERATOR_VALUE_CPTR(&it->entry); +} + +/*** CLASS DEFINITION *********************************************************/ + +// ---- b_directory DEFINITION +B_TYPE_CLASS_DEFINITION_BEGIN(b_directory) + B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) + B_INTERFACE_ENTRY(to_string) = NULL; + B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) + + B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE) + B_INTERFACE_ENTRY(it_begin) = iterator_begin; + B_INTERFACE_ENTRY(it_cbegin) = iterator_cbegin; + B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE) +B_TYPE_CLASS_DEFINITION_END(b_directory) + +B_TYPE_DEFINITION_BEGIN(b_directory) + B_TYPE_ID(0x10d36546, 0x7f96, 0x464b, 0xbc4d, 0xe504b283fa45); + B_TYPE_CLASS(b_directory_class); + B_TYPE_IMPLEMENTS(B_TYPE_ITERABLE); + B_TYPE_INSTANCE_PRIVATE(struct b_directory_p); + B_TYPE_INSTANCE_INIT(directory_init); + B_TYPE_INSTANCE_FINI(directory_fini); +B_TYPE_DEFINITION_END(b_directory) + +// ---- b_directory_iterator DEFINITION +B_TYPE_CLASS_DEFINITION_BEGIN(b_directory_iterator) + B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) + B_INTERFACE_ENTRY(to_string) = NULL; + B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) + + B_TYPE_CLASS_INTERFACE_BEGIN(b_iterator, B_TYPE_ITERATOR) + B_INTERFACE_ENTRY(it_move_next) = iterator_move_next; + B_INTERFACE_ENTRY(it_erase) = iterator_erase; + B_INTERFACE_ENTRY(it_get_value) = iterator_get_value; + B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue; + B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR) +B_TYPE_CLASS_DEFINITION_END(b_directory_iterator) + +B_TYPE_DEFINITION_BEGIN(b_directory_iterator) + B_TYPE_ID(0xc707fce6, 0xc895, 0x4925, 0x8700, 0xa60641dee0cc); + B_TYPE_EXTENDS(B_TYPE_ITERATOR); + B_TYPE_CLASS(b_directory_iterator_class); + B_TYPE_INSTANCE_PRIVATE(struct b_directory_iterator_p); +B_TYPE_DEFINITION_END(b_directory_iterator)