2
0

fileSystemFunctions.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "console/console.h"
  24. #include "console/consoleInternal.h"
  25. #include "console/engineAPI.h"
  26. #include "console/ast.h"
  27. #include "core/stream/fileStream.h"
  28. #include "console/compiler.h"
  29. #include "platform/platformInput.h"
  30. #include "torqueConfig.h"
  31. #include "core/frameAllocator.h"
  32. // Buffer for expanding script filenames.
  33. static char sgScriptFilenameBuffer[1024];
  34. //-------------------------------------- Helper Functions
  35. static void forwardslash(char *str)
  36. {
  37. while(*str)
  38. {
  39. if(*str == '\\')
  40. *str = '/';
  41. str++;
  42. }
  43. }
  44. //----------------------------------------------------------------
  45. static Vector<String> sgFindFilesResults;
  46. static U32 sgFindFilesPos = 0;
  47. static S32 buildFileList(const char* pattern, bool recurse, bool multiMatch)
  48. {
  49. static const String sSlash( "/" );
  50. sgFindFilesResults.clear();
  51. String sPattern(Torque::Path::CleanSeparators(pattern));
  52. if(sPattern.isEmpty())
  53. {
  54. Con::errorf("findFirstFile() requires a search pattern");
  55. return -1;
  56. }
  57. if(!Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), sPattern.c_str()))
  58. {
  59. Con::errorf("findFirstFile() given initial directory cannot be expanded: '%s'", pattern);
  60. return -1;
  61. }
  62. sPattern = String::ToString(sgScriptFilenameBuffer);
  63. String::SizeType slashPos = sPattern.find('/', 0, String::Right);
  64. // if(slashPos == String::NPos)
  65. // {
  66. // Con::errorf("findFirstFile() missing search directory or expression: '%s'", sPattern.c_str());
  67. // return -1;
  68. // }
  69. // Build the initial search path
  70. Torque::Path givenPath(Torque::Path::CompressPath(sPattern));
  71. givenPath.setFileName("*");
  72. givenPath.setExtension("*");
  73. if(givenPath.getPath().length() > 0 && givenPath.getPath().find('*', 0, String::Right) == givenPath.getPath().length()-1)
  74. {
  75. // Deal with legacy searches of the form '*/*.*'
  76. String suspectPath = givenPath.getPath();
  77. String::SizeType newLen = suspectPath.length()-1;
  78. if(newLen > 0 && suspectPath.find('/', 0, String::Right) == suspectPath.length()-2)
  79. {
  80. --newLen;
  81. }
  82. givenPath.setPath(suspectPath.substr(0, newLen));
  83. }
  84. Torque::FS::FileSystemRef fs = Torque::FS::GetFileSystem(givenPath);
  85. //Torque::Path path = fs->mapTo(givenPath);
  86. Torque::Path path = givenPath;
  87. // Make sure that we have a root so the correct file system can be determined when using zips
  88. if(givenPath.isRelative())
  89. path = Torque::Path::Join(Torque::FS::GetCwd(), '/', givenPath);
  90. path.setFileName(String::EmptyString);
  91. path.setExtension(String::EmptyString);
  92. if(!Torque::FS::IsDirectory(path))
  93. {
  94. Con::errorf("findFirstFile() invalid initial search directory: '%s'", path.getFullPath().c_str());
  95. return -1;
  96. }
  97. // Build the search expression
  98. const String expression(slashPos != String::NPos ? sPattern.substr(slashPos+1) : sPattern);
  99. if(expression.isEmpty())
  100. {
  101. Con::errorf("findFirstFile() requires a search expression: '%s'", sPattern.c_str());
  102. return -1;
  103. }
  104. S32 results = Torque::FS::FindByPattern(path, expression, recurse, sgFindFilesResults, multiMatch );
  105. if(givenPath.isRelative() && results > 0)
  106. {
  107. // Strip the CWD out of the returned paths
  108. // MakeRelativePath() returns incorrect results (it adds a leading ..) so doing this the dirty way
  109. const String cwd = Torque::FS::GetCwd().getFullPath();
  110. for(S32 i = 0;i < sgFindFilesResults.size();++i)
  111. {
  112. String str = sgFindFilesResults[i];
  113. if(str.compare(cwd, cwd.length(), String::NoCase) == 0)
  114. str = str.substr(cwd.length());
  115. sgFindFilesResults[i] = str;
  116. }
  117. }
  118. return results;
  119. }
  120. //-----------------------------------------------------------------------------
  121. DefineEngineFunction( findFirstFile, String, ( const char* pattern, bool recurse ), ( "", true ),
  122. "@brief Returns the first file in the directory system matching the given pattern.\n\n"
  123. "Use the corresponding findNextFile() to step through "
  124. "the results. If you're only interested in the number of files returned by the "
  125. "pattern match, use getFileCount().\n\n"
  126. "This function differs from findFirstFileMultiExpr() in that it supports a single search "
  127. "pattern being passed in.\n\n"
  128. "@note You cannot run multiple simultaneous file system searches with these functions. Each "
  129. "call to findFirstFile() and findFirstFileMultiExpr() initiates a new search and renders "
  130. "a previous search invalid.\n\n"
  131. "@param pattern The path and file name pattern to match against.\n"
  132. "@param recurse If true, the search will exhaustively recurse into subdirectories of the given path and match the given filename pattern.\n"
  133. "@return The path of the first file matched by the search or an empty string if no matching file could be found.\n\n"
  134. "@tsexample\n"
  135. "// Execute all .cs files in a subdirectory and its subdirectories.\n"
  136. "for( %file = findFirstFile( \"subdirectory/*.cs\" ); %file !$= \"\"; %file = findNextFile() )\n"
  137. " exec( %file );\n"
  138. "@endtsexample\n\n"
  139. "@see findNextFile()"
  140. "@see getFileCount()"
  141. "@see findFirstFileMultiExpr()"
  142. "@ingroup FileSearches" )
  143. {
  144. S32 numResults = buildFileList( pattern, recurse, false);
  145. // For Debugging
  146. //for ( S32 i = 0; i < sgFindFilesResults.size(); i++ )
  147. // Con::printf( " [%i] [%s]", i, sgFindFilesResults[i].c_str() );
  148. sgFindFilesPos = 1;
  149. if(numResults < 0)
  150. {
  151. Con::errorf("findFirstFile() search directory not found: '%s'", pattern);
  152. return String();
  153. }
  154. return numResults ? sgFindFilesResults[0] : String();
  155. }
  156. //-----------------------------------------------------------------------------
  157. DefineEngineFunction( findNextFile, String, ( const char* pattern ), ( "" ),
  158. "@brief Returns the next file matching a search begun in findFirstFile().\n\n"
  159. "@param pattern The path and file name pattern to match against. This is optional "
  160. "and may be left out as it is not used by the code. It is here for legacy reasons.\n"
  161. "@return The path of the next filename matched by the search or an empty string if no more files match.\n\n"
  162. "@tsexample\n"
  163. "// Execute all .cs files in a subdirectory and its subdirectories.\n"
  164. "for( %file = findFirstFile( \"subdirectory/*.cs\" ); %file !$= \"\"; %file = findNextFile() )\n"
  165. " exec( %file );\n"
  166. "@endtsexample\n\n"
  167. "@see findFirstFile()"
  168. "@ingroup FileSearches" )
  169. {
  170. if ( sgFindFilesPos + 1 > sgFindFilesResults.size() )
  171. return String();
  172. return sgFindFilesResults[sgFindFilesPos++];
  173. }
  174. //-----------------------------------------------------------------------------
  175. DefineEngineFunction( getFileCount, S32, ( const char* pattern, bool recurse ), ( "", true ),
  176. "@brief Returns the number of files in the directory tree that match the given patterns\n\n"
  177. "This function differs from getFileCountMultiExpr() in that it supports a single search "
  178. "pattern being passed in.\n\n"
  179. "If you're interested in a list of files that match the given pattern and not just "
  180. "the number of files, use findFirstFile() and findNextFile().\n\n"
  181. "@param pattern The path and file name pattern to match against.\n"
  182. "@param recurse If true, the search will exhaustively recurse into subdirectories of the given path and match the given filename pattern "
  183. "counting files in subdirectories.\n"
  184. "@return Number of files located using the pattern\n\n"
  185. "@tsexample\n"
  186. "// Count the number of .cs files in a subdirectory and its subdirectories.\n"
  187. "getFileCount( \"subdirectory/*.cs\" );\n"
  188. "@endtsexample\n\n"
  189. "@see findFirstFile()"
  190. "@see findNextFile()"
  191. "@see getFileCountMultiExpr()"
  192. "@ingroup FileSearches" )
  193. {
  194. S32 numResults = buildFileList( pattern, recurse, false );
  195. if(numResults < 0)
  196. {
  197. return 0;
  198. }
  199. return numResults;
  200. }
  201. //-----------------------------------------------------------------------------
  202. DefineEngineFunction(findFirstFileMultiExpr, String, ( const char* pattern, bool recurse ), ( "", true),
  203. "@brief Returns the first file in the directory system matching the given patterns.\n\n"
  204. "Use the corresponding findNextFileMultiExpr() to step through "
  205. "the results. If you're only interested in the number of files returned by the "
  206. "pattern match, use getFileCountMultiExpr().\n\n"
  207. "This function differs from findFirstFile() in that it supports multiple search patterns "
  208. "to be passed in.\n\n"
  209. "@note You cannot run multiple simultaneous file system searches with these functions. Each "
  210. "call to findFirstFile() and findFirstFileMultiExpr() initiates a new search and renders "
  211. "a previous search invalid.\n\n"
  212. "@param pattern The path and file name pattern to match against, such as *.cs. Separate "
  213. "multiple patterns with TABs. For example: \"*.cs\" TAB \"*.dso\"\n"
  214. "@param recurse If true, the search will exhaustively recurse into subdirectories "
  215. "of the given path and match the given filename patterns.\n"
  216. "@return String of the first matching file path, or an empty string if no matching "
  217. "files were found.\n\n"
  218. "@tsexample\n"
  219. "// Find all DTS or Collada models\n"
  220. "%filePatterns = \"*.dts\" TAB \"*.dae\";\n"
  221. "%fullPath = findFirstFileMultiExpr( %filePatterns );\n"
  222. "while ( %fullPath !$= \"\" )\n"
  223. "{\n"
  224. " echo( %fullPath );\n"
  225. " %fullPath = findNextFileMultiExpr( %filePatterns );\n"
  226. "}\n"
  227. "@endtsexample\n\n"
  228. "@see findNextFileMultiExpr()"
  229. "@see getFileCountMultiExpr()"
  230. "@see findFirstFile()"
  231. "@ingroup FileSearches")
  232. {
  233. S32 numResults = buildFileList(pattern, recurse, true);
  234. // For Debugging
  235. //for ( S32 i = 0; i < sgFindFilesResults.size(); i++ )
  236. // Con::printf( " [%i] [%s]", i, sgFindFilesResults[i].c_str() );
  237. sgFindFilesPos = 1;
  238. if(numResults < 0)
  239. {
  240. Con::errorf("findFirstFileMultiExpr() search directory not found: '%s'", pattern);
  241. return String();
  242. }
  243. return numResults ? sgFindFilesResults[0] : String();
  244. }
  245. DefineEngineFunction(findNextFileMultiExpr, String, ( const char* pattern ), (""),
  246. "@brief Returns the next file matching a search begun in findFirstFileMultiExpr().\n\n"
  247. "@param pattern The path and file name pattern to match against. This is optional "
  248. "and may be left out as it is not used by the code. It is here for legacy reasons.\n"
  249. "@return String of the next matching file path, or an empty string if no matching "
  250. "files were found.\n\n"
  251. "@tsexample\n"
  252. "// Find all DTS or Collada models\n"
  253. "%filePatterns = \"*.dts\" TAB \"*.dae\";\n"
  254. "%fullPath = findFirstFileMultiExpr( %filePatterns );\n"
  255. "while ( %fullPath !$= \"\" )\n"
  256. "{\n"
  257. " echo( %fullPath );\n"
  258. " %fullPath = findNextFileMultiExpr( %filePatterns );\n"
  259. "}\n"
  260. "@endtsexample\n\n"
  261. "@see findFirstFileMultiExpr()"
  262. "@ingroup FileSearches")
  263. {
  264. if ( sgFindFilesPos + 1 > sgFindFilesResults.size() )
  265. return String();
  266. return sgFindFilesResults[sgFindFilesPos++];
  267. }
  268. DefineEngineFunction(getFileCountMultiExpr, S32, ( const char* pattern, bool recurse ), ( "", true),
  269. "@brief Returns the number of files in the directory tree that match the given patterns\n\n"
  270. "If you're interested in a list of files that match the given patterns and not just "
  271. "the number of files, use findFirstFileMultiExpr() and findNextFileMultiExpr().\n\n"
  272. "@param pattern The path and file name pattern to match against, such as *.cs. Separate "
  273. "multiple patterns with TABs. For example: \"*.cs\" TAB \"*.dso\"\n"
  274. "@param recurse If true, the search will exhaustively recurse into subdirectories "
  275. "of the given path and match the given filename pattern.\n"
  276. "@return Number of files located using the patterns\n\n"
  277. "@tsexample\n"
  278. "// Count all DTS or Collada models\n"
  279. "%filePatterns = \"*.dts\" TAB \"*.dae\";\n"
  280. "echo( \"Nunmer of shape files:\" SPC getFileCountMultiExpr( %filePatterns ) );\n"
  281. "@endtsexample\n\n"
  282. "@see findFirstFileMultiExpr()"
  283. "@see findNextFileMultiExpr()"
  284. "@ingroup FileSearches")
  285. {
  286. S32 numResults = buildFileList(pattern, recurse, true);
  287. if(numResults < 0)
  288. {
  289. return 0;
  290. }
  291. return numResults;
  292. }
  293. DefineEngineFunction(getFileCRC, S32, ( const char* fileName ),,
  294. "@brief Provides the CRC checksum of the given file.\n\n"
  295. "@param fileName The path to the file.\n"
  296. "@return The calculated CRC checksum of the file, or -1 if the file "
  297. "could not be found.\n"
  298. "@ingroup FileSystem")
  299. {
  300. String cleanfilename(Torque::Path::CleanSeparators(fileName));
  301. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), cleanfilename.c_str());
  302. Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
  303. Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode( givenPath );
  304. if ( fileRef == NULL )
  305. {
  306. Con::errorf("getFileCRC() - could not access file: [%s]", givenPath.getFullPath().c_str() );
  307. return -1;
  308. }
  309. return fileRef->getChecksum();
  310. }
  311. DefineEngineFunction(isFile, bool, ( const char* fileName ),,
  312. "@brief Determines if the specified file exists or not\n\n"
  313. "@param fileName The path to the file.\n"
  314. "@return Returns true if the file was found.\n"
  315. "@ingroup FileSystem")
  316. {
  317. String cleanfilename(Torque::Path::CleanSeparators(fileName));
  318. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), cleanfilename.c_str());
  319. Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
  320. return Torque::FS::IsFile(givenPath);
  321. }
  322. DefineEngineFunction( IsDirectory, bool, ( const char* directory ),,
  323. "@brief Determines if a specified directory exists or not\n\n"
  324. "@param directory String containing path in the form of \"foo/bar\"\n"
  325. "@return Returns true if the directory was found.\n"
  326. "@note Do not include a trailing slash '/'.\n"
  327. "@ingroup FileSystem")
  328. {
  329. String dir(Torque::Path::CleanSeparators(directory));
  330. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), dir.c_str());
  331. Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
  332. return Torque::FS::IsDirectory( givenPath );
  333. }
  334. DefineEngineFunction(isWriteableFileName, bool, ( const char* fileName ),,
  335. "@brief Determines if a file name can be written to using File I/O\n\n"
  336. "@param fileName Name and path of file to check\n"
  337. "@return Returns true if the file can be written to.\n"
  338. "@ingroup FileSystem")
  339. {
  340. String filename(Torque::Path::CleanSeparators(fileName));
  341. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), filename.c_str());
  342. Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
  343. Torque::FS::FileSystemRef fs = Torque::FS::GetFileSystem(givenPath);
  344. Torque::Path path = fs->mapTo(givenPath);
  345. return !Torque::FS::IsReadOnly(path);
  346. }
  347. DefineEngineFunction(startFileChangeNotifications, void, (),,
  348. "@brief Start watching resources for file changes\n\n"
  349. "Typically this is called during initializeCore().\n\n"
  350. "@see stopFileChangeNotifications()\n"
  351. "@ingroup FileSystem")
  352. {
  353. Torque::FS::StartFileChangeNotifications();
  354. }
  355. DefineEngineFunction(stopFileChangeNotifications, void, (),,
  356. "@brief Stop watching resources for file changes\n\n"
  357. "Typically this is called during shutdownCore().\n\n"
  358. "@see startFileChangeNotifications()\n"
  359. "@ingroup FileSystem")
  360. {
  361. Torque::FS::StopFileChangeNotifications();
  362. }
  363. DefineEngineFunction(getDirectoryList, String, ( const char* path, S32 depth ), ( "", 0 ),
  364. "@brief Gathers a list of directories starting at the given path.\n\n"
  365. "@param path String containing the path of the directory\n"
  366. "@param depth Depth of search, as in how many subdirectories to parse through\n"
  367. "@return Tab delimited string containing list of directories found during search, \"\" if no files were found\n"
  368. "@ingroup FileSystem")
  369. {
  370. // Grab the full path.
  371. char fullpath[1024];
  372. Platform::makeFullPathName(dStrcmp(path, "/") == 0 ? "" : path, fullpath, sizeof(fullpath));
  373. //dSprintf(fullpath, 511, "%s/%s", Platform::getWorkingDirectory(), path);
  374. // Append a trailing backslash if it's not present already.
  375. if (fullpath[dStrlen(fullpath) - 1] != '/')
  376. {
  377. S32 pos = dStrlen(fullpath);
  378. fullpath[pos] = '/';
  379. fullpath[pos + 1] = '\0';
  380. }
  381. // Dump the directories.
  382. Vector<StringTableEntry> directories;
  383. Platform::dumpDirectories(fullpath, directories, depth, true);
  384. if( directories.empty() )
  385. return "";
  386. // Grab the required buffer length.
  387. S32 length = 0;
  388. for (S32 i = 0; i < directories.size(); i++)
  389. length += dStrlen(directories[i]) + 1;
  390. // Get a return buffer.
  391. char* buffer = Con::getReturnBuffer(length);
  392. char* p = buffer;
  393. // Copy the directory names to the buffer.
  394. for (S32 i = 0; i < directories.size(); i++)
  395. {
  396. dStrcpy(p, directories[i]);
  397. p += dStrlen(directories[i]);
  398. // Tab separated.
  399. p[0] = '\t';
  400. p++;
  401. }
  402. p--;
  403. p[0] = '\0';
  404. return buffer;
  405. }
  406. DefineEngineFunction(fileSize, S32, ( const char* fileName ),,
  407. "@brief Determines the size of a file on disk\n\n"
  408. "@param fileName Name and path of the file to check\n"
  409. "@return Returns filesize in bytes, or -1 if no file\n"
  410. "@ingroup FileSystem")
  411. {
  412. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileName);
  413. return Platform::getFileSize( sgScriptFilenameBuffer );
  414. }
  415. DefineEngineFunction( fileModifiedTime, String, ( const char* fileName ),,
  416. "@brief Returns a platform specific formatted string with the last modified time for the file.\n\n"
  417. "@param fileName Name and path of file to check\n"
  418. "@return Formatted string (OS specific) containing modified time, \"9/3/2010 12:33:47 PM\" for example\n"
  419. "@ingroup FileSystem")
  420. {
  421. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileName);
  422. FileTime ft = {0};
  423. Platform::getFileTimes( sgScriptFilenameBuffer, NULL, &ft );
  424. Platform::LocalTime lt = {0};
  425. Platform::fileToLocalTime( ft, &lt );
  426. String fileStr = Platform::localTimeToString( lt );
  427. char *buffer = Con::getReturnBuffer( fileStr.size() );
  428. dStrcpy( buffer, fileStr );
  429. return buffer;
  430. }
  431. DefineEngineFunction( fileCreatedTime, String, ( const char* fileName ),,
  432. "@brief Returns a platform specific formatted string with the creation time for the file."
  433. "@param fileName Name and path of file to check\n"
  434. "@return Formatted string (OS specific) containing created time, \"9/3/2010 12:33:47 PM\" for example\n"
  435. "@ingroup FileSystem")
  436. {
  437. Con::expandScriptFilename( sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileName );
  438. FileTime ft = {0};
  439. Platform::getFileTimes( sgScriptFilenameBuffer, &ft, NULL );
  440. Platform::LocalTime lt = {0};
  441. Platform::fileToLocalTime( ft, &lt );
  442. String fileStr = Platform::localTimeToString( lt );
  443. char *buffer = Con::getReturnBuffer( fileStr.size() );
  444. dStrcpy( buffer, fileStr );
  445. return buffer;
  446. }
  447. DefineEngineFunction(fileDelete, bool, ( const char* path ),,
  448. "@brief Delete a file from the hard drive\n\n"
  449. "@param path Name and path of the file to delete\n"
  450. "@note THERE IS NO RECOVERY FROM THIS. Deleted file is gone for good.\n"
  451. "@return True if file was successfully deleted\n"
  452. "@ingroup FileSystem")
  453. {
  454. static char fileName[1024];
  455. static char sandboxFileName[1024];
  456. Con::expandScriptFilename( fileName, sizeof( fileName ), path );
  457. Platform::makeFullPathName(fileName, sandboxFileName, sizeof(sandboxFileName));
  458. return dFileDelete(sandboxFileName);
  459. }
  460. //----------------------------------------------------------------
  461. DefineEngineFunction(fileExt, String, ( const char* fileName ),,
  462. "@brief Get the extension of a file\n\n"
  463. "@param fileName Name and path of file\n"
  464. "@return String containing the extension, such as \".exe\" or \".cs\"\n"
  465. "@ingroup FileSystem")
  466. {
  467. const char *ret = dStrrchr(fileName, '.');
  468. if(ret)
  469. return ret;
  470. return "";
  471. }
  472. DefineEngineFunction(fileBase, String, ( const char* fileName ),,
  473. "@brief Get the base of a file name (removes extension and path)\n\n"
  474. "@param fileName Name and path of file to check\n"
  475. "@return String containing the file name, minus extension and path\n"
  476. "@ingroup FileSystem")
  477. {
  478. S32 pathLen = dStrlen( fileName );
  479. FrameTemp<char> szPathCopy( pathLen + 1);
  480. dStrcpy( szPathCopy, fileName );
  481. forwardslash( szPathCopy );
  482. const char *path = dStrrchr(szPathCopy, '/');
  483. if(!path)
  484. path = szPathCopy;
  485. else
  486. path++;
  487. char *ret = Con::getReturnBuffer(dStrlen(path) + 1);
  488. dStrcpy(ret, path);
  489. char *ext = dStrrchr(ret, '.');
  490. if(ext)
  491. *ext = 0;
  492. return ret;
  493. }
  494. DefineEngineFunction(fileName, String, ( const char* fileName ),,
  495. "@brief Get only the file name of a path and file name string (removes path)\n\n"
  496. "@param fileName Name and path of file to check\n"
  497. "@return String containing the file name, minus the path\n"
  498. "@ingroup FileSystem")
  499. {
  500. S32 pathLen = dStrlen( fileName );
  501. FrameTemp<char> szPathCopy( pathLen + 1);
  502. dStrcpy( szPathCopy, fileName );
  503. forwardslash( szPathCopy );
  504. const char *name = dStrrchr(szPathCopy, '/');
  505. if(!name)
  506. name = szPathCopy;
  507. else
  508. name++;
  509. char *ret = Con::getReturnBuffer(dStrlen(name));
  510. dStrcpy(ret, name);
  511. return ret;
  512. }
  513. DefineEngineFunction(filePath, String, ( const char* fileName ),,
  514. "@brief Get the path of a file (removes name and extension)\n\n"
  515. "@param fileName Name and path of file to check\n"
  516. "@return String containing the path, minus name and extension\n"
  517. "@ingroup FileSystem")
  518. {
  519. S32 pathLen = dStrlen( fileName );
  520. FrameTemp<char> szPathCopy( pathLen + 1);
  521. dStrcpy( szPathCopy, fileName );
  522. forwardslash( szPathCopy );
  523. const char *path = dStrrchr(szPathCopy, '/');
  524. if(!path)
  525. return "";
  526. U32 len = path - (char*)szPathCopy;
  527. char *ret = Con::getReturnBuffer(len + 1);
  528. dStrncpy(ret, szPathCopy, len);
  529. ret[len] = 0;
  530. return ret;
  531. }
  532. DefineEngineFunction(getWorkingDirectory, String, (),,
  533. "@brief Reports the current directory\n\n"
  534. "@return String containing full file path of working directory\n"
  535. "@ingroup FileSystem")
  536. {
  537. return Platform::getCurrentDirectory();
  538. }
  539. //-----------------------------------------------------------------------------
  540. // [tom, 5/1/2007] I changed these to be ordinary console functions as they
  541. // are just string processing functions. They are needed by the 3D tools which
  542. // are not currently built with TORQUE_TOOLS defined.
  543. DefineEngineFunction(makeFullPath, String, ( const char* path, const char* cwd ), ( "", ""),
  544. "@brief Converts a relative file path to a full path\n\n"
  545. "For example, \"./console.log\" becomes \"C:/Torque/t3d/examples/FPS Example/game/console.log\"\n"
  546. "@param path Name of file or path to check\n"
  547. "@param cwd Optional current working directory from which to build the full path.\n"
  548. "@return String containing non-relative directory of path\n"
  549. "@ingroup FileSystem")
  550. {
  551. static const U32 bufSize = 512;
  552. char *buf = Con::getReturnBuffer(bufSize);
  553. Platform::makeFullPathName(path, buf, bufSize, dStrlen(cwd) > 1 ? cwd : NULL);
  554. return buf;
  555. }
  556. DefineEngineFunction(makeRelativePath, String, ( const char* path, const char* to ), ( "", ""),
  557. "@brief Turns a full or local path to a relative one\n\n"
  558. "For example, \"./game/art\" becomes \"game/art\"\n"
  559. "@param path Full path (may include a file) to convert\n"
  560. "@param to Optional base path used for the conversion. If not supplied the current "
  561. "working directory is used.\n"
  562. "@returns String containing relative path\n"
  563. "@ingroup FileSystem")
  564. {
  565. return Platform::makeRelativePathName( path, dStrlen(to) > 1 ? to : NULL );
  566. }
  567. DefineEngineFunction(pathConcat, String, ( const char* path, const char* file), ( "", ""),
  568. "@brief Combines two separate strings containing a file path and file name together into a single string\n\n"
  569. "@param path String containing file path\n"
  570. "@param file String containing file name\n"
  571. "@return String containing concatenated file name and path\n"
  572. "@ingroup FileSystem")
  573. {
  574. static const U32 bufSize = 1024;
  575. char *buf = Con::getReturnBuffer(bufSize);
  576. Platform::makeFullPathName(file, buf, bufSize, path);
  577. return buf;
  578. }
  579. //-----------------------------------------------------------------------------
  580. DefineEngineFunction(getExecutableName, String, (),,
  581. "@brief Gets the name of the game's executable\n\n"
  582. "@return String containing this game's executable name\n"
  583. "@ingroup FileSystem")
  584. {
  585. return Platform::getExecutableName();
  586. }
  587. //-----------------------------------------------------------------------------
  588. DefineEngineFunction( getMainDotCsDir, String, (),,
  589. "@brief Get the absolute path to the directory that contains the main.cs script from which the engine was started.\n\n"
  590. "This directory will usually contain all the game assets and, in a user-side game installation, will usually be "
  591. "read-only.\n\n"
  592. "@return The path to the main game assets.\n\n"
  593. "@ingroup FileSystem\n")
  594. {
  595. return Platform::getMainDotCsDir();
  596. }
  597. //-----------------------------------------------------------------------------
  598. // Tools Only Functions
  599. //-----------------------------------------------------------------------------
  600. #ifdef TORQUE_TOOLS
  601. //-----------------------------------------------------------------------------
  602. DefineEngineFunction( openFolder, void, ( const char* path ),,
  603. "@brief Open the given folder in the system's file manager.\n\n"
  604. "@param path full path to a directory.\n\n"
  605. "@note Only present in a Tools build of Torque.\n"
  606. "@ingroup FileSystem\n")
  607. {
  608. Platform::openFolder( path );
  609. }
  610. //-----------------------------------------------------------------------------
  611. DefineEngineFunction( openFile, void, ( const char* file ),,
  612. "@brief Open the given @a file through the system. This will usually open the file in its "
  613. "associated application.\n"
  614. "@param file %Path of the file to open.\n\n"
  615. "@note Only present in a Tools build of Torque.\n"
  616. "@ingroup FileSystem\n")
  617. {
  618. Platform::openFile( file );
  619. }
  620. //-----------------------------------------------------------------------------
  621. DefineEngineFunction( pathCopy, bool, ( const char* fromFile, const char* toFile, bool noOverwrite ), ( "", "", true ),
  622. "@brief Copy a file to a new location.\n"
  623. "@param fromFile %Path of the file to copy.\n"
  624. "@param toFile %Path where to copy @a fromFile to.\n"
  625. "@param noOverwrite If true, then @a fromFile will not overwrite a file that may already exist at @a toFile.\n"
  626. "@return True if the file was successfully copied, false otherwise.\n"
  627. "@note Only present in a Tools build of Torque.\n"
  628. "@ingroup FileSystem")
  629. {
  630. char qualifiedFromFile[ 2048 ];
  631. char qualifiedToFile[ 2048 ];
  632. Platform::makeFullPathName( fromFile, qualifiedFromFile, sizeof( qualifiedFromFile ) );
  633. Platform::makeFullPathName( toFile, qualifiedToFile, sizeof( qualifiedToFile ) );
  634. return dPathCopy( qualifiedFromFile, qualifiedToFile, noOverwrite );
  635. }
  636. //-----------------------------------------------------------------------------
  637. DefineEngineFunction( getCurrentDirectory, String, (),,
  638. "@brief Return the current working directory.\n\n"
  639. "@return The absolute path of the current working directory.\n\n"
  640. "@note Only present in a Tools build of Torque.\n"
  641. "@see getWorkingDirectory()"
  642. "@ingroup FileSystem")
  643. {
  644. return Platform::getCurrentDirectory();
  645. }
  646. //-----------------------------------------------------------------------------
  647. DefineEngineFunction( setCurrentDirectory, bool, ( const char* path ),,
  648. "@brief Set the current working directory.\n\n"
  649. "@param path The absolute or relative (to the current working directory) path of the directory which should be made the new "
  650. "working directory.\n\n"
  651. "@return True if the working directory was successfully changed to @a path, false otherwise.\n\n"
  652. "@note Only present in a Tools build of Torque.\n"
  653. "@ingroup FileSystem")
  654. {
  655. return Platform::setCurrentDirectory( StringTable->insert( path ) );
  656. }
  657. //-----------------------------------------------------------------------------
  658. DefineEngineFunction( createPath, bool, ( const char* path ),,
  659. "@brief Create the given directory or the path leading to the given filename.\n\n"
  660. "If @a path ends in a trailing slash, then all components in the given path will be created as directories (if not already in place). If @a path, "
  661. "does @b not end in a trailing slash, then the last component of the path is taken to be a file name and only the directory components "
  662. "of the path will be created.\n\n"
  663. "@param path The path to create.\n\n"
  664. "@note Only present in a Tools build of Torque.\n"
  665. "@ingroup FileSystem" )
  666. {
  667. static char pathName[1024];
  668. Con::expandScriptFilename( pathName, sizeof( pathName ), path );
  669. return Platform::createPath( pathName );
  670. }
  671. #endif // TORQUE_TOOLS