diff --git a/core/CLogger.cpp b/core/CLogger.cpp index 1f98f247..3e56a65c 100644 --- a/core/CLogger.cpp +++ b/core/CLogger.cpp @@ -35,6 +35,7 @@ void CLogger::_NewMapFile() { g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; + return; } else { char date[32]; strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); @@ -125,7 +126,10 @@ void CLogger::LogMessage(const char *vafmt, ...) if (m_mode == LoggingMode_HL2) { - _PrintToHL2Log(vafmt); + va_list ap; + va_start(ap, vafmt); + _PrintToHL2Log(vafmt, ap); + va_end(ap); return; } @@ -135,7 +139,7 @@ void CLogger::LogMessage(const char *vafmt, ...) _NewMapFile(); } - static char msg[3072]; + char msg[3072]; va_list ap; va_start(ap, vafmt); vsnprintf(msg, sizeof(msg), vafmt, ap); @@ -215,7 +219,7 @@ void CLogger::LogError(const char *vafmt, ...) m_ErrMapStart = false; } - static char msg[3072]; + char msg[3072]; va_list ap; va_start(ap, vafmt); vsnprintf(msg, sizeof(msg), vafmt, ap); @@ -235,6 +239,7 @@ void CLogger::LogError(const char *vafmt, ...) } else { g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n"); m_Active = false; + return; } g_SMAPI->ConPrintf("L %s: %s\n", date, msg); @@ -265,17 +270,16 @@ void CLogger::MapChange(const char *mapname) m_ErrMapStart = false; } -void CLogger::_PrintToHL2Log(const char *fmt, ...) +void CLogger::_PrintToHL2Log(const char *fmt, va_list ap) { - static char msg[3072]; + char msg[3072]; size_t len; - va_list ap; - va_start(ap, fmt); - len = vsnprintf(msg, sizeof(msg)-1, fmt, ap); + len = vsnprintf(msg, sizeof(msg)-2, fmt, ap); + len = (len >= sizeof(msg)) ? (sizeof(msg) - 2) : len; + msg[len++] = '\n'; msg[len] = '\0'; - va_end(ap); engine->LogPrint(msg); } \ No newline at end of file diff --git a/core/CLogger.h b/core/CLogger.h index 5d3aa3c6..9eed457d 100644 --- a/core/CLogger.h +++ b/core/CLogger.h @@ -40,7 +40,7 @@ public: private: void _CloseFile(); void _NewMapFile(); - void _PrintToHL2Log(const char *fmt, ...); + void _PrintToHL2Log(const char *fmt, va_list ap); private: String m_NrmFileName; String m_ErrFileName; diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index e0ccd463..ae3a54c5 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -1,5 +1,6 @@ #include "sm_srvcmds.h" #include "sm_version.h" +#include "sm_stringutil.h" ConVarAccessor g_ConCmdAccessor; @@ -70,15 +71,15 @@ CON_COMMAND(sm, "SourceMod Menu") int len = 0; const sm_plugininfo_t *info = pl->GetPublicInfo(); - len += snprintf(&buffer[len], sizeof(buffer)-len, " %02d <%s>", id, StatusToStr(pl->GetStatus())); - len += snprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); + len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, StatusToStr(pl->GetStatus())); + len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename()); if (IS_STR_FILLED(info->version)) { - len += snprintf(&buffer[len], sizeof(buffer)-len, " (%s)", info->version); + len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", info->version); } if (IS_STR_FILLED(info->author)) { - snprintf(&buffer[len], sizeof(buffer)-len, " by %s", info->author); + UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", info->author); } META_CONPRINTF("%s\n", buffer); } diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 25a37ba0..ff89a123 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "sm_stringutil.h" #define ALT 0x00000001 /* alternate form */ @@ -471,3 +472,13 @@ unsigned int strncopy(char *dest, const char *src, size_t count) return (dest - start); } + +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); + + return (len >= maxlength) ? (maxlength - 1) : len; +} \ No newline at end of file diff --git a/core/sm_stringutil.h b/core/sm_stringutil.h index 5dce299f..49facef6 100644 --- a/core/sm_stringutil.h +++ b/core/sm_stringutil.h @@ -10,5 +10,6 @@ using namespace SourcePawn; size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param); const char *stristr(const char *str, const char *substr); unsigned int strncopy(char *dest, const char *src, size_t count); +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); #endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_ diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 75db63f2..949f153c 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -1,6 +1,8 @@ +#include #include "sm_globals.h" #include "HandleSys.h" #include "LibrarySys.h" +#include "sm_stringutil.h" HandleType_t g_FileType; HandleType_t g_DirType; @@ -36,7 +38,7 @@ public: }; -cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) +static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) { char *path; int err; @@ -58,7 +60,7 @@ cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) return g_HandleSys.CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL); } -cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) +static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); IDirectory *pDir; @@ -109,6 +111,324 @@ cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) return true; } +static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params) +{ + char *name, *mode; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + if ((err=pContext->LocalToString(params[2], &mode)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + + FILE *pFile = fopen(realpath, mode); + if (!pFile) + { + return 0; + } + + return g_HandleSys.CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL); +} + +static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params) +{ + char *name; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + + return (unlink(realpath)) ? 0 : 1; +} + +static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + FILE *pFile; + int err; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + char *buf; + if ((err=pContext->LocalToString(params[2], &buf)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + fgets(buf, params[3], pFile); + + return 1; +} + +static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + FILE *pFile; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + return (feof(pFile)) ? 1 : 0; +} + +static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + FILE *pFile; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + fseek(pFile, params[2], params[3]); + + return 1; +} + +static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + FILE *pFile; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + return ftell(pFile); +} + +static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params) +{ + char *name; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); +#ifdef PLATFORM_WINDOWS + struct _stat s; + if (_stat(realpath, &s) != 0) + { + return 0; + } + if (s.st_mode & S_IFREG) + { + return 1; + } + return 0; +#elif PLATFORM_LINUX + struct stat s; + if (stat(realpath, &s) != 0) + { + return 0; + } + if (S_ISREG(s.st_mode)) + { + return 1; + } + return 0; +#endif +} + +static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params) +{ + char *newpath, *oldpath; + int err; + if ((err=pContext->LocalToString(params[1], &newpath)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + if ((err=pContext->LocalToString(params[2], &oldpath)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char new_realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(new_realpath, sizeof(new_realpath), "%s/%s", g_SourceMod.GetBaseDir(), newpath); + char old_realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(old_realpath, sizeof(old_realpath), "%s/%s", g_SourceMod.GetBaseDir(), oldpath); + +#ifdef PLATFORM_WINDOWS + return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0; +#elif PLATFORM_LINUX + return (rename(old_realpath, new_realpath)) ? 0 : 1; +#endif +} + +static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params) +{ + char *name; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); +#ifdef PLATFORM_WINDOWS + struct _stat s; + if (_stat(realpath, &s) != 0) + { + return 0; + } + if (s.st_mode & S_IFDIR) + { + return 1; + } + return 0; +#elif PLATFORM_LINUX + struct stat s; + if (stat(realpath, &s) != 0) + { + return 0; + } + if (S_ISDIR(s.st_mode)) + { + return 1; + } + return 0; +#endif +} + +static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params) +{ + char *name; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return -1; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); +#ifdef PLATFORM_WINDOWS + struct _stat s; + if (_stat(realpath, &s) != 0) + { + return -1; + } + if (s.st_mode & S_IFREG) + { + return static_cast(s.st_size); + } + return -1; +#elif PLATFORM_LINUX + struct stat s; + if (stat(realpath, &s) != 0) + { + return -1; + } + if (S_ISREG(s.st_mode)) + { + return static_cast(s.st_size); + } + return -1; +#endif +} + +static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params) +{ + char *name; + int err; + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char realpath[PLATFORM_MAX_PATH+1]; + g_LibSys.PathFormat(realpath, sizeof(realpath), "%s/%s", g_SourceMod.GetBaseDir(), name); + + return (rmdir(realpath)) ? 0 : 1; +} + +static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + FILE *pFile; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + char *fmt; + int err; + if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + char buffer[2048]; + int arg = 3; + atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg); + fprintf(pFile, "%s\n", buffer); + + return 1; +} + +//:TODO: DEBUG CODE HERE cell_t PrintStuff(IPluginContext *pContext, const cell_t *params) { char *stuff; @@ -127,6 +447,18 @@ REGISTER_NATIVES(filesystem) { {"OpenDirectory", sm_OpenDirectory}, {"ReadDirEntry", sm_ReadDirEntry}, - {"PrintStuff", PrintStuff}, + {"PrintStuff", PrintStuff},//:TODO: remove this when no longer needed + {"OpenFile", sm_OpenFile}, + {"DeleteFile", sm_DeleteFile}, + {"ReadFileLine", sm_ReadFileLine}, + {"IsEndOfFile", sm_IsEndOfFile}, + {"FileSeek", sm_FileSeek}, + {"FilePosition", sm_FilePosition}, + {"FileExists", sm_FileExists}, + {"RenameFile", sm_RenameFile}, + {"DirExists", sm_DirExists}, + {"FileSize", sm_FileSize}, + {"RemoveDir", sm_RemoveDir}, + {"WriteFileLine", sm_WriteFileLine}, {NULL, NULL}, }; diff --git a/core/smn_string.cpp b/core/smn_string.cpp index d8b7436c..2fbfca82 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -84,8 +84,9 @@ static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params) { char *str; pCtx->LocalToString(params[2], &str); + size_t res = UTIL_Format(str, params[3], "%d", params[1]); - return snprintf(str, params[3], "%d", params[1]); + return static_cast(res); } static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params) @@ -102,8 +103,9 @@ static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params) { char *str; pCtx->LocalToString(params[2], &str); + size_t res = UTIL_Format(str, params[3], "%f", sp_ctof(params[1])); - return snprintf(str, params[3], "%f", sp_ctof(params[1])); + return static_cast(res); } static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params) diff --git a/core/systems/LibrarySys.cpp b/core/systems/LibrarySys.cpp index 6fc467b1..2bc57460 100644 --- a/core/systems/LibrarySys.cpp +++ b/core/systems/LibrarySys.cpp @@ -289,6 +289,8 @@ void LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...) size_t mylen = vsnprintf(buffer, len, fmt, ap); va_end(ap); + mylen = (mylen >= len) ? (len - 1) : mylen; + for (size_t i=0; i