Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

348 lines
7.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Contains the Implementations of the OS Interfaces
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. //
  8. //------------------------------------------------------------------------------------------------------
  9. // $Log: $
  10. //
  11. // $NoKeywords: $
  12. //=============================================================================//
  13. #include "TFStatsOSInterface.h"
  14. #include "util.h"
  15. //------------------------------------------------------------------------------------------------------
  16. // Function: getNextDirectory
  17. // Purpose: a wrapper for strtok, to return the next directory name out of a path
  18. // Input: path - the path (will be modified by the call to strtok)
  19. // Output: char*
  20. //------------------------------------------------------------------------------------------------------
  21. char* CTFStatsOSInterface::getNextDirectory(char* path)
  22. {
  23. char seps[3];
  24. seps[0]=pathSeperator();
  25. seps[1]=0;
  26. return strtok( path, seps );
  27. }
  28. //------------------------------------------------------------------------------------------------------
  29. // Function: makeDirectory
  30. // Purpose: makes a directory hierarchy. because mkdir can't make nested dirs
  31. // Input: dir - the string of the path to make
  32. // Output: Returns true on success, false on failure.
  33. // Note: Notice how easy the linux part of this function is... no drive letters. :)
  34. //------------------------------------------------------------------------------------------------------
  35. bool CTFStatsOSInterface::makeHier(string dir)
  36. {
  37. errno=0;
  38. //printf("TRYING TO MAKE %s\n",dir.c_str());
  39. char startingDir[500];
  40. this->getcwd(startingDir,500);
  41. bool retval=true;
  42. const char* nextDir=NULL;
  43. char path[500];
  44. char* dirs=path;
  45. strcpy(path,dir.c_str());
  46. //have to parse out directories one at a time. because mkdir just can't handle making nested directories that don't exist (just like md.)
  47. //in otherwords, it's lame.
  48. #ifdef WIN32
  49. //get drive out of path change to it.
  50. //if it's only one character, then interpret it as a path, make it and return;
  51. //only do this test because the tests below rely on at least 2 characters in the path
  52. if (strlen(path)<2)
  53. {
  54. this->mkdir(path);
  55. return true;
  56. }
  57. //what should we do with remote machines?
  58. //hmm, let's force users to use mapped drives.
  59. if (path[0]=='\\' && path[1]=='\\')
  60. {
  61. Util::debug_dir_printf("Cannot make a directory on a remote machine.\nMap the share to a drive and specify that drive instead.\n");
  62. retval=false;
  63. goto end;
  64. }
  65. //if it's a drive specification
  66. if (path[0]=='\\')
  67. {
  68. if (this->chdir("\\")!=0)
  69. Util::debug_dir_printf("Could not change to root on drive %c\n",this->getdrive() + 'a' - 1);
  70. dirs=&path[1];
  71. }
  72. else if (path[1]==':')
  73. {
  74. //this little formula turns a drive number into the drive letter
  75. int drive=path[0]+1 - 'a';
  76. if (this->chdrive(drive)!=0)
  77. {
  78. Util::debug_dir_printf("Drive \"%c:\" does not exist\n",path[0]);
  79. retval=false;
  80. goto end;
  81. }
  82. if (path[2]=='\\')
  83. {
  84. if (this->chdir("\\")!=0)
  85. {
  86. Util::debug_dir_printf("Could not change to root on drive %c\n",path[0]);
  87. retval=false;
  88. goto end;
  89. }
  90. dirs=&path[3];
  91. }
  92. else
  93. {
  94. dirs=&path[2];
  95. }
  96. }
  97. #else // if linux
  98. if (path[0]=='/')
  99. {
  100. this->chdir("/");
  101. dirs=&path[1];
  102. char temp[100];
  103. this->getcwd(temp,100);
  104. Util::debug_dir_printf("switched to root. current dir is %s\n",temp);
  105. }
  106. #endif
  107. if (dirs[0]==0)
  108. {
  109. retval=true;
  110. goto end;
  111. }
  112. //parse out directories. keep trying to changedir into them one by one
  113. // when one fails, make it, and continue.
  114. nextDir=getNextDirectory(path);
  115. do
  116. {
  117. if (this->chdir(nextDir)!=0)
  118. {
  119. if (this->mkdir(nextDir)!=0)
  120. {
  121. char buf[500];
  122. Util::debug_dir_printf("Could not create directory (current directory is %s) (failed on %s)\n",getcwd(buf,500),nextDir);
  123. retval=false;
  124. goto end;
  125. }
  126. else
  127. Util::debug_dir_printf("created %s\n",nextDir);
  128. //try one more time
  129. if (this->chdir(nextDir)!=0)
  130. {
  131. char buf[500];
  132. Util::debug_dir_printf("Could not create directory (current directory is %s) failed on second attempt to change to %s\n",getcwd(buf,500),nextDir);
  133. retval=false;
  134. goto end;
  135. }
  136. char temp[200];
  137. this->getcwd(temp,200);
  138. Util::debug_dir_printf("Now in %s\n",temp);
  139. }
  140. nextDir=getNextDirectory(NULL);
  141. }while(nextDir);
  142. retval=true;
  143. end:
  144. this->chdir(startingDir);
  145. Util::debug_dir_printf("changingDirectory to %s\n",startingDir);
  146. return retval;
  147. }
  148. string& CTFStatsOSInterface::addDirSlash(string& tempbuf)
  149. {
  150. if (tempbuf!="")
  151. {
  152. int buflen=tempbuf.length();
  153. if (tempbuf.at(buflen-1) != pathSeperator())
  154. tempbuf+= pathSeperator();
  155. }
  156. return tempbuf;
  157. }
  158. string& CTFStatsOSInterface::removeDirSlash(string& tempbuf)
  159. {
  160. int buflen=tempbuf.length();
  161. if (buflen > 0 && tempbuf.at(buflen-1) == pathSeperator())
  162. tempbuf.erase(tempbuf.length()-1,1);
  163. return tempbuf;
  164. }
  165. #ifdef WIN32
  166. #include <io.h>
  167. bool CTFStatsWin32Interface::findfirstfile(char* filemask,string& filename)
  168. {
  169. if (hFindFile!=-1)
  170. return false;
  171. _finddata_t fd;
  172. hFindFile=_findfirst(filemask,&fd);
  173. filename=fd.name;
  174. return hFindFile != -1;
  175. }
  176. bool CTFStatsWin32Interface::findnextfile(string& filename)
  177. {
  178. filename="";
  179. if (hFindFile==-1)
  180. return false;
  181. _finddata_t fd;
  182. int result=_findnext(hFindFile,&fd);
  183. filename=fd.name;
  184. return result!=-1;
  185. }
  186. bool CTFStatsWin32Interface::findfileclose()
  187. {
  188. if (hFindFile==-1)
  189. return false;
  190. int result = _findclose(hFindFile);
  191. return result != -1;
  192. }
  193. #endif
  194. #ifndef WIN32
  195. #include <dirent.h>
  196. string CTFStatsLinuxInterface::filemask;
  197. bool CTFStatsLinuxInterface::findfirstfile(char* filemask,string& filename)
  198. {
  199. if (foundFileIterator >= 0)
  200. findfileclose();
  201. foundFileIterator=-1;
  202. numFiles=0;
  203. foundFiles=NULL;
  204. struct dirent** namelist;
  205. int n;
  206. CTFStatsLinuxInterface::filemask=filemask;
  207. n=scandir(".",&namelist,CTFStatsLinuxInterface::filenameCompare,alphasort);
  208. if (n<0)
  209. return false;
  210. foundFileIterator=0;
  211. numFiles=n;
  212. foundFiles=namelist;
  213. return findnextfile(filename);
  214. }
  215. bool CTFStatsLinuxInterface::findnextfile(string& filename)
  216. {
  217. if (foundFileIterator == -1 || foundFiles == NULL || numFiles == 0)
  218. return false;
  219. if (foundFileIterator >= numFiles)
  220. return false;
  221. filename=foundFiles[foundFileIterator]->d_name;
  222. free(foundFiles[foundFileIterator]);
  223. foundFileIterator++;
  224. return true;
  225. }
  226. bool CTFStatsLinuxInterface::findfileclose()
  227. {
  228. free(foundFiles);
  229. return true;
  230. }
  231. void CTFStatsLinuxInterface::filemask2RegExp(char* buf)
  232. {
  233. char* read=filemask.c_str();
  234. char* write=buf;
  235. while (*read)
  236. {
  237. if (*read=='?')
  238. {
  239. *write='.';
  240. }
  241. else if (*read=='*')
  242. {
  243. *write='.';
  244. write++;
  245. *write='*';
  246. }
  247. else if (*read=='.' || *read=='*' || *read=='?' || *read=='+' || *read=='(' || *read==')' || *read=='{' || *read=='}' || *read=='[' || *read==']' || *read=='^' || *read=='$' )
  248. {
  249. *write='\\';
  250. write++;
  251. *write=*read;
  252. }
  253. else
  254. *write=*read;
  255. read++;
  256. write++;
  257. }
  258. *write=0;
  259. }
  260. #include <regex>
  261. int CTFStatsLinuxInterface::filenameCompare(dirent* file)
  262. {
  263. //scan the filemask, turn it into a regular expression
  264. //then fire up the regex engine and scan the filename;
  265. char buf[5000];
  266. filemask2RegExp(buf);
  267. //printf("trying to match %s against %s\n",buf,file->d_name);
  268. string sbuf=buf;
  269. regex expression(sbuf);
  270. cmatch what;
  271. bool result=query_match((const char*)file->d_name, (const char*)(file->d_name + strlen(file->d_name)), what, expression);
  272. //if (result)
  273. // printf("\tsuccessful\n");
  274. // else
  275. //printf("\tno dice\n");
  276. return result?1:0;
  277. }
  278. char* CTFStatsLinuxInterface::ultoa(unsigned long theNum, char* buf,int radix)
  279. {
  280. {
  281. char ascii[]={"0123456789abcdefghijklmnopqrstuvwxyz"};
  282. if (radix > 36)
  283. {
  284. buf[0]=0;
  285. return NULL;
  286. }
  287. string holder;
  288. while (theNum)
  289. {
  290. char next;
  291. int i=theNum % radix;
  292. next=ascii[i];
  293. holder+=next;
  294. theNum/=radix;
  295. }
  296. int i=0;
  297. string::reverse_iterator it;
  298. for (it=holder.rbegin();it!=holder.rend();++it)
  299. {
  300. buf[i++]=*it;
  301. }
  302. buf[i]=0;
  303. return buf;
  304. }
  305. }
  306. #endif