1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-14 03:37:16 +01:00
SqMod/module/Base/Utility.cpp

824 lines
23 KiB
C++
Raw Normal View History

// ------------------------------------------------------------------------------------------------
#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
// ------------------------------------------------------------------------------------------------
#include <sqstdstring.h>
#include "Library/Numeric/LongInt.hpp"
// ------------------------------------------------------------------------------------------------
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] ");
2020-03-22 08:16:40 +01:00
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY); // NOLINT(hicpp-signed-bitwise)
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);
2020-03-22 08:16:40 +01:00
SetConsoleTextAttribute(hstdout, FOREGROUND_RED | FOREGROUND_INTENSITY); // NOLINT(hicpp-signed-bitwise)
std::printf("[SQMOD] ");
2020-03-22 08:16:40 +01:00
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY); // NOLINT(hicpp-signed-bitwise)
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
2020-03-22 08:16:40 +01:00
throw Sqrat::Exception(g_Buffer); // NOLINT(hicpp-exception-baseclass,cert-err60-cpp)
}
// ------------------------------------------------------------------------------------------------
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 >();
}
// ------------------------------------------------------------------------------------------------
SQRESULT SqThrowErrorF(HSQUIRRELVM vm, CCStr 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)
{
return sq_throwerror(vm, _SC("Formatting error occurred while throwing a script error"));
}
// Finalize the argument list
va_end(args);
// Throw the resulted string
return sq_throwerror(vm, g_Buffer);
}
// ------------------------------------------------------------------------------------------------
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';
2020-03-22 08:16:40 +01:00
// 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;
}
// ------------------------------------------------------------------------------------------------
StackStrF & DummyStackStrF()
{
static StackStrF s;
s.Release();
return s;
}
// ------------------------------------------------------------------------------------------------
Object & NullObject()
{
static Object o;
o.Release();
return o;
}
// ------------------------------------------------------------------------------------------------
LightObj & NullLightObj()
{
static LightObj 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;
}
2020-05-10 11:56:23 +02:00
// ------------------------------------------------------------------------------------------------
String & StringRef(const SQChar * str)
{
static String s;
s.assign(str);
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)
{
2020-03-22 08:16:40 +01:00
return std::strcmp(s, "true") == 0;
}
bool ConvNum< bool >::FromStr(CSStr s, Int32 /*base*/)
{
2020-03-22 08:16:40 +01:00
return std::strcmp(s, "true") == 0;
}
// ------------------------------------------------------------------------------------------------
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);
// Did the conversion failed?
if (SQ_FAILED(val.Proc(false)))
{
return _SC("unknown");
}
// Return the obtained string value
2020-03-22 08:16:40 +01:00
return String(val.mPtr, static_cast< size_t >(val.mLen));
}
// ------------------------------------------------------------------------------------------------
Object BufferToStrObj(const Buffer & b)
{
// Obtain the initial stack size
const StackGuard sg(SqVM());
// Push the string onto the stack
sq_pushstring(SqVM(), b.Data(), b.Position());
// Obtain the object from the stack and return it
return Var< Object >(SqVM(), -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(SqVM());
// Push the string onto the stack
sq_pushstring(SqVM(), b.Data(), size);
// Obtain the object from the stack and return it
return Var< Object >(SqVM(), -1).value;
}
// ------------------------------------------------------------------------------------------------
SQInteger PopStackInteger(HSQUIRRELVM vm, SQInteger idx)
{
// Identify which type must be extracted
switch (sq_gettype(vm, idx))
{
case OT_INTEGER:
{
SQInteger val;
sq_getinteger(vm, idx, &val);
return val;
2020-03-22 08:16:40 +01:00
}
case OT_FLOAT:
{
SQFloat val;
sq_getfloat(vm, idx, &val);
return ConvTo< SQInteger >::From(val);
2020-03-22 08:16:40 +01:00
}
case OT_BOOL:
{
SQBool val;
sq_getbool(vm, idx, &val);
return static_cast< SQInteger >(val);
2020-03-22 08:16:40 +01:00
}
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));
2020-03-22 08:16:40 +01:00
} else break;
}
case OT_ARRAY:
case OT_TABLE:
case OT_CLASS:
case OT_USERDATA:
{
return sq_getsize(vm, idx);
2020-03-22 08:16:40 +01:00
}
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);
2020-03-22 08:16:40 +01:00
}
default: break;
}
// Default to 0
return 0;
}
// ------------------------------------------------------------------------------------------------
SQFloat PopStackFloat(HSQUIRRELVM vm, SQInteger idx)
{
// Identify which type must be extracted
switch (sq_gettype(vm, idx))
{
case OT_FLOAT:
{
SQFloat val;
sq_getfloat(vm, idx, &val);
return val;
2020-03-22 08:16:40 +01:00
}
case OT_INTEGER:
{
SQInteger val;
sq_getinteger(vm, idx, &val);
return ConvTo< SQFloat >::From(val);
2020-03-22 08:16:40 +01:00
}
case OT_BOOL:
{
SQBool val;
sq_getbool(vm, idx, &val);
return ConvTo< SQFloat >::From(val);
2020-03-22 08:16:40 +01:00
}
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
2020-03-22 08:16:40 +01:00
} else break;
}
case OT_ARRAY:
case OT_TABLE:
case OT_CLASS:
case OT_USERDATA:
{
return ConvTo< SQFloat >::From(sq_getsize(vm, idx));
2020-03-22 08:16:40 +01:00
}
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));
2020-03-22 08:16:40 +01:00
}
default: break;
}
// Default to 0
return 0.0;
}
} // Namespace:: SqMod