casedir.patch 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. Index: framework/FileSystem.cpp
  2. ===================================================================
  3. --- framework/FileSystem.cpp (revision 528)
  4. +++ framework/FileSystem.cpp (working copy)
  5. @@ -159,7 +159,7 @@
  6. };
  7. // 3 search patch (fs_savepath fs_basepath fs_cdpath)
  8. -// .jpg then .tga for
  9. +// often .jpg and .tga patterns
  10. #define MAX_CACHED_DIRS 6
  11. class idDEntry : public idStrList {
  12. @@ -173,6 +173,11 @@
  13. void Init(const char *directory, const char *extension, const idStrList &list );
  14. };
  15. +typedef struct {
  16. + idStr path;
  17. + idStr OSpath;
  18. +} casematch_t;
  19. +
  20. class idFileSystem_local : public idFileSystem {
  21. public:
  22. idFileSystem_local( void );
  23. @@ -227,11 +232,14 @@
  24. int numServerPaks;
  25. int serverPaks[MAX_SEARCH_PATHS];
  26. - idDEntry dir_cache[MAX_CACHED_DIRS]; // fifo
  27. + idDEntry dir_cache[MAX_CACHED_DIRS]; // fifo
  28. int dir_cache_index;
  29. int dir_cache_count;
  30. +
  31. + idList<casematch_t> dir_case; // match directories in a case insensitive way
  32. private:
  33. + const char * CaseSearch(const char *in_dir);
  34. void ReplaceSeparators( idStr &path, char sep = PATHSEPERATOR_CHAR );
  35. long HashFileName( const char *fname ) const;
  36. bool FilenameCompare( const char *s1, const char *s2 );
  37. @@ -1118,6 +1126,89 @@
  38. /*
  39. ===============
  40. +idFileSystem_local::CaseSearch
  41. +===============
  42. +*/
  43. +const char* idFileSystem_local::CaseSearch(const char *in_dir) {
  44. + const char *ret;
  45. + int i, j;
  46. + // FIXME: go faster with a hash?
  47. + for( i=0; i<dir_case.Num(); i++ ) {
  48. + if ( !dir_case[i].path.Cmp( in_dir ) ) {
  49. + ret = dir_case[i].OSpath.c_str();
  50. + Com_Printf("index %d: '%s' matched as '%s'\n", i, in_dir, ret);
  51. + if ( ret[0] == '\0' ) {
  52. + return NULL;
  53. + }
  54. + return ret;
  55. + }
  56. + }
  57. + casematch_t entry;
  58. + entry.path = in_dir;
  59. + Com_Printf("CaseSearch not found: '%s'\n", in_dir);
  60. + // walk down the directory tree searching for a case insensitive match
  61. + // use StripFilename to bust out the chunks
  62. + idStrList dirs;
  63. + idStrList entries;
  64. + idStr walk_path = in_dir;
  65. + idStr current_dir;
  66. + int list_ret;
  67. + do {
  68. + walk_path.ExtractFileName(current_dir);
  69. + dirs.Append(current_dir);
  70. + walk_path.StripFilename(); // this is double work
  71. + Com_Printf("have walk_path: %s, current_dir: %s\n", walk_path.c_str(), current_dir.c_str());
  72. + } while ( walk_path.Length() && ( list_ret = Sys_ListFiles( walk_path.c_str(), "/", entries ) == -1 ) );
  73. + // we have walked up to the first directory
  74. + if ( list_ret == -1 ) {
  75. + Com_DPrintf("WARNING: didn't find any matching root directory for '%s'\n", in_dir);
  76. + dir_case.Append(entry);
  77. + return NULL;
  78. + }
  79. + // start walking down and doing matches
  80. + bool bMatched;
  81. + entry.OSpath = walk_path;
  82. + for( i=dirs.Num()-1 ; i>=0; i-- ) {
  83. + Com_Printf("chunk: %s\n", dirs[i].c_str() );
  84. + bMatched = false;
  85. + for( j=0 ; j<entries.Num() ; j++ ) {
  86. + Com_Printf("match %s and %s\n", dirs[i].c_str(), entries[j].c_str());
  87. + if ( !dirs[i].Icmp(entries[j]) ) {
  88. + Com_Printf("we have a match, add this to the path and go down\n");
  89. + bMatched = true;
  90. + break; // NOTE: we could keep scanning and detect conflicts?
  91. + }
  92. + }
  93. + // if we didn't match, abort
  94. + if (!bMatched) {
  95. + Com_Printf("no match\n");
  96. + entry.OSpath = "";
  97. + dir_case.Append(entry);
  98. + return NULL;
  99. + }
  100. + entry.OSpath += PATHSEPERATOR_STR;
  101. + entry.OSpath += entries[j];
  102. + // get the directory list
  103. + if ( Sys_ListFiles( entry.OSpath.c_str(), "/", entries ) == -1 ) {
  104. + Com_DPrintf("WARNING: didn't find entries in '%s' after successful icase match\n", entry.OSpath.c_str());
  105. + entry.OSpath = "";
  106. + dir_case.Append(entry);
  107. + return NULL;
  108. + }
  109. + }
  110. +
  111. + dir_case.Append(entry);
  112. + ret = dir_case[ dir_case.Num() - 1 ].OSpath.c_str();
  113. + Com_Printf("case matched '%s' as '%s'\n", in_dir, ret);
  114. + if ( ret[0] == '\0' ) {
  115. + Com_DPrintf("WARNING: unexpected empty entry after successful case walk for '%s'\n", in_dir);
  116. + return NULL;
  117. + }
  118. + return ret;
  119. +}
  120. +
  121. +/*
  122. +===============
  123. idFileSystem_local::ListOSFiles
  124. call to the OS for a listing of files in an OS directory
  125. @@ -1156,10 +1247,19 @@
  126. ret = Sys_ListFiles( directory, extension, list );
  127. if ( ret == -1 ) {
  128. - return -1;
  129. + // try a case insensitive directory walk
  130. + const char *cased_dir = CaseSearch(directory);
  131. + if (!cased_dir) {
  132. + return -1;
  133. + }
  134. + ret = Sys_ListFiles( cased_dir, extension, list );
  135. + if ( ret == -1 ) {
  136. + Com_DPrintf("idFileSystem_local::ListOSFiles: unexpected, Sys_ListFiles failed on case matched directory\n");
  137. + return -1;
  138. + }
  139. }
  140. - // push a new entry
  141. + // push a new entry - (if case matched we are caching with the requested directory name)
  142. dir_cache[dir_cache_index].Init( directory, extension, list );
  143. dir_cache_index = (++dir_cache_index) % MAX_CACHED_DIRS;
  144. if ( dir_cache_count < MAX_CACHED_DIRS ) {
  145. @@ -1633,6 +1733,11 @@
  146. dir_cache_index = 0;
  147. dir_cache_count = 0;
  148. + for ( int i = 0 ; i < MAX_CACHED_DIRS ; i++ ) {
  149. + dir_cache[i].Clear();
  150. + }
  151. +
  152. + dir_case.Clear();
  153. // free everything
  154. for ( sp = searchPaths; sp; sp = next ) {
  155. Index: sys/linux/ChangeLog
  156. ===================================================================
  157. --- sys/linux/ChangeLog (revision 528)
  158. +++ sys/linux/ChangeLog (working copy)
  159. @@ -81,6 +81,31 @@
  160. renderer TODO:
  161. - bring up logging capability on *nix (implies non-implicit GL dependency mode)
  162. +case insensitive directory walk - NOTES:
  163. +
  164. +wrote the base stuff. keeps a list of attempted/not found dirs.
  165. +with the case sensitive match if exists
  166. +dumb lookup currently, probably a bit expensive in CPU and mem
  167. +hash table would speed this up
  168. +
  169. +still not sure that's the right way to go with this. I think the client should send
  170. +out warnings when it finds bad cased directory, and in the long run abort
  171. +with an error. That would be the only way to safe keep portability.
  172. +
  173. +trying to find good test case for that stuff
  174. +scary: 300 entries for game/admin?
  175. +design the search tree some other way? binary tree? (yeah why not)
  176. +grep "Couldn't load" run.log | grep -v nin
  177. +
  178. +WARNING: Couldn't load image: models/mapobjects/tables/udesk/udesk_local
  179. +
  180. +timo@slinky:~/Id/DoomBase.ftpfs/base$ ls models/mapobjects/tables/Udesk/
  181. +udesk.lwo udesk2.tga udesk_local.tga work
  182. +udesk.tga udesk_base.lwo udesk_s.tga
  183. +
  184. +Is there an entry point for a directory instead of a file? What happens?
  185. +(i.e. last directory of the path is cased)
  186. +
  187. idBoneController
  188. 2003-05-09 TTimo <ttimo@idsoftware.com>
  189. Index: sys/sys_public.h
  190. ===================================================================
  191. --- sys/sys_public.h (revision 528)
  192. +++ sys/sys_public.h (working copy)
  193. @@ -137,6 +137,7 @@
  194. // use fs_debug to verbose Sys_ListFiles
  195. // returns -1 if directory was not found (the list is cleared)
  196. +// if there is a / passed as extension, return directories
  197. int Sys_ListFiles( const char *directory, const char *extension, idStrList &list);
  198. // For the mac, we need to explicitly flush vertex buffer areas before using them