1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 08:47:17 +01:00
SqMod/source/Command.cpp

1908 lines
67 KiB
C++

// ------------------------------------------------------------------------------------------------
#include "Command.hpp"
#include "Core.hpp"
#include "Entity/Player.hpp"
// ------------------------------------------------------------------------------------------------
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <algorithm>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
CmdManager CmdManager::s_Inst;
// ------------------------------------------------------------------------------------------------
SQInteger CmdListener::Typename(HSQUIRRELVM vm)
{
static const SQChar name[] = _SC("SqCmdListener");
sq_pushstring(vm, name, sizeof(name));
return 1;
}
// ------------------------------------------------------------------------------------------------
static void ValidateName(CSStr name)
{
// Is the name empty?
if (!name || *name == '\0')
{
STHROWF("Invalid or empty command name");
}
// Inspect name characters
while (*name != '\0')
{
// Does it contain spaces?
if (std::isspace(*name) != 0)
{
STHROWF("Command names cannot contain spaces");
}
// Move to the next character
++name;
}
}
// ------------------------------------------------------------------------------------------------
CSStr CmdArgSpecToStr(Uint8 spec)
{
switch (spec)
{
case CMDARG_ANY: return _SC("any");
case CMDARG_INTEGER: return _SC("integer");
case CMDARG_FLOAT: return _SC("float");
case CMDARG_BOOLEAN: return _SC("boolean");
case CMDARG_STRING:
case CMDARG_LOWER:
case CMDARG_UPPER:
case CMDARG_GREEDY: return _SC("string");
default: return _SC("unknown");
}
}
/* ------------------------------------------------------------------------------------------------
* Forward the call to initialize the command manager.
*/
void InitializeCmdManager()
{
CmdManager::Get().Initialize();
}
/* ------------------------------------------------------------------------------------------------
* Forward the call to terminate the command manager.
*/
void TerminateCmdManager()
{
CmdManager::Get().Deinitialize();
}
// ------------------------------------------------------------------------------------------------
CmdManager::Context::Context(Int32 invoker)
: mBuffer(512)
, mInvoker(invoker)
, mCommand()
, mArgument()
, mInstance(nullptr)
, mObject()
, mArgv()
, mArgc(0)
{
// Reserve enough space upfront
mCommand.reserve(64);
mArgument.reserve(512);
}
// ------------------------------------------------------------------------------------------------
CmdManager::Guard::Guard(const CtxRef & ctx)
: mPrevious(CmdManager::Get().m_Context), mCurrent(ctx)
{
CmdManager::Get().m_Context = mCurrent;
}
// ------------------------------------------------------------------------------------------------
CmdManager::Guard::~Guard()
{
if (CmdManager::Get().m_Context == mCurrent)
{
CmdManager::Get().m_Context = mPrevious;
}
}
// ------------------------------------------------------------------------------------------------
Object & CmdManager::Attach(const String & name, CmdListener * ptr, bool autorel)
{
// Obtain the unique identifier of the specified name
const std::size_t hash = std::hash< String >()(name);
// Make sure the command doesn't already exist
for (const auto & cmd : m_Commands)
{
// Are the hashes identical?
if (cmd.mHash == hash)
{
// Do we have to release this listener instance our self?
if (autorel)
{
delete ptr; // Let's avoid memory leaks!
}
// Now it's safe to throw the exception
// (include information necessary to help identify hash collisions!)
STHROWF("Command '%s' already exists as '%s' for hash (%zu)",
name.c_str(), cmd.mName.c_str(), hash);
}
}
// Obtain the initial stack size
const StackGuard sg;
// Push this instance on the stack
ClassType< CmdListener >::PushInstance(DefaultVM::Get(), ptr);
// Attempt to insert the command
m_Commands.emplace_back(hash, name, Var< Object >(DefaultVM::Get(), -1).value);
// Return the script object of the listener
return m_Commands.back().mObj;
}
// ------------------------------------------------------------------------------------------------
void CmdManager::Detach(const String & name)
{
// Obtain the unique identifier of the specified name
const std::size_t hash = std::hash< String >()(name);
// Iterator to the found command, if any
CmdList::const_iterator itr = m_Commands.cbegin();
// Attempt to find the specified command
for (; itr != m_Commands.cend(); ++itr)
{
// Are the hashes identical?
if (itr->mHash == hash)
{
break; // We found our command!
}
}
// Make sure the command exist before attempting to remove it
if (itr != m_Commands.end())
{
m_Commands.erase(itr);
}
}
// ------------------------------------------------------------------------------------------------
void CmdManager::Detach(CmdListener * ptr)
{
// Iterator to the found command, if any
CmdList::const_iterator itr = m_Commands.cbegin();
// Attempt to find the specified command
for (; itr != m_Commands.cend(); ++itr)
{
// Are the instances identical?
if (itr->mPtr == ptr)
{
break; // We found our command!
}
}
// Make sure the command exists before attempting to remove it
if (itr != m_Commands.end())
{
m_Commands.erase(itr);
}
}
// ------------------------------------------------------------------------------------------------
bool CmdManager::Attached(const String & name) const
{
// Obtain the unique identifier of the specified name
const std::size_t hash = std::hash< String >()(name);
// Attempt to find the specified command
for (const auto & cmd : m_Commands)
{
// Are the hashes identical?
if (cmd.mHash == hash)
{
return true; // We found our command!
}
}
// No such command exists
return false;
}
// ------------------------------------------------------------------------------------------------
bool CmdManager::Attached(const CmdListener * ptr) const
{
// Attempt to find the specified command
for (const auto & cmd : m_Commands)
{
// Are the instances identical?
if (cmd.mPtr == ptr)
{
return true; // We found our command!
}
}
// No such command exists
return false;
}
// ------------------------------------------------------------------------------------------------
CmdManager::CmdManager()
: m_Commands()
, m_Context()
, m_OnFail()
, m_OnAuth()
{
/* ... */
}
// ------------------------------------------------------------------------------------------------
CmdManager::~CmdManager()
{
/* ... */
}
// ------------------------------------------------------------------------------------------------
void CmdManager::Initialize()
{
}
// ------------------------------------------------------------------------------------------------
void CmdManager::Deinitialize()
{
// Release the script resources from command instances
for (const auto & cmd : m_Commands)
{
if (cmd.mPtr)
{
// Release the local command callbacks
cmd.mPtr->m_OnExec.ReleaseGently();
cmd.mPtr->m_OnAuth.ReleaseGently();
cmd.mPtr->m_OnPost.ReleaseGently();
cmd.mPtr->m_OnFail.ReleaseGently();
}
}
// Clear the command list and release all references
m_Commands.clear();
// Release the global callbacks
m_OnFail.ReleaseGently();
m_OnAuth.ReleaseGently();
}
// ------------------------------------------------------------------------------------------------
void CmdManager::Sort()
{
std::sort(m_Commands.begin(), m_Commands.end(),
[](CmdList::const_reference a, CmdList::const_reference b) -> bool {
return (b.mName < a.mName);
});
}
// ------------------------------------------------------------------------------------------------
const Object & CmdManager::FindByName(const String & name)
{
// Obtain the unique identifier of the specified name
const std::size_t hash = std::hash< String >()(name);
// Attempt to find the specified command
for (const auto & cmd : m_Commands)
{
// Are the hashes identical?
if (cmd.mHash == hash)
{
return cmd.mObj; // We found our command!
}
}
// No such command exist
return NullObject();
}
// ------------------------------------------------------------------------------------------------
Int32 CmdManager::Run(Int32 invoker, CCStr command)
{
// Validate the string command
if (!command || *command == '\0')
{
// Tell the script callback to deal with the error
SqError(CMDERR_EMPTY_COMMAND, _SC("Invalid or empty command name"), invoker);
// Execution failed!
return -1;
}
// Create the command execution context
CtxRef ctx_ref(new Context(invoker));
// Grab a direct reference to the context instance
Context & ctx = *ctx_ref;
// Skip white-space until the command name
while (std::isspace(*command))
{
++command;
}
// Anything left to process?
if (*command == '\0')
{
// Tell the script callback to deal with the error
SqError(CMDERR_EMPTY_COMMAND, _SC("Invalid or empty command name"), invoker);
// Execution failed!
return -1;
}
// Where the name ends and argument begins
CCStr split = command;
// Find where the command name ends
while (*split != '\0' && !std::isspace(*split))
{
++split;
}
// Are there any arguments specified?
if (split != '\0')
{
// Save the command name
ctx.mCommand.assign(command, (split - command));
// Skip white space after command name
while (std::isspace(*split))
{
++split;
}
// Save the command argument
ctx.mArgument.assign(split);
}
// No arguments specified
else
{
// Save the command name
ctx.mCommand.assign(command);
// Leave argument empty
ctx.mArgument.assign(_SC(""));
}
// Do we have a valid command name?
try
{
ValidateName(ctx.mCommand.c_str());
}
catch (const Sqrat::Exception & e)
{
// Tell the script callback to deal with the error
SqError(CMDERR_INVALID_COMMAND, ToStrF("%s", e.Message().c_str()), invoker);
// Execution failed!
return -1;
}
catch (...)
{
// Tell the script callback to deal with the error
SqError(CMDERR_INVALID_COMMAND, _SC("Cannot execute invalid command name"), invoker);
// Execution failed!
return -1;
}
// We're about to enter execution land, so let's be safe
const Guard g(ctx_ref);
// Attempt to find the specified command
ctx.mObject = FindByName(ctx.mCommand);
// Have we found anything?
if (ctx.mObject.IsNull())
{
// Tell the script callback to deal with the error
SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), ctx.mCommand);
// Execution failed!
return -1;
}
// Save the command instance
ctx.mInstance = ctx.mObject.Cast< CmdListener * >();
// Is the command instance valid? (just in case)
if (!ctx.mInstance)
{
// Tell the script callback to deal with the error
SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), ctx.mCommand);
// Execution failed!
return -1;
}
// Attempt to execute the command
try
{
return Exec(ctx);
}
catch (...)
{
// Tell the script callback to deal with the error
SqError(CMDERR_EXECUTION_FAILED, _SC("Exceptions occurred during execution"), ctx.mInvoker);
}
// Execution failed
return -1;
}
// ------------------------------------------------------------------------------------------------
Int32 CmdManager::Exec(Context & ctx)
{
// Clear previous arguments
ctx.mArgv.clear();
// Reset the argument counter
ctx.mArgc = 0;
// Make sure the invoker has enough authority to execute this command
if (!ctx.mInstance->AuthCheckID(ctx.mInvoker))
{
// Tell the script callback to deal with the error
SqError(CMDERR_INSUFFICIENT_AUTH, _SC("Insufficient authority to execute command"), ctx.mInvoker);
// Execution failed!
return -1;
}
// Make sure an executer was specified
else if (ctx.mInstance->GetOnExec().IsNull())
{
// Tell the script callback to deal with the error
SqError(CMDERR_MISSING_EXECUTER, _SC("No executer was specified for this command"), ctx.mInvoker);
// Execution failed!
return -1;
}
// See if there are any arguments to parse
else if (!ctx.mArgument.empty() && !Parse(ctx))
{
// The error message was reported while parsing
return -1;
}
// Make sure we have enough arguments specified
else if (ctx.mInstance->GetMinArgC() > ctx.mArgc)
{
// Tell the script callback to deal with the error
SqError(CMDERR_INCOMPLETE_ARGS, _SC("Incomplete command arguments"), ctx.mInstance->GetMinArgC());
// Execution failed!
return -1;
}
// The check during the parsing may omit the last argument
else if (ctx.mInstance->GetMaxArgC() < ctx.mArgc)
{
// Tell the script callback to deal with the error
SqError(CMDERR_EXTRANEOUS_ARGS, _SC("Extraneous command arguments"), ctx.mInstance->GetMaxArgC());
// Execution failed!
return -1;
}
// Check argument types against the command specifiers
for (Uint32 arg = 0; arg < ctx.mArgc; ++arg)
{
if (!ctx.mInstance->ArgCheck(arg, ctx.mArgv[arg].first))
{
// Tell the script callback to deal with the error
SqError(CMDERR_UNSUPPORTED_ARG, _SC("Unsupported command argument"), arg);
// Execution failed!
return -1;
}
}
// Result of the command execution
SQInteger result = -1;
// Clear any data from the buffer to make room for the error message
ctx.mBuffer.At(0) = '\0';
// Whether the command execution failed
bool failed = false;
// Do we have to call the command with an associative container?
if (ctx.mInstance->m_Associate)
{
// Create the associative container
Table args(DefaultVM::Get());
// Copy the arguments into the table
for (Uint32 arg = 0; arg < ctx.mArgc; ++arg)
{
// Do we have use the argument index as the key?
if (ctx.mInstance->m_ArgTags[arg].empty())
{
args.SetValue(SQInteger(arg), ctx.mArgv[arg].second);
}
// Nope, we have a name for this argument!
else
{
args.SetValue(ctx.mInstance->m_ArgTags[arg].c_str(), ctx.mArgv[arg].second);
}
}
// Attempt to execute the command with the specified arguments
try
{
result = ctx.mInstance->Execute(Core::Get().GetPlayer(ctx.mInvoker).mObj, args);
}
catch (const Sqrat::Exception & e)
{
// Let's store the exception message
ctx.mBuffer.Write(0, e.Message().c_str(), e.Message().size());
// Specify that the command execution failed
failed = true;
}
catch (const std::exception & e)
{
// Let's store the exception message
ctx.mBuffer.WriteF(0, "Application exception occurred [%s]", e.what());
// Specify that the command execution failed
failed = true;
}
}
else
{
// Reserve an array for the extracted arguments
Array args(DefaultVM::Get(), ctx.mArgc);
// Copy the arguments into the array
for (Uint32 arg = 0; arg < ctx.mArgc; ++arg)
{
args.Bind(SQInteger(arg), ctx.mArgv[arg].second);
}
// Attempt to execute the command with the specified arguments
try
{
result = ctx.mInstance->Execute(Core::Get().GetPlayer(ctx.mInvoker).mObj, args);
}
catch (const Sqrat::Exception & e)
{
// Let's store the exception message
ctx.mBuffer.Write(0, e.Message().c_str(), e.Message().size());
// Specify that the command execution failed
failed = true;
}
catch (const std::exception & e)
{
// Let's store the exception message
ctx.mBuffer.WriteF(0, "Application exception occurred [%s]", e.what());
// Specify that the command execution failed
failed = true;
}
}
// Was there a runtime exception during the execution?
if (failed)
{
// Tell the script callback to deal with the error
SqError(CMDERR_EXECUTION_FAILED, _SC("Command execution failed"), ctx.mBuffer.Data());
// Is there a script callback that handles failures?
if (!ctx.mInstance->m_OnFail.IsNull())
{
// Then attempt to relay the result to that function
try
{
ctx.mInstance->m_OnFail.Execute(Core::Get().GetPlayer(ctx.mInvoker).mObj, result);
}
catch (const Sqrat::Exception & e)
{
// Tell the script callback to deal with the error
SqError(CMDERR_UNRESOLVED_FAILURE, _SC("Unable to resolve command failure"), e.Message());
}
catch (const std::exception & e)
{
// Tell the script callback to deal with the error
SqError(CMDERR_UNRESOLVED_FAILURE, _SC("Unable to resolve command failure"), e.what());
}
}
// Result is invalid at this point
result = -1;
}
// Was the command aborted explicitly?
else if (!result)
{
// Tell the script callback to deal with the error
SqError(CMDERR_EXECUTION_ABORTED, _SC("Command execution aborted"), result);
// Is there a script callback that handles failures?
if (!ctx.mInstance->m_OnFail.IsNull())
{
// Then attempt to relay the result to that function
try
{
ctx.mInstance->m_OnFail.Execute(Core::Get().GetPlayer(ctx.mInvoker).mObj, result);
}
catch (const Sqrat::Exception & e)
{
// Tell the script callback to deal with the error
SqError(CMDERR_UNRESOLVED_FAILURE, _SC("Unable to resolve command failure"), e.Message());
}
catch (const std::exception & e)
{
// Tell the script callback to deal with the error
SqError(CMDERR_UNRESOLVED_FAILURE, _SC("Unable to resolve command failure"), e.what());
}
}
}
// Is there a callback that must be executed after a successful execution?
else if (!ctx.mInstance->m_OnPost.IsNull())
{
// Then attempt to relay the result to that function
try
{
ctx.mInstance->m_OnPost.Execute(Core::Get().GetPlayer(ctx.mInvoker).mObj, result);
}
catch (const Sqrat::Exception & e)
{
// Tell the script callback to deal with the error
SqError(CMDERR_POST_PROCESSING_FAILED, _SC("Unable to complete command post processing"), e.Message());
}
catch (const std::exception & e)
{
// Tell the script callback to deal with the error
SqError(CMDERR_POST_PROCESSING_FAILED, _SC("Unable to complete command post processing"), e.what());
}
}
// Return the result
return ConvTo< Int32 >::From(result);
}
// ------------------------------------------------------------------------------------------------
bool CmdManager::Parse(Context & ctx)
{
// Is there anything to parse?
if (ctx.mArgument.empty())
{
return true; // Done parsing!
}
// Obtain the flags of the currently processed argument
Uint8 arg_flags = ctx.mInstance->m_ArgSpec[ctx.mArgc];
// Adjust the internal buffer if necessary (mostly never)
ctx.mBuffer.Adjust(ctx.mArgument.size());
// The iterator to the currently processed character
String::const_iterator itr = ctx.mArgument.cbegin();
// Previous and currently processed character
String::value_type prev = 0, elem = 0;
// Maximum arguments allowed to be processed
const Uint8 max_arg = ctx.mInstance->m_MaxArgc;
// Process loop result
bool good = true;
// Process the specified command text
while (good)
{
// Extract the current characters before advancing
prev = elem, elem = *itr;
// See if we have anything left to parse or we have what we need already
if (elem == '\0' || ctx.mArgc >= max_arg)
{
break; // We only parse what we need or what we have!
}
// Is this a greedy argument?
else if (arg_flags & CMDARG_GREEDY)
{
// Remember the current stack size
const StackGuard sg;
// Skip white-space characters
itr = std::find_if(itr, ctx.mArgument.cend(), IsNotCType(std::isspace));
// Anything left to copy to the argument?
if (itr != ctx.mArgument.end())
{
// Transform it into a script object
sq_pushstring(DefaultVM::Get(), &(*itr), std::distance(itr, ctx.mArgument.cend()));
}
// Just push an empty string
else
{
sq_pushstring(DefaultVM::Get(), _SC(""), 0);
}
// Get the object from the stack and add it to the argument list along with it's type
ctx.mArgv.emplace_back(CMDARG_STRING, Var< Object >(DefaultVM::Get(), -1).value);
// Include this argument into the count
++ctx.mArgc;
// Nothing left to parse
break;
}
// Do we have to extract a string argument?
else if ((elem == '\'' || elem == '"') && prev != '\\')
{
// Obtain the beginning and ending of the internal buffer
SStr str = ctx.mBuffer.Begin< SQChar >();
SStr end = (ctx.mBuffer.End< SQChar >() - 1); // + null terminator
// Save the closing quote type
const SQChar close = elem;
// Skip the opening quote
++itr;
// Attempt to consume the string argument
while (good)
{
// Extract the current characters before advancing
prev = elem, elem = *itr;
// See if there's anything left to parse
if (elem == '\0')
{
// Tell the script callback to deal with the error
SqError(CMDERR_SYNTAX_ERROR, _SC("String argument not closed properly"), ctx.mArgc);
// Parsing aborted
good = false;
// Stop parsing
break;
}
// First un-escaped matching quote character ends the argument
else if (elem == close)
{
// Was this not escaped?
if (prev != '\\')
{
// Terminate the string value in the internal buffer
*str = '\0';
// Stop parsing
break;
}
// Overwrite last character when replicating
else
{
--str;
}
}
// See if the internal buffer needs to scale
else if (str >= end)
{
// We should already have a buffer as big as the entire command!
SqError(CMDERR_BUFFER_OVERFLOW, _SC("Command buffer was exceeded unexpectedly"), ctx.mInvoker);
// Parsing aborted
good = false;
// Stop parsing
break;
}
// Simply replicate the character to the internal buffer
*str = elem;
// Advance to the next character
++str, ++itr;
}
// See if the argument was valid
if (!good)
{
break; // Propagate the failure!
}
// Swap the beginning and ending of the extracted string
end = str, str = ctx.mBuffer.Begin();
// Make sure the string is null terminated
*end = '\0';
// Do we have to make the string lowercase?
if (arg_flags & CMDARG_LOWER)
{
for (CStr chr = str; chr < end; ++chr)
{
*chr = static_cast< SQChar >(std::tolower(*chr));
}
}
// Do we have to make the string uppercase?
else if (arg_flags & CMDARG_UPPER)
{
for (CStr chr = str; chr < end; ++chr)
{
*chr = static_cast< SQChar >(std::toupper(*chr));
}
}
// Remember the current stack size
const StackGuard sg;
// Was the specified string empty?
if (str >= end)
{
// Just push an empty string
sq_pushstring(DefaultVM::Get(), _SC(""), 0);
}
// Add it to the argument list along with it's type
else
{
// Transform it into a script object
sq_pushstring(DefaultVM::Get(), str, end - str - 1);
}
// Get the object from the stack and add it to the argument list along with it's type
ctx.mArgv.emplace_back(CMDARG_STRING, Var< Object >(DefaultVM::Get(), -1).value);
// Advance to the next argument and obtain its flags
arg_flags = ctx.mInstance->m_ArgSpec[++ctx.mArgc];
}
// Ignore white-space characters until another valid character is found
else if (!std::isspace(elem) && (std::isspace(prev) || prev == '\0'))
{
// Find the first space character that marks the end of the argument
String::const_iterator pos = std::find_if(itr, ctx.mArgument.cend(), IsCType(std::isspace));
// Obtain both ends of the argument string
CCStr str = &(*itr), end = &(*pos);
// Compute the argument string size
const Uint32 sz = std::distance(itr, pos);
// Update the main iterator position
itr = pos;
// Update the currently processed character
elem = *itr;
// Used to exclude all other checks when a valid type was identified
bool identified = false;
// Attempt to treat the value as an integer number if possible
if (!identified && (arg_flags & CMDARG_INTEGER))
{
// Let's us know if the whole argument was part of the resulted value
CStr next = nullptr;
// Attempt to extract the integer value from the string
const Int64 value = std::strtoll(str, &next, 10);
// See if this whole string was indeed an integer
if (next == end)
{
// Remember the current stack size
const StackGuard sg;
// Transform it into a script object
sq_pushinteger(DefaultVM::Get(), ConvTo< SQInteger >::From(value));
// Get the object from the stack and add it to the argument list along with it's type
ctx.mArgv.emplace_back(CMDARG_INTEGER, Var< Object >(DefaultVM::Get(), -1).value);
// We've identified the correct value type
identified = false;
}
}
// Attempt to treat the value as an floating point number if possible
if (!identified && (arg_flags & CMDARG_FLOAT))
{
// Let's us know if the whole argument was part of the resulted value
CStr next = nullptr;
// Attempt to extract the integer value from the string
#ifdef SQUSEDOUBLE
const Float64 value = std::strtod(str, &next);
#else
const Float32 value = std::strtof(str, &next);
#endif // SQUSEDOUBLE
// See if this whole string was indeed an integer
if (next == end)
{
// Remember the current stack size
const StackGuard sg;
// Transform it into a script object
sq_pushfloat(DefaultVM::Get(), ConvTo< SQFloat >::From(value));
// Get the object from the stack and add it to the argument list along with it's type
ctx.mArgv.emplace_back(CMDARG_FLOAT, Var< Object >(DefaultVM::Get(), -1).value);
// We've identified the correct value type
identified = false;
}
}
// Attempt to treat the value as a boolean if possible
if (!identified && (arg_flags & CMDARG_BOOLEAN) && sz <= 5)
{
// Allocate memory for enough data to form a boolean value
CharT lc[6];
// Fill the temporary buffer with data from the internal buffer
std::snprintf(lc, 6, "%.5s", str);
// Convert all characters to lowercase
for (Uint32 i = 0; i < 5; ++i)
{
lc[i] = std::tolower(lc[i]);
}
// Remember the current stack size
const StackGuard sg;
// Is this a boolean true value?
if (std::strcmp(lc, "true") == 0 || std::strcmp(lc, "on") == 0)
{
// Transform it into a script object
sq_pushbool(DefaultVM::Get(), true);
// We've identified the correct value type
identified = true;
}
// Is this a boolean false value?
else if (std::strcmp(lc, "false") == 0 || std::strcmp(lc, "off") == 0)
{
// Transform it into a script object
sq_pushbool(DefaultVM::Get(), false);
// We've identified the correct value type
identified = true;
}
// Could the value inside the string be interpreted as a boolean?
if (identified)
{
// Get the object from the stack and add it to the argument list along with it's type
ctx.mArgv.emplace_back(CMDARG_BOOLEAN, Var< Object >(DefaultVM::Get(), -1).value);
}
}
// If everything else failed then simply treat the value as a string
if (!identified)
{
// Remember the current stack size
const StackGuard sg;
// Do we have to make the string lowercase?
if (arg_flags & CMDARG_LOWER)
{
// Convert all characters from the argument string into the buffer
for (CStr chr = ctx.mBuffer.Data(); str < end; ++str, ++chr)
{
*chr = static_cast< CharT >(std::tolower(*str));
}
// Transform it into a script object
sq_pushstring(DefaultVM::Get(), ctx.mBuffer.Get< SQChar >(), sz);
}
// Do we have to make the string uppercase?
else if (arg_flags & CMDARG_UPPER)
{
// Convert all characters from the argument string into the buffer
for (CStr chr = ctx.mBuffer.Data(); str < end; ++str, ++chr)
{
*chr = static_cast< CharT >(std::toupper(*str));
}
// Transform it into a script object
sq_pushstring(DefaultVM::Get(), ctx.mBuffer.Get< SQChar >(), sz);
}
else
{
// Transform it into a script object
sq_pushstring(DefaultVM::Get(), str, sz);
}
// Get the object from the stack and add it to the argument list along with it's type
ctx.mArgv.emplace_back(CMDARG_STRING, Var< Object >(DefaultVM::Get(), -1).value);
}
// Advance to the next argument and obtain its flags
arg_flags = ctx.mInstance->m_ArgSpec[++ctx.mArgc];
}
// Is there anything left to parse?
if (itr >= ctx.mArgument.end())
{
break;
}
// Advance to the next character
++itr;
}
// Return whether the parsing was successful
return good;
}
// ------------------------------------------------------------------------------------------------
Object & CmdManager::Create(CSStr name)
{
return Attach(name, new CmdListener(name), true);
}
Object & CmdManager::Create(CSStr name, CSStr spec)
{
return Attach(name, new CmdListener(name, spec), true);
}
Object & CmdManager::Create(CSStr name, CSStr spec, Array & tags)
{
return Attach(name, new CmdListener(name, spec, tags), true);
}
Object & CmdManager::Create(CSStr name, CSStr spec, Uint8 min, Uint8 max)
{
return Attach(name, new CmdListener(name, spec, min, max), true);
}
Object & CmdManager::Create(CSStr name, CSStr spec, Array & tags, Uint8 min, Uint8 max)
{
return Attach(name, new CmdListener(name, spec, tags, min, max), true);
}
// ------------------------------------------------------------------------------------------------
void CmdListener::Init(CSStr name, CSStr spec, Array & tags, Uint8 min, Uint8 max)
{
m_Name.assign("");
// Initialize the specifiers and tags to default values
for (Uint8 n = 0; n < SQMOD_MAX_CMD_ARGS; ++n)
{
m_ArgSpec[n] = CMDARG_ANY;
m_ArgTags[n].assign("");
}
// Default to minimum and maximum arguments
m_MinArgc = 0;
m_MaxArgc = (SQMOD_MAX_CMD_ARGS - 1);
// Default to no specifiers, help or informational message
m_Spec.assign("");
m_Help.assign("");
m_Info.assign("");
// Default to no authority check
m_Authority = -1;
// Default to unprotected command
m_Protected = false;
// Default to unsuspended command
m_Suspended = false;
// Default to non-associative arguments
m_Associate = false;
// Set the specified minimum and maximum allowed arguments
SetMinArgC(min);
SetMaxArgC(max);
// Extract the specified argument tags
SetArgTags(tags);
// Bind to the specified command name
SetName(name);
// Apply the specified argument rules
SetSpec(spec);
}
// ------------------------------------------------------------------------------------------------
CmdListener::CmdListener(CSStr name)
{
Init(name, _SC(""), NullArray(), 0, SQMOD_MAX_CMD_ARGS-1);
}
CmdListener::CmdListener(CSStr name, CSStr spec)
{
Init(name, spec, NullArray(), 0, SQMOD_MAX_CMD_ARGS-1);
}
CmdListener::CmdListener(CSStr name, CSStr spec, Array & tags)
{
Init(name, spec, tags, 0, SQMOD_MAX_CMD_ARGS-1);
}
CmdListener::CmdListener(CSStr name, CSStr spec, Uint8 min, Uint8 max)
{
Init(name, spec, NullArray(), min, max);
}
CmdListener::CmdListener(CSStr name, CSStr spec, Array & tags, Uint8 min, Uint8 max)
{
Init(name, spec, tags, min, max);
}
// ------------------------------------------------------------------------------------------------
CmdListener::~CmdListener()
{
// Detach this command (shouldn't be necessary!)
CmdManager::Get().Detach(this);
// Release callbacks
m_OnExec.ReleaseGently();
m_OnAuth.ReleaseGently();
m_OnPost.ReleaseGently();
m_OnFail.ReleaseGently();
}
// ------------------------------------------------------------------------------------------------
Int32 CmdListener::Cmp(const CmdListener & o) const
{
if (m_Name == o.m_Name)
{
return 0;
}
else if (m_Name.size() > o.m_Name.size())
{
return 1;
}
else
{
return -1;
}
}
// ------------------------------------------------------------------------------------------------
CSStr CmdListener::ToString() const
{
return m_Name.c_str();
}
// ------------------------------------------------------------------------------------------------
void CmdListener::Attach()
{
// Is the associated name even valid?
if (m_Name.empty())
{
STHROWF("Invalid or empty command name");
}
// Are we already attached?
else if (CmdManager::Get().Attached(this))
{
STHROWF("Command is already attached");
}
// Attempt to attach this command
CmdManager::Get().Attach(m_Name, this, false);
}
// ------------------------------------------------------------------------------------------------
void CmdListener::Detach()
{
// Detach this command
CmdManager::Get().Detach(this);
}
// ------------------------------------------------------------------------------------------------
Uint8 CmdListener::GetArgFlags(Uint32 idx) const
{
if (idx < SQMOD_MAX_CMD_ARGS)
return m_ArgSpec[idx];
return CMDARG_ANY;
}
// ------------------------------------------------------------------------------------------------
CSStr CmdListener::GetName() const
{
return m_Name.c_str();
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetName(CSStr name)
{
// Validate the specified name
ValidateName(name);
// Is this command already attached to a name?
if (CmdManager::Get().Attached(this))
{
// Detach from the current name if necessary
CmdManager::Get().Detach(this);
// Now it's safe to assign the new name
m_Name.assign(name);
// We know the new name is valid
CmdManager::Get().Attach(m_Name, this, false);
}
else
{
// Just assign the name
m_Name.assign(name);
}
}
// ------------------------------------------------------------------------------------------------
CSStr CmdListener::GetSpec() const
{
return m_Spec.c_str();
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetSpec(CSStr spec)
{
// Attempt to process the specified string
ProcSpec(spec);
// At this point there were no errors
m_Spec.assign(spec);
}
// ------------------------------------------------------------------------------------------------
Array CmdListener::GetArgTags() const
{
// Allocate an array to encapsulate all tags
Array arr(DefaultVM::Get(), SQMOD_MAX_CMD_ARGS);
// Put the tags to the allocated array
for (Uint32 arg = 0; arg < SQMOD_MAX_CMD_ARGS; ++arg)
{
arr.SetValue(arg, m_ArgTags[arg]);
}
// Return the array with the tags
return arr;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetArgTags(Array & tags)
{
// Attempt to retrieve the number of specified tags
const Uint32 max = static_cast< Uint32 >(tags.Length());
// If no tags were specified then clear current tags
if (tags.IsNull() || max == 0)
{
for (Uint8 n = 0; n < SQMOD_MAX_CMD_ARGS; ++n)
{
m_ArgTags[n].assign("");
}
}
// See if we're in range
else if (max < SQMOD_MAX_CMD_ARGS)
{
// Attempt to get all arguments in one go
tags.GetArray(m_ArgTags, max);
}
else
{
STHROWF("Argument tag (%u) is out of range (%u)", max, SQMOD_MAX_CMD_ARGS);
}
}
// ------------------------------------------------------------------------------------------------
bool CmdListener::Attached() const
{
return CmdManager::Get().Attached(this);
}
// ------------------------------------------------------------------------------------------------
CSStr CmdListener::GetHelp() const
{
return m_Help.c_str();
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetHelp(CSStr help)
{
m_Help.assign(help);
}
// ------------------------------------------------------------------------------------------------
CSStr CmdListener::GetInfo() const
{
return m_Info.c_str();
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetInfo(CSStr info)
{
m_Info.assign(info);
}
// ------------------------------------------------------------------------------------------------
Int32 CmdListener::GetAuthority() const
{
return m_Authority;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetAuthority(Int32 level)
{
m_Authority = level;
}
// ------------------------------------------------------------------------------------------------
bool CmdListener::GetProtected() const
{
return m_Protected;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetProtected(bool toggle)
{
m_Protected = toggle;
}
// ------------------------------------------------------------------------------------------------
bool CmdListener::GetSuspended() const
{
return m_Suspended;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetSuspended(bool toggle)
{
m_Suspended = toggle;
}
// ------------------------------------------------------------------------------------------------
bool CmdListener::GetAssociate() const
{
return m_Associate;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetAssociate(bool toggle)
{
m_Associate = toggle;
}
// ------------------------------------------------------------------------------------------------
Uint8 CmdListener::GetMinArgC() const
{
return m_MinArgc;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetMinArgC(Uint8 val)
{
// Perform a range check on the specified argument index
if (val >= SQMOD_MAX_CMD_ARGS)
{
STHROWF("Argument (%u) is out of total range (%u)", val, SQMOD_MAX_CMD_ARGS);
}
else if (val > m_MaxArgc)
{
STHROWF("Minimum argument (%u) exceeds maximum (%u)", val, m_MaxArgc);
}
// Apply the specified value
m_MinArgc = val;
}
// ------------------------------------------------------------------------------------------------
Uint8 CmdListener::GetMaxArgC() const
{
return m_MaxArgc;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetMaxArgC(Uint8 val)
{
// Perform a range check on the specified argument index
if (val >= SQMOD_MAX_CMD_ARGS)
{
STHROWF("Argument (%u) is out of total range (%u)", val, SQMOD_MAX_CMD_ARGS);
}
else if (val < m_MinArgc)
{
STHROWF("Minimum argument (%u) exceeds maximum (%u)", m_MinArgc, val);
}
// Apply the specified value
m_MaxArgc = val;
}
// ------------------------------------------------------------------------------------------------
Function & CmdListener::GetOnExec()
{
return m_OnExec;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetOnExec(Object & env, Function & func)
{
// Make sure that we are allowed to store script resources
if (m_Name.empty())
{
STHROWF("Invalid commands cannot store script resources");
}
// Apply the specified information
m_OnExec = Function(env.GetVM(), env.GetObject(), func.GetFunc());
}
// ------------------------------------------------------------------------------------------------
Function & CmdListener::GetOnAuth()
{
return m_OnAuth;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetOnAuth(Object & env, Function & func)
{
// Make sure that we are allowed to store script resources
if (m_Name.empty())
{
STHROWF("Invalid commands cannot store script resources");
}
// Apply the specified information
m_OnAuth = Function(env.GetVM(), env.GetObject(), func.GetFunc());
}
// ------------------------------------------------------------------------------------------------
Function & CmdListener::GetOnPost()
{
return m_OnPost;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetOnPost(Object & env, Function & func)
{
// Make sure that we are allowed to store script resources
if (m_Name.empty())
{
STHROWF("Invalid commands cannot store script resources");
}
// Apply the specified information
m_OnPost = Function(env.GetVM(), env.GetObject(), func.GetFunc());
}
// ------------------------------------------------------------------------------------------------
Function & CmdListener::GetOnFail()
{
return m_OnFail;
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetOnFail(Object & env, Function & func)
{
// Make sure that we are allowed to store script resources
if (m_Name.empty())
{
STHROWF("Invalid commands cannot store script resources");
}
// Apply the specified information
m_OnFail = Function(env.GetVM(), env.GetObject(), func.GetFunc());
}
// ------------------------------------------------------------------------------------------------
CSStr CmdListener::GetArgTag(Uint32 arg) const
{
// Perform a range check on the specified argument index
if (arg >= SQMOD_MAX_CMD_ARGS)
{
STHROWF("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS);
}
// Return the requested information
return m_ArgTags[arg].c_str();
}
// ------------------------------------------------------------------------------------------------
void CmdListener::SetArgTag(Uint32 arg, CSStr name)
{
// Perform a range check on the specified argument index
if (arg >= SQMOD_MAX_CMD_ARGS)
{
STHROWF("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS);
}
// The string type doesn't appreciate null values
else if (name)
{
m_ArgTags[arg].assign(name);
}
// Clear previous name in this case
else
m_ArgTags[arg].clear();
}
// ------------------------------------------------------------------------------------------------
void CmdListener::GenerateInfo(bool full)
{
// Clear any previously generated informational message
m_Info.clear();
// Process each supported command argument
for (Uint32 arg = 0; arg < m_MaxArgc; ++arg)
{
// If this is not a full command request then see if we must stop
if (!full)
{
// Default to stop if criteria are not meet
bool stop = true;
// Check all arguments after this and see if there's any left
for (Uint32 idx = arg; idx < m_MaxArgc; ++idx)
{
// If the argument has a name or a type specifier then it's valid
if (!m_ArgTags[idx].empty() || m_ArgSpec[idx] != CMDARG_ANY)
{
// We have more arguments that need to be parsed
stop = false;
// Go back to the main loop
break;
}
}
// Is there any argument left?
if (stop)
{
break; // Stop the main loop as well
}
}
// Begin the argument block
m_Info.push_back('<');
// If the current argument is beyond minimum then mark it as optional
if (arg >= m_MinArgc)
{
m_Info.push_back('*');
}
// If the argument has a tag/name associated then add it as well
if (!m_ArgTags[arg].empty())
{
// Add the name first
m_Info.append(m_ArgTags[arg]);
// Separate the name from the specifiers
m_Info.push_back(':');
}
// Obtain the argument specifier
const Uint8 spec = m_ArgSpec[arg];
// Is this a greedy argument?
if (spec & CMDARG_GREEDY)
{
m_Info.append("...");
}
// If the argument has any explicit types specified
else if (spec != CMDARG_ANY)
{
// Does it support integers?
if (spec & CMDARG_INTEGER)
{
m_Info.append("integer");
}
// Does it support floats?
if (spec & CMDARG_FLOAT)
{
// Add a separator if this is not the first enabled type!
if (m_Info.back() != ':' && m_Info.back() != '<')
{
m_Info.push_back(',');
}
// Now add the type name
m_Info.append("float");
}
// Does it support booleans?
if (spec & CMDARG_BOOLEAN)
{
// Add a separator if this is not the first enabled type!
if (m_Info.back() != ':' && m_Info.back() != '<')
{
m_Info.push_back(',');
}
// Now add the type name
m_Info.append("boolean");
}
// Does it support strings?
if (spec & CMDARG_STRING)
{
// Add a separator if this is not the first enabled type?
if (m_Info.back() != ':' && m_Info.back() != '<')
{
m_Info.push_back(',');
}
// Now add the type name
m_Info.append("string");
}
}
// Any kind of value is supported by this argument
else
{
m_Info.append("any");
}
// Terminate the argument block
m_Info.push_back('>');
// Don't process anything after greedy arguments
if (spec & CMDARG_GREEDY)
{
break;
}
// If this is not the last argument then add a separator
else if (arg+1 != m_MaxArgc)
{
m_Info.push_back(' ');
}
}
}
// ------------------------------------------------------------------------------------------------
bool CmdListener::ArgCheck(Uint32 arg, Uint8 flag) const
{
// Perform a range check on the specified argument index
if (arg >= SQMOD_MAX_CMD_ARGS)
{
STHROWF("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS);
}
// Retrieve the argument flags
const Uint8 f = m_ArgSpec[arg];
// Perform the requested check
return (f == CMDARG_ANY) || /* Requires check? */
(f & flag) || /* Exact match? */
(f & CMDARG_GREEDY && flag & CMDARG_STRING);
}
// ------------------------------------------------------------------------------------------------
bool CmdListener::AuthCheck(CPlayer & player)
{
return AuthCheckID(player.GetID());
}
// ------------------------------------------------------------------------------------------------
bool CmdListener::AuthCheckID(Int32 id)
{
// Do we need explicit authority verification?
if (!m_Protected)
{
return true;
}
// Allow execution by default
bool allow = true;
// Was there a custom authority inspector specified?
if (!m_OnAuth.IsNull())
{
// Ask the specified authority inspector if this execution should be allowed
SharedPtr< bool > ret = m_OnAuth.Evaluate< bool, Object & >(Core::Get().GetPlayer(id).mObj);
// See what the custom authority inspector said or default to disallow
allow = (!ret ? false : *ret);
}
// Was there a global authority inspector specified?
else if (!CmdManager::Get().GetOnAuth().IsNull())
{
// Ask the specified authority inspector if this execution should be allowed
SharedPtr< bool > ret = CmdManager::Get().GetOnAuth().Evaluate< bool, Object & >(Core::Get().GetPlayer(id).mObj);
// See what the custom authority inspector said or default to disallow
allow = (!ret ? false : *ret);
}
// Can we use the default authority system?
else if (m_Authority >= 0)
{
allow = (Core::Get().GetPlayer(id).mAuthority >= m_Authority);
}
// Return result
return allow;
}
// ------------------------------------------------------------------------------------------------
SQInteger CmdListener::Execute(Object & invoker, Array & args)
{
// Attempt to evaluate the specified executer knowing the manager did the validations
SharedPtr< SQInteger > ret = m_OnExec.Evaluate< SQInteger, Object &, Array & >(invoker, args);
// See if the executer succeeded and return the result or default to failed
return (!ret ? 0 : *ret);
}
// ------------------------------------------------------------------------------------------------
SQInteger CmdListener::Execute(Object & invoker, Table & args)
{
// Attempt to evaluate the specified executer knowing the manager did the validations
SharedPtr< SQInteger > ret = m_OnExec.Evaluate< SQInteger, Object &, Table & >(invoker, args);
// See if the executer succeeded and return the result or default to failed
return (!ret ? 0 : *ret);
}
// ------------------------------------------------------------------------------------------------
void CmdListener::ProcSpec(CSStr str)
{
// Reset current argument specifiers
memset(m_ArgSpec, CMDARG_ANY, sizeof(m_ArgSpec));
// Make sure we have anything to parse
if (!str || *str == '\0')
{
return;
}
// Currently processed argument
Uint32 idx = 0;
// Try to apply the specified type specifiers
try
{
// Process until null terminator or an error occurs
while (*str != 0)
{
// See if we need to move to the next argument
if (*str == '|')
{
if (idx >= SQMOD_MAX_CMD_ARGS)
{
STHROWF("Extraneous type specifiers: %d >= %d", idx, SQMOD_MAX_CMD_ARGS);
}
// Move to the next character
++str;
// Advance to the next argument
++idx;
}
// Simply ignore a type specifier delimiter
else if (*str != ',')
{
// Ignore non-alphabetic characters
while (*str != 0 && !isalpha(*str))
{
++str;
}
// Apply the type specifier
switch(*str++)
{
// Did we reached the end of the string?
case '\0':
break;
// Is this a greedy argument?
case 'g':
{
m_ArgSpec[idx] = CMDARG_GREEDY;
} break;
// Is this a integer type
case 'i':
{
m_ArgSpec[idx] |= CMDARG_INTEGER;
// Disable greedy argument flag if set
if (m_ArgSpec[idx] & CMDARG_GREEDY)
{
m_ArgSpec[idx] ^= CMDARG_GREEDY;
}
} break;
// Is this a float type
case 'f':
{
m_ArgSpec[idx] |= CMDARG_FLOAT;
// Disable greedy argument flag if set
if (m_ArgSpec[idx] & CMDARG_GREEDY)
{
m_ArgSpec[idx] ^= CMDARG_GREEDY;
}
} break;
// Is this a boolean type
case 'b':
{
m_ArgSpec[idx] |= CMDARG_BOOLEAN;
// Disable greedy argument flag if set
if (m_ArgSpec[idx] & CMDARG_GREEDY)
{
m_ArgSpec[idx] ^= CMDARG_GREEDY;
}
} break;
// Is this a string type
case 's':
{
m_ArgSpec[idx] |= CMDARG_STRING;
// Disable greedy argument flag if set
if (m_ArgSpec[idx] & CMDARG_GREEDY)
{
m_ArgSpec[idx] ^= CMDARG_GREEDY;
}
} break;
// Is this a lowercase string?
case 'l':
{
m_ArgSpec[idx] |= CMDARG_STRING;
m_ArgSpec[idx] |= CMDARG_LOWER;
// Disable greedy argument flag if set
if (m_ArgSpec[idx] & CMDARG_GREEDY)
{
m_ArgSpec[idx] ^= CMDARG_GREEDY;
}
} break;
// Is this a uppercase string?
case 'u':
{
m_ArgSpec[idx] |= CMDARG_STRING;
m_ArgSpec[idx] |= CMDARG_UPPER;
// Disable greedy argument flag if set
if (m_ArgSpec[idx] & CMDARG_GREEDY)
{
m_ArgSpec[idx] ^= CMDARG_GREEDY;
}
} break;
// Unknown type!
default: STHROWF("Unknown type specifier (%c) at argument: %u", *str, idx);
}
}
}
}
catch (const Sqrat::Exception & e)
{
// Reset all argument specifiers if failed
memset(m_ArgSpec, CMDARG_ANY, sizeof(m_ArgSpec));
// Propagate the exception back to the caller
throw e;
}
// Attempt to generate an informational message
GenerateInfo(false);
}
/* ------------------------------------------------------------------------------------------------
* Forward the call to run a command.
*/
static Int32 Cmd_Run(Int32 invoker, CSStr command)
{
return CmdManager::Get().Run(invoker, command);
}
// ------------------------------------------------------------------------------------------------
static void Cmd_Sort()
{
CmdManager::Get().Sort();
}
// ------------------------------------------------------------------------------------------------
static Uint32 Cmd_Count()
{
return CmdManager::Get().Count();
}
// ------------------------------------------------------------------------------------------------
static const Object & Cmd_FindByName(CSStr name)
{
// Validate the specified name
ValidateName(name);
// Now perform the requested search
return CmdManager::Get().FindByName(name);
}
// ------------------------------------------------------------------------------------------------
static Function & Cmd_GetOnFail()
{
return CmdManager::Get().GetOnFail();
}
// ------------------------------------------------------------------------------------------------
static void Cmd_SetOnFail(Object & env, Function & func)
{
CmdManager::Get().SetOnFail(env, func);
}
// ------------------------------------------------------------------------------------------------
static Function & Cmd_GetOnAuth()
{
return CmdManager::Get().GetOnAuth();
}
// ------------------------------------------------------------------------------------------------
static void Cmd_SetOnAuth(Object & env, Function & func)
{
CmdManager::Get().SetOnAuth(env, func);
}
// ------------------------------------------------------------------------------------------------
static bool Cmd_IsContext()
{
return CmdManager::Get().IsContext();
}
// ------------------------------------------------------------------------------------------------
static Object & Cmd_GetInvoker()
{
return Core::Get().GetPlayer(CmdManager::Get().GetInvoker()).mObj;
}
// ------------------------------------------------------------------------------------------------
static Int32 Cmd_GetInvokerID()
{
return CmdManager::Get().GetInvoker();
}
// ------------------------------------------------------------------------------------------------
static const Object & Cmd_GetObject()
{
return CmdManager::Get().GetObject();
}
// ------------------------------------------------------------------------------------------------
static const String & Cmd_GetCommand()
{
return CmdManager::Get().GetCommand();
}
// ------------------------------------------------------------------------------------------------
static const String & Cmd_GetArgument()
{
return CmdManager::Get().GetArgument();
}
// ------------------------------------------------------------------------------------------------
Object & Cmd_Create(CSStr name)
{
return CmdManager::Get().Create(name);
}
Object & Cmd_Create(CSStr name, CSStr spec)
{
return CmdManager::Get().Create(name, spec);
}
Object & Cmd_Create(CSStr name, CSStr spec, Array & tags)
{
return CmdManager::Get().Create(name, spec, tags);
}
Object & Cmd_Create(CSStr name, CSStr spec, Uint8 min, Uint8 max)
{
return CmdManager::Get().Create(name,spec, min, max);
}
Object & Cmd_Create(CSStr name, CSStr spec, Array & tags, Uint8 min, Uint8 max)
{
return CmdManager::Get().Create(name, spec, tags, min, max);
}
// ================================================================================================
void Register_Command(HSQUIRRELVM vm)
{
Table cmdns(vm);
cmdns.Bind(_SC("Listener"), Class< CmdListener, NoConstructor< CmdListener > >(vm, _SC("SqCmdListener"))
// Meta-methods
.Func(_SC("_cmp"), &CmdListener::Cmp)
.SquirrelFunc(_SC("_typename"), &CmdListener::Typename)
.Func(_SC("_tostring"), &CmdListener::ToString)
// Member Properties
.Prop(_SC("Attached"), &CmdListener::Attached)
.Prop(_SC("Name"), &CmdListener::GetName, &CmdListener::SetName)
.Prop(_SC("Spec"), &CmdListener::GetSpec, &CmdListener::SetSpec)
.Prop(_SC("Specifier"), &CmdListener::GetSpec, &CmdListener::SetSpec)
.Prop(_SC("Tags"), &CmdListener::GetArgTags, &CmdListener::SetArgTags)
.Prop(_SC("Help"), &CmdListener::GetHelp, &CmdListener::SetHelp)
.Prop(_SC("Info"), &CmdListener::GetInfo, &CmdListener::SetInfo)
.Prop(_SC("Authority"), &CmdListener::GetAuthority, &CmdListener::SetAuthority)
.Prop(_SC("Protected"), &CmdListener::GetProtected, &CmdListener::SetProtected)
.Prop(_SC("Suspended"), &CmdListener::GetSuspended, &CmdListener::SetSuspended)
.Prop(_SC("Associate"), &CmdListener::GetAssociate, &CmdListener::SetAssociate)
.Prop(_SC("MinArgs"), &CmdListener::GetMinArgC, &CmdListener::SetMinArgC)
.Prop(_SC("MaxArgs"), &CmdListener::GetMaxArgC, &CmdListener::SetMaxArgC)
.Prop(_SC("OnExec"), &CmdListener::GetOnExec)
.Prop(_SC("OnAuth"), &CmdListener::GetOnAuth)
.Prop(_SC("OnPost"), &CmdListener::GetOnPost)
.Prop(_SC("OnFail"), &CmdListener::GetOnFail)
// Member Methods
.Func(_SC("Attach"), &CmdListener::Attach)
.Func(_SC("Detach"), &CmdListener::Detach)
.Func(_SC("BindExec"), &CmdListener::SetOnExec)
.Func(_SC("BindAuth"), &CmdListener::SetOnAuth)
.Func(_SC("BindPost"), &CmdListener::SetOnPost)
.Func(_SC("BindFail"), &CmdListener::SetOnFail)
.Func(_SC("GetArgTag"), &CmdListener::GetArgTag)
.Func(_SC("SetArgTag"), &CmdListener::SetArgTag)
.Func(_SC("GenerateInfo"), &CmdListener::GenerateInfo)
.Func(_SC("ArgCheck"), &CmdListener::ArgCheck)
.Func(_SC("AuthCheck"), &CmdListener::AuthCheck)
.Func(_SC("AuthCheckID"), &CmdListener::AuthCheckID)
);
cmdns.Func(_SC("Run"), &Cmd_Run);
cmdns.Func(_SC("Sort"), &Cmd_Sort);
cmdns.Func(_SC("Count"), &Cmd_Count);
cmdns.Func(_SC("FindByName"), &Cmd_FindByName);
cmdns.Func(_SC("GetOnFail"), &Cmd_GetOnFail);
cmdns.Func(_SC("SetOnFail"), &Cmd_SetOnFail);
cmdns.Func(_SC("BindFail"), &Cmd_SetOnFail);
cmdns.Func(_SC("GetOnAuth"), &Cmd_GetOnAuth);
cmdns.Func(_SC("SetOnAuth"), &Cmd_SetOnAuth);
cmdns.Func(_SC("BindAuth"), &Cmd_SetOnAuth);
cmdns.Func(_SC("Context"), &Cmd_IsContext);
cmdns.Func(_SC("Invoker"), &Cmd_GetInvoker);
cmdns.Func(_SC("InvokerID"), &Cmd_GetInvokerID);
cmdns.Func(_SC("Instance"), &Cmd_GetObject);
cmdns.Func(_SC("Name"), &Cmd_GetCommand);
cmdns.Func(_SC("Command"), &Cmd_GetCommand);
cmdns.Func(_SC("Text"), &Cmd_GetArgument);
cmdns.Func(_SC("Argument"), &Cmd_GetArgument);
cmdns.Overload< Object & (CSStr) >(_SC("Create"), &Cmd_Create);
cmdns.Overload< Object & (CSStr, CSStr) >(_SC("Create"), &Cmd_Create);
cmdns.Overload< Object & (CSStr, CSStr, Array &) >(_SC("Create"), &Cmd_Create);
cmdns.Overload< Object & (CSStr, CSStr, Uint8, Uint8) >(_SC("Create"), &Cmd_Create);
cmdns.Overload< Object & (CSStr, CSStr, Array &, Uint8, Uint8) >(_SC("Create"), &Cmd_Create);
RootTable(vm).Bind(_SC("SqCmd"), cmdns);
ConstTable(vm).Enum(_SC("CmdArg"), Enumeration(vm)
.Const(_SC("Any"), CMDARG_ANY)
.Const(_SC("Integer"), CMDARG_INTEGER)
.Const(_SC("Float"), CMDARG_FLOAT)
.Const(_SC("Boolean"), CMDARG_BOOLEAN)
.Const(_SC("String"), CMDARG_STRING)
.Const(_SC("Lower"), CMDARG_LOWER)
.Const(_SC("Upper"), CMDARG_UPPER)
.Const(_SC("Greedy"), CMDARG_GREEDY)
);
ConstTable(vm).Enum(_SC("CmdErr"), Enumeration(vm)
.Const(_SC("Unknown"), CMDERR_UNKNOWN)
.Const(_SC("EmptyCommand"), CMDERR_EMPTY_COMMAND)
.Const(_SC("InvalidCommand"), CMDERR_INVALID_COMMAND)
.Const(_SC("SyntaxError"), CMDERR_SYNTAX_ERROR)
.Const(_SC("UnknownCommand"), CMDERR_UNKNOWN_COMMAND)
.Const(_SC("MissingExecuter"), CMDERR_MISSING_EXECUTER)
.Const(_SC("InsufficientAuth"), CMDERR_INSUFFICIENT_AUTH)
.Const(_SC("IncompleteArgs"), CMDERR_INCOMPLETE_ARGS)
.Const(_SC("ExtraneousArgs"), CMDERR_EXTRANEOUS_ARGS)
.Const(_SC("UnsupportedArg"), CMDERR_UNSUPPORTED_ARG)
.Const(_SC("BufferOverflow"), CMDERR_BUFFER_OVERFLOW)
.Const(_SC("ExecutionFailed"), CMDERR_EXECUTION_FAILED)
.Const(_SC("ExecutionAborted"), CMDERR_EXECUTION_ABORTED)
.Const(_SC("PostProcessingFailed"), CMDERR_POST_PROCESSING_FAILED)
.Const(_SC("UnresolvedFailure"), CMDERR_UNRESOLVED_FAILURE)
.Const(_SC("Max"), CMDERR_MAX)
);
}
} // Namespace:: SqMod