From 05226d7799a48d2c0a95ebe4c6c23d156230566e Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Wed, 21 Mar 2007 17:45:28 +0000 Subject: [PATCH] Bail will probably kill me for all this but... 1) Fixed amb93: Improved mod path detection. 2) Fixed various rare string inconsistencies. 3) Updated changelog 4) Other various internal things that don't matter much :o --HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40349 --- sourcemm/CPlugin.cpp | 30 ++-- sourcemm/CSmmAPI.cpp | 49 ++++--- sourcemm/ISmmPlugin.h | 16 +-- sourcemm/changelog.txt | 2 + sourcemm/concommands.cpp | 24 ++-- sourcemm/msvc8/sourcemm.vcproj | 4 +- sourcemm/oslink.h | 22 +-- sourcemm/sourcemm.cpp | 250 +++++++++++++-------------------- sourcemm/util.cpp | 146 ++++++++++++------- sourcemm/util.h | 48 ++++++- 10 files changed, 308 insertions(+), 283 deletions(-) diff --git a/sourcemm/CPlugin.cpp b/sourcemm/CPlugin.cpp index 4969a79..246adcc 100644 --- a/sourcemm/CPlugin.cpp +++ b/sourcemm/CPlugin.cpp @@ -188,7 +188,7 @@ bool CPluginManager::Pause(PluginId id, char *error, size_t maxlen) if (!pl) { - snprintf(error, maxlen, "Plugin id not found"); + UTIL_Format(error, maxlen, "Plugin id not found"); return false; } @@ -208,7 +208,7 @@ bool CPluginManager::Unpause(PluginId id, char *error, size_t maxlen) if (!pl) { - snprintf(error, maxlen, "Plugin id not found"); + UTIL_Format(error, maxlen, "Plugin id not found"); return false; } @@ -228,7 +228,7 @@ bool CPluginManager::Unload(PluginId id, bool force, char *error, size_t maxlen) if (!pl) { - snprintf(error, maxlen, "Plugin %d not found", id); + UTIL_Format(error, maxlen, "Plugin %d not found", id); return false; } @@ -252,7 +252,7 @@ bool CPluginManager::Retry(PluginId id, char *error, size_t len) { if ( (*i)->m_Status >= Pl_Paused) { - snprintf(error, len, "Plugin %d is already running.", id); + UTIL_Format(error, len, "Plugin %d is already running.", id); return false; } CPlugin *pl = _Load((*i)->m_File.c_str(), Pl_Console, error, len); @@ -281,7 +281,7 @@ bool CPluginManager::Retry(PluginId id, char *error, size_t len) } } - snprintf(error, len, "Plugin %d not found,", id); + UTIL_Format(error, len, "Plugin %d not found,", id); return false; } @@ -321,7 +321,7 @@ CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source if (!fp) { if (error) - snprintf(error, maxlen, "File not found: %s", file); + UTIL_Format(error, maxlen, "File not found: %s", file); pl->m_Status = Pl_NotFound; } @@ -335,32 +335,32 @@ CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source if (!pl->m_Lib) { if (error) - snprintf(error, maxlen, "%s", dlerror()); + UTIL_Format(error, maxlen, "%s", dlerror()); pl->m_Status = Pl_Error; } else { CreateInterfaceFn pfn = (CreateInterfaceFn)(dlsym(pl->m_Lib, PL_EXPOSURE_C)); if (!pfn) { if (error) - snprintf(error, maxlen, "Function %s not found", PL_EXPOSURE_C); + UTIL_Format(error, maxlen, "Function %s not found", PL_EXPOSURE_C); pl->m_Status = Pl_Error; } else { pl->m_API = static_cast((pfn)(PLAPI_NAME, NULL)); if (!pl->m_API) { if (error) - snprintf(error, maxlen, "Failed to get API"); + UTIL_Format(error, maxlen, "Failed to get API"); pl->m_Status = Pl_Error; } else { int api = pl->m_API->GetApiVersion(); if (api < PLAPI_MIN_VERSION) { if (error) - snprintf(error, maxlen, "Plugin API %d is out of date with required minimum (%d)", api, PLAPI_MIN_VERSION); + UTIL_Format(error, maxlen, "Plugin API %d is out of date with required minimum (%d)", api, PLAPI_MIN_VERSION); pl->m_Status = Pl_Error; } else if (api > PLAPI_VERSION) { if (error) - snprintf(error, maxlen, "Plugin API %d is newer than internal version (%d)", api, PLAPI_VERSION); + UTIL_Format(error, maxlen, "Plugin API %d is newer than internal version (%d)", api, PLAPI_VERSION); pl->m_Status = Pl_Error; } else { if (pl->m_API->Load(pl->m_Id, static_cast(&g_SmmAPI), error, maxlen, m_AllLoaded)) @@ -456,7 +456,7 @@ bool CPluginManager::_Pause(CPluginManager::CPlugin *pl, char *error, size_t max if (pl->m_Status != Pl_Running || !pl->m_API) { if (error) - snprintf(error, maxlen, "Plugin cannot be paused"); + UTIL_Format(error, maxlen, "Plugin cannot be paused"); } else { if (pl->m_API->Pause(error, maxlen)) { @@ -478,7 +478,7 @@ bool CPluginManager::_Unpause(CPluginManager::CPlugin *pl, char *error, size_t m if (pl->m_Status != Pl_Paused || !pl->m_API) { if (error) - snprintf(error, maxlen, "Plugin cannot be unpaused"); + UTIL_Format(error, maxlen, "Plugin cannot be unpaused"); } else { if (pl->m_API->Unpause(error, maxlen)) { @@ -506,7 +506,7 @@ bool CPluginManager::UnloadAll() for (i=remqueue.begin(); i!=remqueue.end(); i++) { - if ( !_Unload( (*i), true, error, sizeof(error)-1) ) + if ( !_Unload( (*i), true, error, sizeof(error)) ) status = false; } @@ -537,7 +537,7 @@ bool CPluginManager::QueryRunning(PluginId id, char *error, size_t maxlength) if (!pl || !pl->m_API) { if (error) - snprintf(error, maxlength, "Plugin not valid"); + UTIL_Format(error, maxlength, "Plugin not valid"); return false; } diff --git a/sourcemm/CSmmAPI.cpp b/sourcemm/CSmmAPI.cpp index 00f2283..497b98f 100644 --- a/sourcemm/CSmmAPI.cpp +++ b/sourcemm/CSmmAPI.cpp @@ -42,10 +42,8 @@ void CSmmAPI::LogMsg(ISmmPlugin *pl, const char *msg, ...) va_list ap; static char buffer[2048]; - buffer[0] = '\0'; - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer)-1, msg, ap); + UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap); va_end(ap); LogMessage("[%s] %s", pl->GetLogTag(), buffer); @@ -131,11 +129,13 @@ void CSmmAPI::ConPrint(const char *fmt) void CSmmAPI::ConPrintf(const char *fmt, ...) { va_list ap; - static char buf[4096]; + static char buffer[4096]; + va_start(ap, fmt); - vsnprintf(buf, sizeof(buf)-1, fmt, ap); - ConPrint(buf); + UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap); va_end(ap); + + (m_ConPrintf)("%s", buffer); } void CSmmAPI::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener) @@ -275,7 +275,7 @@ bool CSmmAPI::CacheCmds() } #endif - if (!offs || ptr[offs-1] != IA32_CALL) + if (!offs || ptr[offs - 1] != IA32_CALL) { m_ConPrintf = (CONPRINTF_FUNC)Msg; return false; @@ -322,11 +322,11 @@ int CSmmAPI::FormatIface(char iface[], unsigned int maxlength) int i; int num = 0; - for (i=length-1; i>=0; i--) + for (i = length - 1; i >= 0; i--) { if (!isdigit(iface[i])) { - if (i != length-1) + if (i != length - 1) { num = 1; } @@ -334,12 +334,12 @@ int CSmmAPI::FormatIface(char iface[], unsigned int maxlength) } } - if ( (num && ((int)maxlength <= length)) || (!num && ((int)maxlength <= length+3)) ) + if ( (num && ((int)maxlength <= length)) || (!num && ((int)maxlength <= length + 3)) ) { return -1; } - if (i != length-1) + if (i != length - 1) num = atoi(&(iface[++i])); num++; @@ -384,10 +384,10 @@ void *CSmmAPI::InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, void *CSmmAPI::VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min) { char buffer[256]; /* assume no interface will go beyond this */ - int len = static_cast(strlen(iface)); + size_t len = strlen(iface); int ret; /* just in case something doesn't handle NULL properly */ - if (len > static_cast(sizeof(buffer) - 4)) + if (len > sizeof(buffer) - 4) { return NULL; } @@ -396,7 +396,7 @@ void *CSmmAPI::VInterfaceMatch(CreateInterfaceFn fn, const char *iface, int min) if (min != -1) { - char *ptr = &buffer[len-1]; + char *ptr = &buffer[len - 1]; int digits = 0; while (isdigit(*ptr) && digits <=3) { @@ -427,30 +427,29 @@ const char *CSmmAPI::GetBaseDir() void CSmmAPI::PathFormat(char *buffer, size_t len, const char *fmt, ...) { va_list ap; - va_start(ap,fmt); - size_t mylen = vsnprintf(buffer, len, fmt, ap); + va_start(ap, fmt); + size_t mylen = UTIL_FormatArgs(buffer, len, fmt, ap); va_end(ap); - if (mylen == 0xFFFFFFFF || mylen >= len) - { - mylen = len - 1; - } - - for (size_t i=0; iClientPrintf(client, buf); + UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap); va_end(ap); + + g_Engine.engine->ClientPrintf(client, buffer); } void CSmmAPI::LoadAsVSP() diff --git a/sourcemm/ISmmPlugin.h b/sourcemm/ISmmPlugin.h index f38cbe8..dea7700 100644 --- a/sourcemm/ISmmPlugin.h +++ b/sourcemm/ISmmPlugin.h @@ -76,9 +76,9 @@ public: * @brief Called on plugin unload. You can return false if you know your plugin * is not capable of restoring critical states it modifies. * - * @param error Error message buffer - * @param maxlen Size of error message buffer - * @return True on success, return false to request no unload. + * @param error Error message buffer + * @param maxlen Size of error message buffer + * @return True on success, return false to request no unload. */ virtual bool Unload(char *error, size_t maxlen) { @@ -353,7 +353,7 @@ public: #define META_CONPRINT g_SMAPI->ConPrint #define META_CONPRINTF g_SMAPI->ConPrintf -//probably should use this up above someday +/* Probably should use this up above someday */ #define CONCMD_VARNAME(name) name##_command #if !defined SMM_API @@ -374,7 +374,7 @@ public: * @param v_factory Factory method to use from ISmmAPI (such as engineFactory). * @param v_var Variable name to store into. * @param v_type Interface type (do not include the pointer/asterisk). - * @param v_name Inteface name. + * @param v_name Interface name. */ #define GET_V_IFACE_CURRENT(v_factory, v_var, v_type, v_name) \ v_var = (v_type *)ismm->VInterfaceMatch(ismm->v_factory(), v_name); \ @@ -390,10 +390,10 @@ public: /** * @brief Same as GET_V_IFACE, except searches for any. * - * @param v_factory Factory method to use from ISmmAPI (such as engineFactory). - * @param v_var Variable name to store into. + * @param v_factory Factory method to use from ISmmAPI (such as engineFactory). + * @param v_var Variable name to store into. * @param v_type Interface type (do not include the pointer/asterisk). - * @param v_name Inteface name. + * @param v_name Interface name. */ #define GET_V_IFACE_ANY(v_factory, v_var, v_type, v_name) \ v_var = (v_type *)ismm->VInterfaceMatch(ismm->v_factory(), v_name, 0); \ diff --git a/sourcemm/changelog.txt b/sourcemm/changelog.txt index 434fdf1..5888823 100644 --- a/sourcemm/changelog.txt +++ b/sourcemm/changelog.txt @@ -2,6 +2,8 @@ - Added API functions for retrieving User Message info without potentially crashing. - Added API functions for letting SourceMM plugins use Valve Server Plugin callbacks. - Changed version numbering to include the build number (SVN revision). + - Fixed amb93 (improved mod path detection). + - Fixed various potential buffer overflows. 2006/11/29 1.3d: - Updated Metamod:Source to recognize the latest Source Engine version (ServerGameDLL006) diff --git a/sourcemm/concommands.cpp b/sourcemm/concommands.cpp index 7315bea..e0b030c 100644 --- a/sourcemm/concommands.cpp +++ b/sourcemm/concommands.cpp @@ -185,7 +185,7 @@ CON_COMMAND(meta, "Metamod:Source Menu") return; } else if (strcmp(command, "refresh") == 0) { char full_path[255]; - g_SmmAPI.PathFormat(full_path, sizeof(full_path) - 1, "%s/%s", g_ModPath.c_str(), GetPluginsFile()); + g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile()); LoadPluginsFromFile(full_path); @@ -359,7 +359,7 @@ CON_COMMAND(meta, "Metamod:Source Menu") char error[255]; - if (!g_PluginMngr.Pause(id, error, sizeof(error)-1)) + if (!g_PluginMngr.Pause(id, error, sizeof(error))) { CONMSG("Pause failed: %s\n", error); return; @@ -379,7 +379,7 @@ CON_COMMAND(meta, "Metamod:Source Menu") int id = atoi(e->Cmd_Argv(2)); char error[255]; - if (!g_PluginMngr.Unpause(id, error, sizeof(error)-1)) + if (!g_PluginMngr.Unpause(id, error, sizeof(error))) { CONMSG("Unpause failed: %s\n", error); return; @@ -407,8 +407,7 @@ CON_COMMAND(meta, "Metamod:Source Menu") if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0) { - g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s", file); - snprintf(full_path, sizeof(full_path)-1, "%s", file); + g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s", file); } else { const char *ext = UTIL_GetExtension(file); #if defined WIN32 || defined _WIN32 @@ -416,14 +415,14 @@ CON_COMMAND(meta, "Metamod:Source Menu") #else ext = ext ? "" : "_i486.so"; #endif - g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s/%s%s", g_ModPath.c_str(), file, ext); + g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext); } char error[255]={0}; bool already; SourceMM::CPluginManager::CPlugin *pl; - PluginId id = g_PluginMngr.Load(full_path, Pl_Console, already, error, sizeof(error)-1); + PluginId id = g_PluginMngr.Load(full_path, Pl_Console, already, error, sizeof(error)); pl = g_PluginMngr.FindById(id); if (!pl || id < Pl_MinId || (pl->m_Status < Pl_Paused)) { @@ -511,8 +510,7 @@ CON_COMMAND(meta, "Metamod:Source Menu") /* first check if it's a known filename */ if (file[0] == '/' || strcmp(&(file[1]), ":\\") == 0) { - g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s", file); - snprintf(full_path, sizeof(full_path)-1, "%s", file); + g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s", file); } else { const char *ext = UTIL_GetExtension(file); #if defined WIN32 || defined _WIN32 @@ -520,7 +518,7 @@ CON_COMMAND(meta, "Metamod:Source Menu") #else ext = ext ? "" : "_i486.so"; #endif - g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s/%s%s", g_ModPath.c_str(), file, ext); + g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext); } SourceHook::List::iterator iter, end; @@ -543,7 +541,7 @@ CON_COMMAND(meta, "Metamod:Source Menu") } } - if (!g_PluginMngr.Unload(id, false, error, sizeof(error)-1)) + if (!g_PluginMngr.Unload(id, false, error, sizeof(error))) { CONMSG("Unload failed: %s\n", error); return; @@ -560,7 +558,7 @@ CON_COMMAND(meta, "Metamod:Source Menu") int id = atoi(e->Cmd_Argv(2)); char error[255]={0}; - if (!g_PluginMngr.Unload(id, false, error, sizeof(error)-1)) + if (!g_PluginMngr.Unload(id, false, error, sizeof(error))) { CONMSG("Force unload failed: %s\n", error); return; @@ -590,7 +588,7 @@ CON_COMMAND(meta, "Metamod:Source Menu") int id = atoi(e->Cmd_Argv(2)); char error[255]; - if (!g_PluginMngr.Retry(id, error, sizeof(error)-1)) + if (!g_PluginMngr.Retry(id, error, sizeof(error))) { CONMSG("Error reloading plugin: %s\n", error); return; diff --git a/sourcemm/msvc8/sourcemm.vcproj b/sourcemm/msvc8/sourcemm.vcproj index 4d626e4..615c8d1 100644 --- a/sourcemm/msvc8/sourcemm.vcproj +++ b/sourcemm/msvc8/sourcemm.vcproj @@ -41,7 +41,7 @@ #include #include #include - #define dlmount(x) dlopen(x,RTLD_NOW) typedef void* HINSTANCE; - #define PATH_SEP_STR "/" - #define PATH_SEP_CHAR '/' - #define ALT_SEP_CHAR '\\' + #define dlmount(x) dlopen(x,RTLD_NOW) + #define abspath(x, s) realpath(s, x) + #define PATH_SEP_STR "/" + #define PATH_SEP_CHAR '/' + #define ALT_SEP_CHAR '\\' + #define PATH_SIZE PATH_MAX #define stricmp strcasecmp #define strnicmp strncasecmp - #define SERVER_DLL "server_i486.so" + #define SERVER_DLL "server_i486.so" #endif #if defined __linux__ diff --git a/sourcemm/sourcemm.cpp b/sourcemm/sourcemm.cpp index 57b2469..bedead1 100644 --- a/sourcemm/sourcemm.cpp +++ b/sourcemm/sourcemm.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "sourcemm.h" #include "concommands.h" #include "CSmmAPI.h" @@ -26,6 +27,9 @@ using namespace SourceMM; * @file sourcemm.cpp */ +#undef CommandLine +DLL_IMPORT ICommandLine *CommandLine(); + SH_DECL_HOOK4(IServerGameDLL, DLLInit, SH_NOATTRIB, false, bool, CreateInterfaceFn, CreateInterfaceFn, CreateInterfaceFn, CGlobalVars *); SH_DECL_HOOK0_void(IServerGameDLL, DLLShutdown, SH_NOATTRIB, false); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); @@ -46,17 +50,19 @@ SourceHook::CSourceHookImpl g_SourceHook; SourceHook::ISourceHook *g_SHPtr = &g_SourceHook; SourceHook::String g_ModPath; SourceHook::String g_BinPath; -PluginId g_PLID = Pl_Console; //Technically, SourceMM is the "Console" plugin... :p +PluginId g_PLID = Pl_Console; /* Technically, SourceMM is the "Console" plugin... :p */ bool bInFirstLevel = true; bool gParsedGameInfo = false; bool bGameInit = false; SourceHook::List gamedll_list; SourceHook::CallClass *g_GameDllPatch; int g_GameDllVersion = 0; +const char VSPIFACE[] = "ISERVERPLUGINS"; +const char GAMEINFO_PATH[] = "|gameinfo_path|"; void ClearGamedllList(); -//helper macro +/* Helper Macro */ #define IFACE_MACRO(orig,nam) \ CPluginManager::CPlugin *pl; \ SourceHook::List::iterator event; \ @@ -92,16 +98,17 @@ void ClearGamedllList(); // Main code for HL2 Interaction // /////////////////////////////////// -//Initialize everything here +/* Initialize everything here */ void InitMainStates() { - char full_path[260] = {0}; - GetFileOfAddress((void *)g_GameDll.factory, full_path, sizeof(full_path)-1); + char full_path[PATH_SIZE] = {0}; + GetFileOfAddress((void *)g_GameDll.factory, full_path, sizeof(full_path)); g_BinPath.assign(full_path); - //Like metamod, reload plugins at the end of the map. - //This is so plugins can hook everything on load, BUT, new plugins will be reloaded - // if the server is shut down (silly, but rare case). + /* Like Metamod, reload plugins at the end of the map. + * This is so plugins can hook everything on load, BUT, new plugins will be reloaded + * if the server is shut down (silly, but rare case). + */ bInFirstLevel = true; SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLInit, g_GameDll.pGameDLL, DLLInit, false); @@ -115,7 +122,7 @@ void InitMainStates() { SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, g_GameDll.pGameClients, ClientCommand_handler, false); } else { - // If IServerGameClients isn't found, this really isn't a fatal error so... + /* If IServerGameClients isn't found, this really isn't a fatal error so... */ LogMessage("[META] Warning: Could not find IServerGameClients!"); LogMessage("[META] Warning: The 'meta' command will not be available to clients."); } @@ -143,7 +150,7 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, g_Engine.loaded = true; - //Initialize our console hooks + /* Initialize our console hooks */ ConCommandBaseMgr::OneTimeInit(static_cast(&g_SMConVarAccessor)); g_GameDllPatch = SH_GET_CALLCLASS(g_GameDll.pGameDLL); @@ -157,7 +164,8 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, if (!g_SmmAPI.CacheUserMessages()) { /* Don't know of a mod that has stripped out user messages completely, - but perhaps should do something different here? */ + * but perhaps should do something different here? + */ LogMessage("[META] Warning: Failed to get list of user messages."); LogMessage("[META] Warning: The 'meta game' command will not display user messages."); } @@ -169,7 +177,7 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, } char full_path[260]; - g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s/%s", g_ModPath.c_str(), pluginFile); + g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), pluginFile); LoadPluginsFromFile(full_path); @@ -201,11 +209,10 @@ bool DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFact RETURN_META_VALUE(MRES_IGNORED, true); } -//This is where the magic happens +/* This is where the magic happens */ SMM_API void *CreateInterface(const char *iface, int *ret) { - // Prevent loading of self as a SourceMM plugin or Valve server plugin :x - const char *vspIface = "ISERVERPLUGINCALLBACKS"; + /* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */ if (strcmp(iface, PLAPI_NAME) == 0) { Warning("Do not try loading Metamod:Source as a SourceMM or Valve server plugin.\n"); @@ -218,7 +225,7 @@ SMM_API void *CreateInterface(const char *iface, int *ret) return NULL; } - if (strncmp(iface, vspIface, 22) == 0) + if (strncmp(iface, VSPIFACE, sizeof(VSPIFACE) - 1) == 0) { if (ret) { @@ -231,127 +238,52 @@ SMM_API void *CreateInterface(const char *iface, int *ret) if (!gParsedGameInfo) { gParsedGameInfo = true; - char curpath[260] = {0}; - char dllpath[260] = {0}; - getcwd(curpath, sizeof(curpath)-1); - if (!GetFileOfAddress((void *)CreateInterface, dllpath, sizeof(dllpath)-1)) + const char *gameDir = NULL; + char gamePath[PATH_SIZE]; + char smmPath[PATH_SIZE]; + + /* Get path to SourceMM DLL */ + if (!GetFileOfAddress((void *)CreateInterface, smmPath, sizeof(smmPath))) { Error("GetFileOfAddress() failed! Metamod cannot load.\n"); return NULL; } - SourceHook::String s_dllpath(dllpath); - //begin the heuristics for searching for the mod path (these are quite ugly). - //for OS compatibility purposes, we're going to do case insensitivity on windows. - size_t path_len = strlen(curpath); - size_t dll_len = strlen(dllpath); - //strip the dll path off - //:TODO: with path stuff - in Linux, \ can exist in a file path as a non-seperator! - for (size_t i=dll_len-1; i>0; i--) - { - if (dllpath[i] == '\\' || dllpath[i] == '/') - { - if (i == dll_len-1) - break; - //save path by stripping off file name and ending terminator - dllpath[i] = '\0'; - dll_len = i; - break; - } - } + /* Get value of -game from command line, defaulting to hl2 as engine seems to do */ + gameDir = CommandLine()->ParmValue("-game", "hl2"); - //strip absolute path terminators if any! - if (curpath[path_len-1] == '/' || curpath[path_len-1] == '\\') - curpath[--path_len] = '\0'; + /* Get absolute path */ + abspath(gamePath, gameDir); + g_ModPath.assign(gamePath); - //if the base path doesn't fit into the module path, something is wrong! - // ex: c:\games\srcds - // c:\gaben.dll - if (path_len > dll_len) - { - Error("Could not detect GameDLL path! Metamod cannot load[1].\n"); - return NULL; - } + char tempPath[PATH_SIZE]; - //we are now in such a position that the two dir names SHOULD MATCH! - typedef int (*STRNCMP)(const char *str1, const char *str2, size_t n); - STRNCMP cmp = -#ifdef WIN32 - strnicmp; -#else - strncmp; -#endif - //are they equal? - if ( ((cmp)(curpath, dllpath, path_len)) != 0 ) - { - //:TODO: In this case, we should read /proc/self/maps and find srcds! - Error("Could not detect GameDLL path! Metamod cannot load[2].\n"); - return NULL; - } - //this will skip past the dir and its separator char - char *ptr = &(dllpath[path_len+1]); - path_len = strlen(ptr); - for (size_t i=0; ifactory, buffer, sizeof(buffer)-1)) + if (GetFileOfAddress((void *)pCheck->factory, buffer, sizeof(buffer))) { - if (UTIL_PathCmp(temp_path, buffer)) + if (UTIL_PathCmp(tempPath, buffer)) { found = true; break; @@ -417,7 +352,7 @@ SMM_API void *CreateInterface(const char *iface, int *ret) if (found) continue; fclose(fp); - HINSTANCE gamedll = dlmount(temp_path); + HINSTANCE gamedll = dlmount(tempPath); if (gamedll == NULL) continue; CreateInterfaceFn fn = (CreateInterfaceFn)dlsym(gamedll, "CreateInterface"); @@ -447,12 +382,12 @@ SMM_API void *CreateInterface(const char *iface, int *ret) if (strncmp(iface, str, len) == 0) { - //This is the interface we want! Right now we support versions 3 through 5. + /* This is the interface we want! Right now we support versions 3 through 8 */ g_GameDllVersion = atoi(&(iface[len])); int sizeTooBig = 0; //rename this to sizeWrong in the future! if (g_GameDllVersion < MIN_GAMEDLL_VERSION || g_GameDllVersion > MAX_GAMEDLL_VERSION) { - //maybe this will get used in the future + /* Maybe this will get used in the future */ sizeTooBig = g_GameDllVersion; if (ret) { @@ -468,7 +403,7 @@ SMM_API void *CreateInterface(const char *iface, int *ret) ptr = (pInfo->factory)(iface, ret); if (ptr) { - //this is our gamedll. unload the others. + /* This is our GameDLL. Unload the others. */ gamedll_list.erase(iter); ClearGamedllList(); pInfo->pGameDLL = static_cast(ptr); @@ -497,14 +432,14 @@ SMM_API void *CreateInterface(const char *iface, int *ret) return NULL; } } else { - //wtf do we do... - //:TODO: .. something a bit more intelligent? + /* wtf do we do... */ + /* :TODO: .. something a bit more intelligent? */ Error("Engine requested unknown interface before GameDLL was known!\n"); return NULL; } } - //if we got here, there's definitely a gamedll. + /* If we got here, there's definitely a GameDLL */ IFACE_MACRO(g_GameDll.factory, GameDLL); } @@ -525,10 +460,10 @@ void ClearGamedllList() void DLLShutdown_handler() { - //Unload plugins + /* Unload plugins */ g_PluginMngr.UnloadAll(); - // Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly + /* Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly */ g_SMConVarAccessor.MarkCommandsAsGameDLL(); g_SMConVarAccessor.UnregisterGameDLLCommands(); @@ -566,7 +501,7 @@ int LoadPluginsFromFile(const char *_file) while (!feof(fp)) { buffer[0] = '\0'; - fgets(buffer, sizeof(buffer)-1, fp); + fgets(buffer, sizeof(buffer), fp); length = strlen(buffer); if (!length) continue; @@ -618,11 +553,11 @@ int LoadPluginsFromFile(const char *_file) { continue; } - //First find if it's an absolute path or not... + /* First find if it's an absolute path or not... */ if (file[0] == '/' || strncmp(&(file[1]), ":\\", 2) == 0) { - //If we're in an absolute path, ignore our normal heuristics - id = g_PluginMngr.Load(file, Pl_File, already, error, sizeof(error)-1); + /* If we're in an absolute path, ignore our normal heuristics */ + id = g_PluginMngr.Load(file, Pl_File, already, error, sizeof(error)); if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused) { LogMessage("[META] Failed to load plugin %s. %s", buffer, error); @@ -633,9 +568,9 @@ int LoadPluginsFromFile(const char *_file) total++; } } else { - //Attempt to find a file extension + /* Attempt to find a file extension */ ptr = UTIL_GetExtension(file); - //Add an extension if there's none there + /* Add an extension if there's none there */ if (!ptr) { #if defined WIN32 || defined _WIN32 @@ -646,9 +581,9 @@ int LoadPluginsFromFile(const char *_file) } else { ext = ""; } - //Format the new path - g_SmmAPI.PathFormat(full_path, sizeof(full_path)-1, "%s/%s%s", g_ModPath.c_str(), file, ext); - id = g_PluginMngr.Load(full_path, Pl_File, already, error, sizeof(error)-1); + /* Format the new path */ + g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s%s", g_ModPath.c_str(), file, ext); + id = g_PluginMngr.Load(full_path, Pl_File, already, error, sizeof(error)); if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused) { LogMessage("[META] Failed to load plugin %s. %s", buffer, error); @@ -672,22 +607,25 @@ int LoadPluginsFromFile(const char *_file) return total; } -//Wrapper function. This is called when the GameDLL thinks it's using -// the engine's real engineFactory. +/* Wrapper function. This is called when the GameDLL thinks it's using + * the engine's real engineFactory. + */ void *EngineFactory(const char *iface, int *ret) { IFACE_MACRO(g_Engine.engineFactory, Engine); } -//Wrapper function. This is called when the GameDLL thinks it's using -// the engine's real physicsFactory. +/* Wrapper function. This is called when the GameDLL thinks it's using + * the engine's real physicsFactory. + */ void *PhysicsFactory(const char *iface, int *ret) { IFACE_MACRO(g_Engine.physicsFactory, Physics); } -//Wrapper function. This is called when the GameDLL thinks it's using -// the engine's real fileSystemFactory. +/* Wrapper function. This is called when the GameDLL thinks it's using + * the engine's real fileSystemFactory. + */ void *FileSystemFactory(const char *iface, int *ret) { IFACE_MACRO(g_Engine.fileSystemFactory, FileSystem); @@ -698,13 +636,13 @@ void LogMessage(const char *msg, ...) va_list ap; static char buffer[2048]; - buffer[0] = '\0'; - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer)-5, msg, ap); - strcat(buffer, "\n"); + size_t len = vsnprintf(buffer, sizeof(buffer) - 2, msg, ap); va_end(ap); + buffer[len++] = '\n'; + buffer[len] = '\0'; + if (!g_Engine.engine) { fprintf(stdout, "%s", buffer); @@ -718,7 +656,7 @@ void LevelShutdown_handler(void) if (!bInFirstLevel) { char full_path[255]; - g_SmmAPI.PathFormat(full_path, sizeof(full_path) - 1, "%s/%s", g_ModPath.c_str(), GetPluginsFile()); + g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile()); LoadPluginsFromFile(full_path); } else { diff --git a/sourcemm/util.cpp b/sourcemm/util.cpp index 792a624..d70407b 100644 --- a/sourcemm/util.cpp +++ b/sourcemm/util.cpp @@ -10,67 +10,86 @@ #include #include -#include #include #include "util.h" #include "oslink.h" /** - * @brief Utility functons + * @brief Utility functions * @file util.cpp */ -/* UTIL_GetExtension - * Returns a pointer to the extension in a file name - */ const char *UTIL_GetExtension(const char *file) { int len = strlen(file); int i = 0; - for (i=len-1; i>=0; i--) + for (i = len - 1; i >= 0; i--) { if (file[i] == '/' || file[i] == '\\') - return NULL; - - if ((file[i] == '.') && (i != len-1)) { - return (const char *)&(file[i+1]); + return NULL; + } + + if ((file[i] == '.') && (i != len - 1)) + { + return (const char *)&(file[i + 1]); } } return NULL; } -/* UTIL_TrimLeft - * Removes whitespace characters from left side of string - */ void UTIL_TrimLeft(char *buffer) { - // Let's think of this as our iterator + /* Let's think of this as our iterator */ char *i = buffer; - // Make sure the buffer isn't null + /* Make sure the buffer isn't null */ if (i && *i) { - // Add up number of whitespace characters - while(isspace(*i)) + /* Add up number of whitespace characters */ + while(isspace((unsigned char) *i)) + { i++; + } - // If whitespace chars in buffer then adjust string so first non-whitespace char is at start of buffer + /* If whitespace chars in buffer then adjust string so first non-whitespace char is at start of buffer */ if (i != buffer) + { memmove(buffer, i, (strlen(i) + 1) * sizeof(char)); + } } } -//:TODO: this should skip string literals +void UTIL_TrimRight(char *buffer) +{ + /* Make sure buffer isn't null */ + if (buffer) + { + size_t len = strlen(buffer); + + /* Loop through buffer backwards while replacing whitespace chars with null chars */ + for (size_t i = len - 1; i >= 0; i--) + { + if (isspace((unsigned char) buffer[i])) + { + buffer[i] = '\0'; + } else { + break; + } + } + } +} + +/* :TODO: this should skip string literals */ void UTIL_TrimComments(char *buffer) { int num_sc = 0; size_t len = strlen(buffer); if (buffer) { - for (int i=(int)len-1; i>=0; i--) + for (int i = len - 1; i >= 0; i--) { if (buffer[i] == '/') { @@ -87,72 +106,62 @@ void UTIL_TrimComments(char *buffer) } num_sc = 0; } - //size_t won't go below 0, manually break out + /* size_t won't go below 0, manually break out */ if (i == 0) + { break; + } } } } -/* UTIL_TrimRight - * Removes whitespace characters from right side of string - */ -void UTIL_TrimRight(char *buffer) -{ - // Make sure buffer isn't null - if (buffer) - { - // Loop through buffer backwards while replacing whitespace chars with null chars - for (int i = (int)strlen(buffer) - 1; i >= 0; i--) - { - if (isspace(buffer[i])) - buffer[i] = '\0'; - else - break; - } - } -} - -/* UTIL_KeySplit - * Breaks a string at the first space until it reaches a nonspace - */ void UTIL_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2) { size_t start; size_t len = strlen(str); - for (start=0; start= len1) + { break; + } buf1[c] = str[i]; } buf1[c] = '\0'; - for (start=end; start= len2) + { break; + } buf2[c] = str[start]; } buf2[c] = '\0'; @@ -172,32 +181,61 @@ bool UTIL_PathCmp(const char *path1, const char *path2) if (path1[pos1] == PATH_SEP_CHAR) { if (path2[pos2] != PATH_SEP_CHAR) + { return false; - //look for extra path chars + } + + /* Look for extra path chars */ while (path1[++pos1]) { if (path1[pos1] != PATH_SEP_CHAR) + { break; + } } while (path2[++pos2]) { if (path2[pos2] != PATH_SEP_CHAR) + { break; + } } continue; } - //if we're at a different non-alphanumeric, the next character MUST Match + /* If we're at a different non-alphanumeric, the next character MUST match */ if (!isalpha(path1[pos1]) && (path1[pos1] != path2[pos2])) + { return false; + } -#ifdef WIN32 + #ifdef WIN32 if (toupper(path1[pos1]) != toupper(path2[pos2])) -#else + #else if (path1[pos1] != path2[pos2]) -#endif + #endif + { return false; + } + pos1++; pos2++; } } + +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + size_t len = vsnprintf(buffer, maxlength, fmt, ap); + va_end(ap); + + if (len >= maxlength) + { + len = maxlength - 1; + buffer[len] = '\0'; + } + + return len; +} diff --git a/sourcemm/util.h b/sourcemm/util.h index 2a97433..2dbfda6 100644 --- a/sourcemm/util.h +++ b/sourcemm/util.h @@ -11,16 +11,62 @@ #ifndef _INCLUDE_UTIL_H #define _INCLUDE_UTIL_H +#include + /** - * @brief Utility functons + * @brief Utility functions * @file util.h */ +/** + * @brief Returns a pointer to the extension in a file name. + */ const char *UTIL_GetExtension(const char *file); + +/** + * @brief Removes C-style comments from string. + */ void UTIL_TrimComments(char *buffer); + +/** + * @brief Removes whitespace characters from left side of string. + */ void UTIL_TrimLeft(char *buffer); + +/** + * @brief Removes whitespace characters from right side of string. + */ void UTIL_TrimRight(char *buffer); + +/** + * @brief Breaks a string at the first space until it reaches a non-space. + */ void UTIL_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2); + +/** + * @brief Compares two file paths. + */ bool UTIL_PathCmp(const char *path1, const char *path2); +/** + * @brief Same as snprintf except that it ensures the string buffer is null terminated. + */ +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); + +/** + * @brief Same as vsnprintf except that it ensures the string buffer is null terminated. + */ +inline size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params) +{ + size_t len = vsnprintf(buffer, maxlength, fmt, params); + + if (len >= maxlength) + { + len = maxlength - 1; + buffer[len] = '\0'; + } + + return len; +} + #endif //_INCLUDE_UTIL_H