// ------------------------------------------------------------------------------------------------ #include "Core/Common.hpp" #include "Core/Buffer.hpp" #include "Core/Utility.hpp" #include "Library/Numeric/Long.hpp" // ------------------------------------------------------------------------------------------------ #include #include // ------------------------------------------------------------------------------------------------ #ifdef SQMOD_OS_WINDOWS #include #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