quadrilateralcowboy/sys/linux/casedir.patch
2020-06-12 14:06:25 -07:00

213 lines
6.8 KiB
Diff

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