split off FDB

This commit is contained in:
Glenn Maynard
2003-07-03 02:41:27 +00:00
parent 9d52c28315
commit 524c29c1e2
7 changed files with 544 additions and 508 deletions
+3 -450
View File
@@ -11,22 +11,15 @@
*/
#include "RageUtil.h"
#include "RageUtil_FileDB.h"
#include "RageTimer.h"
#include "RageLog.h"
#include <numeric>
#include <time.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fstream>
#include <map>
#include <set>
#include "RageTimer.h"
#include "RageLog.h"
#if !defined(WIN32)
#include <dirent.h>
#endif
unsigned long randseed = time(NULL);
@@ -348,15 +341,6 @@ void GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bRe
}
#endif
void GetCwd(CString &s)
{
char buf[PATH_MAX];
bool ret = getcwd(buf, PATH_MAX) != NULL;
ASSERT(ret);
s = buf;
}
/* Reference: http://www.theorem.com/java/CRC32.java, rewritten by Glenn Maynard.
* Public domain. */
unsigned int GetHashForString ( CString s )
@@ -385,12 +369,6 @@ unsigned int GetHashForString ( CString s )
return crc;
}
bool DoStat(CString sPath, struct stat *st)
{
TrimRight(sPath, "/\\");
return stat(sPath.c_str(), st) != -1;
}
unsigned int GetHashForFile( CString sPath )
{
unsigned int hash = 0;
@@ -423,42 +401,6 @@ unsigned int GetHashForDirectory( CString sDir )
return hash;
}
unsigned GetFileSizeInBytes( const CString &sFilePath )
{
struct stat st;
if(!DoStat(sFilePath, &st))
return 0;
return st.st_size;
}
#if 0
bool DoesFileExist( const CString &sPath ) { return FDB.DoesFileExist(sPath); }
bool IsAFile( const CString &sPath ) { return FDB.IsAFile(sPath); }
bool IsADirectory( const CString &sPath ) { return FDB.IsADirectory(sPath); }
#else
bool DoesFileExist( const CString &sPath )
{
if(sPath.empty()) return false;
struct stat st;
return DoStat(sPath, &st);
}
bool IsAFile( const CString &sPath )
{
return DoesFileExist(sPath) && ! IsADirectory(sPath);
}
bool IsADirectory( const CString &sPath )
{
if(sPath.empty()) return false;
struct stat st;
if (!DoStat(sPath, &st))
return false;
return !!(st.st_mode & S_IFDIR);
}
#endif
bool CompareCStringsAsc(const CString &str1, const CString &str2)
{
return str1.CompareNoCase( str2 ) < 0;
@@ -893,41 +835,6 @@ int memicmp(const char *s1, const char *s2, size_t n)
}
#endif
/* ASCII-only case insensitivity. */
struct char_traits_char_nocase: public char_traits<char>
{
static bool eq( char c1, char c2 )
{ return toupper(c1) == toupper(c2); }
static bool ne( char c1, char c2 )
{ return toupper(c1) != toupper(c2); }
static bool lt( char c1, char c2 )
{ return toupper(c1) < toupper(c2); }
static int compare( const char* s1, const char* s2, size_t n ) {
return memicmp( s1, s2, n );
}
static inline char fasttoupper(char a)
{
if(a < 'a' || a > 'z')
return a;
return a+('A'-'a');
}
static const char *find( const char* s, int n, char a ) {
a = fasttoupper(a);
while( n-- > 0 && fasttoupper(*s) != a ) {
++s;
}
if(fasttoupper(*s) == a)
return s;
return NULL;
}
};
/* Replace &#nnnn; (decimal) &xnnnn; (hex) with corresponding UTF-8 characters. */
void Replace_Unicode_Markers( CString &Text )
{
@@ -1002,359 +909,6 @@ CString WcharDisplayText(wchar_t c)
return chr;
}
typedef basic_string<char,char_traits_char_nocase> istring;
struct File {
istring name;
bool dir;
File() { dir=false; }
File(istring fn, bool dir_=false): name(fn), dir(dir) { }
bool operator== (const File &rhs) const { return name==rhs.name; }
bool operator< (const File &rhs) const { return name<rhs.name; }
bool equal(const File &rhs) const { return name == rhs.name; }
bool equal(const CString &rhs) const {
return !stricmp(name.c_str(), rhs.c_str());
}
};
struct FileSet
{
set<File> files;
RageTimer age;
void LoadFromDir(const CString &dir);
void GetFilesMatching(
const CString &beginning, const CString &containing, const CString &ending,
vector<CString> &out, bool bOnlyDirs) const;
void GetFilesEqualTo(const CString &pat, vector<CString> &out, bool bOnlyDirs) const;
bool DoesFileExist(const CString &path) const;
bool IsADirectory(const CString &path) const;
bool IsAFile(const CString &path) const;
};
void FileSet::LoadFromDir(const CString &dir)
{
age.GetDeltaTime(); /* reset */
files.clear();
CString oldpath;
GetCwd(oldpath);
if(chdir(dir) == -1) return;
#if defined(WIN32)
WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile( "*", &fd );
if( hFind == INVALID_HANDLE_VALUE )
{
chdir(oldpath);
return;
}
do {
if(!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, ".."))
continue;
File f;
if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
f.dir = true;
f.name=fd.cFileName;
files.insert(f);
} while( FindNextFile( hFind, &fd ) );
FindClose(hFind);
#else
DIR *d = opendir(".");
while(struct dirent *ent = readdir(d))
{
if(!strcmp(ent->d_name, ".")) continue;
if(!strcmp(ent->d_name, "..")) continue;
File f;
f.dir = IsADirectory(ent->d_name);
f.name=ent->d_name;
files.insert(f);
}
closedir(d);
#endif
chdir(oldpath);
}
/* Search for "beginning*containing*ending". */
void FileSet::GetFilesMatching(const CString &beginning, const CString &containing, const CString &ending, vector<CString> &out, bool bOnlyDirs) const
{
set<File>::const_iterator i = files.lower_bound(File(beginning.c_str()));
for( ; i != files.end(); ++i)
{
if(bOnlyDirs && !i->dir) continue;
/* Check beginning. */
if(beginning.size() > i->name.size()) continue; /* can't start with it */
if(strnicmp(i->name.c_str(), beginning.c_str(), beginning.size())) continue; /* doesn't start with it */
/* Position the end starts on: */
int end_pos = int(i->name.size())-int(ending.size());
/* Check end. */
if(end_pos < 0) continue; /* can't end with it */
if(stricmp(i->name.c_str()+end_pos, ending.c_str())) continue; /* doesn't end with it */
/* Check containing. Do this last, since it's the slowest (substring
* search instead of string match). */
if(containing.size())
{
unsigned pos = i->name.find(containing, beginning.size());
if(pos == i->name.npos) continue; /* doesn't contain it */
if(pos + containing.size() > unsigned(end_pos)) continue; /* found it but it overlaps with the end */
}
out.push_back(i->name.c_str());
}
}
void FileSet::GetFilesEqualTo(const CString &str, vector<CString> &out, bool bOnlyDirs) const
{
set<File>::const_iterator i = files.find(File(str.c_str()));
if(i == files.end())
return;
if(bOnlyDirs && !i->dir)
return;
out.push_back(i->name.c_str());
}
bool FileSet::DoesFileExist(const CString &path) const
{
return files.find(File(path.c_str())) != files.end();
}
bool FileSet::IsADirectory(const CString &path) const
{
set<File>::const_iterator i = files.find(File(path.c_str()));
if(i == files.end())
return false;
return i->dir;
}
bool FileSet::IsAFile(const CString &path) const
{
set<File>::const_iterator i = files.find(File(path.c_str()));
if(i == files.end())
return false;
return !i->dir;
}
/* Given "foo/bar/baz/" or "foo/bar/baz", return "foo/bar/" and "baz". */
static void SplitPath( CString Path, CString &Dir, CString &Name )
{
/* Must always have at least one slash. */
static Regex split("(.*/)([^/]+)");
CStringArray match;
if(split.Compare(Path, match)) {
Dir = match[0];
Name = match[1];
} else {
/* No slash. */
Dir = "./";
Name = Path;
}
}
bool FilenameDB::DoesFileExist( const CString &sPath )
{
CString Dir, Name;
SplitPath(sPath, Dir, Name);
FileSet &fs = GetFileSet(Dir);
return fs.DoesFileExist(Name);
}
bool FilenameDB::IsAFile( const CString &sPath )
{
CString Dir, Name;
SplitPath(sPath, Dir, Name);
FileSet &fs = GetFileSet(Dir);
return fs.IsAFile(Name);
}
bool FilenameDB::IsADirectory( const CString &sPath )
{
CString Dir, Name;
SplitPath(sPath, Dir, Name);
FileSet &fs = GetFileSet(Dir);
return fs.IsADirectory(Name);
}
/* XXX: this won't work right for URIs, eg \\foo\bar */
bool FilenameDB::ResolvePath(CString &path)
{
if(path == ".") return true;
if(path == "") return true;
path.Replace("\\", "/");
/* Split path into components. */
vector<CString> p;
split(path, "/", p, true);
/* Resolve each component. Assume the first component is correct. */
CString ret = p[0];
for(unsigned i = 1; i < p.size(); ++i)
{
ret += "/";
vector<CString> lst;
FileSet &fs = GetFileSet(ret);
fs.GetFilesEqualTo(p[i], lst, false);
/* If there were no matches, the path isn't found. */
if(lst.empty()) return false;
if(lst.size() > 1)
LOG->Warn("Ambiguous filenames \"%s\" and \"%s\"",
lst[0].c_str(), lst[1].c_str());
ret += lst[0];
}
if(path[path.size()-1] == '/')
path = ret + "/";
else
path = ret;
return true;
}
void FilenameDB::GetFilesMatching(const CString &dir, const CString &beginning, const CString &containing, const CString &ending, vector<CString> &out, bool bOnlyDirs)
{
FileSet &fs = GetFileSet(dir);
fs.GetFilesMatching(beginning, containing, ending, out, bOnlyDirs);
}
void FilenameDB::GetFilesEqualTo(const CString &dir, const CString &fn, vector<CString> &out, bool bOnlyDirs)
{
FileSet &fs = GetFileSet(dir);
fs.GetFilesEqualTo(fn, out, bOnlyDirs);
}
void FilenameDB::GetFilesSimpleMatch(const CString &dir, const CString &fn, vector<CString> &out, bool bOnlyDirs)
{
/* Does this contain a wildcard? */
unsigned first_pos = fn.find_first_of('*');
if(first_pos == fn.npos)
{
/* No; just do a regular search. */
GetFilesEqualTo(dir, fn, out, bOnlyDirs);
} else {
unsigned second_pos = fn.find_first_of('*', first_pos+1);
if(second_pos == fn.npos)
{
/* Only one *: "A*B". */
GetFilesMatching(dir, fn.substr(0, first_pos), "", fn.substr(first_pos+1), out, bOnlyDirs);
} else {
/* Two *s: "A*B*C". */
GetFilesMatching(dir,
fn.substr(0, first_pos),
fn.substr(first_pos+1, second_pos-first_pos-1),
fn.substr(second_pos+1), out, bOnlyDirs);
}
}
}
FileSet &FilenameDB::GetFileSet(CString dir, bool ResolveCase)
{
/* Normalize the path. */
dir.Replace("\\", "/"); /* foo\bar -> foo/bar */
dir.Replace("//", "/"); /* foo//bar -> foo/bar */
FileSet *ret;
map<CString, FileSet *>::iterator i = dirs.find(dir);
bool reload = false;
if(i == dirs.end())
{
ret = new FileSet;
dirs[dir] = ret;
reload = true;
}
else
{
ret = i->second;
if(ret->age.PeekDeltaTime() > 30)
reload = true;
}
if(reload)
{
CString RealDir = dir;
if(ResolveCase)
{
/* Resolve path cases (path/Path -> PATH/path). */
ResolvePath(RealDir);
/* Alias this name, too. */
dirs[RealDir] = ret;
}
ret->LoadFromDir(RealDir);
}
return *ret;
}
FilenameDB FDB;
void GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo )
{
/* If you want the CWD, use ".". */
ASSERT(!sPath.empty());
/* XXX: for case-insensitive resolving, we assume the first element is
* correct (we need a place to start from); so if sPath is relative,
* prepend "./" */
/* Strip off the last path element and use it as a mask. */
unsigned pos = sPath.find_last_of("/\\");
CString fn;
if(pos != sPath.npos)
{
fn = sPath.substr(pos+1);
sPath = sPath.substr(0, pos+1);
}
/* If there was only one path element, or if the last element was empty,
* use "*". */
if(fn.size() == 0)
fn = "*";
unsigned start = AddTo.size();
FDB.GetFilesSimpleMatch(sPath, fn, AddTo, bOnlyDirs);
if(bReturnPathToo && start < AddTo.size())
{
FDB.ResolvePath(sPath);
while(start < AddTo.size())
{
AddTo[start] = sPath + AddTo[start];
start++;
}
}
}
void FilenameDB::FlushDirCache()
{
dirs.clear();
}
/* Return the last named component of dir:
* a/b/c -> c
* a/b/c/ -> c
@@ -1370,7 +924,6 @@ CString Basename(CString dir)
return dir;
}
CString Capitalize( CString s )
{
if( s.GetLength()==0 )
+36 -35
View File
@@ -13,6 +13,7 @@
*/
#include <map>
#include "RageUtil_FileDB.h"
//-----------------------------------------------------------------------------
// SAFE_ Macros
@@ -186,12 +187,6 @@ 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
bool DoStat(CString sPath, struct stat *st);
bool DoesFileExist( const CString &sPath );
bool IsAFile( const CString &sPath );
bool IsADirectory( const CString &sPath );
unsigned GetFileSizeInBytes( const CString &sFilePath );
bool CompareCStringsAsc(const CString &str1, const CString &str2);
bool CompareCStringsDesc(const CString &str1, const CString &str2);
void SortCStringArray( CStringArray &AddTo, const bool bSortAcsending = true );
@@ -223,35 +218,6 @@ public:
bool Compare(const CString &str, vector<CString> &matches);
};
struct FileSet;
class FilenameDB
{
FileSet &GetFileSet(CString dir, bool ResolveCase = true);
/* Directories we have cached: */
map<CString, FileSet *> dirs;
void GetFilesEqualTo(const CString &dir, const CString &fn, vector<CString> &out, bool bOnlyDirs);
void GetFilesMatching(const CString &dir,
const CString &beginning, const CString &containing, const CString &ending,
vector<CString> &out, bool bOnlyDirs);
public:
/* This handles at most one * wildcard. If we need anything more complicated,
* we'll need to use fnmatch or regex. */
void GetFilesSimpleMatch(const CString &dir, const CString &fn, vector<CString> &out, bool bOnlyDirs);
/* Search for "path" case-insensitively and replace it with the correct
* case. If "path" doesn't exist at all, return false and don't change it. */
bool ResolvePath(CString &path);
bool DoesFileExist(const CString &path);
bool IsAFile(const CString &path);
bool IsADirectory(const CString &path);
void FlushDirCache();
};
extern FilenameDB FDB;
void Replace_Unicode_Markers( CString &Text );
void ReplaceText( CString &Text, const map<CString,CString> &m );
@@ -265,4 +231,39 @@ CString Capitalize( CString s );
#include <unistd.h> /* correct place with correct definitions */
#endif
/* ASCII-only case insensitivity. */
struct char_traits_char_nocase: public char_traits<char>
{
static bool eq( char c1, char c2 )
{ return toupper(c1) == toupper(c2); }
static bool ne( char c1, char c2 )
{ return toupper(c1) != toupper(c2); }
static bool lt( char c1, char c2 )
{ return toupper(c1) < toupper(c2); }
static int compare( const char* s1, const char* s2, size_t n ) {
return memicmp( s1, s2, n );
}
static inline char fasttoupper(char a)
{
if(a < 'a' || a > 'z')
return a;
return a+('A'-'a');
}
static const char *find( const char* s, int n, char a ) {
a = fasttoupper(a);
while( n-- > 0 && fasttoupper(*s) != a ) {
++s;
}
if(fasttoupper(*s) == a)
return s;
return NULL;
}
};
typedef basic_string<char,char_traits_char_nocase> istring;
#endif
+451
View File
@@ -0,0 +1,451 @@
#include "global.h"
#include "RageUtil_FileDB.h"
#include "RageUtil.h"
#include "RageTimer.h"
#include "RageLog.h"
#include <map>
#include <set>
#include <sys/stat.h>
#include <sys/types.h>
#if !defined(WIN32)
#include <dirent.h>
#endif
static void GetCwd(CString &s)
{
char buf[PATH_MAX];
bool ret = getcwd(buf, PATH_MAX) != NULL;
ASSERT(ret);
s = buf;
}
struct File {
istring name;
bool dir;
File() { dir=false; }
File(istring fn, bool dir_=false): name(fn), dir(dir) { }
bool operator== (const File &rhs) const { return name==rhs.name; }
bool operator< (const File &rhs) const { return name<rhs.name; }
bool equal(const File &rhs) const { return name == rhs.name; }
bool equal(const CString &rhs) const {
return !stricmp(name.c_str(), rhs.c_str());
}
};
/* This represents a directory. */
struct FileSet
{
set<File> files;
RageTimer age;
void LoadFromDir(const CString &dir);
void GetFilesMatching(
const CString &beginning, const CString &containing, const CString &ending,
vector<CString> &out, bool bOnlyDirs) const;
void GetFilesEqualTo(const CString &pat, vector<CString> &out, bool bOnlyDirs) const;
bool DoesFileExist(const CString &path) const;
bool IsADirectory(const CString &path) const;
bool IsAFile(const CString &path) const;
};
void FileSet::LoadFromDir(const CString &dir)
{
age.GetDeltaTime(); /* reset */
files.clear();
CString oldpath;
GetCwd(oldpath);
if(chdir(dir) == -1) return;
#if defined(WIN32)
WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile( "*", &fd );
if( hFind == INVALID_HANDLE_VALUE )
{
chdir(oldpath);
return;
}
do {
if(!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, ".."))
continue;
File f;
f.name=fd.cFileName;
f.dir = !!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
files.insert(f);
} while( FindNextFile( hFind, &fd ) );
FindClose(hFind);
#else
DIR *d = opendir(".");
while(struct dirent *ent = readdir(d))
{
if(!strcmp(ent->d_name, ".")) continue;
if(!strcmp(ent->d_name, "..")) continue;
File f;
f.name=ent->d_name;
f.dir = IsADirectory(ent->d_name);
files.insert(f);
}
closedir(d);
#endif
chdir(oldpath);
}
/* Search for "beginning*containing*ending". */
void FileSet::GetFilesMatching(const CString &beginning, const CString &containing, const CString &ending, vector<CString> &out, bool bOnlyDirs) const
{
set<File>::const_iterator i = files.lower_bound(File(beginning.c_str()));
for( ; i != files.end(); ++i)
{
if(bOnlyDirs && !i->dir) continue;
/* Check beginning. */
if(beginning.size() > i->name.size()) continue; /* can't start with it */
if(strnicmp(i->name.c_str(), beginning.c_str(), beginning.size())) continue; /* doesn't start with it */
/* Position the end starts on: */
int end_pos = int(i->name.size())-int(ending.size());
/* Check end. */
if(end_pos < 0) continue; /* can't end with it */
if(stricmp(i->name.c_str()+end_pos, ending.c_str())) continue; /* doesn't end with it */
/* Check containing. Do this last, since it's the slowest (substring
* search instead of string match). */
if(containing.size())
{
unsigned pos = i->name.find(containing, beginning.size());
if(pos == i->name.npos) continue; /* doesn't contain it */
if(pos + containing.size() > unsigned(end_pos)) continue; /* found it but it overlaps with the end */
}
out.push_back(i->name.c_str());
}
}
void FileSet::GetFilesEqualTo(const CString &str, vector<CString> &out, bool bOnlyDirs) const
{
set<File>::const_iterator i = files.find(File(str.c_str()));
if(i == files.end())
return;
if(bOnlyDirs && !i->dir)
return;
out.push_back(i->name.c_str());
}
bool FileSet::DoesFileExist(const CString &path) const
{
return files.find(File(path.c_str())) != files.end();
}
bool FileSet::IsADirectory(const CString &path) const
{
set<File>::const_iterator i = files.find(File(path.c_str()));
if(i == files.end())
return false;
return i->dir;
}
bool FileSet::IsAFile(const CString &path) const
{
set<File>::const_iterator i = files.find(File(path.c_str()));
if(i == files.end())
return false;
return !i->dir;
}
/* Given "foo/bar/baz/" or "foo/bar/baz", return "foo/bar/" and "baz". */
static void SplitPath( CString Path, CString &Dir, CString &Name )
{
static Regex split("(.*/)([^/]+)");
CStringArray match;
if(split.Compare(Path, match)) {
/* At least one slash. */
Dir = match[0];
Name = match[1];
} else {
/* No slash. */
Dir = "./";
Name = Path;
}
}
class FilenameDB
{
FileSet &GetFileSet(CString dir, bool ResolveCase = true);
/* Directories we have cached: */
map<istring, FileSet *> dirs;
void GetFilesEqualTo(const CString &dir, const CString &fn, vector<CString> &out, bool bOnlyDirs);
void GetFilesMatching(const CString &dir,
const CString &beginning, const CString &containing, const CString &ending,
vector<CString> &out, bool bOnlyDirs);
public:
/* This handles at most one * wildcard. If we need anything more complicated,
* we'll need to use fnmatch or regex. */
void GetFilesSimpleMatch(const CString &dir, const CString &fn, vector<CString> &out, bool bOnlyDirs);
/* Search for "path" case-insensitively and replace it with the correct
* case. If "path" doesn't exist at all, return false and don't change it. */
bool ResolvePath(CString &path);
bool DoesFileExist(const CString &path);
bool IsAFile(const CString &path);
bool IsADirectory(const CString &path);
void FlushDirCache();
};
bool FilenameDB::DoesFileExist( const CString &sPath )
{
CString Dir, Name;
SplitPath(sPath, Dir, Name);
FileSet &fs = GetFileSet(Dir.c_str());
return fs.DoesFileExist(Name);
}
bool FilenameDB::IsAFile( const CString &sPath )
{
CString Dir, Name;
SplitPath(sPath, Dir, Name);
FileSet &fs = GetFileSet(Dir.c_str());
return fs.IsAFile(Name);
}
bool FilenameDB::IsADirectory( const CString &sPath )
{
CString Dir, Name;
SplitPath(sPath, Dir, Name);
FileSet &fs = GetFileSet(Dir.c_str());
return fs.IsADirectory(Name);
}
/* XXX: this won't work right for URIs, eg \\foo\bar */
bool FilenameDB::ResolvePath(CString &path)
{
if(path == ".") return true;
if(path == "") return true;
path.Replace("\\", "/");
/* Split path into components. */
vector<CString> p;
split(path, "/", p, true);
/* Resolve each component. Assume the first component is correct. XXX
* don't do that! "Songs/" vs "songs/" */
CString ret = p[0];
for(unsigned i = 1; i < p.size(); ++i)
{
ret += "/";
vector<CString> lst;
FileSet &fs = GetFileSet(ret.c_str());
fs.GetFilesEqualTo(p[i], lst, false);
/* If there were no matches, the path isn't found. */
if(lst.empty()) return false;
if(lst.size() > 1)
LOG->Warn("Ambiguous filenames \"%s\" and \"%s\"",
lst[0].c_str(), lst[1].c_str());
ret += lst[0];
}
if(path[path.size()-1] == '/')
path = ret + "/";
else
path = ret;
return true;
}
void FilenameDB::GetFilesMatching(const CString &dir, const CString &beginning, const CString &containing, const CString &ending, vector<CString> &out, bool bOnlyDirs)
{
FileSet &fs = GetFileSet(dir.c_str());
fs.GetFilesMatching(beginning, containing, ending, out, bOnlyDirs);
}
void FilenameDB::GetFilesEqualTo(const CString &dir, const CString &fn, vector<CString> &out, bool bOnlyDirs)
{
FileSet &fs = GetFileSet(dir.c_str());
fs.GetFilesEqualTo(fn, out, bOnlyDirs);
}
void FilenameDB::GetFilesSimpleMatch(const CString &dir, const CString &fn, vector<CString> &out, bool bOnlyDirs)
{
/* Does this contain a wildcard? */
unsigned first_pos = fn.find_first_of('*');
if(first_pos == fn.npos)
{
/* No; just do a regular search. */
GetFilesEqualTo(dir, fn, out, bOnlyDirs);
} else {
unsigned second_pos = fn.find_first_of('*', first_pos+1);
if(second_pos == fn.npos)
{
/* Only one *: "A*B". */
GetFilesMatching(dir, fn.substr(0, first_pos), "", fn.substr(first_pos+1), out, bOnlyDirs);
} else {
/* Two *s: "A*B*C". */
GetFilesMatching(dir,
fn.substr(0, first_pos),
fn.substr(first_pos+1, second_pos-first_pos-1),
fn.substr(second_pos+1), out, bOnlyDirs);
}
}
}
FileSet &FilenameDB::GetFileSet(CString dir, bool ResolveCase)
{
/* Normalize the path. */
dir.Replace("\\", "/"); /* foo\bar -> foo/bar */
dir.Replace("//", "/"); /* foo//bar -> foo/bar */
FileSet *ret;
map<istring, FileSet *>::iterator i = dirs.find(dir.c_str());
bool reload = false;
if(i == dirs.end())
{
ret = new FileSet;
dirs[dir.c_str()] = ret;
reload = true;
}
else
{
ret = i->second;
if(ret->age.PeekDeltaTime() > 30)
reload = true;
}
if(reload)
{
CString RealDir = dir;
if(ResolveCase)
{
/* Resolve path cases (path/Path -> PATH/path). */
ResolvePath(RealDir);
/* Alias this name, too. */
dirs[RealDir.c_str()] = ret;
}
ret->LoadFromDir(RealDir);
}
return *ret;
}
void FilenameDB::FlushDirCache()
{
dirs.clear();
}
FilenameDB FDB;
void GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo )
{
/* If you want the CWD, use ".". */
ASSERT(!sPath.empty());
/* XXX: for case-insensitive resolving, we assume the first element is
* correct (we need a place to start from); so if sPath is relative,
* prepend "./" */
/* Strip off the last path element and use it as a mask. */
unsigned pos = sPath.find_last_of("/\\");
CString fn;
if(pos != sPath.npos)
{
fn = sPath.substr(pos+1);
sPath = sPath.substr(0, pos+1);
}
/* If there was only one path element, or if the last element was empty,
* use "*". */
if(fn.size() == 0)
fn = "*";
unsigned start = AddTo.size();
FDB.GetFilesSimpleMatch(sPath, fn, AddTo, bOnlyDirs);
if(bReturnPathToo && start < AddTo.size())
{
FDB.ResolvePath(sPath);
while(start < AddTo.size())
{
AddTo[start] = sPath + AddTo[start];
start++;
}
}
}
#if 0
bool DoesFileExist( const CString &sPath ) { return FDB.DoesFileExist(sPath); }
bool IsAFile( const CString &sPath ) { return FDB.IsAFile(sPath); }
bool IsADirectory( const CString &sPath ) { return FDB.IsADirectory(sPath); }
#else
bool DoesFileExist( const CString &sPath )
{
if(sPath.empty()) return false;
struct stat st;
return DoStat(sPath, &st);
}
bool IsAFile( const CString &sPath )
{
return DoesFileExist(sPath) && !IsADirectory(sPath);
}
bool IsADirectory( const CString &sPath )
{
if(sPath.empty()) return false;
struct stat st;
if (!DoStat(sPath, &st))
return false;
return !!(st.st_mode & S_IFDIR);
}
#endif
/* XXX */
bool DoStat(CString sPath, struct stat *st)
{
TrimRight(sPath, "/\\");
return stat(sPath.c_str(), st) != -1;
}
unsigned GetFileSizeInBytes( const CString &sFilePath )
{
struct stat st;
if(!DoStat(sFilePath, &st))
return 0;
return st.st_size;
}
void FlushDirCache()
{
FDB.FlushDirCache();
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef RAGE_UTIL_FILEDB
#define RAGE_UTIL_FILEDB 1
bool DoesFileExist( const CString &sPath );
bool IsAFile( const CString &sPath );
bool IsADirectory( const CString &sPath );
unsigned GetFileSizeInBytes( const CString &sFilePath );
bool DoStat(CString sPath, struct stat *st);
void FlushDirCache();
#endif
+35 -22
View File
@@ -1,5 +1,5 @@
# Microsoft Developer Studio Project File - Name="StepMania" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 60000
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
@@ -61,10 +61,10 @@ LINK32=link.exe
# SUBTRACT LINK32 /verbose /profile /pdb:none /incremental:no /nodefaultlib
# Begin Special Build Tool
IntDir=.\../Debug6
TargetDir=\stepmania\stepmania
TargetDir=\temp\stepmania
TargetName=StepMania-debug
SOURCE="$(InputPath)"
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi ia32.vdi
# End Special Build Tool
@@ -82,29 +82,25 @@ PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania
# PROP Intermediate_Dir "StepMania___Xbox_Debug___VC6"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I "SDL-1.2.5\include" /I "SDL_image-1.2" /I "plib-1.6.0" /D "WIN32" /D "_XBOX" /D "_DEBUG" /Fr /YX"global.h" /FD /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I "SDL-1.2.5\include" /I "SDL_image-1.2" /I "plib-1.6.0" /D "WIN32" /D "_XBOX" /D "_DEBUG" /Fr /YX"global.h" /FD /c
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
XBCP=xbecopy.exe
# ADD BASE XBCP /NOLOGO
# ADD XBCP /NOLOGO
XBE=imagebld.exe
# ADD BASE XBE /nologo /stack:0x10000 /debug
# ADD XBE /nologo /stack:0x10000 /debug
LINK32=link.exe
# ADD BASE LINK32 $(intdir)\verstub.obj kernel32.lib shell32.lib user32.lib gdi32.lib advapi32.lib winmm.lib /nologo /pdb:"../debug6/StepMania-debug.pdb" /map /debug /machine:IX86 /nodefaultlib:"libcmtd.lib" /out:"../StepMania-debug.exe"
# SUBTRACT BASE LINK32 /verbose /profile /pdb:none /incremental:no /nodefaultlib
# ADD LINK32 $(intdir)\verstub.obj kernel32.lib shell32.lib user32.lib gdi32.lib advapi32.lib winmm.lib /nologo /pdb:"../debug6/StepMania-debug.pdb" /map /debug /machine:IX86 /nodefaultlib:"libcmtd.lib" /out:"../StepMania-debug.exe"
# SUBTRACT LINK32 /verbose /profile /pdb:none /incremental:no /nodefaultlib
XBE=imagebld.exe
# ADD BASE XBE /nologo /stack:0x10000 /debug
# ADD XBE /nologo /stack:0x10000 /debug
XBCP=xbecopy.exe
# ADD BASE XBCP /NOLOGO
# ADD XBCP /NOLOGO
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I "SDL-1.2.5\include" /I "SDL_image-1.2" /I "plib-1.6.0" /D "WIN32" /D "_XBOX" /D "_DEBUG" /Fr /YX"global.h" /FD /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I "SDL-1.2.5\include" /I "SDL_image-1.2" /I "plib-1.6.0" /D "WIN32" /D "_XBOX" /D "_DEBUG" /Fr /YX"global.h" /FD /c
# Begin Special Build Tool
IntDir=.\StepMania___Xbox_Debug___VC6
TargetDir=.\StepMania___Xbox_Debug___VC6
TargetName=StepMania
SOURCE="$(InputPath)"
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi ia32.vdi
# End Special Build Tool
@@ -141,10 +137,10 @@ LINK32=link.exe
# SUBTRACT LINK32 /verbose /pdb:none
# Begin Special Build Tool
IntDir=.\../Release6
TargetDir=\stepmania\stepmania
TargetDir=\temp\stepmania
TargetName=StepMania
SOURCE="$(InputPath)"
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi ia32.vdi
# End Special Build Tool
@@ -669,6 +665,23 @@ SOURCE=.\RageUtil_CharConversions.cpp
SOURCE=.\RageUtil_CharConversions.h
# End Source File
# Begin Source File
SOURCE=.\RageUtil_FileDB.cpp
!IF "$(CFG)" == "StepMania - Win32 Debug"
!ELSEIF "$(CFG)" == "StepMania - Xbox Debug"
!ELSEIF "$(CFG)" == "StepMania - Win32 Release"
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\RageUtil_FileDB.h
# End Source File
# End Group
# Begin Group "Data Structures"
+6
View File
@@ -1605,6 +1605,12 @@ cl /Zl /nologo /c verstub.cpp /Fo&quot;$(IntDir)&quot;\
<File
RelativePath="RageUtil_CharConversions.h">
</File>
<File
RelativePath="RageUtil_FileDB.cpp">
</File>
<File
RelativePath="RageUtil_FileDB.h">
</File>
<Filter
Name="Helpers"
Filter="">
+1 -1
View File
@@ -154,7 +154,7 @@ try_element_again:
if( asElementPaths.size() > 1 )
{
FDB.FlushDirCache();
FlushDirCache();
CString message = ssprintf(
"There is more than one theme element element that matches "