mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 16:57:16 +01:00
414 lines
13 KiB
C++
414 lines
13 KiB
C++
|
// ------------------------------------------------------------------------------------------------
|
||
|
#include "Base/Stack.hpp"
|
||
|
#include "Base/Shared.hpp"
|
||
|
#include "Base/Buffer.hpp"
|
||
|
#include "Library/Numeric.hpp"
|
||
|
|
||
|
// ------------------------------------------------------------------------------------------------
|
||
|
#include <sqstdstring.h>
|
||
|
|
||
|
// ------------------------------------------------------------------------------------------------
|
||
|
namespace SqMod {
|
||
|
|
||
|
// ------------------------------------------------------------------------------------------------
|
||
|
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;
|
||
|
} 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 fallback
|
||
|
return sq_getsize(vm, idx);
|
||
|
} break;
|
||
|
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;
|
||
|
} 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 fallback
|
||
|
return ConvTo< SQFloat >::From(sq_getsize(vm, idx));
|
||
|
} break;
|
||
|
default: break;
|
||
|
}
|
||
|
// Default to 0
|
||
|
return 0.0;
|
||
|
}
|
||
|
|
||
|
// ------------------------------------------------------------------------------------------------
|
||
|
Int64 PopStackLong(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 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 fallback
|
||
|
return static_cast< Int64 >(sq_getsize(vm, idx));
|
||
|
} break;
|
||
|
default: break;
|
||
|
}
|
||
|
// Default to 0
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// ------------------------------------------------------------------------------------------------
|
||
|
Uint64 PopStackULong(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 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 fallback
|
||
|
return ConvTo< Uint64 >::From(sq_getsize(vm, idx));
|
||
|
} break;
|
||
|
default: break;
|
||
|
}
|
||
|
// Default to 0
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------------------------
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ------------------------------------------------------------------------------------------------
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
// ------------------------------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
} // Namespace:: SqMod
|