1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 08:47:17 +01:00
SqMod/shared/Base/Utility.inl
Sandu Liviu Catalin 66d1110733 Rvised the API distribution system to avoid segmentation fault crashes on Linux and make the overal code cleaner.
Moved the constants in IRC module into their own source and implemented a faster method of registering them.
Various other minor changes and adjustments. Some of them in order to comply with the new API distribution system.
2016-07-17 03:24:07 +03:00

1510 lines
46 KiB
C++

// ------------------------------------------------------------------------------------------------
#include "Base/Utility.hpp"
#include "Base/Buffer.hpp"
// ------------------------------------------------------------------------------------------------
#include <ctime>
#include <cfloat>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
// ------------------------------------------------------------------------------------------------
#ifdef SQMOD_OS_WINDOWS
#include <windows.h>
#endif // SQMOD_OS_WINDOWS
// ------------------------------------------------------------------------------------------------
#ifndef SQMOD_PLUGIN_API
#include "Library/Numeric/LongInt.hpp"
#include <sqstdstring.h>
#endif // SQMOD_PLUGIN_API
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
PluginFuncs* _Func = nullptr;
PluginCallbacks* _Clbk = nullptr;
PluginInfo* _Info = nullptr;
/* ------------------------------------------------------------------------------------------------
* Common buffers to reduce memory allocations. To be immediately copied upon return!
*/
static SQChar g_Buffer[4096];
static SQChar g_NumBuf[1024];
// ------------------------------------------------------------------------------------------------
SStr GetTempBuff()
{
return g_Buffer;
}
// ------------------------------------------------------------------------------------------------
Uint32 GetTempBuffSize()
{
return sizeof(g_Buffer);
}
/* --------------------------------------------------------------------------------------------
* Raw console message output.
*/
static inline void OutputMessageImpl(CCStr msg, va_list args)
{
#ifdef SQMOD_OS_WINDOWS
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csb_before;
GetConsoleScreenBufferInfo( hstdout, &csb_before);
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN);
std::printf("[SQMOD] ");
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY);
std::vprintf(msg, args);
std::puts("");
SetConsoleTextAttribute(hstdout, csb_before.wAttributes);
#else
std::printf("\033[21;32m[SQMOD]\033[0m");
std::vprintf(msg, args);
std::puts("");
#endif // SQMOD_OS_WINDOWS
}
/* --------------------------------------------------------------------------------------------
* Raw console error output.
*/
static inline void OutputErrorImpl(CCStr msg, va_list args)
{
#ifdef SQMOD_OS_WINDOWS
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csb_before;
GetConsoleScreenBufferInfo( hstdout, &csb_before);
SetConsoleTextAttribute(hstdout, FOREGROUND_RED | FOREGROUND_INTENSITY);
std::printf("[SQMOD] ");
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY);
std::vprintf(msg, args);
std::puts("");
SetConsoleTextAttribute(hstdout, csb_before.wAttributes);
#else
std::printf("\033[21;91m[SQMOD]\033[0m");
std::vprintf(msg, args);
std::puts("");
#endif // SQMOD_OS_WINDOWS
}
// --------------------------------------------------------------------------------------------
void OutputDebug(CCStr msg, ...)
{
#ifdef _DEBUG
// Initialize the arguments list
va_list args;
va_start(args, msg);
// Call the output function
OutputMessageImpl(msg, args);
// Finalize the arguments list
va_end(args);
#else
SQMOD_UNUSED_VAR(msg);
#endif
}
// --------------------------------------------------------------------------------------------
void OutputMessage(CCStr msg, ...)
{
// Initialize the arguments list
va_list args;
va_start(args, msg);
// Call the output function
OutputMessageImpl(msg, args);
// Finalize the arguments list
va_end(args);
}
// --------------------------------------------------------------------------------------------
void OutputError(CCStr msg, ...)
{
// Initialize the arguments list
va_list args;
va_start(args, msg);
// Call the output function
OutputErrorImpl(msg, args);
// Finalize the arguments list
va_end(args);
}
// ------------------------------------------------------------------------------------------------
void SqThrowF(CSStr str, ...)
{
// Initialize the argument list
va_list args;
va_start (args, str);
// Write the requested contents
if (std::vsnprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0)
{
// Write a generic message at least
std::strcpy(g_Buffer, "Unknown error has occurred");
}
// Finalize the argument list
va_end(args);
// Throw the exception with the resulted message
throw Sqrat::Exception(g_Buffer);
}
// ------------------------------------------------------------------------------------------------
CSStr FmtStr(CSStr str, ...)
{
// Initialize the argument list
va_list args;
va_start (args, str);
// Write the requested contents
if (std::vsnprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0)
{
STHROWF("Failed to run the specified string format");
}
// Finalize the argument list
va_end(args);
// Return the data from the buffer
return g_Buffer;
}
// ------------------------------------------------------------------------------------------------
CSStr ToStrF(CSStr str, ...)
{
// Prepare the arguments list
va_list args;
va_start(args, str);
// Write the requested contents
if (std::vsnprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0)
{
g_Buffer[0] = '\0'; // Make sure the string is null terminated
}
// Finalize the argument list
va_end(args);
// Return the resulted string
return g_Buffer;
}
// ------------------------------------------------------------------------------------------------
CSStr ToStringF(CSStr str, ...)
{
// Acquire a moderately sized buffer
Buffer b(128);
// Prepare the arguments list
va_list args;
va_start (args, str);
// Attempt to run the specified format
if (b.WriteF(0, str, args) == 0)
{
b.At(0) = '\0'; // Make sure the string is null terminated
}
// Finalize the argument list
va_end(args);
// Return the resulted string
return b.Get< SQChar >();
}
// ------------------------------------------------------------------------------------------------
bool SToB(CSStr str)
{
// Temporary buffer to store the lowercase string
SQChar buffer[8];
// The currently processed character
unsigned i = 0;
// Convert only the necessary characters to lowercase
while (i < 7 && *str != '\0')
{
buffer[i++] = static_cast< SQChar >(std::tolower(*(str++)));
}
// Add the null terminator
buffer[i] = '\0';
// Compare the lowercase string and return the result
return (std::strcmp(buffer, "true") == 0 || std::strcmp(buffer, "yes") == 0 ||
std::strcmp(buffer, "on") == 0 || std::strcmp(buffer, "1") == 0) ? true : false;
}
// ------------------------------------------------------------------------------------------------
Object & NullObject()
{
static Object o;
o.Release();
return o;
}
// ------------------------------------------------------------------------------------------------
Table & NullTable()
{
static Table t;
t.Release();
return t;
}
// ------------------------------------------------------------------------------------------------
Array & NullArray()
{
static Array a;
a.Release();
return a;
}
// ------------------------------------------------------------------------------------------------
Function & NullFunction()
{
static Function f;
f.Release();
return f;
}
// ------------------------------------------------------------------------------------------------
String & NullString()
{
static String s;
s.resize(0);
return s;
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Int8 >::ToStr(Int8 v)
{
// Write the numeric value to the buffer
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%d", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the beginning of the buffer
return g_NumBuf;
}
Int8 ConvNum< Int8 >::FromStr(CSStr s)
{
return ConvTo< Int8 >::From(std::strtol(s, nullptr, 10));
}
Int8 ConvNum< Int8 >::FromStr(CSStr s, Int32 base)
{
return ConvTo< Int8 >::From(std::strtol(s, nullptr, base));
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Uint8 >::ToStr(Uint8 v)
{
// Write the numeric value to the buffer
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%u", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the beginning of the buffer
return g_NumBuf;
}
Uint8 ConvNum< Uint8 >::FromStr(CSStr s)
{
return ConvTo< Uint8 >::From(std::strtoul(s, nullptr, 10));
}
Uint8 ConvNum< Uint8 >::FromStr(CSStr s, Int32 base)
{
return ConvTo< Uint8 >::From(std::strtoul(s, nullptr, base));
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Int16 >::ToStr(Int16 v)
{
// Write the numeric value to the buffer
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%d", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the beginning of the buffer
return g_NumBuf;
}
Int16 ConvNum< Int16 >::FromStr(CSStr s)
{
return ConvTo< Int16 >::From(std::strtol(s, nullptr, 10));
}
Int16 ConvNum< Int16 >::FromStr(CSStr s, Int32 base)
{
return ConvTo< Int16 >::From(std::strtol(s, nullptr, base));
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Uint16 >::ToStr(Uint16 v)
{
// Write the numeric value to the buffer
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%u", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the beginning of the buffer
return g_NumBuf;
}
Uint16 ConvNum< Uint16 >::FromStr(CSStr s)
{
return ConvTo< Uint16 >::From(std::strtoul(s, nullptr, 10));
}
Uint16 ConvNum< Uint16 >::FromStr(CSStr s, Int32 base)
{
return ConvTo< Uint16 >::From(std::strtoul(s, nullptr, base));
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Int32 >::ToStr(Int32 v)
{
// Write the numeric value to the buffer
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%d", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the beginning of the buffer
return g_NumBuf;
}
Int32 ConvNum< Int32 >::FromStr(CSStr s)
{
return ConvTo< Int32 >::From(std::strtol(s, nullptr, 10));
}
Int32 ConvNum< Int32 >::FromStr(CSStr s, Int32 base)
{
return ConvTo< Int32 >::From(std::strtol(s, nullptr, base));
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Uint32 >::ToStr(Uint32 v)
{
// Write the numeric value to the buffer
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%u", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the beginning of the buffer
return g_NumBuf;
}
Uint32 ConvNum< Uint32 >::FromStr(CSStr s)
{
return ConvTo< Uint32 >::From(std::strtoul(s, nullptr, 10));
}
Uint32 ConvNum< Uint32 >::FromStr(CSStr s, Int32 base)
{
return ConvTo< Uint32 >::From(std::strtoul(s, nullptr, base));
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Int64 >::ToStr(Int64 v)
{
// Write the numeric value to the buffer
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%lld", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the beginning of the buffer
return g_NumBuf;
}
Int64 ConvNum< Int64 >::FromStr(CSStr s)
{
return std::strtoll(s, nullptr, 10);
}
Int64 ConvNum< Int64 >::FromStr(CSStr s, Int32 base)
{
return std::strtoll(s, nullptr, base);
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Uint64 >::ToStr(Uint64 v)
{
// Write the numeric value to the buffer
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%llu", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the beginning of the buffer
return g_NumBuf;
}
Uint64 ConvNum< Uint64 >::FromStr(CSStr s)
{
return std::strtoull(s, nullptr, 10);
}
Uint64 ConvNum< Uint64 >::FromStr(CSStr s, Int32 base)
{
return std::strtoull(s, nullptr, base);
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< LongI >::ToStr(LongI v)
{
// Write the numeric value to the buffer
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%ld", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the beginning of the buffer
return g_NumBuf;
}
LongI ConvNum< LongI >::FromStr(CSStr s)
{
return std::strtol(s, nullptr, 10);
}
LongI ConvNum< LongI >::FromStr(CSStr s, Int32 base)
{
return std::strtol(s, nullptr, base);
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Ulong >::ToStr(Ulong v)
{
// Write the numeric value to the buffer
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%lu", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the beginning of the buffer
return g_NumBuf;
}
Ulong ConvNum< Ulong >::FromStr(CSStr s)
{
return std::strtoul(s, nullptr, 10);
}
Ulong ConvNum< Ulong >::FromStr(CSStr s, Int32 base)
{
return std::strtoul(s, nullptr, base);
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Float32 >::ToStr(Float32 v)
{
// Attempt to convert the value to a string
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%f", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the data from the buffer
return g_NumBuf;
}
Float32 ConvNum< Float32 >::FromStr(CSStr s)
{
return std::strtof(s, nullptr);
}
Float32 ConvNum< Float32 >::FromStr(CSStr s, Int32 /*base*/)
{
return std::strtof(s, nullptr);
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< Float64 >::ToStr(Float64 v)
{
// Attempt to convert the value to a string
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%f", v) < 0)
{
g_NumBuf[0] = '\0';
}
// Return the data from the buffer
return g_NumBuf;
}
Float64 ConvNum< Float64 >::FromStr(CSStr s)
{
return std::strtod(s, nullptr);
}
Float64 ConvNum< Float64 >::FromStr(CSStr s, Int32 /*base*/)
{
return std::strtod(s, nullptr);
}
// ------------------------------------------------------------------------------------------------
CSStr ConvNum< bool >::ToStr(bool v)
{
if (v)
{
g_NumBuf[0] = 't';
g_NumBuf[1] = 'r';
g_NumBuf[2] = 'u';
g_NumBuf[3] = 'e';
g_NumBuf[4] = '\0';
}
else
{
g_NumBuf[0] = 'f';
g_NumBuf[1] = 'a';
g_NumBuf[2] = 'l';
g_NumBuf[3] = 's';
g_NumBuf[4] = 'e';
g_NumBuf[5] = '\0';
}
return g_NumBuf;
}
bool ConvNum< bool >::FromStr(CSStr s)
{
return (std::strcmp(s, "true") == 0) ? true : false;
}
bool ConvNum< bool >::FromStr(CSStr s, Int32 /*base*/)
{
return (std::strcmp(s, "true") == 0) ? true : false;
}
// --------------------------------------------------------------------------------------------
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_getstringandsize(vm, idx, &mPtr, &mLen);
}
// 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_getstringandsize(vm, -1, &mPtr, &mLen);
}
}
// 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);
}
}
// ------------------------------------------------------------------------------------------------
CSStr SqTypeName(SQObjectType type)
{
switch (type)
{
case OT_NULL: return _SC("null");
case OT_INTEGER: return _SC("integer");
case OT_FLOAT: return _SC("float");
case OT_BOOL: return _SC("bool");
case OT_STRING: return _SC("string");
case OT_TABLE: return _SC("table");
case OT_ARRAY: return _SC("array");
case OT_USERDATA: return _SC("userdata");
case OT_CLOSURE: return _SC("closure");
case OT_NATIVECLOSURE: return _SC("nativeclosure");
case OT_GENERATOR: return _SC("generator");
case OT_USERPOINTER: return _SC("userpointer");
case OT_THREAD: return _SC("thread");
case OT_FUNCPROTO: return _SC("funcproto");
case OT_CLASS: return _SC("class");
case OT_INSTANCE: return _SC("instance");
case OT_WEAKREF: return _SC("weakref");
case OT_OUTER: return _SC("outer");
default: return _SC("unknown");
}
}
// ------------------------------------------------------------------------------------------------
String SqTypeName(HSQUIRRELVM vm, SQInteger idx)
{
// Remember the current stack size
const StackGuard sg(vm);
// Attempt to retrieve the type name of the specified value
if (SQ_FAILED(sq_typeof(vm, idx)))
{
return _SC("unknown");
}
// Attempt to convert the obtained value to a string
StackStrF val(vm, -1, false);
// Did the conversion failed?
if (SQ_FAILED(val.mRes))
{
return _SC("unknown");
}
// Return the obtained string value
return String(val.mPtr, val.mLen);
}
// ------------------------------------------------------------------------------------------------
Object BufferToStrObj(const Buffer & b)
{
// Obtain the initial stack size
const StackGuard sg(DefaultVM::Get());
// Push the string onto the stack
sq_pushstring(DefaultVM::Get(), b.Data(), b.Position());
// Obtain the object from the stack and return it
return Var< Object >(DefaultVM::Get(), -1).value;
}
// --------------------------------------------------------------------------------------------
Object BufferToStrObj(const Buffer & b, Uint32 size)
{
// Perform a range check on the specified buffer
if (size > b.Capacity())
{
STHROWF("The specified buffer size is out of range: %u >= %u", size, b.Capacity());
}
// Obtain the initial stack size
const StackGuard sg(DefaultVM::Get());
// Push the string onto the stack
sq_pushstring(DefaultVM::Get(), b.Data(), size);
// Obtain the object from the stack and return it
return Var< Object >(DefaultVM::Get(), -1).value;
}
// ------------------------------------------------------------------------------------------------
Object MakeSLongObj(Int64 value)
{
// Obtain the default virtual machine
HSQUIRRELVM vm = DefaultVM::Get();
// Obtain the initial stack size
const StackGuard sg(vm);
#ifdef SQMOD_PLUGIN_API
// Push a long integer instance with the requested value on the stack
SqMod_PushSLongObject(vm, value);
#else
// Transform the specified value into a script object
PushVar< SLongInt >(vm, SLongInt(value));
#endif // SQMOD_PLUGIN_API
// Obtain the object from the stack and return it
return Var< Object >(vm, -1).value;
}
// ------------------------------------------------------------------------------------------------
Object MakeULongObj(Uint64 value)
{
// Obtain the default virtual machine
HSQUIRRELVM vm = DefaultVM::Get();
// Obtain the initial stack size
const StackGuard sg(vm);
#ifdef SQMOD_PLUGIN_API
// Push a long integer instance with the requested value on the stack
SqMod_PushULongObject(vm, value);
#else
// Transform the specified value into a script object
PushVar< ULongInt >(vm, ULongInt(value));
#endif // SQMOD_PLUGIN_API
// Obtain the object from the stack and return it
return Var< Object >(vm, -1).value;
}
// ------------------------------------------------------------------------------------------------
Object MakeSLongObj(HSQUIRRELVM vm, Int64 value)
{
// Obtain the initial stack size
const StackGuard sg(vm);
#ifdef SQMOD_PLUGIN_API
// Push a long integer instance with the requested value on the stack
SqMod_PushSLongObject(vm, value);
#else
// Transform the specified value into a script object
PushVar< SLongInt >(vm, SLongInt(value));
#endif // SQMOD_PLUGIN_API
// Obtain the object from the stack and return it
return Var< Object >(vm, -1).value;
}
// ------------------------------------------------------------------------------------------------
Object MakeULongObj(HSQUIRRELVM vm, Uint64 value)
{
// Obtain the initial stack size
const StackGuard sg(vm);
#ifdef SQMOD_PLUGIN_API
// Push a long integer instance with the requested value on the stack
SqMod_PushULongObject(vm, value);
#else
// Transform the specified value into a script object
PushVar< ULongInt >(vm, ULongInt(value));
#endif // SQMOD_PLUGIN_API
// Obtain the object from the stack and return it
return Var< Object >(vm, -1).value;
}
// ------------------------------------------------------------------------------------------------
Int64 FetchSLongObjVal(const Object & value)
{
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Obtain the initial stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// Retrieve and return the object value from the stack
return PopStackSLong(vm, -1);
}
// ------------------------------------------------------------------------------------------------
Uint64 FetchULongObjVal(const Object & value)
{
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Obtain the initial stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// Retrieve and return the object value from the stack
return PopStackSLong(vm, -1);
}
// ------------------------------------------------------------------------------------------------
SQRESULT FetchDateObjVal(const Object & value, Uint16 & year, Uint8 & month, Uint8 & day)
{
#ifdef SQMOD_PLUGIN_API
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Remember the current stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// Grab the date components from the date instance
return SqMod_GetDate(vm, -1, &year, &month, &day);
#else
STHROWF("This method is only available in modules");
// Should not reach this point
return SQ_ERROR;
// Avoid unused parameter warnings
SQMOD_UNUSED_VAR(value);
SQMOD_UNUSED_VAR(year);
SQMOD_UNUSED_VAR(month);
SQMOD_UNUSED_VAR(day);
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
CSStr FetchDateObjStr(const Object & value)
{
#ifdef SQMOD_PLUGIN_API
static SQChar buffer[32];
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Remember the current stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// Grab the date instance as a string
const StackStrF val(vm, -1, false);
// Validate the result
if (SQ_FAILED(val.mRes))
{
return _SC("1000-01-01");
}
// Copy the string into the common buffer
std::strncpy(buffer, val.mPtr, sizeof(buffer));
// Return the obtained string
return buffer;
#else
STHROWF("This method is only available in modules");
// Should not reach this point
return nullptr;
// Avoid unused parameter warnings
SQMOD_UNUSED_VAR(value);
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
SQRESULT FetchTimeObjVal(const Object & value, Uint8 & hour, Uint8 & minute, Uint8 & second)
{
#ifdef SQMOD_PLUGIN_API
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Remember the current stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// Grab the date components from the date instance
return SqMod_GetTime(vm, -1, &hour, &minute, &second, nullptr);
#else
STHROWF("This method is only available in modules");
// Should not reach this point
return SQ_ERROR;
// Avoid unused parameter warnings
SQMOD_UNUSED_VAR(value);
SQMOD_UNUSED_VAR(hour);
SQMOD_UNUSED_VAR(minute);
SQMOD_UNUSED_VAR(second);
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
SQRESULT FetchTimeObjVal(const Object & value, Uint8 & hour, Uint8 & minute, Uint8 & second, Uint16 & millisecond)
{
#ifdef SQMOD_PLUGIN_API
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Remember the current stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// Grab the date components from the date instance
return SqMod_GetTime(vm, -1, &hour, &minute, &second, &millisecond);
#else
STHROWF("This method is only available in modules");
// Should not reach this point
return SQ_ERROR;
// Avoid unused parameter warnings
SQMOD_UNUSED_VAR(value);
SQMOD_UNUSED_VAR(hour);
SQMOD_UNUSED_VAR(minute);
SQMOD_UNUSED_VAR(second);
SQMOD_UNUSED_VAR(millisecond);
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
CSStr FetchTimeObjStr(const Object & value)
{
#ifdef SQMOD_PLUGIN_API
static SQChar buffer[32];
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Remember the current stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// Grab the time instance as a string
const StackStrF val(vm, -1, false);
// Validate the result
if (SQ_FAILED(val.mRes))
{
return _SC("00:00:00");
}
// Copy the string into the common buffer
std::strncpy(buffer, val.mPtr, sizeof(buffer));
// Remove the millisecond part from the string, if any
buffer[8] = '\0';
// Return the obtained string
return buffer;
#else
STHROWF("This method is only available in modules");
// Should not reach this point
return nullptr;
// Avoid unused parameter warnings
SQMOD_UNUSED_VAR(value);
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
Int32 FetchTimeObjSeconds(const Object & value)
{
#ifdef SQMOD_PLUGIN_API
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Remember the current stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// The time components
uint8_t h = 0, m = 0, s = 0;
// Grab the time components from the time instance
if (SQ_FAILED(SqMod_GetTime(vm, -1, &h, &m, &s, nullptr)))
{
STHROWF("Unable to obtain the time info");
}
// Return the number of seconds in the specified time
return ((h * (60 * 60)) + (m * 60) + s);
#else
STHROWF("This method is only available in modules");
// Should not reach this point
return 0;
// Avoid unused parameter warnings
SQMOD_UNUSED_VAR(value);
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
SQRESULT FetchDatetimeObjVal(const Object & value, Uint16 & year, Uint8 & month, Uint8 & day, Uint8 & hour,
Uint8 & minute, Uint8 & second)
{
#ifdef SQMOD_PLUGIN_API
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Remember the current stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// Grab the date components from the date instance
return SqMod_GetDatetime(vm, -1, &year, &month, &day, &hour, &minute, &second, nullptr);
#else
STHROWF("This method is only available in modules");
// Should not reach this point
return SQ_ERROR;
// Avoid unused parameter warnings
SQMOD_UNUSED_VAR(value);
SQMOD_UNUSED_VAR(year);
SQMOD_UNUSED_VAR(month);
SQMOD_UNUSED_VAR(day);
SQMOD_UNUSED_VAR(hour);
SQMOD_UNUSED_VAR(minute);
SQMOD_UNUSED_VAR(second);
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
SQRESULT FetchDatetimeObjVal(const Object & value, Uint16 & year, Uint8 & month, Uint8 & day, Uint8 & hour,
Uint8 & minute, Uint8 & second, Uint16 & millisecond)
{
#ifdef SQMOD_PLUGIN_API
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Remember the current stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// Grab the date components from the date instance
return SqMod_GetDatetime(vm, -1, &year, &month, &day, &hour, &minute, &second, &millisecond);
#else
STHROWF("This method is only available in modules");
// Should not reach this point
return SQ_ERROR;
// Avoid unused parameter warnings
SQMOD_UNUSED_VAR(value);
SQMOD_UNUSED_VAR(year);
SQMOD_UNUSED_VAR(month);
SQMOD_UNUSED_VAR(day);
SQMOD_UNUSED_VAR(hour);
SQMOD_UNUSED_VAR(minute);
SQMOD_UNUSED_VAR(second);
SQMOD_UNUSED_VAR(millisecond);
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
CSStr FetchDatetimeObjStr(const Object & value)
{
#ifdef SQMOD_PLUGIN_API
static SQChar buffer[32];
// Grab the associated object virtual machine
HSQUIRRELVM vm = value.GetVM();
// Remember the current stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, value);
// Grab the date-time instance as a string
const StackStrF val(vm, -1, false);
// Validate the result
if (SQ_FAILED(val.mRes))
{
return _SC("1000-01-01 00:00:00");
}
// Copy the string into the common buffer
std::strncpy(buffer, val.mPtr, sizeof(buffer));
// Remove the millisecond part from the string, if any
buffer[19] = '\0';
// Return the obtained string
return buffer;
#else
STHROWF("This method is only available in modules");
// Should not reach this point
return nullptr;
// Avoid unused parameter warnings
SQMOD_UNUSED_VAR(value);
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
SQInteger PopStackInteger(HSQUIRRELVM vm, SQInteger idx)
{
#ifdef SQMOD_PLUGIN_API
return SqMod_PopStackInteger(vm, idx);
#else
// Identify which type must be extracted
switch (sq_gettype(vm, idx))
{
case OT_INTEGER:
{
SQInteger val;
sq_getinteger(vm, idx, &val);
return val;
} break;
case OT_FLOAT:
{
SQFloat val;
sq_getfloat(vm, idx, &val);
return ConvTo< SQInteger >::From(val);
} break;
case OT_BOOL:
{
SQBool val;
sq_getbool(vm, idx, &val);
return static_cast< SQInteger >(val);
} break;
case OT_STRING:
{
CSStr val = nullptr;
// Attempt to retrieve and convert the string
if (SQ_SUCCEEDED(sq_getstring(vm, idx, &val)) && val != nullptr && *val != '\0')
{
return ConvTo< SQInteger >::From(std::strtoll(val, nullptr, 10));
}
} break;
case OT_ARRAY:
case OT_TABLE:
case OT_CLASS:
case OT_USERDATA:
{
return sq_getsize(vm, idx);
} break;
case OT_INSTANCE:
{
// Attempt to treat the value as a signed long instance
try
{
return ConvTo< SQInteger >::From(Var< const SLongInt & >(vm, idx).value.GetNum());
}
catch (...)
{
// Just ignore it...
}
// Attempt to treat the value as a unsigned long instance
try
{
return ConvTo< SQInteger >::From(Var< const ULongInt & >(vm, idx).value.GetNum());
}
catch (...)
{
// Just ignore it...
}
// Attempt to get the size of the instance as a fall back
return sq_getsize(vm, idx);
} break;
default: break;
}
// Default to 0
return 0;
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
SQFloat PopStackFloat(HSQUIRRELVM vm, SQInteger idx)
{
#ifdef SQMOD_PLUGIN_API
return SqMod_PopStackFloat(vm, idx);
#else
// Identify which type must be extracted
switch (sq_gettype(vm, idx))
{
case OT_FLOAT:
{
SQFloat val;
sq_getfloat(vm, idx, &val);
return val;
} break;
case OT_INTEGER:
{
SQInteger val;
sq_getinteger(vm, idx, &val);
return ConvTo< SQFloat >::From(val);
} break;
case OT_BOOL:
{
SQBool val;
sq_getbool(vm, idx, &val);
return ConvTo< SQFloat >::From(val);
} break;
case OT_STRING:
{
CSStr val = nullptr;
// Attempt to retrieve and convert the string
if (SQ_SUCCEEDED(sq_getstring(vm, idx, &val)) && val != nullptr && *val != '\0')
{
#ifdef SQUSEDOUBLE
return std::strtod(val, nullptr);
#else
return std::strtof(val, nullptr);
#endif // SQUSEDOUBLE
}
} break;
case OT_ARRAY:
case OT_TABLE:
case OT_CLASS:
case OT_USERDATA:
{
return ConvTo< SQFloat >::From(sq_getsize(vm, idx));
} break;
case OT_INSTANCE:
{
// Attempt to treat the value as a signed long instance
try
{
return ConvTo< SQFloat >::From(Var< const SLongInt & >(vm, idx).value.GetNum());
}
catch (...)
{
// Just ignore it...
}
// Attempt to treat the value as a unsigned long instance
try
{
return ConvTo< SQFloat >::From(Var< const ULongInt & >(vm, idx).value.GetNum());
}
catch (...)
{
// Just ignore it...
}
// Attempt to get the size of the instance as a fall back
return ConvTo< SQFloat >::From(sq_getsize(vm, idx));
} break;
default: break;
}
// Default to 0
return 0.0;
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
Int64 PopStackSLong(HSQUIRRELVM vm, SQInteger idx)
{
#ifdef SQMOD_PLUGIN_API
return SqMod_PopStackSLong(vm, idx);
#else
// Identify which type must be extracted
switch (sq_gettype(vm, idx))
{
case OT_INTEGER:
{
SQInteger val;
sq_getinteger(vm, idx, &val);
return static_cast< Int64 >(val);
} break;
case OT_FLOAT:
{
SQFloat val;
sq_getfloat(vm, idx, &val);
return ConvTo< Int64 >::From(val);
} break;
case OT_BOOL:
{
SQBool val;
sq_getbool(vm, idx, &val);
return static_cast< Int64 >(val);
} break;
case OT_STRING:
{
CSStr val = nullptr;
// Attempt to retrieve and convert the string
if (SQ_SUCCEEDED(sq_getstring(vm, idx, &val)) && val != nullptr && *val != '\0')
{
return std::strtoll(val, nullptr, 10);
}
} break;
case OT_ARRAY:
case OT_TABLE:
case OT_CLASS:
case OT_USERDATA:
{
return static_cast< Int64 >(sq_getsize(vm, idx));
} break;
case OT_INSTANCE:
{
// Attempt to treat the value as a signed long instance
try
{
return Var< const SLongInt & >(vm, idx).value.GetNum();
}
catch (...)
{
// Just ignore it...
}
// Attempt to treat the value as a unsigned long instance
try
{
return ConvTo< Int64 >::From(Var< const ULongInt & >(vm, idx).value.GetNum());
}
catch (...)
{
// Just ignore it...
}
// Attempt to get the size of the instance as a fall back
return static_cast< Int64 >(sq_getsize(vm, idx));
} break;
default: break;
}
// Default to 0
return 0;
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
Uint64 PopStackULong(HSQUIRRELVM vm, SQInteger idx)
{
#ifdef SQMOD_PLUGIN_API
return SqMod_PopStackULong(vm, idx);
#else
// Identify which type must be extracted
switch (sq_gettype(vm, idx))
{
case OT_INTEGER:
{
SQInteger val;
sq_getinteger(vm, idx, &val);
return ConvTo< Uint64 >::From(val);
} break;
case OT_FLOAT:
{
SQFloat val;
sq_getfloat(vm, idx, &val);
return ConvTo< Uint64 >::From(val);
} break;
case OT_BOOL:
{
SQBool val;
sq_getbool(vm, idx, &val);
return ConvTo< Uint64 >::From(val);
} break;
case OT_STRING:
{
CSStr val = nullptr;
// Attempt to retrieve and convert the string
if (SQ_SUCCEEDED(sq_getstring(vm, idx, &val)) && val != nullptr && *val != '\0')
{
return std::strtoull(val, nullptr, 10);
}
} break;
case OT_ARRAY:
case OT_TABLE:
case OT_CLASS:
case OT_USERDATA:
{
return ConvTo< Uint64 >::From(sq_getsize(vm, idx));
} break;
case OT_INSTANCE:
{
// Attempt to treat the value as a signed long instance
try
{
return ConvTo< Uint64 >::From(Var< const SLongInt & >(vm, idx).value.GetNum());
}
catch (...)
{
// Just ignore it...
}
// Attempt to treat the value as a unsigned long instance
try
{
return Var< const ULongInt & >(vm, idx).value.GetNum();
}
catch (...)
{
// Just ignore it...
}
// Attempt to get the size of the instance as a fall back
return ConvTo< Uint64 >::From(sq_getsize(vm, idx));
} break;
default: break;
}
// Default to 0
return 0;
#endif // SQMOD_PLUGIN_API
}
// ------------------------------------------------------------------------------------------------
#ifdef SQMOD_PLUGIN_API
// ------------------------------------------------------------------------------------------------
bool CheckModuleAPIVer(CCStr ver, CCStr mod)
{
// Obtain the numeric representation of the API version
const LongI 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", mod);
OutputMessage("=> Requested: %ld Have: %ld", vernum, SQMOD_API_VER);
// Invoker should not attempt to communicate through the module API
return false;
}
// ------------------------------------------------------------------------------------------------
bool CheckModuleOrder(PluginFuncs * vcapi, Uint32 mod_id, CCStr mod)
{
// Make sure a valid server API was provided
if (!vcapi)
{
OutputError("Invalid pointer to server API structure");
// Validation failed!
return false;
}
// Attempt to find the host plug-in identifier
const int plugin_id = vcapi->FindPlugin(SQMOD_HOST_NAME);
// See if our module was loaded after the host plug-in
if (plugin_id < 0)
{
OutputError("%s: could find the host plug-in", mod);
// Validation failed!
return false;
}
// Should never reach this point but just in case
else if (static_cast< Uint32 >(plugin_id) > mod_id)
{
OutputError("%s: loaded after the host plug-in", mod);
// Validation failed!
return false;
}
// Loaded in the correct order
return true;
}
// ------------------------------------------------------------------------------------------------
void ImportModuleAPI(PluginFuncs * vcapi, CCStr mod)
{
// Make sure a valid server API was provided
if (!vcapi)
{
STHROWF("%s: Invalid pointer to server API structure", mod);
}
size_t exports_struct_size;
// Attempt to find the host plug-in identifier
int plugin_id = vcapi->FindPlugin(SQMOD_HOST_NAME);
// Validate the obtained plug-in identifier
if (plugin_id < 0)
{
STHROWF("%s: Unable to obtain the host plug-in identifier", mod);
}
// Attempt to retrieve the host plug-in exports
const void ** raw_plugin_exports = vcapi->GetPluginExports(plugin_id, &exports_struct_size);
// See if the size of the exports structure matches
if (exports_struct_size <= 0)
{
STHROWF("%s: Incompatible host plug-in exports structure", mod);
}
// See if we have any exports from the host plug-in
else if (raw_plugin_exports == nullptr)
{
STHROWF("%s: Unable to obtain pointer host plug-in exports", mod);
}
// Obtain pointer to the exports structure
const SQMODEXPORTS * plugin_exports = *reinterpret_cast< const SQMODEXPORTS ** >(raw_plugin_exports);
// See if we have a valid pointer to the exports structure
if (plugin_exports == nullptr)
{
STHROWF("%s: Invalid pointer to host plug-in exports structure", mod);
}
else if (plugin_exports->PopulateModuleAPI == nullptr || plugin_exports->PopulateSquirrelAPI == nullptr)
{
STHROWF("%s: Invalid pointer to host plug-in import functions", mod);
}
// Prepare a structure to obtain the module API
SQMODAPI sqmodapi;
// Attempt to populate the structure
switch (plugin_exports->PopulateModuleAPI(&sqmodapi, sizeof(SQMODAPI)))
{
case -1: STHROWF("%s: Incompatible module API structure", mod);
case 0: STHROWF("%s: Invalid pointer to module API structure", mod);
}
// Prepare a structure to obtain the squirrel API
SQLIBAPI sqlibapi;
// Attempt to populate the structure
switch (plugin_exports->PopulateSquirrelAPI(&sqlibapi, sizeof(SQLIBAPI)))
{
case -1: STHROWF("%s: Incompatible squirrel API structure", mod);
case 0: STHROWF("%s: Invalid pointer to squirrel API structure", mod);
}
// Attempt to expand the obtained API
if (!sqmod_api_expand(&sqmodapi))
{
// Collapse the API first
sqmod_api_collapse();
// Now it's safe to throw the exception
STHROWF("%s: Unable to expand module API structure", mod);
}
else if (!sqlib_api_expand(&sqlibapi))
{
// Collapse the API first
sqmod_api_collapse();
sqlib_api_collapse();
// Now it's safe to throw the exception
STHROWF("%s: Unable to expand module API structure", mod);
}
}
#endif // SQMOD_PLUGIN_API
} // Namespace:: SqMod