_FindFirst.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /**
  2. * Original file by the_viking, fixed by Rômulo Fernandes, fixed by Emmanuel Nars
  3. * Should emulate windows finddata structure
  4. */
  5. #if (defined(__GNUC__) || defined(__GCCXML__)) && !defined(_WIN32)
  6. #include "_FindFirst.h"
  7. #include "DS_List.h"
  8. #include <sys/stat.h>
  9. #include <fnmatch.h>
  10. static DataStructures::List< _findinfo_t* > fileInfo;
  11. #include "RakMemoryOverride.h"
  12. #include "RakAssert.h"
  13. /**
  14. * _findfirst - equivalent
  15. */
  16. long _findfirst(const char *name, _finddata_t *f)
  17. {
  18. RakNet::RakString nameCopy = name;
  19. RakNet::RakString filter;
  20. // This is linux only, so don't bother with '\'
  21. const char* lastSep = strrchr(name,'/');
  22. if(!lastSep)
  23. {
  24. // filter pattern only is given, search current directory.
  25. filter = nameCopy;
  26. nameCopy = ".";
  27. } else
  28. {
  29. // strip filter pattern from directory name, leave
  30. // trailing '/' intact.
  31. filter = lastSep+1;
  32. unsigned sepIndex = lastSep - name;
  33. nameCopy.Erase(sepIndex+1, nameCopy.GetLength() - sepIndex-1);
  34. }
  35. DIR* dir = opendir(nameCopy);
  36. if(!dir) return -1;
  37. _findinfo_t* fi = RakNet::OP_NEW<_findinfo_t>( _FILE_AND_LINE_ );
  38. fi->filter = filter;
  39. fi->dirName = nameCopy; // we need to remember this for stat()
  40. fi->openedDir = dir;
  41. fileInfo.Insert(fi, _FILE_AND_LINE_);
  42. long ret = fileInfo.Size()-1;
  43. // Retrieve the first file. We cannot rely on the first item
  44. // being '.'
  45. if (_findnext(ret, f) == -1) return -1;
  46. else return ret;
  47. }
  48. int _findnext(long h, _finddata_t *f)
  49. {
  50. RakAssert(h >= 0 && h < (long)fileInfo.Size());
  51. if (h < 0 || h >= (long)fileInfo.Size()) return -1;
  52. _findinfo_t* fi = fileInfo[h];
  53. while(true)
  54. {
  55. dirent* entry = readdir(fi->openedDir);
  56. if(entry == 0) return -1;
  57. // Only report stuff matching our filter
  58. if (fnmatch(fi->filter, entry->d_name, FNM_PATHNAME) != 0) continue;
  59. // To reliably determine the entry's type, we must do
  60. // a stat... don't rely on entry->d_type, as this
  61. // might be unavailable!
  62. struct stat filestat;
  63. RakNet::RakString fullPath = fi->dirName + entry->d_name;
  64. if (stat(fullPath, &filestat) != 0)
  65. {
  66. RAKNET_DEBUG_PRINTF("Cannot stat %s\n", fullPath.C_String());
  67. continue;
  68. }
  69. if (S_ISREG(filestat.st_mode))
  70. {
  71. f->attrib = _A_NORMAL;
  72. } else if (S_ISDIR(filestat.st_mode))
  73. {
  74. f->attrib = _A_SUBDIR;
  75. } else continue; // We are interested in files and
  76. // directories only. Links currently
  77. // are not supported.
  78. f->size = filestat.st_size;
  79. strncpy(f->name, entry->d_name, STRING_BUFFER_SIZE);
  80. return 0;
  81. }
  82. return -1;
  83. }
  84. /**
  85. * _findclose - equivalent
  86. */
  87. int _findclose(long h)
  88. {
  89. if (h==-1) return 0;
  90. if (h < 0 || h >= (long)fileInfo.Size())
  91. {
  92. RakAssert(false);
  93. return -1;
  94. }
  95. _findinfo_t* fi = fileInfo[h];
  96. closedir(fi->openedDir);
  97. fileInfo.RemoveAtIndex(h);
  98. RakNet::OP_DELETE(fi, _FILE_AND_LINE_);
  99. return 0;
  100. }
  101. #endif
粤ICP备19079148号