Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » [A5] for_each_file - missing

This thread is locked; no one can reply to it. rss feed Print
[A5] for_each_file - missing
PeKaGM
Member #15,654
June 2014

Hi to all.I'm trying to rewrite Allegro 4 code to Allegro 5 and I miss function - for_each_file - in A5. I found some routines on the net but they are not working. I have only little free time for programing so I can't study those routines for errors.Could someone tell me where can I find functional routine or some really simple way to replace function for_each_file in A5. I need to find all files in directory for example ".jpg" files and store their file names in a field of strings.Thank you very much.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Basically you al_create_fs_entry a filesystem entry for your desired directory, then you al_open_directory the directory, al_read_directory it until there are no entries left, and then al_close_directory it.

Here is an example program that lists all the files in a given directory. You can specify the directory as a command line argument or else it will default to the current directory.

#SelectExpand
1 2#include "allegro5/allegro.h" 3 4#include <cstdio> 5#include <string> 6 7 8int main(int argc , char** argv) { 9 10 char* read_dir = 0; 11 bool free_dir = false; 12 bool close_dir = false; 13 14 15 if (!al_init()) {return 1;} 16 17 if (argc == 2) { 18 // Use first argument as read directory 19 read_dir = argv[1]; 20 } 21 else { 22 // Use current directory as read directory 23 read_dir = al_get_current_directory(); 24 free_dir = true; 25 } 26 27 ALLEGRO_FS_ENTRY* fs_dir_entry = al_create_fs_entry(read_dir); 28 29 30 unsigned int mode = al_get_fs_entry_mode(fs_dir_entry); 31 32 if (!(mode & ALLEGRO_FILEMODE_ISDIR)) { 33 printf("Invalid directory! (%s)\n" , read_dir); 34 } 35 36 if (!al_open_directory(fs_dir_entry)) { 37 printf("Could not open directory %s\n" , read_dir); 38 } 39 else { 40 /// Directory is now open 41 close_dir = true; 42 43 printf("Contents of directory %s\n" , read_dir); 44 45 // prime the while loop 46 ALLEGRO_FS_ENTRY* fs_entry = al_read_directory(fs_dir_entry); 47 48 // Loop until there are not more entries 49 while(fs_entry) { 50 51 // String manip to get short name of file/dir 52 std::string s = al_get_fs_entry_name(fs_entry); 53 std::string s2; 54 char path_sep = '\\'; 55 if (s.find_first_of('/') != std::string::npos) { 56 path_sep = '/'; 57 } 58 unsigned int last_separator = s.find_last_of(path_sep); 59 if (last_separator == std::string::npos) { 60 s2 = s; 61 } 62 else { 63 s2 = s.substr(s.find_last_of(path_sep) + 1); 64 } 65 66 // output short file/dir name 67 printf("%s\n" , s2.c_str()); 68 69 al_destroy_fs_entry(fs_entry); 70 71 fs_entry = al_read_directory(fs_dir_entry); 72 } 73 } 74 75 76 if (close_dir) { 77 al_close_directory(fs_dir_entry); 78 } 79 80 if (fs_dir_entry) { 81 al_destroy_fs_entry(fs_dir_entry); 82 fs_dir_entry = 0; 83 } 84 85 if (free_dir) { 86 al_free(read_dir); 87 read_dir = 0; 88 } 89 return 0; 90}

beoran
Member #12,636
March 2011

Hmm, seeing that the code to replicate for_each_file is relatively long, I'm in favor of adding an al_for_each_file() function.

Elias
Member #358
May 2000

beoran +1

--
"Either help out or stop whining" - Evert

Thomas Fjellstrom
Member #476
June 2000
avatar

He could also use the ALLEGRO_PATH api to handle paths and files. Would cut out a bit of that code.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Elias
Member #358
May 2000

He could also use the ALLEGRO_PATH api to handle paths and files. Would cut out a bit of that code.

Replace the loop with this then:

#SelectExpand
1while(fs_entry) { 2 ALLEGRO_PATH *path = al_create_path(al_get_fs_entry_name(fs_entry)) 3 /* Note: ownership of the strings stays with path */ 4 char const *name = al_get_path_filename(path) 5 if (not name[0]) { 6 /* Note: ownership of the strings stays with path */ 7 name = al_get_path_component(path, -1); 8 } 9 if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0) { 10 bool is_dir = al_get_fs_entry_mode(fs_entry) & ALLEGRO_FILEMODE_ISDIR 11 12 printf("%s%s\n", name, is_dir ? "/" : ""); 13 } 14 /* Note: This also invalidates the name string. */ 15 al_destroy_path(path) 16 al_destroy_fs_entry(fs_entry); 17 fs_entry = al_read_directory(fs_dir_entry); 18}

I also added directory detection, but it's still kinda longish. The proposed change would look something like:

void callback(char const *filename, void *user) {
    printf("%s\n", filename);
}
al_for_each_file(read_dir, callback, int flags, user);

Which is much more simple :) It also handles common errors someone would make on implementing it on their own, like not ignoring the "." and ".." entries we have on some platforms and dealing with directories where al_get_path_filename fails.

Possible flags could be:
FULL_PATH - pass the full path to the callback not just the filename
RECURSIVE - also recurse into any directories found
INCLUDE_DIRECTORIES - also call the callback with directory names not just files

--
"Either help out or stop whining" - Evert

beoran
Member #12,636
March 2011

Actually I already made a patch, with two functions, documentation and a test. One function uses a callback with char * file names and the other with ALLEGRO_FS_ENTRY. :)

The flags parameter is a good idea though, I'll modify my patch to use that. I'll probably add the ALLEGRO_EACH_FILE_RECURSE, ALLEGRO_EACH_FILE_DIRECTORIES, ALLEGRO_EACH_FILE_DOTFILES and ALLEGRO_EACH_FILE_SHORT_PATH flags. The default call does not recurse, does not return directories, does return not dotfiles, and does return full file names, not partial ones, since full names are normally most useful.

Go to: