fileSystemFunctions.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  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 ." TORQUE_SCRIPT_EXTENSION " files in a subdirectory and its subdirectories.\n"
  136. "for( %file = findFirstFile( \"subdirectory/*." TORQUE_SCRIPT_EXTENSION "\" ); %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 ." TORQUE_SCRIPT_EXTENSION " files in a subdirectory and its subdirectories.\n"
  164. "for( %file = findFirstFile( \"subdirectory/*." TORQUE_SCRIPT_EXTENSION "\" ); %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 ." TORQUE_SCRIPT_EXTENSION " files in a subdirectory and its subdirectories.\n"
  187. "getFileCount( \"subdirectory/*." TORQUE_SCRIPT_EXTENSION "\" );\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 *." TORQUE_SCRIPT_EXTENSION ". Separate "
  213. "multiple patterns with TABs. For example: \"*." TORQUE_SCRIPT_EXTENSION "\" 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 *." TORQUE_SCRIPT_EXTENSION ". Separate "
  273. "multiple patterns with TABs. For example: \"*." TORQUE_SCRIPT_EXTENSION "\" 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. if (givenPath.getFileName().isEmpty() && givenPath.getExtension().isNotEmpty())
  321. {
  322. //specially named or hidden files, like .gitignore parse incorrectly due to having
  323. //"no" filename, so we adjust that
  324. givenPath.setFileName(String(".") + givenPath.getExtension());
  325. givenPath.setExtension("");
  326. }
  327. return Torque::FS::IsFile(givenPath);
  328. }
  329. DefineEngineFunction(isScriptFile, bool, (const char* fileName), ,
  330. "@brief Determines if the specified file exists or not\n\n"
  331. "@param fileName The path to the file.\n"
  332. "@return Returns true if the file was found.\n"
  333. "@ingroup FileSystem")
  334. {
  335. String cleanfilename(Torque::Path::CleanSeparators(fileName));
  336. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), cleanfilename.c_str());
  337. Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
  338. return Torque::FS::IsScriptFile(givenPath.getFullPath());
  339. }
  340. DefineEngineFunction( IsDirectory, bool, ( const char* directory ),,
  341. "@brief Determines if a specified directory exists or not\n\n"
  342. "@param directory String containing path in the form of \"foo/bar\"\n"
  343. "@return Returns true if the directory was found.\n"
  344. "@note Do not include a trailing slash '/'.\n"
  345. "@ingroup FileSystem")
  346. {
  347. String dir(Torque::Path::CleanSeparators(directory));
  348. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), dir.c_str());
  349. Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
  350. return Torque::FS::IsDirectory( givenPath );
  351. }
  352. DefineEngineFunction(isWriteableFileName, bool, ( const char* fileName ),,
  353. "@brief Determines if a file name can be written to using File I/O\n\n"
  354. "@param fileName Name and path of file to check\n"
  355. "@return Returns true if the file can be written to.\n"
  356. "@ingroup FileSystem")
  357. {
  358. String filename(Torque::Path::CleanSeparators(fileName));
  359. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), filename.c_str());
  360. Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
  361. Torque::FS::FileSystemRef fs = Torque::FS::GetFileSystem(givenPath);
  362. Torque::Path path = fs->mapTo(givenPath);
  363. return !Torque::FS::IsReadOnly(path);
  364. }
  365. DefineEngineFunction(startFileChangeNotifications, void, (),,
  366. "@brief Start watching resources for file changes\n\n"
  367. "Typically this is called during initializeCore().\n\n"
  368. "@see stopFileChangeNotifications()\n"
  369. "@ingroup FileSystem")
  370. {
  371. Torque::FS::StartFileChangeNotifications();
  372. }
  373. DefineEngineFunction(stopFileChangeNotifications, void, (),,
  374. "@brief Stop watching resources for file changes\n\n"
  375. "Typically this is called during shutdownCore().\n\n"
  376. "@see startFileChangeNotifications()\n"
  377. "@ingroup FileSystem")
  378. {
  379. Torque::FS::StopFileChangeNotifications();
  380. }
  381. DefineEngineFunction(getDirectoryList, String, ( const char* path, S32 depth ), ( "", 0 ),
  382. "@brief Gathers a list of directories starting at the given path.\n\n"
  383. "@param path String containing the path of the directory\n"
  384. "@param depth Depth of search, as in how many subdirectories to parse through\n"
  385. "@return Tab delimited string containing list of directories found during search, \"\" if no files were found\n"
  386. "@ingroup FileSystem")
  387. {
  388. // Grab the full path.
  389. char fullpath[1024];
  390. Platform::makeFullPathName(String::compare(path, "/") == 0 ? "" : path, fullpath, sizeof(fullpath));
  391. //dSprintf(fullpath, 511, "%s/%s", Platform::getWorkingDirectory(), path);
  392. // Append a trailing backslash if it's not present already.
  393. if (fullpath[dStrlen(fullpath) - 1] != '/')
  394. {
  395. S32 pos = dStrlen(fullpath);
  396. fullpath[pos] = '/';
  397. fullpath[pos + 1] = '\0';
  398. }
  399. // Dump the directories.
  400. Vector<StringTableEntry> directories;
  401. Platform::dumpDirectories(fullpath, directories, depth, true);
  402. if( directories.empty() )
  403. return "";
  404. // Grab the required buffer length.
  405. S32 length = 0;
  406. for (S32 i = 0; i < directories.size(); i++)
  407. length += dStrlen(directories[i]) + 1;
  408. // Get a return buffer.
  409. char* buffer = Con::getReturnBuffer(length);
  410. char* p = buffer;
  411. // Copy the directory names to the buffer.
  412. for (S32 i = 0; i < directories.size(); i++)
  413. {
  414. dStrcpy(p, directories[i], length - (p - buffer));
  415. p += dStrlen(directories[i]);
  416. // Tab separated.
  417. p[0] = '\t';
  418. p++;
  419. }
  420. p--;
  421. p[0] = '\0';
  422. return buffer;
  423. }
  424. DefineEngineFunction(fileSize, S32, ( const char* fileName ),,
  425. "@brief Determines the size of a file on disk\n\n"
  426. "@param fileName Name and path of the file to check\n"
  427. "@return Returns filesize in bytes, or -1 if no file\n"
  428. "@ingroup FileSystem")
  429. {
  430. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileName);
  431. return Platform::getFileSize( sgScriptFilenameBuffer );
  432. }
  433. DefineEngineFunction( fileModifiedTime, String, ( const char* fileName ),,
  434. "@brief Returns a platform specific formatted string with the last modified time for the file.\n\n"
  435. "@param fileName Name and path of file to check\n"
  436. "@return Formatted string (OS specific) containing modified time, \"9/3/2010 12:33:47 PM\" for example\n"
  437. "@ingroup FileSystem")
  438. {
  439. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileName);
  440. FileTime ft = {0};
  441. Platform::getFileTimes( sgScriptFilenameBuffer, NULL, &ft );
  442. Platform::LocalTime lt = {0};
  443. Platform::fileToLocalTime( ft, &lt );
  444. String fileStr = Platform::localTimeToString( lt );
  445. char *buffer = Con::getReturnBuffer( fileStr.size() );
  446. dStrcpy( buffer, fileStr, fileStr.size() );
  447. return buffer;
  448. }
  449. DefineEngineFunction( fileCreatedTime, String, ( const char* fileName ),,
  450. "@brief Returns a platform specific formatted string with the creation time for the file."
  451. "@param fileName Name and path of file to check\n"
  452. "@return Formatted string (OS specific) containing created time, \"9/3/2010 12:33:47 PM\" for example\n"
  453. "@ingroup FileSystem")
  454. {
  455. Con::expandScriptFilename( sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileName );
  456. FileTime ft = {0};
  457. Platform::getFileTimes( sgScriptFilenameBuffer, &ft, NULL );
  458. Platform::LocalTime lt = {0};
  459. Platform::fileToLocalTime( ft, &lt );
  460. String fileStr = Platform::localTimeToString( lt );
  461. char *buffer = Con::getReturnBuffer( fileStr.size() );
  462. dStrcpy( buffer, fileStr, fileStr.size() );
  463. return buffer;
  464. }
  465. DefineEngineFunction(compareFileTimes, S32, (const char* fileA, const char* fileB), ("", ""),
  466. "@brief Compares 2 files' modified file times."
  467. "@param fileName Name and path of first file to compare\n"
  468. "@param fileName Name and path of second file to compare\n"
  469. "@return S32. If value is 1, then fileA is newer. If value is -1, then fileB is newer. If value is 0, they are equal.\n"
  470. "@ingroup FileSystem")
  471. {
  472. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileA);
  473. FileTime fileATime = { 0 };
  474. Platform::getFileTimes(sgScriptFilenameBuffer, NULL, &fileATime);
  475. Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileB);
  476. FileTime fileBTime = { 0 };
  477. Platform::getFileTimes(sgScriptFilenameBuffer, NULL, &fileBTime);
  478. return Platform::compareFileTimes(fileATime, fileBTime);
  479. }
  480. DefineEngineFunction(fileDelete, bool, ( const char* path ),,
  481. "@brief Delete a file from the hard drive\n\n"
  482. "@param path Name and path of the file to delete\n"
  483. "@note THERE IS NO RECOVERY FROM THIS. Deleted file is gone for good.\n"
  484. "@return True if file was successfully deleted\n"
  485. "@ingroup FileSystem")
  486. {
  487. static char fileName[1024];
  488. static char sandboxFileName[1024];
  489. Con::expandScriptFilename( fileName, sizeof( fileName ), path );
  490. Platform::makeFullPathName(fileName, sandboxFileName, sizeof(sandboxFileName));
  491. return dFileDelete(sandboxFileName);
  492. }
  493. //----------------------------------------------------------------
  494. DefineEngineFunction(fileExt, String, ( const char* fileName ),,
  495. "@brief Get the extension of a file\n\n"
  496. "@param fileName Name and path of file\n"
  497. "@return String containing the extension, such as \".exe\" or \"." TORQUE_SCRIPT_EXTENSION "\"\n"
  498. "@ingroup FileSystem")
  499. {
  500. const char *ret = dStrrchr(fileName, '.');
  501. if(ret)
  502. return ret;
  503. return "";
  504. }
  505. DefineEngineFunction(fileBase, String, ( const char* fileName ),,
  506. "@brief Get the base of a file name (removes extension and path)\n\n"
  507. "@param fileName Name and path of file to check\n"
  508. "@return String containing the file name, minus extension and path\n"
  509. "@ingroup FileSystem")
  510. {
  511. S32 pathLen = dStrlen( fileName );
  512. FrameTemp<char> szPathCopy( pathLen + 1);
  513. dStrcpy( szPathCopy, fileName, pathLen + 1 );
  514. forwardslash( szPathCopy );
  515. const char *path = dStrrchr(szPathCopy, '/');
  516. if(!path)
  517. path = szPathCopy;
  518. else
  519. path++;
  520. dsize_t retLen = dStrlen(path) + 1;
  521. char *ret = Con::getReturnBuffer(retLen);
  522. dStrcpy(ret, path, retLen);
  523. char *ext = dStrrchr(ret, '.');
  524. if(ext)
  525. *ext = 0;
  526. return ret;
  527. }
  528. DefineEngineFunction(fileName, String, ( const char* fileName ),,
  529. "@brief Get only the file name of a path and file name string (removes path)\n\n"
  530. "@param fileName Name and path of file to check\n"
  531. "@return String containing the file name, minus the path\n"
  532. "@ingroup FileSystem")
  533. {
  534. S32 pathLen = dStrlen( fileName );
  535. FrameTemp<char> szPathCopy( pathLen + 1);
  536. dStrcpy( szPathCopy, fileName, pathLen + 1 );
  537. forwardslash( szPathCopy );
  538. const char *name = dStrrchr(szPathCopy, '/');
  539. if(!name)
  540. name = szPathCopy;
  541. else
  542. name++;
  543. dsize_t retLen = dStrlen(name) + 1;
  544. char *ret = Con::getReturnBuffer(retLen);
  545. dStrcpy(ret, name, retLen);
  546. return ret;
  547. }
  548. DefineEngineFunction(filePath, String, ( const char* fileName ),,
  549. "@brief Get the path of a file (removes name and extension)\n\n"
  550. "@param fileName Name and path of file to check\n"
  551. "@return String containing the path, minus name and extension\n"
  552. "@ingroup FileSystem")
  553. {
  554. S32 pathLen = dStrlen( fileName );
  555. FrameTemp<char> szPathCopy( pathLen + 1);
  556. dStrcpy( szPathCopy, fileName, pathLen + 1 );
  557. forwardslash( szPathCopy );
  558. const char *path = dStrrchr(szPathCopy, '/');
  559. if(!path)
  560. return "";
  561. U32 len = path - (char*)szPathCopy;
  562. char *ret = Con::getReturnBuffer(len + 1);
  563. dStrncpy(ret, szPathCopy, len);
  564. ret[len] = 0;
  565. return ret;
  566. }
  567. DefineEngineFunction(getWorkingDirectory, String, (),,
  568. "@brief Reports the current directory\n\n"
  569. "@return String containing full file path of working directory\n"
  570. "@ingroup FileSystem")
  571. {
  572. return Platform::getCurrentDirectory();
  573. }
  574. //-----------------------------------------------------------------------------
  575. // [tom, 5/1/2007] I changed these to be ordinary console functions as they
  576. // are just string processing functions. They are needed by the 3D tools which
  577. // are not currently built with TORQUE_TOOLS defined.
  578. DefineEngineFunction(makeFullPath, String, ( const char* path, const char* cwd ), ( "", ""),
  579. "@brief Converts a relative file path to a full path\n\n"
  580. "For example, \"./console.log\" becomes \"C:/Torque/t3d/examples/FPS Example/game/console.log\"\n"
  581. "@param path Name of file or path to check\n"
  582. "@param cwd Optional current working directory from which to build the full path.\n"
  583. "@return String containing non-relative directory of path\n"
  584. "@ingroup FileSystem")
  585. {
  586. static const U32 bufSize = 512;
  587. char *buf = Con::getReturnBuffer(bufSize);
  588. Platform::makeFullPathName(path, buf, bufSize, dStrlen(cwd) > 1 ? cwd : NULL);
  589. return buf;
  590. }
  591. DefineEngineFunction(makeRelativePath, String, ( const char* path, const char* to ), ( "", ""),
  592. "@brief Turns a full or local path to a relative one\n\n"
  593. "For example, \"./game/art\" becomes \"game/art\"\n"
  594. "@param path Full path (may include a file) to convert\n"
  595. "@param to Optional base path used for the conversion. If not supplied the current "
  596. "working directory is used.\n"
  597. "@returns String containing relative path\n"
  598. "@ingroup FileSystem")
  599. {
  600. return Platform::makeRelativePathName( path, dStrlen(to) > 1 ? to : NULL );
  601. }
  602. DefineEngineFunction(pathConcat, String, ( const char* path, const char* file), ( "", ""),
  603. "@brief Combines two separate strings containing a file path and file name together into a single string\n\n"
  604. "@param path String containing file path\n"
  605. "@param file String containing file name\n"
  606. "@return String containing concatenated file name and path\n"
  607. "@ingroup FileSystem")
  608. {
  609. static const U32 bufSize = 1024;
  610. char *buf = Con::getReturnBuffer(bufSize);
  611. Platform::makeFullPathName(file, buf, bufSize, path);
  612. return buf;
  613. }
  614. //-----------------------------------------------------------------------------
  615. DefineEngineFunction(getExecutableName, String, (),,
  616. "@brief Gets the name of the game's executable\n\n"
  617. "@return String containing this game's executable name\n"
  618. "@ingroup FileSystem")
  619. {
  620. return Platform::getExecutableName();
  621. }
  622. //-----------------------------------------------------------------------------
  623. DefineEngineFunction( getMainDotCsDir, String, (),,
  624. "@brief Get the absolute path to the directory that contains the main." TORQUE_SCRIPT_EXTENSION " script from which the engine was started.\n\n"
  625. "This directory will usually contain all the game assets and, in a user-side game installation, will usually be "
  626. "read-only.\n\n"
  627. "@return The path to the main game assets.\n\n"
  628. "@ingroup FileSystem\n")
  629. {
  630. return Platform::getMainDotCsDir();
  631. }
  632. //-----------------------------------------------------------------------------
  633. // Tools Only Functions
  634. //-----------------------------------------------------------------------------
  635. #ifdef TORQUE_TOOLS
  636. //-----------------------------------------------------------------------------
  637. DefineEngineFunction( openFolder, void, ( const char* path ),,
  638. "@brief Open the given folder in the system's file manager.\n\n"
  639. "@param path full path to a directory.\n\n"
  640. "@note Only present in a Tools build of Torque.\n"
  641. "@ingroup FileSystem\n")
  642. {
  643. Platform::openFolder( path );
  644. }
  645. //-----------------------------------------------------------------------------
  646. DefineEngineFunction( openFile, void, ( const char* file ),,
  647. "@brief Open the given @a file through the system. This will usually open the file in its "
  648. "associated application.\n"
  649. "@param file %Path of the file to open.\n\n"
  650. "@note Only present in a Tools build of Torque.\n"
  651. "@ingroup FileSystem\n")
  652. {
  653. Platform::openFile( file );
  654. }
  655. //-----------------------------------------------------------------------------
  656. DefineEngineFunction( pathCopy, bool, ( const char* fromFile, const char* toFile, bool noOverwrite ), ( "", "", true ),
  657. "@brief Copy a file to a new location.\n"
  658. "@param fromFile %Path of the file to copy.\n"
  659. "@param toFile %Path where to copy @a fromFile to.\n"
  660. "@param noOverwrite If true, then @a fromFile will not overwrite a file that may already exist at @a toFile.\n"
  661. "@return True if the file was successfully copied, false otherwise.\n"
  662. "@note Only present in a Tools build of Torque.\n"
  663. "@ingroup FileSystem")
  664. {
  665. char qualifiedFromFile[ 2048 ];
  666. char qualifiedToFile[ 2048 ];
  667. Platform::makeFullPathName( fromFile, qualifiedFromFile, sizeof( qualifiedFromFile ) );
  668. Platform::makeFullPathName( toFile, qualifiedToFile, sizeof( qualifiedToFile ) );
  669. return dPathCopy( qualifiedFromFile, qualifiedToFile, noOverwrite );
  670. }
  671. //-----------------------------------------------------------------------------
  672. DefineEngineFunction( getCurrentDirectory, String, (),,
  673. "@brief Return the current working directory.\n\n"
  674. "@return The absolute path of the current working directory.\n\n"
  675. "@note Only present in a Tools build of Torque.\n"
  676. "@see getWorkingDirectory()"
  677. "@ingroup FileSystem")
  678. {
  679. return Platform::getCurrentDirectory();
  680. }
  681. //-----------------------------------------------------------------------------
  682. DefineEngineFunction( setCurrentDirectory, bool, ( const char* path ),,
  683. "@brief Set the current working directory.\n\n"
  684. "@param path The absolute or relative (to the current working directory) path of the directory which should be made the new "
  685. "working directory.\n\n"
  686. "@return True if the working directory was successfully changed to @a path, false otherwise.\n\n"
  687. "@note Only present in a Tools build of Torque.\n"
  688. "@ingroup FileSystem")
  689. {
  690. return Platform::setCurrentDirectory( StringTable->insert( path ) );
  691. }
  692. //-----------------------------------------------------------------------------
  693. DefineEngineFunction( createPath, bool, ( const char* path ),,
  694. "@brief Create the given directory or the path leading to the given filename.\n\n"
  695. "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, "
  696. "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 "
  697. "of the path will be created.\n\n"
  698. "@param path The path to create.\n\n"
  699. "@note Only present in a Tools build of Torque.\n"
  700. "@ingroup FileSystem" )
  701. {
  702. static char pathName[1024];
  703. Con::expandScriptFilename( pathName, sizeof( pathName ), path );
  704. return Platform::createPath( pathName );
  705. }
  706. DefineEngineFunction(deleteDirectory, bool, (const char* path), ,
  707. "@brief Delete a directory from the hard drive\n\n"
  708. "@param path Name and path of the folder to delete\n"
  709. "@note THERE IS NO RECOVERY FROM THIS. Deleted files are gone for good.\n"
  710. "@return True if file was successfully deleted\n"
  711. "@ingroup FileSystem")
  712. {
  713. static char fileName[1024];
  714. static char sandboxFileName[1024];
  715. Con::expandScriptFilename(fileName, sizeof(fileName), path);
  716. Platform::makeFullPathName(fileName, sandboxFileName, sizeof(sandboxFileName));
  717. return Platform::deleteDirectory(sandboxFileName);
  718. }
  719. #endif // TORQUE_TOOLS