From 2189c059921742c641f6f8ad6d78c69b3ad0089d Mon Sep 17 00:00:00 2001 From: rovol Date: Mon, 6 Oct 2025 19:51:56 +0800 Subject: [PATCH 1/5] Add incremental directory iterator Functions: - `nob_is_dir_empty()` - `nob_dir_iter_open()` - `nob_dir_iter_next()` - `nob_dir_iter_close()` - `nob_dir_iter_getname()` --- nob.h | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/nob.h b/nob.h index 737f61f..fb3180e 100644 --- a/nob.h +++ b/nob.h @@ -235,6 +235,12 @@ NOBDEF bool nob_write_entire_file(const char *path, const void *data, size_t siz NOBDEF Nob_File_Type nob_get_file_type(const char *path); NOBDEF bool nob_delete_file(const char *path); +NOBDEF int nob_is_dir_empty(const char *path); +NOBDEF bool nob_dir_iter_open(Nob_Dir_Iter *iter, const char *path); +NOBDEF bool nob_dir_iter_next(Nob_Dir_Iter *iter); +NOBDEF bool nob_dir_iter_close(Nob_Dir_Iter **iter); +NOBDEF char *nob_dir_iter_getname(Nob_Dir_Iter *iter); + #define nob_return_defer(value) do { result = (value); goto defer; } while(0) // Initial capacity of a dynamic array @@ -1644,6 +1650,79 @@ NOBDEF bool nob_delete_file(const char *path) #endif // _WIN32 } +// Returns true, false, and -1. +NOBDEF int nob_is_dir_empty(const char *path) { + DIR *dir = opendir(path); + if (dir == NULL) { +#ifdef _WIN32 + nob_log(NOB_ERROR, "Could not open directory %s: %s", path, nob_win32_error_message(GetLastError())); +#else + nob_log(NOB_ERROR, "Could not open directory %s: %s", path, strerror(errno)); +#endif // _WIN32 + return -1; + } + + struct dirent *ent; + while ((ent = readdir(dir)) != NULL) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) + continue; + closedir(dir); + return false; + } + + closedir(dir); + return true; +} + +// Returns NULL if gets failed +NOBDEF bool nob_dir_iter_open(Nob_Dir_Iter *iter, const char *path) { + if (iter == NULL) return false; + if (path == NULL) return false; + + iter->path = path; + iter->dir = opendir(path); + iter->current = NULL; + + if (iter->dir == NULL) { +#ifdef _WIN32 + nob_log(NOB_ERROR, "Could not open directory %s: %s", path, nob_win32_error_message(GetLastError())); +#else + nob_log(NOB_ERROR, "Could not open directory %s: %s", path, strerror(errno)); +#endif // _WIN32 + return false; + } + + return true; +} + +NOBDEF bool nob_dir_iter_next(Nob_Dir_Iter *iter) { + if (iter->dir == NULL) return false; + + struct dirent *ent; + while ((ent = readdir(iter->dir)) != NULL) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) + continue; + iter->current = ent; + return true; + } + + iter->current = NULL; + return false; +} + +NOBDEF void nob_dir_iter_close(Nob_Dir_Iter **iter) { + if (iter && *iter) { + if ((*iter)->dir) + closedir((*iter)->dir); + NOB_FREE(*iter); + *iter = NULL; + } +} + +NOBDEF char *nob_dir_iter_getname(Nob_Dir_Iter *iter) { + return iter->current ? iter->current->d_name : NULL; +} + NOBDEF bool nob_copy_directory_recursively(const char *src_path, const char *dst_path) { bool result = true; From 40665bee40fc0d72c81f4852672ce5884c2baec3 Mon Sep 17 00:00:00 2001 From: rovol Date: Mon, 6 Oct 2025 20:01:45 +0800 Subject: [PATCH 2/5] Add stripped aliases of functions --- nob.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nob.h b/nob.h index fb3180e..d9721cc 100644 --- a/nob.h +++ b/nob.h @@ -2306,6 +2306,11 @@ NOBDEF int closedir(DIR *dirp) #define write_entire_file nob_write_entire_file #define get_file_type nob_get_file_type #define delete_file nob_delete_file + #define is_dir_empty nob_is_dir_empty + #define dir_iter_open nob_dir_iter_open + #define dir_iter_next nob_dir_iter_next + #define dir_iter_close nob_dir_iter_close + #define dir_iter_getname nob_dir_iter_getname #define return_defer nob_return_defer #define da_append nob_da_append #define da_free nob_da_free From 8edb0540eb63df885e9628bae2c0fb5feee867c3 Mon Sep 17 00:00:00 2001 From: rovol Date: Mon, 6 Oct 2025 20:07:48 +0800 Subject: [PATCH 3/5] Fix definition --- nob.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/nob.h b/nob.h index d9721cc..17cdfc8 100644 --- a/nob.h +++ b/nob.h @@ -235,12 +235,6 @@ NOBDEF bool nob_write_entire_file(const char *path, const void *data, size_t siz NOBDEF Nob_File_Type nob_get_file_type(const char *path); NOBDEF bool nob_delete_file(const char *path); -NOBDEF int nob_is_dir_empty(const char *path); -NOBDEF bool nob_dir_iter_open(Nob_Dir_Iter *iter, const char *path); -NOBDEF bool nob_dir_iter_next(Nob_Dir_Iter *iter); -NOBDEF bool nob_dir_iter_close(Nob_Dir_Iter **iter); -NOBDEF char *nob_dir_iter_getname(Nob_Dir_Iter *iter); - #define nob_return_defer(value) do { result = (value); goto defer; } while(0) // Initial capacity of a dynamic array @@ -766,6 +760,18 @@ NOBDEF char *nob_win32_error_message(DWORD err); #endif // NOB_H_ +typedef struct { + const char *path; + DIR *dir; + struct dirent *current; +} Nob_Dir_Iter; + +NOBDEF int nob_is_dir_empty(const char *path); +NOBDEF bool nob_dir_iter_open(Nob_Dir_Iter *iter, const char *path); +NOBDEF bool nob_dir_iter_next(Nob_Dir_Iter *iter); +NOBDEF void nob_dir_iter_close(Nob_Dir_Iter **iter); +NOBDEF char *nob_dir_iter_getname(Nob_Dir_Iter *iter); + #ifdef NOB_IMPLEMENTATION // This is like nob_proc_wait() but waits asynchronously. Depending on the platform ms means different thing. From cf77bbc0d9bfa04e67784cbd75947547b4658d51 Mon Sep 17 00:00:00 2001 From: rovol Date: Mon, 6 Oct 2025 23:15:44 +0800 Subject: [PATCH 4/5] Change allocation method to stack allocation --- nob.c | 1 + nob.h | 20 +++++++++----------- tests/dir_iter.c | 22 ++++++++++++++++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 tests/dir_iter.c diff --git a/nob.c b/nob.c index a580562..97e0842 100644 --- a/nob.c +++ b/nob.c @@ -24,6 +24,7 @@ const char *test_names[] = { "sb_appendf", "da_foreach", "temp_aligned_alloc", + "dir_iter" }; #define test_names_count ARRAY_LEN(test_names) diff --git a/nob.h b/nob.h index 17cdfc8..ea61d98 100644 --- a/nob.h +++ b/nob.h @@ -769,8 +769,8 @@ typedef struct { NOBDEF int nob_is_dir_empty(const char *path); NOBDEF bool nob_dir_iter_open(Nob_Dir_Iter *iter, const char *path); NOBDEF bool nob_dir_iter_next(Nob_Dir_Iter *iter); -NOBDEF void nob_dir_iter_close(Nob_Dir_Iter **iter); -NOBDEF char *nob_dir_iter_getname(Nob_Dir_Iter *iter); +NOBDEF void nob_dir_iter_close(Nob_Dir_Iter *iter); +NOBDEF const char *nob_dir_iter_getname(Nob_Dir_Iter iter); #ifdef NOB_IMPLEMENTATION @@ -1716,17 +1716,14 @@ NOBDEF bool nob_dir_iter_next(Nob_Dir_Iter *iter) { return false; } -NOBDEF void nob_dir_iter_close(Nob_Dir_Iter **iter) { - if (iter && *iter) { - if ((*iter)->dir) - closedir((*iter)->dir); - NOB_FREE(*iter); - *iter = NULL; - } +NOBDEF void nob_dir_iter_close(Nob_Dir_Iter *iter) { + if (!iter) return; + if (iter->dir) + closedir(iter->dir); } -NOBDEF char *nob_dir_iter_getname(Nob_Dir_Iter *iter) { - return iter->current ? iter->current->d_name : NULL; +NOBDEF const char *nob_dir_iter_getname(Nob_Dir_Iter iter) { + return iter.current ? iter.current->d_name : NULL; } NOBDEF bool nob_copy_directory_recursively(const char *src_path, const char *dst_path) @@ -2313,6 +2310,7 @@ NOBDEF int closedir(DIR *dirp) #define get_file_type nob_get_file_type #define delete_file nob_delete_file #define is_dir_empty nob_is_dir_empty + #define Dir_Iter Nob_Dir_Iter #define dir_iter_open nob_dir_iter_open #define dir_iter_next nob_dir_iter_next #define dir_iter_close nob_dir_iter_close diff --git a/tests/dir_iter.c b/tests/dir_iter.c new file mode 100644 index 0000000..181ed99 --- /dev/null +++ b/tests/dir_iter.c @@ -0,0 +1,22 @@ +#define NOB_IMPLEMENTATION +#define NOB_STRIP_PREFIX +#include "nob.h" + +int main(void) { + Dir_Iter iter = {0}; + if (!dir_iter_open(&iter, ".")) + return 1; + + Cmd cmd = {0}; + cmd_append(&cmd, "touch", "file1", "file2", "file3"); + if (!cmd_run(&cmd)) return 1; + + while (dir_iter_next(&iter)) { + const char *dname = dir_iter_getname(iter); + if (dname == NULL) + continue; + nob_log(NOB_INFO, "dname: %s", dname); + } + + return 0; +} From 7c5fce1f04370b97cafd6d36d1d33dc7dcda25da Mon Sep 17 00:00:00 2001 From: rovol Date: Mon, 6 Oct 2025 23:19:24 +0800 Subject: [PATCH 5/5] Fix `nob_dir_iter_close()` --- nob.h | 9 ++++----- tests/dir_iter.c | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/nob.h b/nob.h index ea61d98..694410c 100644 --- a/nob.h +++ b/nob.h @@ -769,7 +769,7 @@ typedef struct { NOBDEF int nob_is_dir_empty(const char *path); NOBDEF bool nob_dir_iter_open(Nob_Dir_Iter *iter, const char *path); NOBDEF bool nob_dir_iter_next(Nob_Dir_Iter *iter); -NOBDEF void nob_dir_iter_close(Nob_Dir_Iter *iter); +NOBDEF void nob_dir_iter_close(Nob_Dir_Iter iter); NOBDEF const char *nob_dir_iter_getname(Nob_Dir_Iter iter); #ifdef NOB_IMPLEMENTATION @@ -1716,10 +1716,9 @@ NOBDEF bool nob_dir_iter_next(Nob_Dir_Iter *iter) { return false; } -NOBDEF void nob_dir_iter_close(Nob_Dir_Iter *iter) { - if (!iter) return; - if (iter->dir) - closedir(iter->dir); +NOBDEF void nob_dir_iter_close(Nob_Dir_Iter iter) { + if (iter.dir) + closedir(iter.dir); } NOBDEF const char *nob_dir_iter_getname(Nob_Dir_Iter iter) { diff --git a/tests/dir_iter.c b/tests/dir_iter.c index 181ed99..80e35ff 100644 --- a/tests/dir_iter.c +++ b/tests/dir_iter.c @@ -18,5 +18,7 @@ int main(void) { nob_log(NOB_INFO, "dname: %s", dname); } + dir_iter_close(iter); + return 0; }