I'm not sure how to do that in PhysFS, but if it helps at all, boost::filesystem does that fairly easily.
Here's my own convenience functions that I use:
//Elsewhere: typedef std::vector<std::string> StringList;
enum SubFoldersEnum {IncludeSubFolders, ExcludeSubFolders};
/*
Returns a list of every file in the folder and (if desired) the files in each sub-folder.
If 'timeThreshold' is specified, only files that have been written to *after* that threshold are returned.
If 'fileFilterFunc' is specified, this filters out all file names (not the entire path) that don't pass the filter.
If 'folderFilterFunc' is specified, entire subdirectories are filtered out.
If 'pathPrefix' is specified, this determines what prefixes the returned paths.
Suggestions for 'pathPrefix' are: Nothing ("FolderA"), "./" ("./FolderA") for relative paths, or passing in baseFolder for absolute paths.
Example:
"./File1.ext"
"./File2.ext"
"./FolderB/File3.ext"
"./FolderB/File4.ext"
"./FolderB/Folder2/File5.ext"
"./File6.ext"
*/
StringList GetFilesInDirectory(const std::string &baseFolder, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
//Call the original function, but with filters that accept everything.
return GetFilesInDirectory(baseFolder, IsAnything, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}
StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
//Call the original function, but with a directory filter that accepts everything.
return GetFilesInDirectory(baseFolder, fileFilterFunc, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}
StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, StringValidatorFunc folderFilterFunc,
SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
StringList listOfFiles;
if(!DirectoryExists(baseFolder))
return listOfFiles;
boost::filesystem::directory_iterator directoryIterator(baseFolder);
boost::filesystem::directory_iterator endOfDirectory; //An unitialized iterator is the end iterator.
//Loop through everything in this directory.
for(; directoryIterator != endOfDirectory; directoryIterator++)
{
//Make sure the item found is a file and not a folder.
if(boost::filesystem::is_regular_file(directoryIterator->path()))
{
//Get the name of the folder.
std::string filename = GetFilenameFromPath(directoryIterator->path().generic_string());
//Check if the filename passes the filter.
if(fileFilterFunc(filename))
{
//Check if it was written to after 'timeThreshold'.
if(timeThreshold == 0 || timeThreshold < boost::filesystem::last_write_time(directoryIterator->path()))
{
//Add it to our list.
listOfFiles.push_back(ConvertWinPathToUnix(pathPrefix + '/' + filename));
}
}
}
else if(boost::filesystem::is_directory(directoryIterator->path()))
{
//Check to make sure we want to crawl subfolders.
if(subFoldersEnum == IncludeSubFolders)
{
//Get the name of the folder.
std::string directoryName = GetFinalDirectoryFromPath(directoryIterator->path().generic_string());
//Check if the directory name passes the filter.
if(folderFilterFunc(directoryName))
{
//Get all subfolders and add them to the list.
listOfFiles += GetFilesInDirectory(baseFolder + "/" + directoryName, fileFilterFunc, folderFilterFunc, IncludeSubFolders, (pathPrefix + '/' + directoryName + '/'), timeThreshold);
}
}
}
}
return listOfFiles;
}
'StringValidatorFunc' is a function pointer (actually, a std::function<bool(const std::string&)>) that can take a string a return either true or false if it accepts the string. I use this for filtering files. Often I pass it my SV_WildcardMatch() functor, to easily filter out something like {"*.jpg", "*.jpeg", "*.png"} - I can also post the code for that, if you desire. It's a slightly modified version of this algorithm.
I have a similar function called GetFoldersInDirectory(). It returns folder names instead of file names.