diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index a892adbcd..3ec7dc1d0 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -978,7 +978,10 @@ cFile:Delete("/usr/bin/virus.exe"); CreateFolder = { Params = "FolderName", Return = "bool", Notes = "(STATIC) Creates a new folder. Returns true if successful." }, Delete = { Params = "FileName", Return = "bool", Notes = "(STATIC) Deletes the specified file. Returns true if successful." }, Exists = { Params = "FileName", Return = "bool", Notes = "(STATIC) Returns true if the specified file exists." }, + GetExecutableExt = { Params = "", Return = "string", Notes = "(STATIC) Returns the customary executable extension used by the current platform (\".exe\" on Windows, empty string on Linux). " }, GetFolderContents = { Params = "FolderName", Return = "array table of strings", Notes = "(STATIC) Returns the contents of the specified folder, as an array table of strings. Each filesystem object is listed. Use the IsFile() and IsFolder() functions to determine the object type." }, + GetLastModificationTime = { Params = "Path", Return = "number", Notes = "(STATIC) Returns the last modification time (in current timezone) of the specified file or folder. Returns zero if file not found / not accessible. The returned value is in the same units as values returned by os.time()." }, + GetPathSeparator = { Params = "", Return = "string", Notes = "(STATIC) Returns the primary path separator used by the current platform. Returns \"\\\" on Windows and \"/\" on Linux. Note that the platform or CRT may support additional path separators, those are not reported." }, GetSize = { Params = "FileName", Return = "number", Notes = "(STATIC) Returns the size of the file, or -1 on failure." }, IsFile = { Params = "Path", Return = "bool", Notes = "(STATIC) Returns true if the specified path points to an existing file." }, IsFolder = { Params = "Path", Return = "bool", Notes = "(STATIC) Returns true if the specified path points to an existing folder." }, diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index c8e96d378..d255c0f8f 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -9,7 +9,7 @@ g_ShowFoodStats = false; -- When true, each player's food stats are sent to the -function Initialize(Plugin) +function Initialize(a_Plugin) --[[ -- Test multiple hook handlers: cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick1); @@ -45,14 +45,12 @@ function Initialize(Plugin) -- Bind all the console commands: RegisterPluginInfoConsoleCommands(); - Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers) - Plugin:AddWebTab("StressTest", HandleRequest_StressTest) + a_Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers) + a_Plugin:AddWebTab("StressTest", HandleRequest_StressTest) -- Enable the following line for BlockArea / Generator interface testing: -- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED); - LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion()) - -- TestBlockAreas() -- TestSQLiteBindings() -- TestExpatBindings() @@ -63,6 +61,10 @@ function Initialize(Plugin) -- TestUUIDFromName() -- TestRankMgr() TestFileExt() + TestFileLastMod() + + local LastSelfMod = cFile:GetLastModificationTime(a_Plugin:GetLocalFolder() .. "/Debuggers.lua") + LOG("Debuggers.lua last modified on " .. os.date("%Y-%m-%dT%H:%M:%S", LastSelfMod)) --[[ -- Test cCompositeChat usage in console-logging: @@ -92,6 +94,19 @@ end +function TestFileLastMod() + local f = assert(io.open("test.txt", "w")) + f:write("test") + f:close() + local filetime = cFile:GetLastModificationTime("test.txt") + local ostime = os.time() + LOG("file time: " .. filetime .. ", OS time: " .. ostime .. ", difference: " .. ostime - filetime) +end + + + + + function TestPluginCalls() -- In order to test the inter-plugin communication, we're going to call Core's ReturnColorFromChar() function -- It is a rather simple function that doesn't need any tables as its params and returns a value, too diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index fcd5ec027..fe72f34b4 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -458,9 +458,14 @@ AString cFile::ChangeFileExt(const AString & a_FileName, const AString & a_NewEx auto res = a_FileName; // If the path separator is the last character of the string, return the string unmodified (refers to a folder): - #ifdef _WIN32 - auto LastPathSep = res.find_last_of("/\\"); // Find either path separator - Windows accepts slashes as separators, too + #if defined(_MSC_VER) + // Find either path separator - MSVC CRT accepts slashes as separators, too + auto LastPathSep = res.find_last_of("/\\"); + #elif defined(_WIN32) + // Windows with different CRTs support only the backslash separator + auto LastPathSep = res.rfind('\\'); #else + // Linux supports only the slash separator auto LastPathSep = res.rfind('/'); #endif if ((LastPathSep != AString::npos) && (LastPathSep + 1 == res.size())) @@ -468,6 +473,7 @@ AString cFile::ChangeFileExt(const AString & a_FileName, const AString & a_NewEx return res; } + // Append or replace the extension: auto DotPos = res.rfind('.'); if ( (DotPos == AString::npos) || // No dot found @@ -491,6 +497,52 @@ AString cFile::ChangeFileExt(const AString & a_FileName, const AString & a_NewEx +unsigned cFile::GetLastModificationTime(const AString & a_FileName) +{ + struct stat st; + if (stat(a_FileName.c_str(), &st) < 0) + { + return 0; + } + #ifdef _WIN32 + // Windows returns times in local time already + return static_cast(st.st_mtime); + #else + // Linux returns UTC time, convert to local timezone: + return static_cast(mktime(localtime(&st.st_mtime))); + #endif +} + + + + + +AString cFile::GetPathSeparator(void) +{ + #ifdef _WIN32 + return "\\"; + #else + return "/"; + #endif +} + + + + + +AString cFile::GetExecutableExt(void) +{ + #ifdef _WIN32 + return ".exe"; + #else + return ""; + #endif +} + + + + + int cFile::Printf(const char * a_Fmt, ...) { AString buf; diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h index 1cf5c71d7..6ee080480 100644 --- a/src/OSSupport/File.h +++ b/src/OSSupport/File.h @@ -131,6 +131,18 @@ public: a_FileName may contain path specification. */ static AString ChangeFileExt(const AString & a_FileName, const AString & a_NewExt); + /** Returns the last modification time (in current timezone) of the specified file. + The value returned is in the same units as the value returned by time() function. + If the file is not found / accessible, zero is returned. */ + static unsigned GetLastModificationTime(const AString & a_FileName); + + /** Returns the path separator used by the current platform. + Note that the platform / CRT may support additional path separators (such as slashes on Windows), these don't get reported. */ + static AString GetPathSeparator(void); + + /** Returns the customary executable extension used by the current platform. */ + static AString GetExecutableExt(void); + // tolua_end /** Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there). */