123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- Index: framework/FileSystem.cpp
- ===================================================================
- --- framework/FileSystem.cpp (revision 528)
- +++ framework/FileSystem.cpp (working copy)
- @@ -159,7 +159,7 @@
- };
-
- // 3 search patch (fs_savepath fs_basepath fs_cdpath)
- -// .jpg then .tga for
- +// often .jpg and .tga patterns
- #define MAX_CACHED_DIRS 6
-
- class idDEntry : public idStrList {
- @@ -173,6 +173,11 @@
- void Init(const char *directory, const char *extension, const idStrList &list );
- };
-
- +typedef struct {
- + idStr path;
- + idStr OSpath;
- +} casematch_t;
- +
- class idFileSystem_local : public idFileSystem {
- public:
- idFileSystem_local( void );
- @@ -227,11 +232,14 @@
- int numServerPaks;
- int serverPaks[MAX_SEARCH_PATHS];
-
- - idDEntry dir_cache[MAX_CACHED_DIRS]; // fifo
- + idDEntry dir_cache[MAX_CACHED_DIRS]; // fifo
- int dir_cache_index;
- int dir_cache_count;
- +
- + idList<casematch_t> dir_case; // match directories in a case insensitive way
-
- private:
- + const char * CaseSearch(const char *in_dir);
- void ReplaceSeparators( idStr &path, char sep = PATHSEPERATOR_CHAR );
- long HashFileName( const char *fname ) const;
- bool FilenameCompare( const char *s1, const char *s2 );
- @@ -1118,6 +1126,89 @@
-
- /*
- ===============
- +idFileSystem_local::CaseSearch
- +===============
- +*/
- +const char* idFileSystem_local::CaseSearch(const char *in_dir) {
- + const char *ret;
- + int i, j;
- + // FIXME: go faster with a hash?
- + for( i=0; i<dir_case.Num(); i++ ) {
- + if ( !dir_case[i].path.Cmp( in_dir ) ) {
- + ret = dir_case[i].OSpath.c_str();
- + Com_Printf("index %d: '%s' matched as '%s'\n", i, in_dir, ret);
- + if ( ret[0] == '\0' ) {
- + return NULL;
- + }
- + return ret;
- + }
- + }
- + casematch_t entry;
- + entry.path = in_dir;
- + Com_Printf("CaseSearch not found: '%s'\n", in_dir);
- + // walk down the directory tree searching for a case insensitive match
- + // use StripFilename to bust out the chunks
- + idStrList dirs;
- + idStrList entries;
- + idStr walk_path = in_dir;
- + idStr current_dir;
- + int list_ret;
- + do {
- + walk_path.ExtractFileName(current_dir);
- + dirs.Append(current_dir);
- + walk_path.StripFilename(); // this is double work
- + Com_Printf("have walk_path: %s, current_dir: %s\n", walk_path.c_str(), current_dir.c_str());
- + } while ( walk_path.Length() && ( list_ret = Sys_ListFiles( walk_path.c_str(), "/", entries ) == -1 ) );
- + // we have walked up to the first directory
- + if ( list_ret == -1 ) {
- + Com_DPrintf("WARNING: didn't find any matching root directory for '%s'\n", in_dir);
- + dir_case.Append(entry);
- + return NULL;
- + }
- + // start walking down and doing matches
- + bool bMatched;
- + entry.OSpath = walk_path;
- + for( i=dirs.Num()-1 ; i>=0; i-- ) {
- + Com_Printf("chunk: %s\n", dirs[i].c_str() );
- + bMatched = false;
- + for( j=0 ; j<entries.Num() ; j++ ) {
- + Com_Printf("match %s and %s\n", dirs[i].c_str(), entries[j].c_str());
- + if ( !dirs[i].Icmp(entries[j]) ) {
- + Com_Printf("we have a match, add this to the path and go down\n");
- + bMatched = true;
- + break; // NOTE: we could keep scanning and detect conflicts?
- + }
- + }
- + // if we didn't match, abort
- + if (!bMatched) {
- + Com_Printf("no match\n");
- + entry.OSpath = "";
- + dir_case.Append(entry);
- + return NULL;
- + }
- + entry.OSpath += PATHSEPERATOR_STR;
- + entry.OSpath += entries[j];
- + // get the directory list
- + if ( Sys_ListFiles( entry.OSpath.c_str(), "/", entries ) == -1 ) {
- + Com_DPrintf("WARNING: didn't find entries in '%s' after successful icase match\n", entry.OSpath.c_str());
- + entry.OSpath = "";
- + dir_case.Append(entry);
- + return NULL;
- + }
- + }
- +
- + dir_case.Append(entry);
- + ret = dir_case[ dir_case.Num() - 1 ].OSpath.c_str();
- + Com_Printf("case matched '%s' as '%s'\n", in_dir, ret);
- + if ( ret[0] == '\0' ) {
- + Com_DPrintf("WARNING: unexpected empty entry after successful case walk for '%s'\n", in_dir);
- + return NULL;
- + }
- + return ret;
- +}
- +
- +/*
- +===============
- idFileSystem_local::ListOSFiles
-
- call to the OS for a listing of files in an OS directory
- @@ -1156,10 +1247,19 @@
- ret = Sys_ListFiles( directory, extension, list );
-
- if ( ret == -1 ) {
- - return -1;
- + // try a case insensitive directory walk
- + const char *cased_dir = CaseSearch(directory);
- + if (!cased_dir) {
- + return -1;
- + }
- + ret = Sys_ListFiles( cased_dir, extension, list );
- + if ( ret == -1 ) {
- + Com_DPrintf("idFileSystem_local::ListOSFiles: unexpected, Sys_ListFiles failed on case matched directory\n");
- + return -1;
- + }
- }
-
- - // push a new entry
- + // push a new entry - (if case matched we are caching with the requested directory name)
- dir_cache[dir_cache_index].Init( directory, extension, list );
- dir_cache_index = (++dir_cache_index) % MAX_CACHED_DIRS;
- if ( dir_cache_count < MAX_CACHED_DIRS ) {
- @@ -1633,6 +1733,11 @@
-
- dir_cache_index = 0;
- dir_cache_count = 0;
- + for ( int i = 0 ; i < MAX_CACHED_DIRS ; i++ ) {
- + dir_cache[i].Clear();
- + }
- +
- + dir_case.Clear();
-
- // free everything
- for ( sp = searchPaths; sp; sp = next ) {
- Index: sys/linux/ChangeLog
- ===================================================================
- --- sys/linux/ChangeLog (revision 528)
- +++ sys/linux/ChangeLog (working copy)
- @@ -81,6 +81,31 @@
- renderer TODO:
- - bring up logging capability on *nix (implies non-implicit GL dependency mode)
-
- +case insensitive directory walk - NOTES:
- +
- +wrote the base stuff. keeps a list of attempted/not found dirs.
- +with the case sensitive match if exists
- +dumb lookup currently, probably a bit expensive in CPU and mem
- +hash table would speed this up
- +
- +still not sure that's the right way to go with this. I think the client should send
- +out warnings when it finds bad cased directory, and in the long run abort
- +with an error. That would be the only way to safe keep portability.
- +
- +trying to find good test case for that stuff
- +scary: 300 entries for game/admin?
- +design the search tree some other way? binary tree? (yeah why not)
- +grep "Couldn't load" run.log | grep -v nin
- +
- +WARNING: Couldn't load image: models/mapobjects/tables/udesk/udesk_local
- +
- +timo@slinky:~/Id/DoomBase.ftpfs/base$ ls models/mapobjects/tables/Udesk/
- +udesk.lwo udesk2.tga udesk_local.tga work
- +udesk.tga udesk_base.lwo udesk_s.tga
- +
- +Is there an entry point for a directory instead of a file? What happens?
- +(i.e. last directory of the path is cased)
- +
- idBoneController
-
- 2003-05-09 TTimo <ttimo@idsoftware.com>
- Index: sys/sys_public.h
- ===================================================================
- --- sys/sys_public.h (revision 528)
- +++ sys/sys_public.h (working copy)
- @@ -137,6 +137,7 @@
-
- // use fs_debug to verbose Sys_ListFiles
- // returns -1 if directory was not found (the list is cleared)
- +// if there is a / passed as extension, return directories
- int Sys_ListFiles( const char *directory, const char *extension, idStrList &list);
-
- // For the mac, we need to explicitly flush vertex buffer areas before using them
|