[AD] al_for_each_fs_entry |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
In this patch, wich is a replacement for my previous
beoran_al_for_each_file.diff, I propose a simple wrapper function
named al_for_each_fs_entry that allows easier use of
al_open_directory(), etc. The function al_for_each_fs_entry will call
a callback and iterate over directory entries. After discussion with
Elias and others on the IRC channel, I decided to simplify and enhance
the al_for_each_filename proposal to this.
The function is fully documented and an example of it's use can be
seen in ex_dir.c .
I hope this is better than my previous suggestion.
Kind Regards,
B.
diff --git a/docs/src/refman/fshook.txt b/docs/src/refman/fshook.txt
index 1aaa5b2..da970a6 100644
--- a/docs/src/refman/fshook.txt
+++ b/docs/src/refman/fshook.txt
@@ -161,6 +161,9 @@ Reads the next directory item and returns a filesystem entry for it.
Returns NULL if there are no more entries or if an error occurs. Call
[al_destroy_fs_entry] on the returned entry when you are done with it.
+This function will ignore any files or directories named `.` or `..` which may
+exist on certain platforms and may signify the current and the parent directory.
+
See also: [al_open_directory], [al_close_directory]
### API: al_close_directory
@@ -211,6 +214,49 @@ Returns the handle on success, NULL on error.
See also: [al_fopen]
+### API: ALLEGRO_FOR_EACH_FS_ENTRY_FLAGS
+
+Flags for the use of [al_for_each_fs_entry].
+
+* ALLEGRO_FOR_EACH_FS_ENTRY_NORMAL - normal operation
+* ALLEGRO_FOR_EACH_FS_ENTRY_RECURSE - recurse into subdirectories.
+
+See also: [al_for_each_fs_entry]
+
+### API: al_for_each_fs_entry
+
+This convenience function will open the `dir` as a directory
+as per [al_open_directory], and then will call the callback function `callback`
+once for every filesystem entry in that directory. Finally it will close the
+directory again as per [al_close_directory].
+
+The callback `callback` must be of type `bool callback(ALLEGRO_FS_ENTRY *
+entry, void * extra)`. The +callback will be called with a pointer
+to an [ALLEGRO_FS_ENTRY] that matches one file in +path+, and the pointer
+passed in the +extra+ parameter.
+
+When `callback` returns true iteration will continue, when it returns false
+iteration will stop. Note that the +entry+ parameter will be destroyed
+automatically when the callback function returns, so if you want to keep it you
+will need to make a duplicate and store that somewhere.
+
+The `callback` will never be called for files or directories named `.`
+or `..` which may exists on certain platforms. This is because
+[al_for_each_fs_entry] uses [al_read_directory] internally, and that function
+also skips over files wich such names.
+
+The `flag` parameter must be either a constant from
+[ALLEGRO_FOR_EACH_FS_ENTRY_FLAGS], either `ALLEGRO_FOR_EACH_FS_ENTRY_NORMAL`
+for normal operation or `ALLEGRO_FOR_EACH_FS_ENTRY_RECURSE`. If this flag is
+set, then [al_for_each_fs_entry] will recurse into every directory it finds.
+
+Returns true if sucessful, false if something went wrong in opening
+the directory. In that case it will use [al_set_errno] to indicate the type
+of error which occurred.
+
+See also: [ALLEGRO_FOR_EACH_FS_ENTRY_FLAGS]
+
+
## Alternative filesystem functions
By default, Allegro uses platform specific filesystem functions for things like
diff --git a/examples/ex_dir.c b/examples/ex_dir.c
index 32623d3..cbe637a 100644
--- a/examples/ex_dir.c
+++ b/examples/ex_dir.c
@@ -53,6 +53,22 @@ static void print_entry(ALLEGRO_FS_ENTRY *entry)
al_close_directory(entry);
}
+
+static bool print_fs_entry_callback(ALLEGRO_FS_ENTRY * entry, void * extra) {
+ (void) extra;
+ print_file(entry);
+ return true;
+}
+
+static void print_fs_entry(ALLEGRO_FS_ENTRY * dir)
+{
+ log_printf("\n------------------------------------\nExample of al_for_each_fs_entry:\n\n");
+ al_for_each_fs_entry(dir, print_fs_entry_callback,
+ ALLEGRO_FOR_EACH_FS_ENTRY_RECURSE,
+ (void*) al_get_fs_entry_name(dir));
+}
+
+
int main(int argc, char **argv)
{
int i;
@@ -62,7 +78,7 @@ int main(int argc, char **argv)
}
open_log_monospace();
- log_printf("%-36s %-6s %8s %8s %8s %8s\n",
+ log_printf("Example of filesystem entry functions:\n\n%-36s %-6s %8s %8s %8s %8s\n",
"name", "flags", "ctime", "mtime", "atime", "size");
log_printf(
"------------------------------------ "
@@ -75,12 +91,14 @@ int main(int argc, char **argv)
if (argc == 1) {
ALLEGRO_FS_ENTRY *entry = al_create_fs_entry("data");
print_entry(entry);
+ print_fs_entry(entry);
al_destroy_fs_entry(entry);
}
for (i = 1; i < argc; i++) {
ALLEGRO_FS_ENTRY *entry = al_create_fs_entry(argv[i]);
print_entry(entry);
+ print_fs_entry(entry);
al_destroy_fs_entry(entry);
}
diff --git a/include/allegro5/fshook.h b/include/allegro5/fshook.h
index 004b0c4..3cd480b 100644
--- a/include/allegro5/fshook.h
+++ b/include/allegro5/fshook.h
@@ -116,6 +116,23 @@ AL_FUNC(ALLEGRO_FILE *, al_open_fs_entry, (ALLEGRO_FS_ENTRY *e,
const char *mode));
+
+/* Helper function for iterating over a directory using a callback. */
+
+/* Type: ALLEGRO_FOR_EACH_FS_ENTRY_FLAGS
+ */
+typedef enum ALLEGRO_FOR_EACH_FS_ENTRY_FLAGS {
+ ALLEGRO_FOR_EACH_FS_ENTRY_NORMAL = 0,
+ ALLEGRO_FOR_EACH_FS_ENTRY_RECURSE = 1
+} ALLEGRO_FOR_EACH_FS_ENTRY_FLAGS;
+
+
+AL_FUNC(bool, al_for_each_fs_entry, (ALLEGRO_FS_ENTRY * dir,
+ bool (*callback)(ALLEGRO_FS_ENTRY * entry, void * extra),
+ int flags,
+ void *extra));
+
+
/* Thread-local state. */
AL_FUNC(const ALLEGRO_FS_INTERFACE *, al_get_fs_interface, (void));
AL_FUNC(void, al_set_fs_interface, (const ALLEGRO_FS_INTERFACE *vtable));
diff --git a/src/fshook.c b/src/fshook.c
index 4cd6d69..0730eb5 100644
--- a/src/fshook.c
+++ b/src/fshook.c
@@ -235,6 +235,47 @@ ALLEGRO_FILE *al_open_fs_entry(ALLEGRO_FS_ENTRY *e, const char *mode)
}
+/* Utility functions for iterating over a directory using callbacks. */
+
+/* Function: al_for_each_fs_entry
+ */
+bool al_for_each_fs_entry(ALLEGRO_FS_ENTRY * dir,
+ bool (*callback)(ALLEGRO_FS_ENTRY * dir, void * extra),
+ int flags,
+ void *extra)
+{
+ ALLEGRO_FS_ENTRY * entry;
+
+ if (!dir || !al_open_directory(dir)) {
+ al_set_errno(ENOENT);
+ return false;
+ }
+
+ for (entry = al_read_directory(dir); entry; entry = al_read_directory(dir)) {
+ bool proceed = true;
+
+ /* Recurse depth-first if requested and needed. */
+ if (flags & ALLEGRO_FOR_EACH_FS_ENTRY_RECURSE) {
+ if (al_get_fs_entry_mode(entry) & ALLEGRO_FILEMODE_ISDIR) {
+ proceed = al_for_each_fs_entry(entry, callback, flags, extra);
+ }
+ }
+
+ /* Now call the callback if needed. */
+ if (proceed) {
+ proceed = callback(entry, extra);
+ }
+
+ al_destroy_fs_entry(entry);
+ if (!proceed) break;
+ }
+
+ return true;
+}
+
+
+
+
/*
* Local Variables:
* c-basic-offset: 3