1 Index: framework/FileSystem.cpp
2 ===================================================================
3 --- framework/FileSystem.cpp (revision 528)
4 +++ framework/FileSystem.cpp (working copy)
8 // 3 search patch (fs_savepath fs_basepath fs_cdpath)
10 +// often .jpg and .tga patterns
11 #define MAX_CACHED_DIRS 6
13 class idDEntry : public idStrList {
15 void Init(const char *directory, const char *extension, const idStrList &list );
23 class idFileSystem_local : public idFileSystem {
25 idFileSystem_local( void );
28 int serverPaks[MAX_SEARCH_PATHS];
30 - idDEntry dir_cache[MAX_CACHED_DIRS]; // fifo
31 + idDEntry dir_cache[MAX_CACHED_DIRS]; // fifo
35 + idList<casematch_t> dir_case; // match directories in a case insensitive way
38 + const char * CaseSearch(const char *in_dir);
39 void ReplaceSeparators( idStr &path, char sep = PATHSEPERATOR_CHAR );
40 long HashFileName( const char *fname ) const;
41 bool FilenameCompare( const char *s1, const char *s2 );
42 @@ -1118,6 +1126,89 @@
46 +idFileSystem_local::CaseSearch
49 +const char* idFileSystem_local::CaseSearch(const char *in_dir) {
52 + // FIXME: go faster with a hash?
53 + for( i=0; i<dir_case.Num(); i++ ) {
54 + if ( !dir_case[i].path.Cmp( in_dir ) ) {
55 + ret = dir_case[i].OSpath.c_str();
56 + Com_Printf("index %d: '%s' matched as '%s'\n", i, in_dir, ret);
57 + if ( ret[0] == '\0' ) {
64 + entry.path = in_dir;
65 + Com_Printf("CaseSearch not found: '%s'\n", in_dir);
66 + // walk down the directory tree searching for a case insensitive match
67 + // use StripFilename to bust out the chunks
70 + idStr walk_path = in_dir;
74 + walk_path.ExtractFileName(current_dir);
75 + dirs.Append(current_dir);
76 + walk_path.StripFilename(); // this is double work
77 + Com_Printf("have walk_path: %s, current_dir: %s\n", walk_path.c_str(), current_dir.c_str());
78 + } while ( walk_path.Length() && ( list_ret = Sys_ListFiles( walk_path.c_str(), "/", entries ) == -1 ) );
79 + // we have walked up to the first directory
80 + if ( list_ret == -1 ) {
81 + Com_DPrintf("WARNING: didn't find any matching root directory for '%s'\n", in_dir);
82 + dir_case.Append(entry);
85 + // start walking down and doing matches
87 + entry.OSpath = walk_path;
88 + for( i=dirs.Num()-1 ; i>=0; i-- ) {
89 + Com_Printf("chunk: %s\n", dirs[i].c_str() );
91 + for( j=0 ; j<entries.Num() ; j++ ) {
92 + Com_Printf("match %s and %s\n", dirs[i].c_str(), entries[j].c_str());
93 + if ( !dirs[i].Icmp(entries[j]) ) {
94 + Com_Printf("we have a match, add this to the path and go down\n");
96 + break; // NOTE: we could keep scanning and detect conflicts?
99 + // if we didn't match, abort
101 + Com_Printf("no match\n");
103 + dir_case.Append(entry);
106 + entry.OSpath += PATHSEPERATOR_STR;
107 + entry.OSpath += entries[j];
108 + // get the directory list
109 + if ( Sys_ListFiles( entry.OSpath.c_str(), "/", entries ) == -1 ) {
110 + Com_DPrintf("WARNING: didn't find entries in '%s' after successful icase match\n", entry.OSpath.c_str());
112 + dir_case.Append(entry);
117 + dir_case.Append(entry);
118 + ret = dir_case[ dir_case.Num() - 1 ].OSpath.c_str();
119 + Com_Printf("case matched '%s' as '%s'\n", in_dir, ret);
120 + if ( ret[0] == '\0' ) {
121 + Com_DPrintf("WARNING: unexpected empty entry after successful case walk for '%s'\n", in_dir);
129 idFileSystem_local::ListOSFiles
131 call to the OS for a listing of files in an OS directory
132 @@ -1156,10 +1247,19 @@
133 ret = Sys_ListFiles( directory, extension, list );
137 + // try a case insensitive directory walk
138 + const char *cased_dir = CaseSearch(directory);
142 + ret = Sys_ListFiles( cased_dir, extension, list );
144 + Com_DPrintf("idFileSystem_local::ListOSFiles: unexpected, Sys_ListFiles failed on case matched directory\n");
149 - // push a new entry
150 + // push a new entry - (if case matched we are caching with the requested directory name)
151 dir_cache[dir_cache_index].Init( directory, extension, list );
152 dir_cache_index = (++dir_cache_index) % MAX_CACHED_DIRS;
153 if ( dir_cache_count < MAX_CACHED_DIRS ) {
154 @@ -1633,6 +1733,11 @@
158 + for ( int i = 0 ; i < MAX_CACHED_DIRS ; i++ ) {
159 + dir_cache[i].Clear();
165 for ( sp = searchPaths; sp; sp = next ) {
166 Index: sys/linux/ChangeLog
167 ===================================================================
168 --- sys/linux/ChangeLog (revision 528)
169 +++ sys/linux/ChangeLog (working copy)
172 - bring up logging capability on *nix (implies non-implicit GL dependency mode)
174 +case insensitive directory walk - NOTES:
176 +wrote the base stuff. keeps a list of attempted/not found dirs.
177 +with the case sensitive match if exists
178 +dumb lookup currently, probably a bit expensive in CPU and mem
179 +hash table would speed this up
181 +still not sure that's the right way to go with this. I think the client should send
182 +out warnings when it finds bad cased directory, and in the long run abort
183 +with an error. That would be the only way to safe keep portability.
185 +trying to find good test case for that stuff
186 +scary: 300 entries for game/admin?
187 +design the search tree some other way? binary tree? (yeah why not)
188 +grep "Couldn't load" run.log | grep -v nin
190 +WARNING: Couldn't load image: models/mapobjects/tables/udesk/udesk_local
192 +timo@slinky:~/Id/DoomBase.ftpfs/base$ ls models/mapobjects/tables/Udesk/
193 +udesk.lwo udesk2.tga udesk_local.tga work
194 +udesk.tga udesk_base.lwo udesk_s.tga
196 +Is there an entry point for a directory instead of a file? What happens?
197 +(i.e. last directory of the path is cased)
201 2003-05-09 TTimo <ttimo@idsoftware.com>
202 Index: sys/sys_public.h
203 ===================================================================
204 --- sys/sys_public.h (revision 528)
205 +++ sys/sys_public.h (working copy)
208 // use fs_debug to verbose Sys_ListFiles
209 // returns -1 if directory was not found (the list is cleared)
210 +// if there is a / passed as extension, return directories
211 int Sys_ListFiles( const char *directory, const char *extension, idStrList &list);
213 // For the mac, we need to explicitly flush vertex buffer areas before using them