summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattes D <github@xoft.cz>2015-04-12 10:54:05 +0200
committerMattes D <github@xoft.cz>2015-04-12 10:54:05 +0200
commit9367d44cb484436cd8b6a77619db0c86582a71d6 (patch)
treecc81ba80cd6355582a505de3b4a019800742e055
parentAdded extra divide operator to Vector3. (diff)
parentcFile:ChangeFileExt now accepts extensions with leading dot, too. (diff)
downloadcuberite-9367d44cb484436cd8b6a77619db0c86582a71d6.tar
cuberite-9367d44cb484436cd8b6a77619db0c86582a71d6.tar.gz
cuberite-9367d44cb484436cd8b6a77619db0c86582a71d6.tar.bz2
cuberite-9367d44cb484436cd8b6a77619db0c86582a71d6.tar.lz
cuberite-9367d44cb484436cd8b6a77619db0c86582a71d6.tar.xz
cuberite-9367d44cb484436cd8b6a77619db0c86582a71d6.tar.zst
cuberite-9367d44cb484436cd8b6a77619db0c86582a71d6.zip
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua5
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua47
-rw-r--r--src/Bindings/PluginLua.cpp249
-rw-r--r--src/OSSupport/File.cpp87
-rw-r--r--src/OSSupport/File.h12
5 files changed, 389 insertions, 11 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index a892adbcd..025e9470d 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -973,12 +973,15 @@ cFile:Delete("/usr/bin/virus.exe");
]],
Functions =
{
- ChangeFileExt = { Params = "FileName, NewExt", Return = "string", Notes = "(STATIC) Returns FileName with its extension changed to NewExt. FileName may contain path elements, extension is recognized as the last dot in the string." },
+ ChangeFileExt = { Params = "FileName, NewExt", Return = "string", Notes = "(STATIC) Returns FileName with its extension changed to NewExt. NewExt may begin with a dot, but needn't, the result is the same in both cases (the first dot, if present, is ignored). FileName may contain path elements, extension is recognized as the last dot after the last path separator in the string." },
Copy = { Params = "SrcFileName, DstFileName", Return = "bool", Notes = "(STATIC) Copies a single file to a new destination. Returns true if successful. Fails if the destination already exists." },
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 (including the dot) 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 d0c362ab4..01a5de81e 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()
@@ -62,6 +60,11 @@ function Initialize(Plugin)
TestStringBase64()
-- 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:
@@ -79,6 +82,40 @@ end;
+function TestFileExt()
+ assert(cFile:ChangeFileExt("fileless_dir/", "new") == "fileless_dir/")
+ assert(cFile:ChangeFileExt("fileless_dir/", ".new") == "fileless_dir/")
+ assert(cFile:ChangeFileExt("pathless_file.ext", "new") == "pathless_file.new")
+ assert(cFile:ChangeFileExt("pathless_file.ext", ".new") == "pathless_file.new")
+ assert(cFile:ChangeFileExt("path/to/file.ext", "new") == "path/to/file.new")
+ assert(cFile:ChangeFileExt("path/to/file.ext", ".new") == "path/to/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file", "new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file", ".new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.ext", "new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.ext", ".new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.longext", "new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.longext", ".new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.", "new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.", ".new") == "path/to.dir/file.new")
+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/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index 0a2a8411d..9bbac92b0 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -208,6 +208,10 @@ void cPluginLua::OnDisable(void)
void cPluginLua::Tick(float a_Dt)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return;
+ }
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TICK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
@@ -222,6 +226,10 @@ void cPluginLua::Tick(float a_Dt)
bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_SPREAD];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -242,6 +250,10 @@ bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int
bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_TO_PICKUPS];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -262,6 +274,10 @@ bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_Bl
bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHAT];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -282,6 +298,10 @@ bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message)
bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_AVAILABLE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -302,6 +322,10 @@ bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -322,6 +346,10 @@ bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ,
bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -342,6 +370,10 @@ bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ,
bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -362,6 +394,10 @@ bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -382,6 +418,10 @@ bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_COLLECTING_PICKUP];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -402,6 +442,10 @@ bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup)
bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CRAFTING_NO_RECIPE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -422,6 +466,10 @@ bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid,
bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -442,6 +490,10 @@ bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason
bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_ADD_EFFECT];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -462,6 +514,10 @@ bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_E
bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXECUTE_COMMAND];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -482,6 +538,10 @@ bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Sp
bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -519,6 +579,10 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can
bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -556,6 +620,10 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool &
bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Username)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HANDSHAKE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -576,8 +644,11 @@ bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Usernam
bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_DstSlotNum, cBlockEntityWithItems & a_SrcEntity, int a_SrcSlotNum)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
-
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PULLING_ITEM];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
@@ -597,6 +668,10 @@ bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper,
bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems & a_DstEntity, int a_DstSlotNum)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PUSHING_ITEM];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -617,6 +692,10 @@ bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper,
bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_KILLING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -637,6 +716,10 @@ bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInf
bool cPluginLua::OnLogin(cClientHandle & a_Client, int a_ProtocolVersion, const AString & a_Username)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_LOGIN];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -657,6 +740,10 @@ bool cPluginLua::OnLogin(cClientHandle & a_Client, int a_ProtocolVersion, const
bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_ANIMATION];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -677,6 +764,10 @@ bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation)
bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BREAKING_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -697,6 +788,10 @@ bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_B
bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BROKEN_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -717,6 +812,10 @@ bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_Blo
bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_DESTROYED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -737,6 +836,10 @@ bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player)
bool cPluginLua::OnPlayerEating(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_EATING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -757,6 +860,10 @@ bool cPluginLua::OnPlayerEating(cPlayer & a_Player)
bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FOOD_LEVEL_CHANGE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -777,6 +884,10 @@ bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel)
bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -797,6 +908,10 @@ bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward)
bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -817,6 +932,10 @@ bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward)
bool cPluginLua::OnPlayerJoined(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_JOINED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -837,6 +956,10 @@ bool cPluginLua::OnPlayerJoined(cPlayer & a_Player)
bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_LEFT_CLICK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -857,6 +980,10 @@ bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_Block
bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_MOVING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -877,6 +1004,10 @@ bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPositi
bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_TELEPORT];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -897,6 +1028,10 @@ bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosi
bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACED_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -922,6 +1057,10 @@ bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_Blo
bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACING_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -947,6 +1086,10 @@ bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_Bl
bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -967,6 +1110,10 @@ bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_Bloc
bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -987,6 +1134,10 @@ bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Ent
bool cPluginLua::OnPlayerShooting(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SHOOTING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1007,6 +1158,10 @@ bool cPluginLua::OnPlayerShooting(cPlayer & a_Player)
bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SPAWNED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1027,6 +1182,10 @@ bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player)
bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_TOSSING_ITEM];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1047,6 +1206,10 @@ bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player)
bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1067,6 +1230,10 @@ bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_Block
bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_ITEM];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1087,6 +1254,10 @@ bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY
bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1107,6 +1278,10 @@ bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_Bloc
bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_ITEM];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1127,6 +1302,10 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block
bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1147,6 +1326,10 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha
bool cPluginLua::OnPluginsLoaded(void)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1165,6 +1348,10 @@ bool cPluginLua::OnPluginsLoaded(void)
bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_POST_CRAFTING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1185,6 +1372,10 @@ bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCra
bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PRE_CRAFTING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1205,6 +1396,10 @@ bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraf
bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1225,6 +1420,10 @@ bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_Bl
bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_ENTITY];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1245,6 +1444,10 @@ bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity
bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SERVER_PING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1265,6 +1468,10 @@ bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_Server
bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_ENTITY];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1285,6 +1492,10 @@ bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_MONSTER];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1305,6 +1516,10 @@ bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster)
bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_ENTITY];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1325,6 +1540,10 @@ bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity)
bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_MONSTER];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1345,6 +1564,10 @@ bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster)
bool cPluginLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TAKE_DAMAGE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1370,6 +1593,10 @@ bool cPluginLua::OnUpdatedSign(
)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATED_SIGN];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1395,6 +1622,10 @@ bool cPluginLua::OnUpdatingSign(
)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1415,6 +1646,10 @@ bool cPluginLua::OnUpdatingSign(
bool cPluginLua::OnWeatherChanged(cWorld & a_World)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1435,6 +1670,10 @@ bool cPluginLua::OnWeatherChanged(cWorld & a_World)
bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1455,6 +1694,10 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
bool cPluginLua::OnWorldStarted(cWorld & a_World)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_STARTED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
@@ -1470,6 +1713,10 @@ bool cPluginLua::OnWorldStarted(cWorld & a_World)
bool cPluginLua::OnWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_TICK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp
index 7ad1b3f81..43105b230 100644
--- a/src/OSSupport/File.cpp
+++ b/src/OSSupport/File.cpp
@@ -456,17 +456,50 @@ AString cFile::ReadWholeFile(const AString & a_FileName)
AString cFile::ChangeFileExt(const AString & a_FileName, const AString & a_NewExt)
{
auto res = a_FileName;
+
+ // If the path separator is the last character of the string, return the string unmodified (refers to a folder):
+ #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()))
+ {
+ return res;
+ }
+
+ // Append or replace the extension:
auto DotPos = res.rfind('.');
- if (DotPos == AString::npos)
+ if (
+ (DotPos == AString::npos) || // No dot found
+ ((LastPathSep != AString::npos) && (LastPathSep > DotPos)) // Last dot is before the last path separator (-> in folder name)
+ )
{
- // No extension, just append it:
- res.push_back('.');
+ // No extension, just append the new one:
+ if (!a_NewExt.empty() && (a_NewExt[0] != '.'))
+ {
+ // a_NewExt doesn't start with a dot, insert one:
+ res.push_back('.');
+ }
res.append(a_NewExt);
}
else
{
// Replace existing extension:
- res.erase(DotPos + 1, AString::npos);
+ if (!a_NewExt.empty() && (a_NewExt[0] != '.'))
+ {
+ // a_NewExt doesn't start with a dot, keep the current one:
+ res.erase(DotPos + 1, AString::npos);
+ }
+ else
+ {
+ res.erase(DotPos, AString::npos);
+ }
res.append(a_NewExt);
}
return res;
@@ -476,6 +509,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<unsigned>(st.st_mtime);
+ #else
+ // Linux returns UTC time, convert to local timezone:
+ return static_cast<unsigned>(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). */