From 4eddf466f28977ce7389eb166c7b779202d0422e Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Thu, 14 Apr 2016 03:08:35 +0300 Subject: [PATCH] Various fixes and improvements in the sample module. --- modules/sample/Common.cpp | 116 +++++++++++++++++++++++++++++++++++--- modules/sample/Common.hpp | 55 +++++++++++++++++- modules/sample/Module.cpp | 77 ++++++++++++++----------- 3 files changed, 206 insertions(+), 42 deletions(-) diff --git a/modules/sample/Common.cpp b/modules/sample/Common.cpp index 5deed336..c3737528 100644 --- a/modules/sample/Common.cpp +++ b/modules/sample/Common.cpp @@ -3,8 +3,9 @@ #include "Module.hpp" // ------------------------------------------------------------------------------------------------ -#include -#include +#include +#include +#include // ------------------------------------------------------------------------------------------------ #include @@ -34,8 +35,10 @@ void SqThrowF(CSStr str, ...) va_list args; va_start (args, str); // Write the requested contents - if (snprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0) - strcpy(g_Buffer, "Unknown error has occurred"); + if (std::vsnprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0) + { + std::strcpy(g_Buffer, "Unknown error has occurred"); + } // Release the argument list va_end(args); // Throw the exception with the resulted message @@ -49,17 +52,26 @@ CSStr FmtStr(CSStr str, ...) va_list args; va_start (args, str); // Write the requested contents - if (snprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0) - g_Buffer[0] = 0; /* make sure the string is terminated */ + if (std::vsnprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0) + { + g_Buffer[0] = '\0'; // Make sure the string is terminated + } // Release the argument list va_end(args); // Return the data from the buffer return g_Buffer; } +// ------------------------------------------------------------------------------------------------ +StackGuard::StackGuard() + : m_VM(_SqVM), m_Top(sq_gettop(m_VM)) +{ + /* ... */ +} + // ------------------------------------------------------------------------------------------------ StackGuard::StackGuard(HSQUIRRELVM vm) - : m_Top(sq_gettop(vm)), m_VM(vm) + : m_VM(vm), m_Top(sq_gettop(vm)) { /* ... */ } @@ -70,6 +82,96 @@ StackGuard::~StackGuard() sq_pop(m_VM, sq_gettop(m_VM) - m_Top); } +// -------------------------------------------------------------------------------------------- +StackStrF::StackStrF(HSQUIRRELVM vm, SQInteger idx, bool fmt) + : mPtr(nullptr) + , mLen(-1) + , mRes(SQ_OK) + , mObj() + , mVM(vm) +{ + const Int32 top = sq_gettop(vm); + // Reset the converted value object + sq_resetobject(&mObj); + // Was the string or value specified? + if (top <= (idx - 1)) + { + mRes = sq_throwerror(vm, "Missing string or value"); + } + // Do we have enough values to call the format function and are we allowed to? + else if (top > idx && fmt) + { + // Pointer to the generated string + SStr str = nullptr; + // Attempt to generate the specified string format + mRes = sqstd_format(vm, idx, &mLen, &str); + // Did the format succeeded but ended up with a null string pointer? + if (SQ_SUCCEEDED(mRes) && !str) + { + mRes = sq_throwerror(vm, "Unable to generate the string"); + } + else + { + mPtr = const_cast< CSStr >(str); + } + } + // Is the value on the stack an actual string? + else if (sq_gettype(vm, idx) == OT_STRING) + { + // Obtain a reference to the string object + mRes = sq_getstackobj(vm, idx, &mObj); + // Could we retrieve the object from the stack? + if (SQ_SUCCEEDED(mRes)) + { + // Keep a strong reference to the object + sq_addref(vm, &mObj); + // Attempt to retrieve the string value from the stack + mRes = sq_getstring(vm, idx, &mPtr); + } + // Did the retrieval succeeded but ended up with a null string pointer? + if (SQ_SUCCEEDED(mRes) && !mPtr) + { + mRes = sq_throwerror(vm, "Unable to retrieve the string"); + } + } + // We have to try and convert it to string + else + { + // Attempt to convert the value from the stack to a string + mRes = sq_tostring(vm, idx); + // Could we convert the specified value to string? + if (SQ_SUCCEEDED(mRes)) + { + // Obtain a reference to the resulted object + mRes = sq_getstackobj(vm, -1, &mObj); + // Could we retrieve the object from the stack? + if (SQ_SUCCEEDED(mRes)) + { + // Keep a strong reference to the object + sq_addref(vm, &mObj); + // Attempt to obtain the string pointer + mRes = sq_getstring(vm, -1, &mPtr); + } + } + // Pop a value from the stack regardless of the result + sq_pop(vm, 1); + // Did the retrieval succeeded but ended up with a null string pointer? + if (SQ_SUCCEEDED(mRes) && !mPtr) + { + mRes = sq_throwerror(vm, "Unable to retrieve the value"); + } + } +} + +// ------------------------------------------------------------------------------------------------ +StackStrF::~StackStrF() +{ + if (mVM && !sq_isnull(mObj)) + { + sq_release(mVM, &mObj); + } +} + // ------------------------------------------------------------------------------------------------ int SampleFunction() { diff --git a/modules/sample/Common.hpp b/modules/sample/Common.hpp index d09634c2..ac2218e9 100644 --- a/modules/sample/Common.hpp +++ b/modules/sample/Common.hpp @@ -4,6 +4,9 @@ // ------------------------------------------------------------------------------------------------ #include "ModBase.hpp" +// ------------------------------------------------------------------------------------------------ +#include + // ------------------------------------------------------------------------------------------------ namespace SqMod { @@ -45,6 +48,11 @@ CSStr FmtStr(CSStr str, ...); */ struct StackGuard { + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + StackGuard(); + /* -------------------------------------------------------------------------------------------- * Base constructor. */ @@ -80,8 +88,51 @@ private: private: // -------------------------------------------------------------------------------------------- - Int32 m_Top; /* The top of the stack when this instance was created. */ - HSQUIRRELVM m_VM; /* The VM where the stack should be restored. */ + HSQUIRRELVM m_VM; // The VM where the stack should be restored. + Int32 m_Top; // The top of the stack when this instance was created. +}; + +/* ------------------------------------------------------------------------------------------------ + * Helper structure for retrieving a value from the stack as a string or a formatted string. +*/ +struct StackStrF +{ + // -------------------------------------------------------------------------------------------- + CSStr mPtr; // Pointer to the C string that was retrieved. + SQInteger mLen; // The string length if it could be retrieved. + SQRESULT mRes; // The result of the retrieval attempts. + HSQOBJECT mObj; // Strong reference to the string object. + HSQUIRRELVM mVM; // The associated virtual machine. + + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + StackStrF(HSQUIRRELVM vm, SQInteger idx, bool fmt = true); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + StackStrF(const StackStrF & o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + StackStrF(StackStrF && o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~StackStrF(); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + StackStrF & operator = (const StackStrF & o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + StackStrF & operator = (StackStrF && o) = delete; }; /* -------------------------------------------------------------------------------------------- diff --git a/modules/sample/Module.cpp b/modules/sample/Module.cpp index ecacfa0b..9014a6d5 100644 --- a/modules/sample/Module.cpp +++ b/modules/sample/Module.cpp @@ -3,12 +3,13 @@ #include "Common.hpp" // -------------------------------------------------------------------------------------------- -#include +#include +#include +#include +#include // -------------------------------------------------------------------------------------------- -#include -#include -#include +#include // -------------------------------------------------------------------------------------------- #if defined(WIN32) || defined(_WIN32) @@ -18,14 +19,14 @@ namespace SqMod { // -------------------------------------------------------------------------------------------- -PluginFuncs* _Func = NULL; -PluginCallbacks* _Clbk = NULL; -PluginInfo* _Info = NULL; +PluginFuncs* _Func = nullptr; +PluginCallbacks* _Clbk = nullptr; +PluginInfo* _Info = nullptr; // -------------------------------------------------------------------------------------------- -HSQAPI _SqAPI = NULL; -HSQEXPORTS _SqMod = NULL; -HSQUIRRELVM _SqVM = NULL; +HSQAPI _SqAPI = nullptr; +HSQEXPORTS _SqMod = nullptr; +HSQUIRRELVM _SqVM = nullptr; /* ------------------------------------------------------------------------------------------------ * Bind speciffic functions to certain server events. @@ -51,7 +52,9 @@ void OnSquirrelInitialize() _SqMod = sq_api_import(_Func); // Did we failed to obtain the plugin exports? if(!_SqMod) + { OutputError("Failed to attach [%s] on host plugin.", SQSAMPLE_NAME); + } else { // Obtain the Squirrel API @@ -68,12 +71,16 @@ void OnSquirrelLoad() { // Make sure that we have a valid plugin API if (!_SqMod) - return; /* Unable to proceed. */ + { + return; // Unable to proceed. + } // Obtain the Squirrel API and VM _SqVM = _SqMod->GetSquirrelVM(); // Make sure that a valid virtual machine exists if (!_SqVM) - return; /* Unable to proceed. */ + { + return; // Unable to proceed. + } // Set this as the default database DefaultVM::Set(_SqVM); // Register the module API @@ -89,7 +96,7 @@ void OnSquirrelTerminate() { OutputMessage("Terminating: %s", SQSAMPLE_NAME); // Release the current database (if any) - DefaultVM::Set(NULL); + DefaultVM::Set(nullptr); // Release script resources... } @@ -99,10 +106,12 @@ void OnSquirrelTerminate() bool CheckAPIVer(CCStr ver) { // Obtain the numeric representation of the API version - long vernum = strtol(ver, NULL, 10); + long vernum = std::strtol(ver, nullptr, 10); // Check against version mismatch if (vernum == SQMOD_API_VER) + { return true; + } // Log the incident OutputError("API version mismatch on %s", SQSAMPLE_NAME); OutputMessage("=> Requested: %ld Have: %ld", vernum, SQMOD_API_VER); @@ -119,7 +128,9 @@ static int OnInternalCommand(unsigned int type, const char * text) { case SQMOD_INITIALIZE_CMD: if (CheckAPIVer(text)) + { OnSquirrelInitialize(); + } break; case SQMOD_LOAD_CMD: OnSquirrelLoad(); @@ -157,9 +168,9 @@ void BindCallbacks() // ------------------------------------------------------------------------------------------------ void UnbindCallbacks() { - _Clbk->OnInitServer = NULL; - _Clbk->OnInternalCommand = NULL; - _Clbk->OnShutdownServer = NULL; + _Clbk->OnInitServer = nullptr; + _Clbk->OnInternalCommand = nullptr; + _Clbk->OnShutdownServer = nullptr; } // -------------------------------------------------------------------------------------------- @@ -185,17 +196,17 @@ void OutputMessageImpl(const char * msg, va_list args) CONSOLE_SCREEN_BUFFER_INFO csb_before; GetConsoleScreenBufferInfo( hstdout, &csb_before); SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN); - printf("[SQMOD] "); + std::printf("[SQMOD] "); SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY); - vprintf(msg, args); - puts(""); + std::vprintf(msg, args); + std::puts(""); SetConsoleTextAttribute(hstdout, csb_before.wAttributes); #else - printf("%c[0;32m[SQMOD]%c[0;37m", 27, 27); - vprintf(msg, args); - puts(""); + std::printf("%c[0;32m[SQMOD]%c[0;37m", 27, 27); + std::vprintf(msg, args); + std::puts(""); #endif } @@ -208,17 +219,17 @@ void OutputErrorImpl(const char * msg, va_list args) CONSOLE_SCREEN_BUFFER_INFO csb_before; GetConsoleScreenBufferInfo( hstdout, &csb_before); SetConsoleTextAttribute(hstdout, FOREGROUND_RED | FOREGROUND_INTENSITY); - printf("[SQMOD] "); + std::printf("[SQMOD] "); SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY); - vprintf(msg, args); - puts(""); + std::vprintf(msg, args); + std::puts(""); SetConsoleTextAttribute(hstdout, csb_before.wAttributes); #else - printf("%c[0;32m[SQMOD]%c[0;37m", 27, 27); - vprintf(msg, args); - puts(""); + std::printf("%c[0;32m[SQMOD]%c[0;37m", 27, 27); + std::vprintf(msg, args); + std::puts(""); #endif } @@ -269,13 +280,13 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs* functions, PluginCallb { using namespace SqMod; // Output plugin header - puts(""); + std::puts(""); OutputMessage("--------------------------------------------------------------------"); OutputMessage("Plugin: %s", SQSAMPLE_NAME); OutputMessage("Author: %s", SQSAMPLE_AUTHOR); OutputMessage("Legal: %s", SQSAMPLE_COPYRIGHT); OutputMessage("--------------------------------------------------------------------"); - puts(""); + std::puts(""); // Attempt to find the host plugin ID int host_plugin_id = functions->FindPlugin((char *)(SQMOD_HOST_NAME)); // See if our plugin was loaded after the host plugin @@ -298,13 +309,13 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs* functions, PluginCallb _Info = info; // Assign plugin information _Info->uPluginVer = SQSAMPLE_VERSION; - strcpy(_Info->szName, SQSAMPLE_HOST_NAME); + std::strcpy(_Info->szName, SQSAMPLE_HOST_NAME); // Bind callbacks BindCallbacks(); // Notify that the plugin was successfully loaded OutputMessage("Successfully loaded %s", SQSAMPLE_NAME); // Dummy spacing - puts(""); + std::puts(""); // Done! return SQMOD_SUCCESS; }