mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 08:47:17 +01:00
441 lines
14 KiB
C++
441 lines
14 KiB
C++
// ------------------------------------------------------------------------------------------------
|
|
#include "Core/Common.hpp"
|
|
#include "Core/Buffer.hpp"
|
|
#include "Core/Utility.hpp"
|
|
#include "Library/Numeric/Long.hpp"
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include <cerrno>
|
|
#include <cstdarg>
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
#include <windows.h>
|
|
#endif // SQMOD_OS_WINDOWS
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
namespace SqMod {
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
PluginFuncs * _Func = nullptr; //NOLINT(bugprone-reserved-identifier)
|
|
PluginCallbacks * _Clbk = nullptr; //NOLINT(bugprone-reserved-identifier)
|
|
PluginInfo * _Info = nullptr; //NOLINT(bugprone-reserved-identifier)
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Raw console message output.
|
|
*/
|
|
static inline void OutputMessageImpl(const char * 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); // 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(const char * 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); // NOLINT(hicpp-signed-bitwise)
|
|
std::printf("[SQMOD] ");
|
|
|
|
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(const char * 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(const char * 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(const char * 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 SqThrowLastF(const SQChar * msg, ...)
|
|
{
|
|
// Acquire a moderately sized buffer
|
|
Buffer b(128);
|
|
// Prepare the arguments list
|
|
va_list args;
|
|
va_start (args, msg);
|
|
// Attempt to run the specified format
|
|
if (b.WriteF(0, msg, args) == 0)
|
|
{
|
|
b.At(0) = '\0'; // Make sure the string is null terminated
|
|
}
|
|
// Finalize the argument list
|
|
va_end(args);
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Get the error message, if any.
|
|
const DWORD error_num = ::GetLastError();
|
|
// Was there an error recorded?
|
|
if(error_num == 0)
|
|
{
|
|
// Invoker is responsible for making sure this doesn't happen!
|
|
SqThrowF("{} [Unknown error]", b.Data());
|
|
}
|
|
// The resulted message buffer
|
|
LPSTR msg_buff = nullptr;
|
|
// Attempt to obtain the error message
|
|
const std::size_t size = FormatMessageA(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, // NOLINT(hicpp-signed-bitwise)
|
|
nullptr, error_num, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // NOLINT(hicpp-signed-bitwise)
|
|
reinterpret_cast< LPSTR >(&msg_buff), 0, nullptr);
|
|
// Copy the message buffer before freeing it
|
|
std::string message(msg_buff, size);
|
|
//Free the message buffer
|
|
LocalFree(msg_buff);
|
|
// Now it's safe to throw the error
|
|
SqThrowF("{} [{}]", b.Data(), message);
|
|
#else
|
|
SqThrowF("{} [{}]", b.Data(), std::strerror(errno));
|
|
#endif // SQMOD_OS_WINDOWS
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
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;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
const SQChar * 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
|
|
return String(val.mPtr, static_cast< size_t >(val.mLen));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
LightObj 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< LightObj >(SqVM(), -1).value;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
LightObj BufferToStrObj(const Buffer & b, uint32_t size)
|
|
{
|
|
// Perform a range check on the specified buffer
|
|
if (size > b.Capacity())
|
|
{
|
|
STHROWF("The specified buffer size is out of range: {} >= {}", 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< LightObj >(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;
|
|
}
|
|
case OT_FLOAT:
|
|
{
|
|
SQFloat val;
|
|
sq_getfloat(vm, idx, &val);
|
|
return ConvTo< SQInteger >::From(val);
|
|
}
|
|
case OT_BOOL:
|
|
{
|
|
SQBool val;
|
|
sq_getbool(vm, idx, &val);
|
|
return static_cast< SQInteger >(val);
|
|
}
|
|
case OT_STRING:
|
|
{
|
|
const SQChar * 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));
|
|
} else break;
|
|
}
|
|
case OT_ARRAY:
|
|
case OT_TABLE:
|
|
case OT_CLASS:
|
|
case OT_USERDATA:
|
|
{
|
|
return sq_getsize(vm, idx);
|
|
}
|
|
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);
|
|
}
|
|
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;
|
|
}
|
|
case OT_INTEGER:
|
|
{
|
|
SQInteger val;
|
|
sq_getinteger(vm, idx, &val);
|
|
return ConvTo< SQFloat >::From(val);
|
|
}
|
|
case OT_BOOL:
|
|
{
|
|
SQBool val;
|
|
sq_getbool(vm, idx, &val);
|
|
return ConvTo< SQFloat >::From(val);
|
|
}
|
|
case OT_STRING:
|
|
{
|
|
const SQChar * 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
|
|
} else break;
|
|
}
|
|
case OT_ARRAY:
|
|
case OT_TABLE:
|
|
case OT_CLASS:
|
|
case OT_USERDATA:
|
|
{
|
|
return ConvTo< SQFloat >::From(sq_getsize(vm, idx));
|
|
}
|
|
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));
|
|
}
|
|
default: break;
|
|
}
|
|
// Default to 0
|
|
return 0.0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool SToB(const SQChar * 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;
|
|
}
|
|
|
|
} // Namespace:: SqMod
|