[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


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/