diff --git a/stepmania/src/RageUtil.cpp b/stepmania/src/RageUtil.cpp index 8c49518989..eaec12b285 100644 --- a/stepmania/src/RageUtil.cpp +++ b/stepmania/src/RageUtil.cpp @@ -12,9 +12,6 @@ */ #include "RageUtil.h" -#if 0 -#include "fnmatch.h" -#endif ULONG randseed = time(NULL); @@ -202,37 +199,24 @@ void splitpath( const bool UsingDirsOnly, const CString &Path, CString& Drive, C //----------------------------------------------------------------------------- void splitrelpath( const CString &Path, CString& Dir, CString& FName, CString& Ext ) { - // need to split on both forward slashes and back slashes - CStringArray sPathBits; + /* Find the last slash or backslash. */ + int Last = max(Path.ReverseFind('/'), Path.ReverseFind('\\')); - CStringArray sBackShashPathBits; - split( Path, "\\", sBackShashPathBits, true ); - - for( int i=0; i files; + CArray exts; + CArray Attributes; + + CString dir; + }; + + const CacheEntry *SearchDirCache( const CString &sPath ); + + void FlushCache(); + ~DirCache() { FlushCache(); } +private: + CacheEntry *LoadDirCache( const CString &sPath ); + + /* We don't have too many directories ... XXX - glenn */ + CArray directory_cache; +} static DirectoryCache; + +void DirCache::FlushCache() +{ + for(int i = 0; i < directory_cache.GetSize(); ++i) + delete directory_cache[i]; + directory_cache.RemoveAll(); +} + +void FlushDirCache() { DirectoryCache.FlushCache(); } + +/* Read a directory and return a CacheEntry object for it. */ +DirCache::CacheEntry *DirCache::LoadDirCache( const CString &sPath ) +{ + CString sFile, sDir, sThrowAway; + splitrelpath( sPath, sDir, sThrowAway, sThrowAway ); + + CString oldpath; + GetCwd(oldpath); + if(chdir(sDir) == -1) return NULL; + + WIN32_FIND_DATA fd; + HANDLE hFind = ::FindFirstFile( "*", &fd ); + + if( hFind == INVALID_HANDLE_VALUE ) + { + chdir(oldpath); + return NULL; + } + + DirCache::CacheEntry *dir = new DirCache::CacheEntry; + dir->dir = sPath; + + do { + if(!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..")) + continue; + + CString sExt, sThrowAway; + splitrelpath( fd.cFileName, sThrowAway, sThrowAway, sExt ); + + dir->files.Add(fd.cFileName); + dir->exts.Add(sExt); + dir->Attributes.Add(fd.dwFileAttributes); + } while( ::FindNextFile( hFind, &fd ) ); + directory_cache.Add(dir); + + chdir(oldpath); + return dir; +} + +/* Return a CacheEntry object for a directory, reading it if necessary. */ +const DirCache::CacheEntry *DirCache::SearchDirCache( const CString &sPath ) +{ + int i; + for(i = 0; i < directory_cache.GetSize(); ++i) + if(directory_cache[i]->dir == sPath) break; + + if(i == directory_cache.GetSize()) + /* Didn't find it. */ + return LoadDirCache( sPath ); + + return directory_cache[i]; +} + +/* GetExtDirListing(V): + * sPath is a path, which may include a filename. If a filename + * portion is included, return only files which have that as a + * prefix. (If you don't use this, make sure the path ends in a + * backslash, to prevent the last element of the directory from + * looking like a filename.) + * + * Each argument (or each element in the array) is an extension to + * return. If no arguments are provided, return all files. */ -#if 0 -bool GetFnmDirListing( const CString &sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo, ... ) +bool GetExtDirListing( const CString &sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo, ... ) { const char *masks[32]; int nmasks = 0; @@ -328,44 +409,50 @@ bool GetFnmDirListing( const CString &sPath, CStringArray &AddTo, bool bOnlyDirs va_start(va, bReturnPathToo); while(const char *next = va_arg(va, const char *)) - masks[nmasks++] = next; - va_end(va); - - CString oldpath; - GetCwd(oldpath); - if(chdir(sPath) == -1) return false; - - WIN32_FIND_DATA fd; - HANDLE hFind = ::FindFirstFile( ".", &fd ); - - if( hFind != INVALID_HANDLE_VALUE ) - do { - if( bOnlyDirs && !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) + masks[nmasks++] = next; + ASSERT(nmasks+1 < sizeof(masks)/sizeof(*masks)); + } + va_end(va); + masks[nmasks++] = NULL; + + return GetExtDirListingV(sPath, AddTo, bOnlyDirs, bReturnPathToo, masks ); +} + +bool GetExtDirListingV( const CString &sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo, const char *masks[] ) +{ + CString sFile, sDir, sThrowAway; + splitrelpath( sPath, sDir, sFile, sThrowAway ); + + const DirCache::CacheEntry *cache = DirectoryCache.SearchDirCache(sDir); + if(!cache) return false; + + for(int i = 0; i < cache->files.GetSize(); ++i) + { + if( bOnlyDirs && !(cache->Attributes[i] & FILE_ATTRIBUTE_DIRECTORY) ) continue; // skip - if(!strcmp(fd.cFileName, ".") || - !strcmp(fd.cFileName, "..")) + if(strnicmp(sFile, cache->files[i], sFile.GetLength())) continue; bool matched = false; - for(int i = 0; !matched && i < nmasks; ++i) - if(!fnmatch(masks[i], fd.cFileName, FNM_CASEFOLD)) - matched = true; + for(int j = 0; !matched && masks[j]; ++j) + { + if(stricmp(masks[j], cache->exts[i])) + continue; + matched = true; + } if(!matched) continue; if( bReturnPathToo ) - AddTo.Add( sPath + fd.cFileName ); + AddTo.Add( sDir + cache->files[i] ); else - AddTo.Add( fd.cFileName ); - } while( ::FindNextFile( hFind, &fd ) ); - ::FindClose( hFind ); + AddTo.Add( cache->files[i] ); + } - chdir(oldpath); return true; } -#endif //----------------------------------------------------------------------------- // Name: GetHashForString( CString s ) diff --git a/stepmania/src/RageUtil.h b/stepmania/src/RageUtil.h index 56b4bb5b2c..f04d5e521e 100644 --- a/stepmania/src/RageUtil.h +++ b/stepmania/src/RageUtil.h @@ -164,7 +164,11 @@ CString join( bool CreateDirectories( CString Path ); void GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs=false, bool bReturnPathToo=false ); -bool GetFnmDirListing( const CString &sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo, ... ); + +bool GetExtDirListing( const CString &sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo, ... ); +bool GetExtDirListingV( const CString &sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo, const char *masks[] ); +void FlushDirCache(); + unsigned int GetHashForString( CString s ); unsigned int GetHashForFile( CString sPath ); unsigned int GetHashForDirectory( CString sDir ); // a hash value that remains the same as long as nothing in the directory has changed