2
0
mirror of https://github.com/rehlds/metamod-r.git synced 2024-12-27 07:05:34 +03:00

Refactoring of mplugin and mlist

This commit is contained in:
asmodai 2017-05-09 18:34:55 +03:00
parent d1d2a9b755
commit f7c115e736
31 changed files with 917 additions and 1105 deletions

View File

@ -186,5 +186,4 @@ inline void UTIL_TraceLine(const Vector &vecStart, const Vector &vecEnd, IGNORE_
TRACE_LINE(vecStart, vecEnd, (igmon == ignore_monsters), pentIgnore, ptr); TRACE_LINE(vecStart, vecEnd, (igmon == ignore_monsters), pentIgnore, ptr);
} }
extern char *UTIL_VarArgs(char *format, ...);
extern void UTIL_LogPrintf(const char *fmt, ...); extern void UTIL_LogPrintf(const char *fmt, ...);

View File

@ -197,7 +197,6 @@
<ClCompile Include="..\src\linkgame.cpp" /> <ClCompile Include="..\src\linkgame.cpp" />
<ClCompile Include="..\src\log_meta.cpp" /> <ClCompile Include="..\src\log_meta.cpp" />
<ClCompile Include="..\src\metamod_rehlds_api.cpp" /> <ClCompile Include="..\src\metamod_rehlds_api.cpp" />
<ClCompile Include="..\src\meta_eiface.cpp" />
<ClCompile Include="..\src\metamod.cpp" /> <ClCompile Include="..\src\metamod.cpp" />
<ClCompile Include="..\src\mlist.cpp" /> <ClCompile Include="..\src\mlist.cpp" />
<ClCompile Include="..\src\mplayer.cpp" /> <ClCompile Include="..\src\mplayer.cpp" />
@ -213,7 +212,6 @@
<ClCompile Include="..\src\reg_support.cpp" /> <ClCompile Include="..\src\reg_support.cpp" />
<ClCompile Include="..\src\sdk_util.cpp" /> <ClCompile Include="..\src\sdk_util.cpp" />
<ClCompile Include="..\src\studioapi.cpp" /> <ClCompile Include="..\src\studioapi.cpp" />
<ClCompile Include="..\src\support_meta.cpp" />
<ClCompile Include="..\src\utils.cpp" /> <ClCompile Include="..\src\utils.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -232,7 +230,6 @@
<ClInclude Include="..\src\log_meta.h" /> <ClInclude Include="..\src\log_meta.h" />
<ClInclude Include="..\src\metamod_rehlds_api.h" /> <ClInclude Include="..\src\metamod_rehlds_api.h" />
<ClInclude Include="..\src\meta_api.h" /> <ClInclude Include="..\src\meta_api.h" />
<ClInclude Include="..\src\meta_eiface.h" />
<ClInclude Include="..\src\metamod.h" /> <ClInclude Include="..\src\metamod.h" />
<ClInclude Include="..\src\mlist.h" /> <ClInclude Include="..\src\mlist.h" />
<ClInclude Include="..\src\mplayer.h" /> <ClInclude Include="..\src\mplayer.h" />
@ -245,7 +242,6 @@
<ClInclude Include="..\src\reg_support.h" /> <ClInclude Include="..\src\reg_support.h" />
<ClInclude Include="..\src\sdk_util.h" /> <ClInclude Include="..\src\sdk_util.h" />
<ClInclude Include="..\src\studioapi.h" /> <ClInclude Include="..\src\studioapi.h" />
<ClInclude Include="..\src\support_meta.h" />
<ClInclude Include="..\src\utils.h" /> <ClInclude Include="..\src\utils.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -41,9 +41,6 @@
<ClCompile Include="..\src\log_meta.cpp"> <ClCompile Include="..\src\log_meta.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\src\meta_eiface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\metamod.cpp"> <ClCompile Include="..\src\metamod.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -77,9 +74,6 @@
<ClCompile Include="..\src\studioapi.cpp"> <ClCompile Include="..\src\studioapi.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\src\support_meta.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\utils.cpp"> <ClCompile Include="..\src\utils.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -130,9 +124,6 @@
<ClInclude Include="..\src\meta_api.h"> <ClInclude Include="..\src\meta_api.h">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\src\meta_eiface.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\metamod.h"> <ClInclude Include="..\src\metamod.h">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClInclude> </ClInclude>
@ -169,9 +160,6 @@
<ClInclude Include="..\src\studioapi.h"> <ClInclude Include="..\src\studioapi.h">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\src\support_meta.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\utils.h"> <ClInclude Include="..\src\utils.h">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClInclude> </ClInclude>

View File

@ -128,7 +128,7 @@ void CForwardCallbackJIT::naked_main()
for (int i = 0, hookid = 0; i < m_jitdata->plugins_count; i++) { for (int i = 0, hookid = 0; i < m_jitdata->plugins_count; i++) {
auto plug = &m_jitdata->plugins[i]; auto plug = &m_jitdata->plugins[i];
if (plug->m_status < PL_RUNNING) // allow only running and paused if (plug->status() < PL_RUNNING) // allow only running and paused
continue; continue;
size_t fn_table = *(size_t *)(size_t(plug) + m_jitdata->table_offset); size_t fn_table = *(size_t *)(size_t(plug) + m_jitdata->table_offset);
@ -141,7 +141,7 @@ void CForwardCallbackJIT::naked_main()
// check status and handler set // check status and handler set
mov(ecx, dword_ptr[fn_table + m_jitdata->pfn_offset]); mov(ecx, dword_ptr[fn_table + m_jitdata->pfn_offset]);
cmp(byte_ptr[size_t(&plug->m_status)], PL_RUNNING); cmp(byte_ptr[plug->status_ptr()], PL_RUNNING);
jecxz(go_next_plugin); jecxz(go_next_plugin);
jnz(go_next_plugin); jnz(go_next_plugin);
@ -209,7 +209,7 @@ void CForwardCallbackJIT::naked_main()
for (int i = 0, hookid = 0; i < m_jitdata->plugins_count; i++) { for (int i = 0, hookid = 0; i < m_jitdata->plugins_count; i++) {
auto plug = &m_jitdata->plugins[i]; auto plug = &m_jitdata->plugins[i];
if (plug->m_status < PL_RUNNING) // allow only running and paused if (plug->status() < PL_RUNNING) // allow only running and paused
continue; continue;
size_t fn_table = *(size_t *)(size_t(plug) + m_jitdata->post_table_offset); size_t fn_table = *(size_t *)(size_t(plug) + m_jitdata->post_table_offset);
@ -222,7 +222,7 @@ void CForwardCallbackJIT::naked_main()
// check status and handler set // check status and handler set
mov(ecx, dword_ptr[fn_table + m_jitdata->pfn_offset]); mov(ecx, dword_ptr[fn_table + m_jitdata->pfn_offset]);
cmp(byte_ptr[size_t(&plug->m_status)], PL_RUNNING); cmp(byte_ptr[plug->status_ptr()], PL_RUNNING);
jecxz(go_next_plugin); jecxz(go_next_plugin);
jnz(go_next_plugin); jnz(go_next_plugin);

View File

@ -335,7 +335,7 @@ void cmd_doplug(PLUG_CMD pcmd)
// Otherwise, print error and exit. // Otherwise, print error and exit.
if (pcmd == PC_REQUIRE) if (pcmd == PC_REQUIRE)
{ {
if (findp && findp->m_status >= PL_RUNNING && unique) if (findp && findp->status() >= PL_RUNNING && unique)
{ {
META_DEBUG(3, "Required plugin '%s' found loaded and running.", arg); META_DEBUG(3, "Required plugin '%s' found loaded and running.", arg);
return; return;
@ -375,69 +375,69 @@ void cmd_doplug(PLUG_CMD pcmd)
{ {
case PC_PAUSE: case PC_PAUSE:
if (findp->pause()) if (findp->pause())
META_CONS("Paused plugin '%s'", findp->m_desc); META_CONS("Paused plugin '%s'", findp->description());
else else
META_CONS("Pause failed for plugin '%s'", findp->m_desc); META_CONS("Pause failed for plugin '%s'", findp->description());
break; break;
case PC_UNPAUSE: case PC_UNPAUSE:
if (findp->unpause()) if (findp->unpause())
META_CONS("Unpaused plugin '%s'", findp->m_desc); META_CONS("Unpaused plugin '%s'", findp->description());
else else
META_CONS("Unpause failed for plugin '%s'", findp->m_desc); META_CONS("Unpause failed for plugin '%s'", findp->description());
break; break;
case PC_UNLOAD: case PC_UNLOAD:
{ {
findp->m_action = PA_UNLOAD; findp->set_action(PA_UNLOAD);
if (findp->unload(PT_ANYTIME, PNL_COMMAND, PNL_COMMAND)) if (findp->unload(PT_ANYTIME, PNL_COMMAND))
{ {
META_CONS("Unloaded plugin '%s'", findp->m_desc); META_CONS("Unloaded plugin '%s'", findp->description());
g_plugins->show(); g_plugins->show();
} }
else if (false /*meta_errno == ME_DELAYED*/) // TODO else if (false /*meta_errno == ME_DELAYED*/) // TODO
META_CONS("Unload delayed for plugin '%s'", findp->m_desc); META_CONS("Unload delayed for plugin '%s'", findp->description());
else else
META_CONS("Unload failed for plugin '%s'", findp->m_desc); META_CONS("Unload failed for plugin '%s'", findp->description());
break; break;
} }
case PC_FORCE_UNLOAD: case PC_FORCE_UNLOAD:
{ {
findp->m_action = PA_UNLOAD; findp->set_action(PA_UNLOAD);
if (findp->unload(PT_ANYTIME, PNL_CMD_FORCED, PNL_CMD_FORCED)) if (findp->unload(PT_ANYTIME, PNL_CMD_FORCED))
{ {
META_CONS("Forced unload plugin '%s'", findp->m_desc); META_CONS("Forced unload plugin '%s'", findp->description());
g_plugins->show(); g_plugins->show();
} }
else else
META_CONS("Forced unload failed for plugin '%s'", findp->m_desc); META_CONS("Forced unload failed for plugin '%s'", findp->description());
break; break;
} }
case PC_RELOAD: case PC_RELOAD:
{ {
findp->m_action = PA_RELOAD; findp->set_action(PA_RELOAD);
if (findp->reload(PT_ANYTIME, PNL_COMMAND)) if (findp->reload(PT_ANYTIME, PNL_COMMAND))
META_CONS("Reloaded plugin '%s'", findp->m_desc); META_CONS("Reloaded plugin '%s'", findp->description());
else if (0/*meta_errno == ME_DELAYED*/) // TODO else if (0/*meta_errno == ME_DELAYED*/) // TODO
META_CONS("Reload delayed for plugin '%s'", findp->m_desc); META_CONS("Reload delayed for plugin '%s'", findp->description());
else if (0/*meta_errno == ME_NOTALLOWED*/) else if (0/*meta_errno == ME_NOTALLOWED*/)
META_CONS("Reload not allowed for plugin '%s' now, only allowed %s", findp->m_desc, findp->str_loadable(SL_ALLOWED)); META_CONS("Reload not allowed for plugin '%s' now, only allowed %s", findp->description(), findp->str_loadable(SL_ALLOWED));
else else
META_CONS("Reload failed for plugin '%s'", findp->m_desc); META_CONS("Reload failed for plugin '%s'", findp->description());
break; break;
} }
case PC_RETRY: case PC_RETRY:
if (findp->retry(PT_ANYTIME, PNL_COMMAND)) if (findp->retry(PT_ANYTIME, PNL_COMMAND))
META_CONS("Retry succeeded for plugin '%s'", findp->m_desc); META_CONS("Retry succeeded for plugin '%s'", findp->description());
else else
META_CONS("Retry failed for plugin '%s'", findp->m_desc); META_CONS("Retry failed for plugin '%s'", findp->description());
break; break;
case PC_CLEAR: case PC_CLEAR:
if (!findp->clear()) if (!findp->clear())
{ {
META_CONS("Clear failed for plugin '%s'", findp->m_desc); META_CONS("Clear failed for plugin '%s'", findp->description());
return; return;
} }
META_CONS("Cleared failed plugin '%s' from list", findp->m_desc); META_CONS("Cleared failed plugin '%s' from list", findp->description());
g_plugins->show(); g_plugins->show();
break; break;
case PC_INFO: case PC_INFO:

View File

@ -193,7 +193,7 @@ void MConfig::set_directory()
} }
#endif #endif
NormalizePath(m_directory); normalize_path(m_directory);
// get directory // get directory
char *dir = Q_strrchr(m_directory, '/'); char *dir = Q_strrchr(m_directory, '/');

View File

@ -3,8 +3,8 @@
#define CDATA_ENG_H(x, p, h) CDATA_ENTRY(enginefuncs_t, x, p, size_t(h)) #define CDATA_ENG_H(x, p, h) CDATA_ENTRY(enginefuncs_t, x, p, size_t(h))
#define CDATA_ENG(x) CDATA_ENTRY(enginefuncs_t, x, P_PRE, 0u) #define CDATA_ENG(x) CDATA_ENTRY(enginefuncs_t, x, P_PRE, 0u)
meta_enginefuncs_t g_meta_engfuncs; // static trampolines to dynamic callbacks (for gamedll) enginefuncs_t g_meta_engfuncs; // static trampolines to dynamic callbacks (for gamedll)
meta_enginefuncs_t g_meta_engfuncs_jit; // dynamic jit callbacks enginefuncs_t g_meta_engfuncs_jit; // dynamic jit callbacks
void MM_PRE_HOOK mm_QueryClientCvarValue(const edict_t* pEdict, const char* cvarName) void MM_PRE_HOOK mm_QueryClientCvarValue(const edict_t* pEdict, const char* cvarName)
{ {

View File

@ -12,8 +12,7 @@ typedef int (*GET_ENGINE_FUNCTIONS_FN)(enginefuncs_s *pengfuncsFromEngine, int *
// Protect against other projects which use this include file but use the // Protect against other projects which use this include file but use the
// normal enginefuncs_t type for their meta_engfuncs. // normal enginefuncs_t type for their meta_engfuncs.
#ifdef METAMOD_CORE #ifdef METAMOD_CORE
#include "meta_eiface.h" // meta_enginefuncs_t extern enginefuncs_t g_meta_engfuncs;
extern meta_enginefuncs_t g_meta_engfuncs;
void compile_engine_callbacks(); void compile_engine_callbacks();
#else #else

View File

@ -10,14 +10,6 @@
// "hack" our way around that by using a flag METAMOD_CORE which is set // "hack" our way around that by using a flag METAMOD_CORE which is set
// when compiling Metamod proper. // when compiling Metamod proper.
#ifdef METAMOD_CORE
#include "meta_eiface.h" // HL_enginefuncs_t
// Use a #define to bend the enginefuncs_t type to our HL_enginefuncs_t
// type instead as we now use that for the global object g_engfuncs.
#define enginefuncs_t HL_enginefuncs_t
#endif
#include <enginecallback.h> // ALERT, etc #include <enginecallback.h> // ALERT, etc
#ifdef METAMOD_CORE #ifdef METAMOD_CORE

View File

@ -116,7 +116,7 @@ bool setup_gamedll(gamedll_t *gamedll)
// If the path is relative, the gamedll file will be missing and // If the path is relative, the gamedll file will be missing and
// it might be found in the cache file. // it might be found in the cache file.
if (!IsAbsolutePath(gamedll->pathname)) if (!is_abs_path(gamedll->pathname))
{ {
char szInstallPath[MAX_PATH]; char szInstallPath[MAX_PATH];
Q_snprintf(szInstallPath, sizeof(szInstallPath), "%s/%s", gamedll->gamedir, gamedll->pathname); Q_snprintf(szInstallPath, sizeof(szInstallPath), "%s/%s", gamedll->gamedir, gamedll->pathname);

View File

@ -34,7 +34,7 @@ void _fini()
#endif #endif
//! Holds engine functionality callbacks //! Holds engine functionality callbacks
HL_enginefuncs_t g_engfuncs; enginefuncs_t g_engfuncs;
globalvars_t* gpGlobals; globalvars_t* gpGlobals;
engine_t g_engine; engine_t g_engine;
@ -49,7 +49,8 @@ void WINAPI GiveFnptrsToDll(enginefuncs_t *pengfuncsFromEngine, globalvars_t *pG
g_engine.funcs = &g_engfuncs; g_engine.funcs = &g_engfuncs;
g_engine.globals = pGlobals; g_engine.globals = pGlobals;
g_engfuncs.initialise_interface(pengfuncsFromEngine); g_engfuncs = *pengfuncsFromEngine;
flush_ALERT_buffer();
// NOTE! Have to call logging function _after_ initialising g_engfuncs, so // NOTE! Have to call logging function _after_ initialising g_engfuncs, so
// that g_engfuncs.pfnAlertMessage() can be resolved properly, heh. :) // that g_engfuncs.pfnAlertMessage() can be resolved properly, heh. :)
META_DEV("called: GiveFnptrsToDll"); META_DEV("called: GiveFnptrsToDll");

View File

@ -1,20 +0,0 @@
#include "precompiled.h"
void meta_new_dll_functions_t::set_from(NEW_DLL_FUNCTIONS* _pFuncs)
{
Q_memcpy(this, _pFuncs, sizeof(NEW_DLL_FUNCTIONS));
}
void meta_enginefuncs_t::set_from(enginefuncs_t* _pFuncs)
{
Q_memcpy(this, _pFuncs, sizeof(enginefuncs_t));
}
void HL_enginefuncs_t::initialise_interface(enginefuncs_t* _pFuncs)
{
set_from(_pFuncs);
// Now the pfnAlertMessage is available and we trust it to be a valid
// pointer, so flush the message buffer.
flush_ALERT_buffer();
}

View File

@ -1,45 +0,0 @@
#pragma once
// We use our own versions of the engine/dll interface structs. We add a
// few dummy entries to the end and set them to 0. That way we are
// protected from updates to the HL SDK adding new functions which would
// cause a) the game dll copying arbitrary values from us and b) the game
// dll overwriting our memory when using an old Metamod with a new game
// dll.
// meta_new_dll_functions_t
struct meta_new_dll_functions_t: public NEW_DLL_FUNCTIONS
{
// Fill this object with pointers copied from a NEW_DLL_FUNCTIONS struct.
void set_from(NEW_DLL_FUNCTIONS* pFuncs);
};
// meta_enginefuncs_t
struct meta_enginefuncs_t : public enginefuncs_t
{
// Fill this object with pointers copied from an enginefuncs_t struct.
void set_from(enginefuncs_t* pFuncs);
};
// This is a specialisation of the meta_enginefuncs_t struct which is only
// used for the initial copy of the engine functions, i.e. those we get
// passed from the HL engine right at the beginning.
// Since there is only one master copy of engine functions this could be
// implemented as a singleton. This is left as an option for later.
struct HL_enginefuncs_t: public meta_enginefuncs_t
{
HL_enginefuncs_t() {};
// Fill this object with pointers copied from an enginefuncs_t struct
// and fixup the interface.
// For this class this happens in the GiveFptrsToDll() function
// with the pointers passed from the HL engine.
void initialise_interface(enginefuncs_t* pFuncs);
private:
// Moving copy_to() and set_from() to the private space.
void set_from(enginefuncs_t* pFuncs)
{
meta_enginefuncs_t::set_from(pFuncs);
}
};

View File

@ -20,7 +20,7 @@ gamedll_t g_GameDLL;
ALIGN16 ALIGN16
meta_globals_t g_metaGlobals; meta_globals_t g_metaGlobals;
meta_enginefuncs_t g_plugin_engfuncs; enginefuncs_t g_plugin_engfuncs;
MPluginList *g_plugins; MPluginList *g_plugins;
MRegCmdList *g_regCmds; MRegCmdList *g_regCmds;
@ -84,7 +84,7 @@ void metamod_startup()
{ {
META_LOG("Configfile specified via localinfo: %s", cp); META_LOG("Configfile specified via localinfo: %s", cp);
if (FileExistsInGameDir(cp)) if (is_file_exists_in_gamedir(cp))
{ {
Q_strncpy(configFile, cp, sizeof configFile - 1); Q_strncpy(configFile, cp, sizeof configFile - 1);
configFile[sizeof configFile - 1] = '\0'; configFile[sizeof configFile - 1] = '\0';
@ -93,7 +93,7 @@ void metamod_startup()
META_ERROR("Empty/missing config.ini file: %s; falling back to %s", cp, configFile); META_ERROR("Empty/missing config.ini file: %s; falling back to %s", cp, configFile);
} }
if (!FileExistsInGameDir(configFile)) if (!is_file_exists_in_gamedir(configFile))
{ {
Q_strncpy(configFile, g_config->directory(), sizeof configFile - 1); Q_strncpy(configFile, g_config->directory(), sizeof configFile - 1);
configFile[sizeof configFile - 1] = '\0'; configFile[sizeof configFile - 1] = '\0';
@ -105,14 +105,14 @@ void metamod_startup()
} }
Q_strcat(configFile, "/" CONFIG_INI); Q_strcat(configFile, "/" CONFIG_INI);
if (!FileExistsInGameDir(configFile)) if (!is_file_exists_in_gamedir(configFile))
{ {
META_DEBUG(2, "No config.ini file found: %s", CONFIG_INI); META_DEBUG(2, "No config.ini file found: %s", CONFIG_INI);
} }
} }
// Load config file // Load config file
if (FileExistsInGameDir(configFile)) if (is_file_exists_in_gamedir(configFile))
g_config->load(configFile); g_config->load(configFile);
// Now, override config options with localinfo commandline options. // Now, override config options with localinfo commandline options.
@ -163,7 +163,7 @@ void metamod_startup()
// Copy, and store pointer in g_engine struct. Yes, we could just store // Copy, and store pointer in g_engine struct. Yes, we could just store
// the actual engine_t struct in g_engine, but then it wouldn't be a // the actual engine_t struct in g_engine, but then it wouldn't be a
// pointer to match the other g_engfuncs. // pointer to match the other g_engfuncs.
g_plugin_engfuncs.set_from(g_engine.funcs); g_plugin_engfuncs = *g_engine.funcs;
g_engine.pl_funcs = &g_plugin_engfuncs; g_engine.pl_funcs = &g_plugin_engfuncs;
// substitute our special versions of various commands // substitute our special versions of various commands
g_engine.pl_funcs->pfnAddServerCommand = meta_AddServerCommand; g_engine.pl_funcs->pfnAddServerCommand = meta_AddServerCommand;
@ -197,7 +197,7 @@ void metamod_startup()
// In fact, we need gamedir even earlier, so moved up above. // In fact, we need gamedir even earlier, so moved up above.
// Load plugins file // Load plugins file
if (!FileExistsInGameDir(pluginFile)) if (!is_file_exists_in_gamedir(pluginFile))
{ {
Q_strncpy(pluginFile, g_config->directory(), sizeof pluginFile - 1); Q_strncpy(pluginFile, g_config->directory(), sizeof pluginFile - 1);
pluginFile[sizeof pluginFile - 1] = '\0'; pluginFile[sizeof pluginFile - 1] = '\0';
@ -209,7 +209,7 @@ void metamod_startup()
} }
Q_strcat(pluginFile, "/" PLUGINS_INI); Q_strcat(pluginFile, "/" PLUGINS_INI);
if (!FileExistsInGameDir(pluginFile)) if (!is_file_exists_in_gamedir(pluginFile))
{ {
META_DEBUG(2, "No plugins.ini file found: %s", PLUGINS_INI); META_DEBUG(2, "No plugins.ini file found: %s", PLUGINS_INI);
} }
@ -243,7 +243,7 @@ void metamod_startup()
execFile[sizeof execFile - 1] = '\0'; execFile[sizeof execFile - 1] = '\0';
} }
if (FileExistsInGameDir(execFile)) if (is_file_exists_in_gamedir(execFile))
{ {
if (execFile[0] == '/') if (execFile[0] == '/')
META_ERROR("Cannot exec absolute pathnames: %s", execFile); META_ERROR("Cannot exec absolute pathnames: %s", execFile);
@ -268,7 +268,7 @@ bool meta_init_gamedll()
Q_memset(&g_GameDLL, 0, sizeof g_GameDLL); Q_memset(&g_GameDLL, 0, sizeof g_GameDLL);
GET_GAME_DIR(gamedir); GET_GAME_DIR(gamedir);
NormalizePath(gamedir); normalize_path(gamedir);
// As of 1.1.1.1, the engine routine GET_GAME_DIR no longer returns a // As of 1.1.1.1, the engine routine GET_GAME_DIR no longer returns a
// full-pathname, but rather just the path specified as the argument to // full-pathname, but rather just the path specified as the argument to
@ -280,7 +280,7 @@ bool meta_init_gamedll()
// Note: the code has always assumed the server op wouldn't do: // Note: the code has always assumed the server op wouldn't do:
// hlds -game other/firearms // hlds -game other/firearms
// //
if (IsAbsolutePath(gamedir)) if (is_abs_path(gamedir))
{ {
// Old style; GET_GAME_DIR returned full pathname. Copy this into // Old style; GET_GAME_DIR returned full pathname. Copy this into
// our gamedir, and truncate to get the game name. // our gamedir, and truncate to get the game name.

View File

@ -6,7 +6,6 @@
#include "conf_meta.h" // MConfig #include "conf_meta.h" // MConfig
#include "osdep.h" // NAME_MAX, etc #include "osdep.h" // NAME_MAX, etc
#include "mplayer.h" // MPlayerList #include "mplayer.h" // MPlayerList
#include "meta_eiface.h" // HL_enginefuncs_t, meta_enginefuncs_t
#include "engine_t.h" // engine_t, Engine #include "engine_t.h" // engine_t, Engine
#define PLUGINS_INI "plugins.ini" // file that lists plugins to load at startup #define PLUGINS_INI "plugins.ini" // file that lists plugins to load at startup
@ -32,11 +31,11 @@ struct gamedll_t
extern gamedll_t g_GameDLL; extern gamedll_t g_GameDLL;
// SDK variables for storing engine funcs and globals. // SDK variables for storing engine funcs and globals.
extern HL_enginefuncs_t g_engfuncs; extern enginefuncs_t g_engfuncs;
extern globalvars_t *gpGlobals; extern globalvars_t *gpGlobals;
// Our modified version of the engine funcs, to give to plugins. // Our modified version of the engine funcs, to give to plugins.
extern meta_enginefuncs_t g_plugin_engfuncs; extern enginefuncs_t g_plugin_engfuncs;
// g_config structure. // g_config structure.
extern MConfig *g_config; extern MConfig *g_config;

View File

@ -11,7 +11,7 @@ MPluginList::MPluginList(const char* ifile) : m_max_loaded_count(0)
Q_memset(m_plist, 0, sizeof m_plist); Q_memset(m_plist, 0, sizeof m_plist);
for (int i = 0; i < MAX_PLUGINS; i++) for (int i = 0; i < MAX_PLUGINS; i++)
{ {
m_plist[i].m_index = i + 1; // 1-based new(m_plist + i) MPlugin(i + 1); // 1-based
} }
m_max_loaded_count = 0; m_max_loaded_count = 0;
@ -67,7 +67,6 @@ MPlugin *MPluginList::find(plid_t id)
{ {
if (m_plist[i].m_status < PL_VALID) if (m_plist[i].m_status < PL_VALID)
continue; continue;
if (m_plist[i].m_info == id) if (m_plist[i].m_info == id)
return &m_plist[i]; return &m_plist[i];
} }
@ -131,10 +130,10 @@ MPlugin *MPluginList::find_match(const char *prefix, bool& unique)
if (plug->m_status < PL_VALID) if (plug->m_status < PL_VALID)
continue; continue;
if (plug->m_info && !Q_strnicmp(plug->m_info->name, prefix, len) if (plug->info() && !Q_strnicmp(plug->info()->name, prefix, len)
|| !Q_strnicmp(plug->m_desc, prefix, len) || !Q_strnicmp(plug->m_desc, prefix, len)
|| !Q_strnicmp(plug->m_file, prefix, len) || !Q_strnicmp(plug->m_file, prefix, len)
|| plug->m_info && !Q_strnicmp(plug->m_info->logtag, prefix, len)) || plug->info() && !Q_strnicmp(plug->info()->logtag, prefix, len))
{ {
if (pfound) { if (pfound) {
unique = false; unique = false;
@ -182,7 +181,7 @@ MPlugin* MPluginList::plugin_addload(plid_t plid, const char* fname, PLUG_LOADTI
return nullptr; return nullptr;
} }
if (pl_temp.resolve() != true) { if (!pl_temp.resolve()) {
META_DEBUG(1, "Couldn't resolve given path into a file: %s", pl_temp.m_file); META_DEBUG(1, "Couldn't resolve given path into a file: %s", pl_temp.m_file);
return nullptr; return nullptr;
} }
@ -215,7 +214,6 @@ MPlugin* MPluginList::plugin_addload(plid_t plid, const char* fname, PLUG_LOADTI
return nullptr; return nullptr;
} }
meta_rebuild_callbacks();
META_DEBUG(1, "Loaded plugin '%s' successfully", pl_added->m_desc); META_DEBUG(1, "Loaded plugin '%s' successfully", pl_added->m_desc);
return pl_added; return pl_added;
@ -263,7 +261,7 @@ MPlugin* MPluginList::add(MPlugin* padd)
// copy pathname // copy pathname
Q_strncpy(iplug->m_pathname, padd->m_pathname, sizeof iplug->m_pathname - 1); Q_strncpy(iplug->m_pathname, padd->m_pathname, sizeof iplug->m_pathname - 1);
iplug->m_pathname[sizeof iplug->m_pathname - 1] = '\0'; iplug->m_pathname[sizeof iplug->m_pathname - 1] = '\0';
NormalizePath(iplug->m_pathname); normalize_path(iplug->m_pathname);
iplug->m_source = padd->m_source; iplug->m_source = padd->m_source;
iplug->m_status = padd->m_status; iplug->m_status = padd->m_status;
@ -272,15 +270,13 @@ MPlugin* MPluginList::add(MPlugin* padd)
return iplug; return iplug;
} }
// Read plugins.ini at server startup. // Read plugins.ini at server startup.
bool MPluginList::ini_startup() bool MPluginList::ini_startup()
{ {
char line[MAX_STRBUF_LEN]; char line[MAX_STRBUF_LEN];
int n, ln; int n, ln;
MPlugin *pmatch;
if (!FileExistsInGameDir(m_inifile)) if (!is_file_exists_in_gamedir(m_inifile))
{ {
META_ERROR("ini: Metamod plugins file empty or missing: %s", m_inifile); META_ERROR("ini: Metamod plugins file empty or missing: %s", m_inifile);
return false; return false;
@ -307,9 +303,7 @@ bool MPluginList::ini_startup()
// Parse directly into next entry in array // Parse directly into next entry in array
if (!m_plist[n].ini_parseline(line)) if (!m_plist[n].ini_parseline(line))
{
continue; continue;
}
// Check for a duplicate - an existing entry with this pathname. // Check for a duplicate - an existing entry with this pathname.
if (find(m_plist[n].m_pathname)) if (find(m_plist[n].m_pathname))
@ -321,18 +315,13 @@ bool MPluginList::ini_startup()
// Check for a matching platform with different platform specifics // Check for a matching platform with different platform specifics
// level. // level.
if (nullptr != (pmatch = find_match(&m_plist[n]))) auto pmatch = find_match(&m_plist[n]);
if (pmatch)
{ {
if (pmatch->m_pfspecific >= m_plist[n].m_pfspecific) META_DEBUG(1, "ini: Plugin in line %d overrides existing plugin", ln);
{ int index = pmatch->m_index;
META_DEBUG(1, "ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, m_inifile, pmatch->m_pfspecific, m_plist[n].m_pfspecific);
continue;
}
META_DEBUG(1, "ini: Plugin in line %d overrides existing plugin with lower platform specific level %d, ours %d", ln, pmatch->m_pfspecific, m_plist[n].m_pfspecific);
int _index = pmatch->m_index;
Q_memset(pmatch, 0, sizeof(MPlugin)); Q_memset(pmatch, 0, sizeof(MPlugin));
pmatch->m_index = _index; pmatch->m_index = index;
} }
m_plist[n].m_action = PA_LOAD; m_plist[n].m_action = PA_LOAD;
META_LOG("ini: Read plugin config for: %s", m_plist[n].m_desc); META_LOG("ini: Read plugin config for: %s", m_plist[n].m_desc);
@ -340,12 +329,10 @@ bool MPluginList::ini_startup()
m_max_loaded_count = n; // mark end of list m_max_loaded_count = n; // mark end of list
} }
META_LOG("ini: Finished reading plugins list: %s; Found %d plugins to load", m_inifile, n); META_LOG("ini: Finished reading plugins list: %s; Found %d plugins to load", m_inifile, n);
fclose(fp); fclose(fp);
if (!n) if (!n)
{ META_LOG("ini: Warning; no plugins found to load?");
META_ERROR("ini: Warning; no plugins found to load?");
}
return true; return true;
} }
@ -355,8 +342,6 @@ bool MPluginList::ini_refresh()
{ {
char line[MAX_STRBUF_LEN]; char line[MAX_STRBUF_LEN];
int n, ln; int n, ln;
MPlugin pl_temp;
MPlugin *pl_found, *pl_added;
FILE* fp = fopen(m_inifile, "r"); FILE* fp = fopen(m_inifile, "r");
if (!fp) if (!fp)
@ -377,7 +362,7 @@ bool MPluginList::ini_refresh()
*cp = '\0'; *cp = '\0';
// Parse into a temp plugin // Parse into a temp plugin
Q_memset(&pl_temp, 0, sizeof pl_temp); MPlugin pl_temp = {};
if (!pl_temp.ini_parseline(line)) if (!pl_temp.ini_parseline(line))
{ {
META_ERROR("ini: Skipping malformed line %d of %s",ln, m_inifile); META_ERROR("ini: Skipping malformed line %d of %s",ln, m_inifile);
@ -385,32 +370,30 @@ bool MPluginList::ini_refresh()
} }
// Try to find plugin with this pathname in the current list of // Try to find plugin with this pathname in the current list of
// plugins. // plugins.
if (!(pl_found = find(pl_temp.m_pathname))) auto pl_found = find(pl_temp.m_pathname);
if (!pl_found)
{ {
// Check for a matching platform with higher platform specifics // Check for a matching platform with higher platform specifics
// level. // level.
if (nullptr != (pl_found = find_match(&pl_temp))) pl_found = find_match(&pl_temp);
if (pl_found)
{ {
if (pl_found->m_pfspecific >= pl_temp.m_pfspecific) if (pl_found->m_action == PA_LOAD)
{ {
META_DEBUG(1, "ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, m_inifile, pl_found->m_pfspecific, pl_temp.m_pfspecific); META_DEBUG(1, "ini: Plugin in line %d overrides loading of plugin", ln);
continue;
}
if (PA_LOAD == pl_found->m_action)
{
META_DEBUG(1, "ini: Plugin in line %d overrides loading of plugin with lower platform specific level %d, ours %d", ln, pl_found->m_pfspecific, pl_temp.m_pfspecific);
int _index = pl_found->m_index; int _index = pl_found->m_index;
Q_memset(pl_found, 0, sizeof(MPlugin)); Q_memset(pl_found, 0, sizeof(MPlugin));
pl_found->m_index = _index; pl_found->m_index = _index;
} }
else else
{ {
META_DEBUG(1, "ini: Plugin in line %d should override existing plugin with lower platform specific level %d, ours %d. Unable to comply.", ln, pl_found->m_pfspecific, pl_temp.m_pfspecific); META_DEBUG(1, "ini: Plugin in line %d should override existing plugin. Unable to comply.", ln);
continue; continue;
} }
} }
// new plugin; add to list // new plugin; add to list
if ((pl_added = add(&pl_temp))) auto pl_added = add(&pl_temp);
if (pl_added)
{ {
// try to load this plugin at the next opportunity // try to load this plugin at the next opportunity
pl_added->m_action = PA_LOAD; pl_added->m_action = PA_LOAD;
@ -447,22 +430,17 @@ bool MPluginList::ini_refresh()
} }
if (pl_found) if (pl_found)
{
META_LOG("ini: Read plugin config for: %s", pl_found->m_desc); META_LOG("ini: Read plugin config for: %s", pl_found->m_desc);
}
else else
{
META_LOG("ini: Read plugin config for: %s", pl_temp.m_desc); META_LOG("ini: Read plugin config for: %s", pl_temp.m_desc);
}
n++; n++;
} }
META_LOG("ini: Finished reading plugins list: %s; Found %d plugins", m_inifile, n); META_LOG("ini: Finished reading plugins list: %s; Found %d plugins", m_inifile, n);
fclose(fp); fclose(fp);
if (!n) if (!n)
{
META_ERROR("ini: Warning; no plugins found to load?"); META_ERROR("ini: Warning; no plugins found to load?");
}
return true; return true;
} }
@ -471,9 +449,7 @@ bool MPluginList::ini_refresh()
bool MPluginList::cmd_addload(const char* args) bool MPluginList::cmd_addload(const char* args)
{ {
MPlugin pl_temp = {}; MPlugin pl_temp = {};
MPlugin *pl_found, *pl_added; if (!pl_temp.cmd_parseline(args))
if (pl_temp.cmd_parseline(args) != true)
{ {
META_CONS("Couldn't parse 'meta load' arguments: %s", args); META_CONS("Couldn't parse 'meta load' arguments: %s", args);
return false; return false;
@ -481,7 +457,7 @@ bool MPluginList::cmd_addload(const char* args)
// resolve given path into a file; accepts various "shortcut" // resolve given path into a file; accepts various "shortcut"
// pathnames. // pathnames.
if (pl_temp.resolve() != true) if (!pl_temp.resolve())
{ {
// Couldn't find a matching file on disk // Couldn't find a matching file on disk
META_CONS("Couldn't resolve given path into a file: %s", pl_temp.m_file); META_CONS("Couldn't resolve given path into a file: %s", pl_temp.m_file);
@ -490,14 +466,16 @@ bool MPluginList::cmd_addload(const char* args)
// Try to find plugin with this pathname in the current list of // Try to find plugin with this pathname in the current list of
// plugins. // plugins.
if ((pl_found = find(pl_temp.m_pathname))) auto pl_found = find(pl_temp.m_pathname);
if (pl_found)
{ {
// Already in list // Already in list
META_CONS("Plugin '%s' already in current list; file=%s desc='%s'", pl_temp.m_file, pl_found->m_file, pl_found->m_desc); META_CONS("Plugin '%s' already in current list; file=%s desc='%s'", pl_temp.m_file, pl_found->m_file, pl_found->m_desc);
return false; return false;
} }
// new plugin; add to list // new plugin; add to list
if (!(pl_added = add(&pl_temp))) auto pl_added = add(&pl_temp);
if (!pl_added)
{ {
META_CONS("Couldn't add plugin '%s' to list; see log", pl_temp.m_desc); META_CONS("Couldn't add plugin '%s' to list; see log", pl_temp.m_desc);
return false; return false;
@ -513,14 +491,13 @@ bool MPluginList::cmd_addload(const char* args)
else else
META_CONS("Couldn't load plugin '%s'; see log", pl_added->m_desc); META_CONS("Couldn't load plugin '%s'; see log", pl_added->m_desc);
show(0); show();
return false; return false;
} }
META_CONS("Loaded plugin '%s' successfully", pl_added->m_desc); META_CONS("Loaded plugin '%s' successfully", pl_added->m_desc);
show();
meta_rebuild_callbacks(); meta_rebuild_callbacks();
show(0);
return true; return true;
} }
@ -540,16 +517,15 @@ bool MPluginList::load()
if (m_plist[i].m_status < PL_VALID) if (m_plist[i].m_status < PL_VALID)
continue; continue;
if (m_plist[i].load(PT_STARTUP) == true) if (m_plist[i].load(PT_STARTUP))
n++; n++;
else else
// all plugins should be loadable at startup... // all plugins should be loadable at startup...
META_ERROR("dll: Failed to load plugin '%s'", m_plist[i].m_file); META_ERROR("dll: Failed to load plugin '%s'", m_plist[i].m_file);
} }
meta_rebuild_callbacks();
META_LOG("dll: Finished loading %d plugins", n); META_LOG("dll: Finished loading %d plugins", n);
meta_rebuild_callbacks();
return true; return true;
} }
@ -598,7 +574,7 @@ bool MPluginList::refresh(PLUG_LOADTIME now)
{ {
META_DEBUG(1, "Unloading plugin '%s'", iplug->m_desc); META_DEBUG(1, "Unloading plugin '%s'", iplug->m_desc);
iplug->m_action = PA_UNLOAD; iplug->m_action = PA_UNLOAD;
if (iplug->unload(now, PNL_INI_DELETED, PNL_INI_DELETED)) if (iplug->unload(now, PNL_INI_DELETED))
nunloaded++; nunloaded++;
/*else if (meta_errno == ME_DELAYED) TODO /*else if (meta_errno == ME_DELAYED) TODO
ndelayed++;*/ ndelayed++;*/
@ -630,9 +606,8 @@ bool MPluginList::refresh(PLUG_LOADTIME now)
ndone++; ndone++;
} }
meta_rebuild_callbacks();
META_LOG("dll: Finished updating %d plugins; kept %d, loaded %d, unloaded %d, reloaded %d, delayed %d", ndone, nkept, nloaded, nunloaded, nreloaded, ndelayed); META_LOG("dll: Finished updating %d plugins; kept %d, loaded %d, unloaded %d, reloaded %d, delayed %d", ndone, nkept, nloaded, nunloaded, nreloaded, ndelayed);
meta_rebuild_callbacks();
return true; return true;
} }
@ -688,9 +663,9 @@ void MPluginList::show(int source_index)
Q_strncpy(file, pl->m_file, sizeof file - 1); Q_strncpy(file, pl->m_file, sizeof file - 1);
file[sizeof file - 1] = '\0'; file[sizeof file - 1] = '\0';
if (pl->m_info && pl->m_info->version) if (pl->info() && pl->info()->version)
{ {
Q_strncpy(vers, pl->m_info->version, sizeof vers - 1); Q_strncpy(vers, pl->info()->version, sizeof vers - 1);
vers[sizeof vers - 1] = '\0'; vers[sizeof vers - 1] = '\0';
} }
else else
@ -724,16 +699,16 @@ void MPluginList::show_client(edict_t *pEntity)
for (int i = 0; i < m_max_loaded_count; i++) for (int i = 0; i < m_max_loaded_count; i++)
{ {
auto pl = &m_plist[i]; auto pl = &m_plist[i];
if (pl->m_status != PL_RUNNING || !pl->m_info) if (pl->m_status != PL_RUNNING || !pl->info())
continue; continue;
n++; n++;
META_CLIENT(pEntity, " [%3d] %s, v%s, %s, by %s, see %s", n, META_CLIENT(pEntity, " [%3d] %s, v%s, %s, by %s, see %s", n,
pl->m_info->name ? pl->m_info->name : "<unknown>", pl->info()->name ? pl->info()->name : "<unknown>",
pl->m_info->version ? pl->m_info->version : "<?>", pl->info()->version ? pl->info()->version : "<?>",
pl->m_info->date ? pl->m_info->date : "<../../..>", pl->info()->date ? pl->info()->date : "<../../..>",
pl->m_info->author ? pl->m_info->author : "<unknown>", pl->info()->author ? pl->info()->author : "<unknown>",
pl->m_info->url ? pl->m_info->url : "<unknown>"); pl->info()->url ? pl->info()->url : "<unknown>");
} }
META_CLIENT(pEntity, "%d plugins", n); META_CLIENT(pEntity, "%d plugins", n);

View File

@ -12,7 +12,8 @@
#define WIDTH_MAX_PLUGINS 2 #define WIDTH_MAX_PLUGINS 2
// A list of plugins. // A list of plugins.
class MPluginList { class MPluginList
{
public: public:
MPluginList(const char *ifile); MPluginList(const char *ifile);

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,12 @@
#pragma once #pragma once
#include "api_info.h" #include "utils.h"
#include "support_meta.h"
// Flags to indicate current "load" state of plugin. // Flags to indicate current "load" state of plugin.
// NOTE: order is important, as greater/less comparisons are made. // NOTE: order is important, as greater/less comparisons are made.
enum PLUG_STATUS : uint8 enum PLUG_STATUS : uint8
{ {
PL_EMPTY = 0, // empty slot PL_EMPTY, // empty slot
PL_VALID, // has valid info in it PL_VALID, // has valid info in it
PL_BADFILE, // nonexistent file (open failed), or not a valid plugin file (query failed) PL_BADFILE, // nonexistent file (open failed), or not a valid plugin file (query failed)
PL_OPENED, // dlopened and queried PL_OPENED, // dlopened and queried
@ -19,7 +18,7 @@ enum PLUG_STATUS : uint8
// Action to take for plugin at next opportunity. // Action to take for plugin at next opportunity.
enum PLUG_ACTION : uint8 enum PLUG_ACTION : uint8
{ {
PA_NULL = 0, PA_NULL,
PA_NONE, // no action needed right now PA_NONE, // no action needed right now
PA_KEEP, // keep, after ini refresh PA_KEEP, // keep, after ini refresh
PA_LOAD, // load (dlopen, query) and try to attach PA_LOAD, // load (dlopen, query) and try to attach
@ -31,7 +30,7 @@ enum PLUG_ACTION : uint8
// Flags to indicate from where the plugin was loaded. // Flags to indicate from where the plugin was loaded.
enum PLOAD_SOURCE : uint8 enum PLOAD_SOURCE : uint8
{ {
PS_INI = 0, // was loaded from the plugins.ini PS_INI, // was loaded from the plugins.ini
PS_CMD, // was loaded via a server command PS_CMD, // was loaded via a server command
PS_PLUGIN, // was loaded by other plugin PS_PLUGIN, // was loaded by other plugin
}; };
@ -48,68 +47,50 @@ enum STR_LOADTIME : uint8
// Flags for how to format description of status. // Flags for how to format description of status.
enum STR_STATUS : uint8 enum STR_STATUS : uint8
{ {
ST_SIMPLE = 0, // single word ST_SIMPLE, // single word
ST_SHOW, // for "show" output, 4 chars ST_SHOW, // for "show" output, 4 chars
}; };
// Flags for how to format description of action. // Flags for how to format description of action.
enum STR_ACTION : uint8 enum STR_ACTION : uint8
{ {
SA_SIMPLE = 0, // single word SA_SIMPLE, // single word
SA_SHOW, // for "show" output, 4 chars SA_SHOW, // for "show" output, 4 chars
}; };
// Flags for how to format description of source. // Flags for how to format description of source.
enum STR_SOURCE : uint8 enum STR_SOURCE : uint8
{ {
SO_SIMPLE = 0, // two words SO_SIMPLE, // two words
SO_SHOW, // for "list" output, 3 chars SO_SHOW, // for "list" output, 3 chars
}; };
enum STR_PLATFORM : uint8
{
SP_WINDOWS,
SP_LINUX
};
// An individual plugin. // An individual plugin.
class MPlugin { class MPlugin
{
public: public:
PLUG_STATUS m_status; // current status of plugin (loaded, etc) MPlugin();
PLUG_ACTION m_action; // what to do with plugin (load, unload, etc) MPlugin(int index);
PLOAD_SOURCE m_source; // source of the request to load the plugin
int m_index; // 1-based
plugin_info_t *m_info; // information plugin provides about itself
CSysModule m_sys_module;
time_t m_time_loaded; // when plugin was loaded
int m_source_plugin_index; // who loaded this plugin
int m_unloader_index;
bool m_is_unloader; // fix to prevent other plugins unload active unloader.
DLL_FUNCTIONS *m_dllapi_table; bool ini_parseline(char *line); // parse line from .ini file
DLL_FUNCTIONS *m_dllapi_post_table;
NEW_DLL_FUNCTIONS *m_newapi_table;
NEW_DLL_FUNCTIONS *m_newapi_post_table;
enginefuncs_t *m_engine_table;
enginefuncs_t *m_engine_post_table;
gamedll_funcs_t m_gamedll_funcs;
mutil_funcs_t m_mutil_funcs;
char m_filename[PATH_MAX]; // ie "dlls/mm_test_i386.so", from inifile
char *m_file; // ie "mm_test_i386.so", ptr from filename
char m_desc[MAX_DESC_LEN]; // ie "Test metamod plugin", from inifile
char m_pathname[PATH_MAX]; // UNIQUE, ie "/home/willday/half-life/cstrike/dlls/mm_test_i386.so", built with GameDLL.gamedir
int m_pfspecific; // level of specific platform affinity, used during load time
bool ini_parseline(char *line); // parse line from inifile
bool cmd_parseline(const char *line); // parse from console command bool cmd_parseline(const char *line); // parse from console command
bool plugin_parseline(const char *fname, int loader_index); // parse from plugin bool plugin_parseline(const char *fname, int loader_index); // parse from plugin
bool check_input(); bool check_input(); // check filename, path, status
bool resolve(); // find a matching file on disk bool resolve(); // find a matching file on disk
char *resolve_dirs(char *path) const; char *resolve_dirs(const char *path, char *tempbuf, size_t bufsize) const; // try resolve filename in different dirs
char *resolve_prefix(char *path) const; char *resolve_suffix(const char *path, char *tempbuf, size_t bufsize) const; // try resolve given filename with different suffixes
char *resolve_suffix(char *path) const;
bool platform_match(MPlugin* plugin) const; bool platform_match(MPlugin* plugin) const; // check if a given plugin is the same but possibly for a different platform
bool load(PLUG_LOADTIME now); bool load(PLUG_LOADTIME now); // load parsed plugin
bool unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL_UNLOAD_REASON real_reason); bool unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason);
bool reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason); bool reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason);
bool pause(); bool pause();
bool unpause(); bool unpause();
@ -120,36 +101,66 @@ public:
bool newer_file() const; // check for newer file on disk bool newer_file() const; // check for newer file on disk
const char *str_status(STR_STATUS fmt) const; const char *str_status(STR_STATUS fmt = ST_SIMPLE) const;
const char *str_action(STR_ACTION fmt) const; const char *str_action(STR_ACTION fmt = SA_SIMPLE) const;
const char *str_source(STR_SOURCE fmt) const; const char *str_source(STR_SOURCE fmt = SO_SIMPLE) const;
const char *str_reason(PL_UNLOAD_REASON reason) const;
const char *str_reason(PL_UNLOAD_REASON preason, PL_UNLOAD_REASON preal_reason) const;
static const char *str_loadtime(PLUG_LOADTIME pallow, STR_LOADTIME fmt); static const char *str_loadtime(PLUG_LOADTIME pallow, STR_LOADTIME fmt);
const char *str_status() { return str_status(ST_SIMPLE); }; const char* str_loadable() const;
const char *str_action() { return str_action(SA_SIMPLE); }; const char* str_unloadable() const;
const char *str_source() { return str_source(SO_SIMPLE); }; const char* str_loadable(STR_LOADTIME fmt) const;
const char* str_unloadable(STR_LOADTIME fmt) const;
const char *str_loadable() { PLUG_STATUS status() const;
if (m_info) return str_loadtime(m_info->loadable, SL_SIMPLE); PLUG_ACTION action() const;
else return " -"; const char* description() const;
}; plugin_info_t* info() const;
const char *str_unloadable() { int index() const;
if (m_info) return str_loadtime(m_info->unloadable, SL_SIMPLE); int source_index() const;
else return " -"; const char* file() const;
}; const char* filename() const;
const char *str_loadable(STR_LOADTIME fmt) { const char* pathname() const;
if (m_info) return str_loadtime(m_info->loadable, fmt); const CSysModule& sys_module() const;
else return " -"; size_t status_ptr();
}; void set_action(PLUG_ACTION action);
const char *str_unloadable(STR_LOADTIME fmt) {
if (m_info) return str_loadtime(m_info->unloadable, fmt);
else return " -";
};
private: private:
bool query(); bool query(); // check exports, call init, getfnptrs and query
bool attach(PLUG_LOADTIME now); bool attach(PLUG_LOADTIME now); // call attach
bool detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason); bool detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason); // call detach
PLUG_STATUS m_status; // current status of plugin (loaded, etc)
PLUG_ACTION m_action; // what to do with plugin (load, unload, etc)
PLOAD_SOURCE m_source; // source of the request to load the plugin
STR_PLATFORM m_platform; // plugin platform
int m_index; // 1-based
plugin_info_t *m_info; // information plugin provides about itself
CSysModule m_sys_module; // system module
time_t m_time_loaded; // when plugin was loaded
int m_source_plugin_index; // who loaded this plugin
int m_unloader_index; // index of unloader plugin
bool m_is_unloader; // fix to prevent other plugins unload active unloader.
public:
// pointers to tables inside plugins
DLL_FUNCTIONS *m_dllapi_table;
DLL_FUNCTIONS *m_dllapi_post_table;
NEW_DLL_FUNCTIONS *m_newapi_table;
NEW_DLL_FUNCTIONS *m_newapi_post_table;
enginefuncs_t *m_engine_table;
enginefuncs_t *m_engine_post_table;
private:
gamedll_funcs_t m_gamedll_funcs;
mutil_funcs_t m_mutil_funcs;
char m_filename[PATH_MAX]; // ie "dlls/mm_test_i386.so", from inifile
char *m_file; // ie "mm_test_i386.so", ptr from filename
char m_desc[MAX_DESC_LEN]; // ie "Test metamod plugin", from inifile
char m_pathname[PATH_MAX]; // UNIQUE, ie "/home/willday/half-life/cstrike/dlls/mm_test_i386.so", built with GameDLL.gamedir
static const char *s_rPrintLoadTime[][4];
friend class MPluginList;
}; };

View File

@ -1,6 +1,6 @@
#include "precompiled.h" #include "precompiled.h"
MRegCmd::MRegCmd(char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin) : m_pfunction(cmd_handler), m_plugid(cmd_plugin->m_index), m_status(RG_VALID) MRegCmd::MRegCmd(char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin) : m_pfunction(cmd_handler), m_plugid(cmd_plugin->index()), m_status(RG_VALID)
{ {
m_name = Q_strdup(cmd_name); m_name = Q_strdup(cmd_name);
} }
@ -112,7 +112,7 @@ void MRegCmdList::show() const
{ {
auto iplug = g_plugins->find(reg->m_plugid); auto iplug = g_plugins->find(reg->m_plugid);
Q_strncpy(bplug, iplug ? iplug->m_desc : "(unknown)", sizeof bplug - 1); Q_strncpy(bplug, iplug ? iplug->description() : "(unknown)", sizeof bplug - 1);
bplug[sizeof bplug - 1] = '\0'; bplug[sizeof bplug - 1] = '\0';
} }
else else
@ -149,7 +149,7 @@ void MRegCmdList::show(int plugin_id) const
META_CONS("%d commands", total_count); META_CONS("%d commands", total_count);
} }
MRegCvar::MRegCvar(cvar_t* cv_ptr, MPlugin* cv_plugin) : m_cvar(cv_ptr), m_plugid(cv_plugin ? cv_plugin->m_index : 0), m_status(RG_VALID) MRegCvar::MRegCvar(cvar_t* cv_ptr, MPlugin* cv_plugin) : m_cvar(cv_ptr), m_plugid(cv_plugin ? cv_plugin->index() : 0), m_status(RG_VALID)
{ {
m_cvar = new cvar_t; m_cvar = new cvar_t;
m_cvar->name = Q_strdup(cv_ptr->name); m_cvar->name = Q_strdup(cv_ptr->name);
@ -228,7 +228,7 @@ void MRegCvarList::show() const
if (reg->m_status == RG_VALID) if (reg->m_status == RG_VALID)
{ {
auto plug = g_plugins->find(reg->m_plugid); auto plug = g_plugins->find(reg->m_plugid);
Q_strncpy(bplug, plug ? plug->m_desc : "(unknown)", sizeof bplug - 1); Q_strncpy(bplug, plug ? plug->description() : "(unknown)", sizeof bplug - 1);
bplug[sizeof bplug - 1] = '\0'; bplug[sizeof bplug - 1] = '\0';
} }
else else

View File

@ -252,7 +252,7 @@ const char* EXT_FUNC mutil_GetPluginPath(plid_t plid)
return nullptr; return nullptr;
} }
Q_strncpy(buf, plug->m_pathname, sizeof buf - 1); Q_strncpy(buf, plug->pathname(), sizeof buf - 1);
buf[sizeof buf - 1] = '\0'; buf[sizeof buf - 1] = '\0';
return buf; return buf;
} }
@ -301,7 +301,6 @@ int EXT_FUNC mutil_LoadMetaPlugin(plid_t plid, const char* fname, PLUG_LOADTIME
} }
auto pl_loaded = g_plugins->plugin_addload(plid, fname, now); auto pl_loaded = g_plugins->plugin_addload(plid, fname, now);
if (!pl_loaded) if (!pl_loaded)
{ {
if (plugin_handle) if (plugin_handle)
@ -309,14 +308,14 @@ int EXT_FUNC mutil_LoadMetaPlugin(plid_t plid, const char* fname, PLUG_LOADTIME
return 1; // TODO: WTF return 1; // TODO: WTF
} }
else
{ meta_rebuild_callbacks();
if (plugin_handle) if (plugin_handle)
*plugin_handle = (void *)pl_loaded->m_sys_module.gethandle(); *plugin_handle = (void *)pl_loaded->sys_module().gethandle();
return 0; return 0;
} }
}
int EXT_FUNC mutil_UnloadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIME now, PL_UNLOAD_REASON reason) int EXT_FUNC mutil_UnloadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
{ {
@ -339,8 +338,10 @@ int EXT_FUNC mutil_UnloadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIM
if (!findp || !unique) if (!findp || !unique)
return 1; return 1;
if (findp->plugin_unload(plid, now, reason)) if (findp->plugin_unload(plid, now, reason)) {
meta_rebuild_callbacks();
return 0; return 0;
}
return 1; return 1;
} }
@ -357,8 +358,10 @@ int EXT_FUNC mutil_UnloadMetaPluginByHandle(plid_t plid, void *plugin_handle, PL
if (!findp) if (!findp)
return 1; return 1;
if (findp->plugin_unload(plid, now, reason)) if (findp->plugin_unload(plid, now, reason)) {
meta_rebuild_callbacks();
return 0; return 0;
}
return 1; return 1;
} }

View File

@ -7,6 +7,7 @@ CSysModule::CSysModule() : m_handle(0), m_base(0), m_size(0)
#ifdef _WIN32 #ifdef _WIN32
module_handle_t CSysModule::load(const char* filepath) module_handle_t CSysModule::load(const char* filepath)
{ {
if (!m_handle) {
m_handle = LoadLibrary(filepath); m_handle = LoadLibrary(filepath);
MODULEINFO module_info; MODULEINFO module_info;
@ -14,13 +15,14 @@ module_handle_t CSysModule::load(const char* filepath)
m_base = (uintptr_t)module_info.lpBaseOfDll; m_base = (uintptr_t)module_info.lpBaseOfDll;
m_size = module_info.SizeOfImage; m_size = module_info.SizeOfImage;
} }
}
return m_handle; return m_handle;
} }
bool CSysModule::unload() bool CSysModule::unload()
{ {
bool ret = false; bool ret = true;
if (m_handle) { if (m_handle) {
ret = FreeLibrary(m_handle) != ERROR; ret = FreeLibrary(m_handle) != ERROR;
@ -34,7 +36,7 @@ bool CSysModule::unload()
void* CSysModule::getsym(const char* name) const void* CSysModule::getsym(const char* name) const
{ {
return GetProcAddress(m_handle, name); return m_handle ? GetProcAddress(m_handle, name) : nullptr;
} }
#else #else
static ElfW(Addr) dlsize(void* base) static ElfW(Addr) dlsize(void* base)
@ -59,6 +61,7 @@ static ElfW(Addr) dlsize(void* base)
module_handle_t CSysModule::load(const char* filepath) module_handle_t CSysModule::load(const char* filepath)
{ {
if (!m_handle) {
m_handle = dlopen(filepath, RTLD_NOW); m_handle = dlopen(filepath, RTLD_NOW);
char buf[1024], dummy[1024], path[260]; char buf[1024], dummy[1024], path[260];
@ -82,12 +85,14 @@ module_handle_t CSysModule::load(const char* filepath)
} }
fclose(fp); fclose(fp);
}
return m_handle; return m_handle;
} }
bool CSysModule::unload() bool CSysModule::unload()
{ {
bool ret = false; bool ret = true;
if (m_handle) { if (m_handle) {
ret = dlclose(m_handle) != 0; ret = dlclose(m_handle) != 0;
@ -101,7 +106,7 @@ bool CSysModule::unload()
void* CSysModule::getsym(const char* name) const void* CSysModule::getsym(const char* name) const
{ {
return dlsym(m_handle, name); return m_handle ? dlsym(m_handle, name) : nullptr;
} }
#endif #endif
@ -130,7 +135,7 @@ const char* CSysModule::getloaderror()
// http://msdn.microsoft.com/library/en-us/debug/errors_0sdh.asp // http://msdn.microsoft.com/library/en-us/debug/errors_0sdh.asp
// except without FORMAT_MESSAGE_ALLOCATE_BUFFER, since we use a local // except without FORMAT_MESSAGE_ALLOCATE_BUFFER, since we use a local
// static buffer. // static buffer.
const char *str_GetLastError() static const char *str_GetLastError()
{ {
static char buf[MAX_STRBUF_LEN]; static char buf[MAX_STRBUF_LEN];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, MAX_STRBUF_LEN - 1, nullptr); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, MAX_STRBUF_LEN - 1, nullptr);

View File

@ -4,7 +4,7 @@
// NOTE: order is crucial, as greater/less comparisons are made. // NOTE: order is crucial, as greater/less comparisons are made.
enum PLUG_LOADTIME enum PLUG_LOADTIME
{ {
PT_NEVER = 0, PT_NEVER,
PT_STARTUP, // should only be loaded/unloaded at initial hlds execution PT_STARTUP, // should only be loaded/unloaded at initial hlds execution
PT_CHANGELEVEL, // can be loaded/unloaded between maps PT_CHANGELEVEL, // can be loaded/unloaded between maps
PT_ANYTIME, // can be loaded/unloaded at any time PT_ANYTIME, // can be loaded/unloaded at any time
@ -14,7 +14,7 @@ enum PLUG_LOADTIME
// Flags to indicate why the plugin is being unloaded. // Flags to indicate why the plugin is being unloaded.
enum PL_UNLOAD_REASON enum PL_UNLOAD_REASON
{ {
PNL_NULL = 0, PNL_NULL,
PNL_INI_DELETED, // was deleted from plugins.ini PNL_INI_DELETED, // was deleted from plugins.ini
PNL_FILE_NEWER, // file on disk is newer than last load PNL_FILE_NEWER, // file on disk is newer than last load
PNL_COMMAND, // requested by server/console command PNL_COMMAND, // requested by server/console command

View File

@ -31,11 +31,9 @@
#include "metamod.h" #include "metamod.h"
#include "log_meta.h" #include "log_meta.h"
#include "conf_meta.h" #include "conf_meta.h"
#include "support_meta.h"
#include "dllapi.h" #include "dllapi.h"
#include "engine_api.h" #include "engine_api.h"
#include "game_support.h" #include "game_support.h"
#include "meta_eiface.h"
#include "mreg.h" #include "mreg.h"
#include "meta_api.h" #include "meta_api.h"
#include "mutil.h" #include "mutil.h"

View File

@ -30,7 +30,7 @@ void EXT_FUNC meta_AddServerCommand(char *cmd_name, void (*function)())
{ {
MPlugin *plug = g_plugins->find_memloc(function); MPlugin *plug = g_plugins->find_memloc(function);
META_DEBUG(4, "called: meta_AddServerCommand; cmd_name=%s, function=%d, plugin=%s", cmd_name, function, plug ? plug->m_file : "unknown"); META_DEBUG(4, "called: meta_AddServerCommand; cmd_name=%s, function=%d, plugin=%s", cmd_name, function, plug ? plug->file() : "unknown");
if (!plug) { if (!plug) {
META_ERROR("Failed to find memloc for regcmd '%s'", cmd_name); META_ERROR("Failed to find memloc for regcmd '%s'", cmd_name);

View File

@ -1,6 +1,6 @@
#include "precompiled.h" #include "precompiled.h"
char *UTIL_VarArgs(char *format, ...) char *UTIL_VarArgs(const char *format, ...)
{ {
va_list argptr; va_list argptr;
static char string[1024]; static char string[1024];

View File

@ -13,4 +13,5 @@
#include "enginecallbacks.h" #include "enginecallbacks.h"
#include <util.h> #include <util.h>
char *UTIL_VarArgs(const char *format, ...);
void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage); void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage);

View File

@ -1,91 +0,0 @@
#include "precompiled.h"
void __declspec(noreturn) do_exit(int exitval)
{
//Allahu Akbar!!
*((int *)nullptr) = 0;
}
// Checks for a non-empty file, relative to the gamedir if necessary.
// Formerly used LOAD_FILE_FOR_ME, which provided a simple way to check for
// a file under the gamedir, but which would _also_ look in the sibling
// "valve" directory, thus sometimes finding files that weren't desired.
// Also, formerly named just "valid_file".
//
// Special-case-recognize "/dev/null" as a valid file.
bool FileExistsInGameDir(const char *path)
{
struct stat st;
char buf[PATH_MAX];
if (!path)
return false;
if (!Q_strcmp(path, "/dev/null"))
return true;
if (IsAbsolutePath(path))
{
Q_strncpy(buf, path, sizeof buf);
buf[sizeof buf - 1] = '\0';
}
else
snprintf(buf, sizeof buf, "%s/%s", g_GameDLL.gamedir, path);
int ret = stat(buf, &st);
if (ret != 0)
{
META_DEBUG(5, "Unable to stat '%s': %s", buf, strerror(errno));
return false;
}
int reg = S_ISREG(st.st_mode);
if (!reg)
{
META_DEBUG(5, "Not a regular file: %s", buf);
return false;
}
if (!st.st_size)
{
META_DEBUG(5, "Empty file: %s", buf);
return false;
}
if (ret == 0 && reg)
return true;
return false;
}
// Turns path into a full path:
// - if not absolute, prepends gamedir
// - calls realpath() to collapse ".." and such
// - calls NormalizePath() to fix backslashes, etc
//
// Much like realpath, buffer pointed to by fullpath is assumed to be
// able to store a string of PATH_MAX length.
char* full_gamedir_path(const char* path, char* fullpath)
{
char buf[PATH_MAX];
// Build pathname from filename, plus gamedir if relative path.
if (IsAbsolutePath(path))
{
Q_strncpy(buf, path, sizeof buf - 1);
buf[sizeof buf - 1] = '\0';
}
else snprintf(buf, sizeof buf, "%s/%s", g_GameDLL.gamedir, path);
// Remove relative path components, if possible.
if (!realpath(buf, fullpath))
{
META_DEBUG(4, "Unable to get realpath for '%s': %s", buf, str_os_error());
Q_strncpy(fullpath, path, sizeof fullpath - 1);
fullpath[sizeof fullpath - 1] = '\0';
}
// Replace backslashes, etc.
NormalizePath(fullpath);
return fullpath;
}

View File

@ -1,23 +0,0 @@
#pragma once
#include <sys/types.h> // stat
#include <sys/stat.h> // stat
#include "osdep.h" // _stricmp, S_ISREG,
void __declspec(noreturn) do_exit(int exitval);
bool FileExistsInGameDir(const char *path);
char *full_gamedir_path(const char *path, char *fullpath);
// Turn a variable/function name into the corresponding string, optionally
// stripping off the leading "len" characters. Useful for things like
// turning 'pfnClientCommand' into "ClientCommand" so we don't have to
// specify strings used for all the debugging/log messages.
#define STRINGIZE(name, len) #name+len
// Max description length for plugins.ini and other places.
#define MAX_DESC_LEN 256
// For various character string buffers.
#define MAX_STRBUF_LEN 1024

View File

@ -1,5 +1,13 @@
#include "precompiled.h" #include "precompiled.h"
const char* g_platform_postfixes[4] =
{
"_i386.so",
"_i486.so",
"_i586.so",
"_i686.so",
};
bool is_yes(const char* str) bool is_yes(const char* str)
{ {
return !Q_strcmp(str, "true") || !Q_strcmp(str, "yes") || !Q_strcmp(str, "1"); return !Q_strcmp(str, "true") || !Q_strcmp(str, "yes") || !Q_strcmp(str, "1");
@ -119,7 +127,7 @@ char *trimbuf(char *str)
return str; return str;
} }
void NormalizePath(char *path) void normalize_path(char *path)
{ {
#ifdef _WIN32 #ifdef _WIN32
for (char* cp = path; *cp; cp++) for (char* cp = path; *cp; cp++)
@ -133,7 +141,7 @@ void NormalizePath(char *path)
#endif #endif
} }
bool IsAbsolutePath(const char *path) bool is_abs_path(const char *path)
{ {
if (path[0] == '/') return true; if (path[0] == '/') return true;
#ifdef _WIN32 #ifdef _WIN32
@ -143,6 +151,23 @@ bool IsAbsolutePath(const char *path)
return false; return false;
} }
bool is_valid_path(const char *path)
{
struct stat st;
return !stat(path, &st) && S_ISREG(st.st_mode);
}
bool is_platform_postfix(const char* pf)
{
if (pf) {
for (size_t i = 0; i < arraysize(g_platform_postfixes); i++) {
if (!Q_strcmp(pf, g_platform_postfixes[i]))
return true;
}
}
return false;
}
#ifdef _WIN32 #ifdef _WIN32
char *realpath(const char *file_name, char *resolved_name) char *realpath(const char *file_name, char *resolved_name)
{ {
@ -162,10 +187,94 @@ char *realpath(const char *file_name, char *resolved_name)
} }
FindClose(handle); FindClose(handle);
NormalizePath(resolved_name); normalize_path(resolved_name);
return resolved_name; return resolved_name;
} }
return nullptr; return nullptr;
} }
#endif // _WIN32 #endif // _WIN32
void __declspec(noreturn) do_exit(int exitval)
{
//Allahu Akbar!!
*((int *)nullptr) = 0;
}
// Checks for a non-empty file, relative to the gamedir if necessary.
// Formerly used LOAD_FILE_FOR_ME, which provided a simple way to check for
// a file under the gamedir, but which would _also_ look in the sibling
// "valve" directory, thus sometimes finding files that weren't desired.
// Also, formerly named just "valid_file".
//
// Special-case-recognize "/dev/null" as a valid file.
bool is_file_exists_in_gamedir(const char *path)
{
char buf[PATH_MAX];
if (!path)
return false;
if (!Q_strcmp(path, "/dev/null"))
return true;
if (is_abs_path(path)) {
Q_strncpy(buf, path, sizeof buf);
buf[sizeof buf - 1] = '\0';
}
else
snprintf(buf, sizeof buf, "%s/%s", g_GameDLL.gamedir, path);
struct stat st;
int ret = stat(buf, &st);
if (ret != 0) {
META_DEBUG(5, "Unable to stat '%s': %s", buf, strerror(errno));
return false;
}
int reg = S_ISREG(st.st_mode);
if (!reg) {
META_DEBUG(5, "Not a regular file: %s", buf);
return false;
}
if (!st.st_size) {
META_DEBUG(5, "Empty file: %s", buf);
return false;
}
if (ret == 0 && reg)
return true;
return false;
}
// Turns path into a full path:
// - if not absolute, prepends gamedir
// - calls realpath() to collapse ".." and such
// - calls NormalizePath() to fix backslashes, etc
//
// Much like realpath, buffer pointed to by fullpath is assumed to be
// able to store a string of PATH_MAX length.
char* full_gamedir_path(const char* path, char* fullpath)
{
char buf[PATH_MAX];
// Build pathname from filename, plus gamedir if relative path.
if (is_abs_path(path)) {
Q_strncpy(buf, path, sizeof buf - 1);
buf[sizeof buf - 1] = '\0';
}
else snprintf(buf, sizeof buf, "%s/%s", g_GameDLL.gamedir, path);
// Remove relative path components, if possible.
if (!realpath(buf, fullpath)) {
META_DEBUG(4, "Unable to get realpath for '%s': %s", buf, str_os_error());
Q_strncpy(fullpath, path, sizeof fullpath - 1);
fullpath[sizeof fullpath - 1] = '\0';
}
// Replace backslashes, etc.
normalize_path(fullpath);
return fullpath;
}

View File

@ -1,5 +1,17 @@
#pragma once #pragma once
// Turn a variable/function name into the corresponding string, optionally
// stripping off the leading "len" characters. Useful for things like
// turning 'pfnClientCommand' into "ClientCommand" so we don't have to
// specify strings used for all the debugging/log messages.
#define STRINGIZE(name, len) #name+len
// Max description length for plugins.ini and other places.
#define MAX_DESC_LEN 256
// For various character string buffers.
#define MAX_STRBUF_LEN 1024
template <typename T, size_t N> template <typename T, size_t N>
char(&ArraySizeHelper(T(&array)[N]))[N]; char(&ArraySizeHelper(T(&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array))) #define arraysize(array) (sizeof(ArraySizeHelper(array)))
@ -54,5 +66,14 @@ char *realpath(const char *file_name, char *resolved_name);
#endif // _WIN32 #endif // _WIN32
char* trimbuf(char *str); char* trimbuf(char *str);
void NormalizePath(char *path); void normalize_path(char *path);
bool IsAbsolutePath(const char *path); bool is_abs_path(const char *path);
bool is_valid_path(const char *path);
bool is_platform_postfix(const char *pf);
void __declspec(noreturn) do_exit(int exitval);
bool is_file_exists_in_gamedir(const char *path);
char *full_gamedir_path(const char *path, char *fullpath);
extern const char* g_platform_postfixes[4];