2016-02-20 23:25:00 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2015-11-07 11:17:39 +01:00
|
|
|
#include "Command.hpp"
|
|
|
|
#include "Core.hpp"
|
2016-02-20 23:25:00 +01:00
|
|
|
#include "Entity/Player.hpp"
|
2015-11-07 11:17:39 +01:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <iterator>
|
|
|
|
#include <algorithm>
|
2015-11-07 11:17:39 +01:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
namespace SqMod {
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
CmdManager * _Cmd = NULL;
|
2015-11-07 11:17:39 +01:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
CSStr CmdArgSpecToStr(Uint8 spec)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
switch (spec)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
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");
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
CmdManager::CmdManager()
|
2016-02-20 23:25:00 +01:00
|
|
|
: m_Buffer(512)
|
|
|
|
, m_Commands()
|
|
|
|
, m_Invoker(SQMOD_UNKNOWN)
|
|
|
|
, m_Command()
|
|
|
|
, m_Argument()
|
|
|
|
, m_Argv()
|
|
|
|
, m_Argc(0)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
/* ... */
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
CmdManager::~CmdManager()
|
|
|
|
{
|
|
|
|
/* ... */
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdManager::Terminate()
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Release the script resources from command instances
|
|
|
|
for (CmdList::iterator itr = m_Commands.begin(); itr != m_Commands.end(); ++itr)
|
|
|
|
{
|
|
|
|
if (itr->second)
|
|
|
|
{
|
2016-02-23 04:23:56 +01:00
|
|
|
itr->second->m_OnExec.ReleaseGently();
|
|
|
|
itr->second->m_OnAuth.ReleaseGently();
|
|
|
|
itr->second->m_OnPost.ReleaseGently();
|
|
|
|
itr->second->m_OnFail.ReleaseGently();
|
2016-02-20 23:25:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Release the script resources from this class
|
|
|
|
m_Argv.clear();
|
2016-02-23 04:23:56 +01:00
|
|
|
m_OnError.ReleaseGently();
|
|
|
|
m_OnAuth.ReleaseGently();
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
Int32 CmdManager::Run(Int32 invoker, CCStr command)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Validate the string command
|
|
|
|
if (!command || strlen(command) <= 0)
|
|
|
|
{
|
|
|
|
SqError(CMDERR_EMPTY_COMMAND, _SC("Invalid or empty command name"), invoker);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-11-07 11:17:39 +01:00
|
|
|
// Save the invoker identifier
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Invoker = invoker;
|
|
|
|
// Skip whitespace until the command name
|
|
|
|
while (*command == ' ') ++command;
|
2015-11-07 11:17:39 +01:00
|
|
|
// Find where the command name ends
|
2016-02-20 23:25:00 +01:00
|
|
|
CCStr split = strchr(command, ' ');
|
|
|
|
// Are there any arguments specified?
|
|
|
|
if (split != NULL)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Save the command name
|
|
|
|
m_Command.assign(command, (split - command));
|
2016-02-21 09:31:10 +01:00
|
|
|
// Skip white space after command name
|
2016-02-20 23:25:00 +01:00
|
|
|
while (*split == ' ') ++split;
|
|
|
|
// Save the command argument
|
|
|
|
m_Argument.assign(split);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
// No arguments specified
|
|
|
|
else
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Command.assign(command);
|
|
|
|
m_Argument.assign("");
|
|
|
|
}
|
|
|
|
// Did anything remain after cleaning?
|
|
|
|
if (m_Command.empty())
|
|
|
|
{
|
|
|
|
SqError(CMDERR_INVALID_COMMAND, _SC("Cannot execute invalid command name"), invoker);
|
|
|
|
return -1;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Attempt to find the specified command
|
|
|
|
CmdList::iterator itr = m_Commands.find(m_Command);
|
|
|
|
// Have we found anything?
|
|
|
|
if (itr == m_Commands.end())
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), m_Command.c_str());
|
|
|
|
return -1;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// Is the command instance valid? (just in case)
|
2016-02-20 23:25:00 +01:00
|
|
|
else if (!itr->second)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Commands.erase(itr);
|
|
|
|
SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), m_Command.c_str());
|
|
|
|
return -1;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// Save the command instance
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Instance = itr->second;
|
|
|
|
// Place a lock on the command
|
|
|
|
m_Instance->m_Locked = true;
|
|
|
|
// Value returned by the command
|
2016-02-21 09:31:10 +01:00
|
|
|
Int32 ret = -1;
|
|
|
|
// Attempt to execute the command
|
|
|
|
try
|
|
|
|
{
|
|
|
|
ret = Exec();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
SqError(CMDERR_EXECUTION_FAILED, _SC("Exceptions occurred during execution"), m_Invoker);
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Remove the lock from the command
|
|
|
|
m_Instance->m_Protected = false;
|
|
|
|
// Release the command instance
|
|
|
|
m_Instance = NULL;
|
|
|
|
// Return the result
|
|
|
|
return ret;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
Int32 CmdManager::Exec()
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Clear previous arguments
|
|
|
|
m_Argv.clear();
|
|
|
|
// Reset the argument counter
|
|
|
|
m_Argc = 0;
|
2016-02-21 09:31:10 +01:00
|
|
|
// Make sure the invoker has enough authority to execute this command
|
2016-02-20 23:25:00 +01:00
|
|
|
if (!m_Instance->AuthCheckID(m_Invoker))
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqError(CMDERR_INSUFFICIENT_AUTH, _SC("Insufficient authority to execute command"), m_Invoker);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Command failed
|
2016-02-20 23:25:00 +01:00
|
|
|
return -1;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// Make sure an executer was specified
|
2016-02-20 23:25:00 +01:00
|
|
|
else if (m_Instance->GetOnExec().IsNull())
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqError(CMDERR_MISSING_EXECUTER, _SC("No executer was specified for this command"), m_Invoker);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Command failed
|
2016-02-20 23:25:00 +01:00
|
|
|
return -1;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
// See if there are any arguments to parse
|
2016-02-20 23:25:00 +01:00
|
|
|
else if (!m_Argument.empty() && !Parse())
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
// The error message was reported while parsing
|
2016-02-20 23:25:00 +01:00
|
|
|
return -1;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// Make sure we have enough arguments specified
|
2016-02-20 23:25:00 +01:00
|
|
|
else if (m_Instance->GetMinArgC() > m_Argc)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqError(CMDERR_INCOMPLETE_ARGS, _SC("Incomplete command arguments"), m_Instance->GetMinArgC());
|
2015-11-07 11:17:39 +01:00
|
|
|
// Command failed
|
2016-02-20 23:25:00 +01:00
|
|
|
return -1;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// The check during the parsing may omit the last argument
|
2016-02-20 23:25:00 +01:00
|
|
|
else if (m_Instance->GetMaxArgC() < m_Argc)
|
2015-11-08 20:34:25 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqError(CMDERR_EXTRANEOUS_ARGS, _SC("Extraneous command arguments"), m_Instance->GetMaxArgC());
|
2015-11-08 20:34:25 +01:00
|
|
|
// Command failed
|
2016-02-20 23:25:00 +01:00
|
|
|
return -1;
|
2015-11-08 20:34:25 +01:00
|
|
|
}
|
2015-11-08 22:25:40 +01:00
|
|
|
// Check argument types against the command specifiers
|
2015-11-07 11:17:39 +01:00
|
|
|
for (Uint32 arg = 0; arg < m_Argc; ++arg)
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
if (!m_Instance->ArgCheck(arg, m_Argv[arg].first))
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqError(CMDERR_UNSUPPORTED_ARG, _SC("Unsupported command argument"), arg);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Command failed
|
2016-02-20 23:25:00 +01:00
|
|
|
return -1;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// Result of the command execution
|
|
|
|
SQInteger result = -1;
|
|
|
|
// Do we have to call the command with an associative container?
|
|
|
|
if (m_Instance->m_Associate)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-21 09:31:10 +01:00
|
|
|
// Create the associative container
|
|
|
|
Table args(DefaultVM::Get());
|
|
|
|
// Copy the arguments into the table
|
|
|
|
for (Uint32 arg = 0; arg < m_Argc; ++arg)
|
|
|
|
{
|
|
|
|
// Do we have use the argument index as the key?
|
|
|
|
if (m_Instance->m_ArgTags[arg].empty())
|
|
|
|
{
|
|
|
|
args.SetValue(SQInteger(arg), m_Argv[arg].second);
|
|
|
|
}
|
|
|
|
// Nope, we have a name for this argument!
|
|
|
|
else
|
|
|
|
{
|
|
|
|
args.SetValue(m_Instance->m_ArgTags[arg].c_str(), m_Argv[arg].second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Attempt to execute the command with the specified arguments
|
|
|
|
result = m_Instance->Execute(_Core->GetPlayer(m_Invoker).mObj, args);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Reserve an array for the extracted arguments
|
|
|
|
Array args(DefaultVM::Get(), m_Argc);
|
|
|
|
// Copy the arguments into the array
|
|
|
|
for (Uint32 arg = 0; arg < m_Argc; ++arg)
|
|
|
|
{
|
|
|
|
args.Bind(SQInteger(arg), m_Argv[arg].second);
|
|
|
|
}
|
|
|
|
// Attempt to execute the command with the specified arguments
|
|
|
|
result = m_Instance->Execute(_Core->GetPlayer(m_Invoker).mObj, args);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// See if an error occurred or an exception was thrown
|
2015-11-07 11:17:39 +01:00
|
|
|
if (Error::Occurred(DefaultVM::Get()))
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqError(CMDERR_EXECUTION_FAILED, _SC("Command execution failed"),
|
|
|
|
Error::Message(DefaultVM::Get()).c_str());
|
|
|
|
if (!m_Instance->m_OnFail.IsNull())
|
|
|
|
{
|
|
|
|
m_Instance->m_OnFail.Execute(_Core->GetPlayer(m_Invoker).mObj, result);
|
|
|
|
}
|
|
|
|
// Result is invalid at this point
|
|
|
|
result = -1;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// See if the command failed explicitly
|
2015-11-07 11:17:39 +01:00
|
|
|
else if (!result)
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqError(CMDERR_EXECUTION_FAILED, _SC("Command execution failed"),
|
|
|
|
_SC("executor evaluated to false"));
|
|
|
|
if (!m_Instance->m_OnFail.IsNull())
|
|
|
|
{
|
|
|
|
m_Instance->m_OnFail.Execute(_Core->GetPlayer(m_Invoker).mObj, result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!m_Instance->m_OnPost.IsNull())
|
|
|
|
{
|
|
|
|
m_Instance->m_OnPost.Execute(_Core->GetPlayer(m_Invoker).mObj, result);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// Return the result
|
|
|
|
return Int32(result);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
bool CmdManager::Parse()
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Is there anything to parse?
|
|
|
|
if (m_Argument.empty())
|
|
|
|
{
|
|
|
|
return true; /* Done parsing */
|
|
|
|
}
|
|
|
|
// Obtain the flags of the currently processed argument
|
2016-02-21 09:31:10 +01:00
|
|
|
Uint8 arg_flags = m_Instance->m_ArgSpec[m_Argc];
|
2016-02-20 23:25:00 +01:00
|
|
|
// Adjust the internal buffer if necessary (mostly never)
|
|
|
|
m_Buffer.Adjust< SQChar >(m_Argument.size());
|
|
|
|
// The iterator to the currently processed character
|
|
|
|
String::iterator itr = m_Argument.begin();
|
2016-02-21 09:31:10 +01:00
|
|
|
// Previous and currently processed character
|
2016-02-20 23:25:00 +01:00
|
|
|
SQChar prev = 0, elem = 0;
|
|
|
|
// Maximum arguments allowed to be processed
|
2016-02-21 09:31:10 +01:00
|
|
|
const Uint8 max_arg = m_Instance->m_MaxArgc;
|
2016-02-20 23:25:00 +01:00
|
|
|
// Process loop result
|
2015-11-07 11:17:39 +01:00
|
|
|
bool good = true;
|
|
|
|
// Process the specified command text
|
|
|
|
while (good)
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Extract the current characters before advancing
|
|
|
|
prev = elem, elem = *itr;
|
2015-11-07 11:17:39 +01:00
|
|
|
// See if there's anything left to parse
|
2016-02-20 23:25:00 +01:00
|
|
|
if (elem == 0)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Early check to prevent parsing extraneous arguments
|
|
|
|
else if (m_Argc >= max_arg)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqError(CMDERR_EXTRANEOUS_ARGS, _SC("Extraneous command arguments"), max_arg);
|
|
|
|
// Parsing aborted
|
2015-11-07 11:17:39 +01:00
|
|
|
good = false;
|
|
|
|
// Stop parsing
|
|
|
|
break;
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Is this a greedy argument?
|
|
|
|
else if (arg_flags & CMDARG_GREEDY)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Skip whitespace
|
|
|
|
while (*itr == ' ' && itr != m_Argument.end()) ++itr;
|
|
|
|
// Anything left to copy?
|
|
|
|
if (itr != m_Argument.end())
|
|
|
|
{
|
|
|
|
// Transform it into a script object
|
|
|
|
sq_pushstring(DefaultVM::Get(), &(*itr), std::distance(itr, m_Argument.end()));
|
|
|
|
}
|
|
|
|
// Just push an empty string
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sq_pushstring(DefaultVM::Get(), _SC(""), 0);
|
|
|
|
}
|
|
|
|
// Get the object from the stack
|
|
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
|
|
|
// Pop the created object from the stack
|
|
|
|
if (!var.value.IsNull())
|
|
|
|
{
|
|
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
|
|
}
|
|
|
|
// Add it to the argument list along with it's type
|
|
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_STRING, var.value));
|
|
|
|
// Include this argument into the count
|
|
|
|
++m_Argc;
|
|
|
|
// Nothing left to parse
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Do we have to extract a string argument?
|
|
|
|
else if ((elem == '\'' || elem == '"') && prev != '\\')
|
|
|
|
{
|
2016-02-21 09:31:10 +01:00
|
|
|
// Obtain the beginning and ending of the internal buffer
|
2016-02-20 23:25:00 +01:00
|
|
|
SStr str = m_Buffer.Begin< SQChar >();
|
|
|
|
CSStr end = (m_Buffer.End< SQChar >()-1); /* + null */
|
|
|
|
// Save the closing quote type
|
|
|
|
SQChar close = elem;
|
|
|
|
// Skip the opening quote
|
|
|
|
++itr;
|
2015-11-07 11:17:39 +01:00
|
|
|
// Attempt to consume the string argument
|
|
|
|
while (good)
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Extract the current characters before advancing
|
|
|
|
prev = elem, elem = *itr;
|
2015-11-07 11:17:39 +01:00
|
|
|
// See if there's anything left to parse
|
2016-02-20 23:25:00 +01:00
|
|
|
if (elem == 0)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqError(CMDERR_SYNTAX_ERROR, _SC("String argument not closed properly"), m_Argc);
|
|
|
|
// Parsing aborted
|
2015-11-07 11:17:39 +01:00
|
|
|
good = false;
|
|
|
|
// Stop parsing
|
|
|
|
break;
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// First un-escaped matching quote character ends the argument
|
|
|
|
else if (elem == close)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
// Was this not escaped?
|
2016-02-20 23:25:00 +01:00
|
|
|
if (prev != '\\')
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Terminate the string value in the internal buffer
|
|
|
|
*str = 0;
|
2015-11-07 11:17:39 +01:00
|
|
|
// Stop parsing
|
|
|
|
break;
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Overwrite last character when replicating
|
2015-11-07 11:17:39 +01:00
|
|
|
else
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
--str;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// See if the internal buffer needs to scale
|
|
|
|
else if (str >= end)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// We should already have a buffer as big as the entire command!
|
|
|
|
SqError(CMDERR_BUFFER_OVERFLOW, _SC("Command buffer was exceeded unexpectedly"), m_Invoker);
|
|
|
|
// Parsing aborted
|
|
|
|
good = false;
|
|
|
|
// Stop parsing
|
|
|
|
break;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Simply replicate the character to the internal buffer
|
|
|
|
*(str++) = elem;
|
2016-02-21 09:31:10 +01:00
|
|
|
// Advance to the next character
|
2016-02-20 23:25:00 +01:00
|
|
|
++itr;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
// See if the argument was valid
|
|
|
|
if (!good)
|
|
|
|
{
|
|
|
|
// Propagate failure
|
|
|
|
break;
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Do we have to make the string lowercase?
|
|
|
|
else if (arg_flags & CMDARG_LOWER)
|
|
|
|
{
|
|
|
|
for (SStr chr = m_Buffer.Begin< SQChar >(); chr <= str; ++chr)
|
|
|
|
{
|
|
|
|
*chr = (SQChar)tolower(*chr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Do we have to make the string uppercase?
|
|
|
|
else if (arg_flags & CMDARG_UPPER)
|
|
|
|
{
|
|
|
|
for (SStr chr = m_Buffer.Begin< SQChar >(); chr <= str; ++chr)
|
|
|
|
{
|
|
|
|
*chr = (SQChar)toupper(*chr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Transform it into a script object
|
|
|
|
sq_pushstring(DefaultVM::Get(), m_Buffer.Get< SQChar >(), str - m_Buffer.Begin< SQChar >());
|
|
|
|
// Get the object from the stack
|
|
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Pop the created object from the stack
|
|
|
|
if (!var.value.IsNull())
|
|
|
|
{
|
|
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
|
|
}
|
|
|
|
// Add it to the argument list along with it's type
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_STRING, var.value));
|
2016-02-21 09:31:10 +01:00
|
|
|
// Advance to the next argument and obtain its flags
|
|
|
|
arg_flags = m_Instance->m_ArgSpec[++m_Argc];
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// Ignore space characters until another valid character is found
|
2016-02-20 23:25:00 +01:00
|
|
|
else if (elem != ' ' && (prev == ' ' || prev == 0))
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Find the first character that marks the end of the argument
|
|
|
|
String::iterator pos = std::find(String::iterator(itr), m_Argument.end(), ' ');
|
2016-02-21 09:31:10 +01:00
|
|
|
// Copy all characters within range into the internal buffer
|
2016-02-20 23:25:00 +01:00
|
|
|
const Uint32 sz = m_Buffer.Write(0, &(*itr), std::distance(itr, pos));
|
|
|
|
// Update the main iterator position
|
|
|
|
itr = pos;
|
|
|
|
// Update the current character
|
|
|
|
elem = *itr;
|
|
|
|
// Make sure the argument string is null terminated
|
|
|
|
m_Buffer.At< SQChar >(sz) = 0;
|
|
|
|
// Used to exclude all other checks when a valid type was identified
|
|
|
|
bool identified = false;
|
2015-11-07 11:17:39 +01:00
|
|
|
// Attempt to treat the value as an integer number
|
2016-02-20 23:25:00 +01:00
|
|
|
if (!identified)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Let's us know if the whole argument was part of the resulted value
|
|
|
|
CStr next = NULL;
|
|
|
|
// Attempt to extract the integer value from the string
|
|
|
|
Int64 value = strtol(m_Buffer.Data(), &next, 10);
|
|
|
|
// See if this whole string was indeed an integer
|
|
|
|
if (next == &m_Buffer.At< SQChar >(sz))
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Transform it into a script object
|
2016-02-21 09:31:10 +01:00
|
|
|
Var< SQInteger >::push(DefaultVM::Get(), SQInteger(value));
|
2016-02-20 23:25:00 +01:00
|
|
|
// Get the object from the stack
|
|
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Pop the created object from the stack
|
|
|
|
if (!var.value.IsNull())
|
|
|
|
{
|
|
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
|
|
}
|
|
|
|
// Add it to the argument list along with it's type
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_INTEGER, var.value));
|
|
|
|
// We identified the correct value
|
|
|
|
identified = true;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Attempt to treat the value as an floating point number
|
|
|
|
if (!identified)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Let's us know if the whole argument was part of the resulted value
|
|
|
|
CStr next = NULL;
|
2016-02-21 09:31:10 +01:00
|
|
|
// Attempt to extract the floating point value from the string
|
2016-02-20 23:25:00 +01:00
|
|
|
Float64 value = strtod(m_Buffer.Data(), &next);
|
2016-02-21 09:31:10 +01:00
|
|
|
// See if this whole string was indeed an floating point
|
2016-02-20 23:25:00 +01:00
|
|
|
if (next == &m_Buffer.At< SQChar >(sz))
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Transform it into a script object
|
2016-02-21 09:31:10 +01:00
|
|
|
Var< SQFloat >::push(DefaultVM::Get(), SQFloat(value));
|
2016-02-20 23:25:00 +01:00
|
|
|
// Get the object from the stack
|
|
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Pop the created object from the stack
|
|
|
|
if (!var.value.IsNull())
|
|
|
|
{
|
|
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
|
|
}
|
|
|
|
// Add it to the argument list along with it's type
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_FLOAT, var.value));
|
|
|
|
// We identified the correct value
|
|
|
|
identified = true;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Attempt to treat the value as a boolean if possible
|
|
|
|
if (!identified && sz <= 6)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Allocate memory for enough data to form a boolean value
|
|
|
|
SQChar lc[6];
|
|
|
|
// Fill the temporary buffer with data from the internal buffer
|
|
|
|
snprintf (lc, 6, "%.5s", m_Buffer.Data());
|
|
|
|
// Convert all characters to lowercase
|
|
|
|
for (Uint32 i = 0; i < 5; ++i)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
lc[i] = tolower(lc[i]);
|
|
|
|
}
|
|
|
|
// Is this a boolean true value?
|
|
|
|
if (strcmp(m_Buffer.Data(), "true") == 0 || strcmp(m_Buffer.Data(), "on") == 0)
|
|
|
|
{
|
|
|
|
// Transform it into a script object
|
2015-11-07 11:17:39 +01:00
|
|
|
Var< bool >::push(DefaultVM::Get(), true);
|
2016-02-20 23:25:00 +01:00
|
|
|
// Get the object from the stack
|
|
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Pop the created object from the stack
|
|
|
|
if (!var.value.IsNull())
|
|
|
|
{
|
|
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
|
|
}
|
|
|
|
// Add it to the argument list along with it's type
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_BOOLEAN, var.value));
|
|
|
|
// We identified the correct value
|
|
|
|
identified = true;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Is this a boolean false value?
|
|
|
|
else if (strcmp(m_Buffer.Data(), "false") == 0 || strcmp(m_Buffer.Data(), "off") == 0)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Transform it into a script object
|
2015-11-07 11:17:39 +01:00
|
|
|
Var< bool >::push(DefaultVM::Get(), false);
|
2016-02-20 23:25:00 +01:00
|
|
|
// Get the object from the stack
|
|
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Pop the created object from the stack
|
|
|
|
if (!var.value.IsNull())
|
|
|
|
{
|
|
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
|
|
}
|
|
|
|
// Add it to the argument list along with it's type
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_BOOLEAN, var.value));
|
|
|
|
// We identified the correct value
|
|
|
|
identified = true;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// If everything else failed then simply treat the value as a string
|
2016-02-20 23:25:00 +01:00
|
|
|
if (!identified)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Do we have to make the string lowercase?
|
|
|
|
if (arg_flags & CMDARG_LOWER)
|
|
|
|
{
|
|
|
|
for (Uint32 n = 0; n < sz; ++n)
|
|
|
|
{
|
|
|
|
m_Buffer.At< SQChar >(n) = (SQChar)tolower(m_Buffer.At< SQChar >(n));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Do we have to make the string uppercase?
|
|
|
|
else if (arg_flags & CMDARG_UPPER)
|
|
|
|
{
|
|
|
|
for (Uint32 n = 0; n < sz; ++n)
|
|
|
|
{
|
|
|
|
m_Buffer.At< SQChar >(n) = (SQChar)toupper(m_Buffer.At< SQChar >(n));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Transform it into a script object
|
|
|
|
sq_pushstring(DefaultVM::Get(), m_Buffer.Get< SQChar >(), sz);
|
|
|
|
// Get the object from the stack
|
|
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Pop the created object from the stack
|
|
|
|
if (!var.value.IsNull())
|
|
|
|
{
|
|
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
|
|
}
|
|
|
|
// Add it to the argument list along with it's type
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_STRING, var.value));
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// Advance to the next argument and obtain its flags
|
|
|
|
arg_flags = m_Instance->m_ArgSpec[++m_Argc];
|
2016-02-20 23:25:00 +01:00
|
|
|
}
|
|
|
|
// Is there anything left to parse?
|
|
|
|
if (itr >= m_Argument.end())
|
|
|
|
{
|
|
|
|
break;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// Advance to the next character
|
2016-02-20 23:25:00 +01:00
|
|
|
++itr;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
// Return whether the parsing was successful
|
|
|
|
return good;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::Init(CSStr name, CSStr spec, Array & tags, Uint8 min, Uint8 max)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Name.assign("");
|
2016-02-21 09:31:10 +01:00
|
|
|
// Initialize the specifiers and tags to default values
|
2016-02-20 23:25:00 +01:00
|
|
|
for (Uint8 n = 0; n < SQMOD_MAX_CMD_ARGS; ++n)
|
|
|
|
{
|
|
|
|
m_ArgSpec[n] = CMDARG_ANY;
|
|
|
|
m_ArgTags[n].assign("");
|
|
|
|
}
|
|
|
|
m_MinArgc = 0;
|
|
|
|
m_MaxArgc = (SQMOD_MAX_CMD_ARGS - 1);
|
|
|
|
m_Spec.assign("");
|
|
|
|
m_Help.assign("");
|
|
|
|
m_Info.assign("");
|
|
|
|
m_OnAuth = _Cmd->GetOnAuth();
|
|
|
|
m_Authority = -1;
|
|
|
|
m_Protected = false;
|
|
|
|
m_Suspended = false;
|
|
|
|
m_Associate = false;
|
|
|
|
m_Locked = false;
|
|
|
|
// Set the 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);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
CmdListener::CmdListener(CSStr name)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
Init(name, _SC(""), NullArray(), 0, SQMOD_MAX_CMD_ARGS-1);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
2016-02-20 23:25:00 +01:00
|
|
|
CmdListener::CmdListener(CSStr name, CSStr spec)
|
2015-11-08 21:31:03 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
Init(name, spec, NullArray(), 0, SQMOD_MAX_CMD_ARGS-1);
|
2015-11-08 21:31:03 +01:00
|
|
|
}
|
|
|
|
|
2016-02-20 23:25:00 +01:00
|
|
|
CmdListener::CmdListener(CSStr name, CSStr spec, Array & tags)
|
2015-11-08 19:53:50 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
Init(name, spec, tags, 0, SQMOD_MAX_CMD_ARGS-1);
|
2015-11-08 19:53:50 +01:00
|
|
|
}
|
|
|
|
|
2016-02-20 23:25:00 +01:00
|
|
|
CmdListener::CmdListener(CSStr name, CSStr spec, Uint8 min, Uint8 max)
|
2015-11-08 21:31:03 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
Init(name, spec, NullArray(), min, max);
|
2015-11-08 21:31:03 +01:00
|
|
|
}
|
|
|
|
|
2016-02-20 23:25:00 +01:00
|
|
|
CmdListener::CmdListener(CSStr name, CSStr spec, Array & tags, Uint8 min, Uint8 max)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
Init(name, spec, tags, min, max);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
CmdListener::~CmdListener()
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// See the instance must be detached
|
|
|
|
if (!m_Name.empty())
|
|
|
|
_Cmd->Detach(m_Name);
|
|
|
|
// Release callbacks
|
2016-02-23 04:23:56 +01:00
|
|
|
m_OnExec.ReleaseGently();
|
|
|
|
m_OnAuth.ReleaseGently();
|
|
|
|
m_OnPost.ReleaseGently();
|
|
|
|
m_OnFail.ReleaseGently();
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
Int32 CmdListener::Cmp(const CmdListener & o) const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
if (m_Name == o.m_Name)
|
|
|
|
return 0;
|
|
|
|
else if (m_Name.size() > o.m_Name.size())
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
CSStr CmdListener::ToString() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
return m_Name.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
Uint8 CmdListener::GetArgFlags(Uint32 idx) const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
if (idx < SQMOD_MAX_CMD_ARGS)
|
|
|
|
return m_ArgSpec[idx];
|
|
|
|
return CMDARG_ANY;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
CSStr CmdListener::GetName() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
return m_Name.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetName(CSStr name)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
if (m_Locked)
|
|
|
|
SqThrow("Cannot change locked command: %s", m_Name.c_str());
|
|
|
|
else if (!name || strlen(name) <= 0)
|
|
|
|
SqThrow("Invalid command name: null");
|
|
|
|
else
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Detach from the current name if necessary
|
2015-11-07 11:17:39 +01:00
|
|
|
if (!m_Name.empty())
|
2016-02-20 23:25:00 +01:00
|
|
|
_Cmd->Detach(name);
|
|
|
|
// Now it's safe to assign the new name
|
2015-11-07 11:17:39 +01:00
|
|
|
m_Name.assign(name);
|
2016-02-20 23:25:00 +01:00
|
|
|
// We know the new name is valid
|
|
|
|
_Cmd->Attach(m_Name, this);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
CSStr CmdListener::GetSpec() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
return m_Spec.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetSpec(CSStr spec)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
if (ProcSpec(spec))
|
|
|
|
m_Spec.assign(spec);
|
2015-11-08 21:31:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
Array CmdListener::GetArgTags() const
|
|
|
|
{
|
|
|
|
// Allocate an array to encapsulate all tags
|
2016-02-20 23:25:00 +01:00
|
|
|
Array arr(DefaultVM::Get(), SQMOD_MAX_CMD_ARGS);
|
2015-11-08 21:31:03 +01:00
|
|
|
// Put the tags to the allocated array
|
2016-02-20 23:25:00 +01:00
|
|
|
for (Uint32 arg = 0; arg < SQMOD_MAX_CMD_ARGS; ++arg)
|
|
|
|
arr.SetValue(arg, m_ArgTags[arg]);
|
2015-11-08 21:31:03 +01:00
|
|
|
// Return the array with the tags
|
|
|
|
return arr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void CmdListener::SetArgTags(Array & tags)
|
|
|
|
{
|
|
|
|
// Attempt to retrieve the number of specified tags
|
2016-02-20 23:25:00 +01:00
|
|
|
const Uint32 max = static_cast< Uint32 >(tags.Length());
|
2015-11-08 21:31:03 +01:00
|
|
|
// If no tags were specified then clear current tags
|
2016-02-20 23:25:00 +01:00
|
|
|
if (tags.IsNull() || max == 0)
|
2015-11-08 21:31:03 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
for (Uint8 n = 0; n < SQMOD_MAX_CMD_ARGS; ++n)
|
|
|
|
{
|
|
|
|
m_ArgTags[n].assign("");
|
|
|
|
}
|
2015-11-08 21:31:03 +01:00
|
|
|
}
|
|
|
|
// See if we're in range
|
2016-02-20 23:25:00 +01:00
|
|
|
else if (max < SQMOD_MAX_CMD_ARGS)
|
2015-11-08 21:31:03 +01:00
|
|
|
// Attempt to get all arguments in one go
|
2016-02-20 23:25:00 +01:00
|
|
|
tags.GetArray(m_ArgTags, max);
|
2015-11-08 21:31:03 +01:00
|
|
|
else
|
2016-02-20 23:25:00 +01:00
|
|
|
SqThrow("Argument tag (%u) is out of range (%u)", max, SQMOD_MAX_CMD_ARGS);
|
2015-11-08 21:31:03 +01:00
|
|
|
}
|
|
|
|
|
2015-11-07 11:17:39 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
CSStr CmdListener::GetHelp() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
return m_Help.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetHelp(CSStr help)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
m_Help.assign(help);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
CSStr CmdListener::GetInfo() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
return m_Info.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetInfo(CSStr info)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
m_Info.assign(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
Int32 CmdListener::GetAuthority() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return m_Authority;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetAuthority(Int32 level)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Authority = level;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
bool CmdListener::GetProtected() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return m_Protected;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetProtected(bool toggle)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Protected = toggle;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
bool CmdListener::GetSuspended() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return m_Suspended;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetSuspended(bool toggle)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Suspended = toggle;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
bool CmdListener::GetAssociate() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return m_Associate;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetAssociate(bool toggle)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Associate = toggle;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
Uint8 CmdListener::GetMinArgC() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return m_MinArgc;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetMinArgC(Uint8 val)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Assuming (m_MaxArgc < SQMOD_MAX_CMD_ARGS) is always true
|
|
|
|
if (val <= m_MaxArgc)
|
|
|
|
m_MinArgc = val;
|
|
|
|
else
|
|
|
|
SqThrow("Minimum argument (%u) exceeds maximum (%u)", val, m_MaxArgc);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
2015-11-08 19:53:50 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
Uint8 CmdListener::GetMaxArgC() const
|
2015-11-08 19:53:50 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return m_MaxArgc;
|
2015-11-08 19:53:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetMaxArgC(Uint8 val)
|
2015-11-08 19:53:50 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
if (val < SQMOD_MAX_CMD_ARGS && val >= m_MinArgc)
|
|
|
|
m_MaxArgc = val;
|
|
|
|
else if (val < m_MinArgc)
|
|
|
|
SqThrow("Minimum argument (%u) exceeds maximum (%u)", m_MinArgc, val);
|
|
|
|
else
|
|
|
|
SqThrow("Argument (%u) is out of total range (%u)", val, SQMOD_MAX_CMD_ARGS);
|
2015-11-08 19:53:50 +01:00
|
|
|
}
|
|
|
|
|
2015-11-07 11:17:39 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
bool CmdListener::GetLocked() const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return m_Locked;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
Function & CmdListener::GetOnExec()
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return m_OnExec;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void CmdListener::SetOnExec(Object & env, Function & func)
|
|
|
|
{
|
|
|
|
if (!m_Name.empty())
|
|
|
|
m_OnExec = Function(env.GetVM(), env.GetObject(), func.GetFunc());
|
2015-11-07 11:17:39 +01:00
|
|
|
else
|
2016-02-20 23:25:00 +01:00
|
|
|
SqThrow("Invalid commands cannot store script resources");
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
Function & CmdListener::GetOnAuth()
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return m_OnAuth;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
void CmdListener::SetOnAuth(Object & env, Function & func)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
if (!m_Name.empty())
|
|
|
|
m_OnAuth = Function(env.GetVM(), env.GetObject(), func.GetFunc());
|
2015-11-07 11:17:39 +01:00
|
|
|
else
|
2016-02-20 23:25:00 +01:00
|
|
|
SqThrow("Invalid commands cannot store script resources");
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
Function & CmdListener::GetOnPost()
|
|
|
|
{
|
|
|
|
return m_OnPost;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void CmdListener::SetOnPost(Object & env, Function & func)
|
|
|
|
{
|
|
|
|
if (!m_Name.empty())
|
|
|
|
m_OnPost = Function(env.GetVM(), env.GetObject(), func.GetFunc());
|
|
|
|
else
|
|
|
|
SqThrow("Invalid commands cannot store script resources");
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
Function & CmdListener::GetOnFail()
|
|
|
|
{
|
|
|
|
return m_OnFail;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void CmdListener::SetOnFail(Object & env, Function & func)
|
|
|
|
{
|
|
|
|
if (!m_Name.empty())
|
|
|
|
m_OnFail = Function(env.GetVM(), env.GetObject(), func.GetFunc());
|
|
|
|
else
|
|
|
|
SqThrow("Invalid commands cannot store script resources");
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
CSStr CmdListener::GetArgTag(Uint32 arg) const
|
|
|
|
{
|
|
|
|
if (arg < SQMOD_MAX_CMD_ARGS)
|
|
|
|
return m_ArgTags[arg].c_str();
|
|
|
|
SqThrow("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS);
|
|
|
|
return g_EmptyStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void CmdListener::SetArgTag(Uint32 arg, CSStr name)
|
|
|
|
{
|
|
|
|
if (arg < SQMOD_MAX_CMD_ARGS)
|
|
|
|
m_ArgTags[arg].assign(name);
|
|
|
|
else
|
|
|
|
SqThrow("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
2015-11-08 22:25:40 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void CmdListener::GenerateInfo(bool full)
|
|
|
|
{
|
|
|
|
// Clear any previously generated informational message
|
|
|
|
m_Info.clear();
|
|
|
|
// Process each supported command argument
|
2016-02-20 23:25:00 +01:00
|
|
|
for (Uint32 arg = 0; arg < m_MaxArgc; ++arg)
|
2015-11-08 22:25:40 +01:00
|
|
|
{
|
|
|
|
// 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
|
2016-02-20 23:25:00 +01:00
|
|
|
if (!m_ArgTags[idx].empty() || m_ArgSpec[idx] != CMDARG_ANY)
|
2015-11-08 22:25:40 +01:00
|
|
|
{
|
|
|
|
// 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)
|
|
|
|
// Stop the main loop as well
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Begin the argument block
|
|
|
|
m_Info += '<';
|
|
|
|
// If the current argument is beyond minimum then mark it as optional
|
|
|
|
if (arg >= m_MinArgc)
|
|
|
|
m_Info += '*';
|
|
|
|
// If the argument has a tag/name associated then add it as well
|
2016-02-20 23:25:00 +01:00
|
|
|
if (!m_ArgTags[arg].empty())
|
2015-11-08 22:25:40 +01:00
|
|
|
{
|
|
|
|
// Add the name first
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Info += m_ArgTags[arg];
|
2015-11-08 22:25:40 +01:00
|
|
|
// Separate the name from the specifiers
|
|
|
|
m_Info += ':';
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Is this a greedy argument?
|
|
|
|
if (m_ArgSpec[arg] & CMDARG_GREEDY)
|
|
|
|
{
|
|
|
|
m_Info += _SC("...");
|
|
|
|
}
|
2015-11-08 22:25:40 +01:00
|
|
|
// If the argument has any explicit types specified
|
2016-02-20 23:25:00 +01:00
|
|
|
else if (m_ArgSpec[arg] != CMDARG_ANY)
|
2015-11-08 22:25:40 +01:00
|
|
|
{
|
|
|
|
// Does it support integers?
|
2016-02-20 23:25:00 +01:00
|
|
|
if (m_ArgSpec[arg] & CMDARG_INTEGER)
|
2015-11-08 22:25:40 +01:00
|
|
|
m_Info += _SC("integer");
|
|
|
|
// Does it support floats?
|
2016-02-20 23:25:00 +01:00
|
|
|
if (m_ArgSpec[arg] & CMDARG_FLOAT)
|
2015-11-08 22:25:40 +01:00
|
|
|
{
|
|
|
|
// Add a separator if this is not the first enabled type?
|
2016-02-20 23:25:00 +01:00
|
|
|
if (m_Info[m_Info.size()-1] != ':' && m_Info[m_Info.size()-1] != '<')
|
2015-11-08 22:25:40 +01:00
|
|
|
m_Info += ',';
|
|
|
|
// Now add the type name
|
|
|
|
m_Info += _SC("float");
|
|
|
|
}
|
|
|
|
// Does it support booleans?
|
2016-02-20 23:25:00 +01:00
|
|
|
if (m_ArgSpec[arg] & CMDARG_BOOLEAN)
|
2015-11-08 22:25:40 +01:00
|
|
|
{
|
|
|
|
// Add a separator if this is not the first enabled type?
|
2016-02-20 23:25:00 +01:00
|
|
|
if (m_Info[m_Info.size()-1] != ':' && m_Info[m_Info.size()-1] != '<')
|
2015-11-08 22:25:40 +01:00
|
|
|
m_Info += ',';
|
|
|
|
// Now add the type name
|
|
|
|
m_Info += _SC("boolean");
|
|
|
|
}
|
|
|
|
// Does it support strings?
|
2016-02-20 23:25:00 +01:00
|
|
|
if (m_ArgSpec[arg] & CMDARG_STRING)
|
2015-11-08 22:25:40 +01:00
|
|
|
{
|
|
|
|
// Add a separator if this is not the first enabled type?
|
2016-02-20 23:25:00 +01:00
|
|
|
if (m_Info[m_Info.size()-1] != ':' && m_Info[m_Info.size()-1] != '<')
|
2015-11-08 22:25:40 +01:00
|
|
|
m_Info += ',';
|
|
|
|
// Now add the type name
|
|
|
|
m_Info += _SC("string");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Any kind of value is supported by this argument
|
|
|
|
else
|
|
|
|
m_Info += _SC("any");
|
|
|
|
// Stop the argument block
|
|
|
|
m_Info += '>';
|
2016-02-20 23:25:00 +01:00
|
|
|
// Don't process anything after greedy arguments
|
|
|
|
if (m_ArgSpec[arg] & CMDARG_GREEDY)
|
2015-11-08 22:25:40 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
break;
|
2015-11-08 22:25:40 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// If this is not the last argument then add a separator
|
|
|
|
else if (arg+1 != m_MaxArgc)
|
|
|
|
m_Info += ' ';
|
2015-11-08 22:25:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-07 11:17:39 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
bool CmdListener::ArgCheck(Uint32 arg, Uint8 flag) const
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
if (arg < SQMOD_MAX_CMD_ARGS)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
const Uint8 f = m_ArgSpec[arg];
|
|
|
|
return (f == CMDARG_ANY) || /* Requires check? */
|
|
|
|
(f & flag) || /* Exact match? */
|
|
|
|
(f & CMDARG_GREEDY && flag & CMDARG_STRING);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
SqThrow("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS);
|
2015-11-07 11:17:39 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-08 22:52:56 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
bool CmdListener::AuthCheck(CPlayer & player)
|
2015-11-08 22:52:56 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return AuthCheckID(player.GetID());
|
2015-11-08 22:52:56 +01:00
|
|
|
}
|
|
|
|
|
2015-11-07 11:17:39 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
bool CmdListener::AuthCheckID(Int32 id)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Do we need explicit authority verification?
|
|
|
|
if (!m_Protected)
|
|
|
|
return true;
|
2015-11-07 11:17:39 +01:00
|
|
|
// Allow execution by default
|
|
|
|
bool allow = true;
|
2016-02-20 23:25:00 +01:00
|
|
|
// Was there a custom authority inspector specified?
|
|
|
|
if (!m_OnAuth.IsNull())
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Ask the specified authority inspector if this execution should be allowed
|
|
|
|
SharedPtr< bool > ret = m_OnAuth.Evaluate< bool, Object & >(_Core->GetPlayer(id).mObj);
|
|
|
|
// See what the custom authority inspector said or default to disallow
|
|
|
|
allow = (!ret ? false : *ret);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Can we use the default authority system?
|
|
|
|
else if (m_Authority >= 0)
|
|
|
|
allow = (_Core->GetPlayer(id).mAuthority >= m_Authority);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Return result
|
|
|
|
return allow;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
SQInteger CmdListener::Execute(Object & invoker, Array & args)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// 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);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
bool CmdListener::ProcSpec(CSStr str)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Reset current argument specifiers
|
|
|
|
memset(m_ArgSpec, CMDARG_ANY, sizeof(m_ArgSpec));
|
2015-11-07 11:17:39 +01:00
|
|
|
// Currently processed character
|
|
|
|
SQChar ch = 0;
|
|
|
|
// When parsing may continue
|
|
|
|
bool good = true;
|
|
|
|
// Currently processed argument
|
2016-02-20 23:25:00 +01:00
|
|
|
Uint32 idx = 0;
|
2015-11-07 11:17:39 +01:00
|
|
|
// Process each character in the specified command
|
|
|
|
while (good)
|
|
|
|
{
|
|
|
|
// Extract the current character before advancing
|
|
|
|
ch = *(str++);
|
|
|
|
// See if there are still things left to parse
|
|
|
|
if (ch == 0)
|
|
|
|
// Finished parsing successfully
|
|
|
|
break;
|
|
|
|
// See if we need to move to the next argument
|
|
|
|
else if (ch == '|')
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
if (idx >= SQMOD_MAX_CMD_ARGS)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqThrow("Extraneous type specifiers: %d >= %d", idx, SQMOD_MAX_CMD_ARGS);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Parsing failed
|
|
|
|
good = false;
|
|
|
|
// Stop parsing
|
|
|
|
break;
|
|
|
|
}
|
2016-02-21 09:31:10 +01:00
|
|
|
// Advance to the next argument
|
2015-11-07 11:17:39 +01:00
|
|
|
++idx;
|
|
|
|
}
|
|
|
|
// Simply ignore a type specifier delimiter
|
|
|
|
else if (ch != ',')
|
|
|
|
{
|
|
|
|
// Consume space when found
|
|
|
|
if (ch == ' ')
|
|
|
|
while (good)
|
|
|
|
{
|
|
|
|
ch = *(str++);
|
|
|
|
// Stop when the text ends or on the first non-space character
|
|
|
|
if (ch == 0 || ch != ' ')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// See if there is a specifier left
|
|
|
|
if (!good)
|
2016-02-20 23:25:00 +01:00
|
|
|
// Propagate the stop
|
2015-11-07 11:17:39 +01:00
|
|
|
break;
|
|
|
|
// Apply the type specifier
|
|
|
|
switch(ch)
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// 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;
|
2015-11-07 11:17:39 +01:00
|
|
|
// Unknown type!
|
|
|
|
default:
|
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
SqThrow("Unknown type specifier (%c) at argument: %u", ch, idx);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Parsing failed
|
|
|
|
good = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Reset all argument specifiers if failed
|
|
|
|
if (!good)
|
2016-02-20 23:25:00 +01:00
|
|
|
memset(m_ArgSpec, CMDARG_ANY, sizeof(m_ArgSpec));
|
2015-11-08 22:25:40 +01:00
|
|
|
// Attempt to generate an informational message
|
|
|
|
GenerateInfo(false);
|
2015-11-07 11:17:39 +01:00
|
|
|
// Return whether the parsing was successful
|
|
|
|
return good;
|
|
|
|
}
|
|
|
|
|
2016-02-23 04:23:56 +01:00
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
|
|
* Forward the call to run a command.
|
|
|
|
*/
|
|
|
|
Int32 RunCommand(Int32 invoker, CSStr command)
|
|
|
|
{
|
|
|
|
return _Cmd->Run(invoker, command);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
|
|
* Forward the call to terminate the command system.
|
|
|
|
*/
|
|
|
|
void TerminateCommand()
|
|
|
|
{
|
|
|
|
_Cmd->Terminate();
|
|
|
|
}
|
|
|
|
|
2015-11-07 11:17:39 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2015-11-08 19:53:50 +01:00
|
|
|
static Function & Cmd_GetOnError()
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
return _Cmd->GetOnError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
static void Cmd_SetOnError(Object & env, Function & func)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
_Cmd->SetOnError(env, func);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2015-11-08 19:53:50 +01:00
|
|
|
static Function & Cmd_GetOnAuth()
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
|
|
|
return _Cmd->GetOnAuth();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
static void Cmd_SetOnAuth(Object & env, Function & func)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
_Cmd->SetOnAuth(env, func);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
static Object & Cmd_GetInvoker()
|
2015-11-08 19:53:50 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return _Core->GetPlayer(_Cmd->GetInvoker()).mObj;
|
2015-11-08 19:53:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
static Int32 Cmd_GetInvokerID()
|
2015-11-08 19:53:50 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return _Cmd->GetInvoker();
|
2015-11-08 19:53:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
static CSStr Cmd_GetCommand()
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return _Cmd->GetCommand();
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
static CSStr Cmd_GetArgument()
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
return _Cmd->GetArgument();
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ================================================================================================
|
2016-02-20 23:25:00 +01:00
|
|
|
void Register_Command(HSQUIRRELVM vm)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
Table cmdns(vm);
|
2015-11-07 11:17:39 +01:00
|
|
|
|
2016-02-20 23:25:00 +01:00
|
|
|
cmdns.Bind(_SC("Listener"), Class< CmdListener, NoCopy< CmdListener > >(vm, _SC("Listener"))
|
2015-11-07 11:17:39 +01:00
|
|
|
/* Constructors */
|
2016-02-20 23:25:00 +01:00
|
|
|
.Ctor< CSStr >()
|
|
|
|
.Ctor< CSStr, CSStr >()
|
|
|
|
.Ctor< CSStr, CSStr, Array & >()
|
|
|
|
.Ctor< CSStr, CSStr, Uint8, Uint8 >()
|
|
|
|
.Ctor< CSStr, CSStr, Array &, Uint8, Uint8 >()
|
2015-11-07 11:17:39 +01:00
|
|
|
/* Metamethods */
|
|
|
|
.Func(_SC("_cmp"), &CmdListener::Cmp)
|
|
|
|
.Func(_SC("_tostring"), &CmdListener::ToString)
|
|
|
|
/* Properties */
|
2016-02-20 23:25:00 +01:00
|
|
|
.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("Locked"), &CmdListener::GetLocked)
|
|
|
|
.Prop(_SC("OnExec"), &CmdListener::GetOnExec)
|
|
|
|
.Prop(_SC("OnAuth"), &CmdListener::GetOnAuth)
|
|
|
|
.Prop(_SC("OnPost"), &CmdListener::GetOnPost)
|
|
|
|
.Prop(_SC("OnFail"), &CmdListener::GetOnFail)
|
2015-11-07 11:17:39 +01:00
|
|
|
/* Functions */
|
2016-02-20 23:25:00 +01:00
|
|
|
.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)
|
2015-11-07 11:17:39 +01:00
|
|
|
);
|
|
|
|
|
2015-11-08 19:53:50 +01:00
|
|
|
cmdns.Func(_SC("GetOnError"), &Cmd_GetOnError);
|
|
|
|
cmdns.Func(_SC("SetOnError"), &Cmd_SetOnError);
|
|
|
|
cmdns.Func(_SC("GetOnAuth"), &Cmd_GetOnAuth);
|
|
|
|
cmdns.Func(_SC("SetOnAuth"), &Cmd_SetOnAuth);
|
|
|
|
cmdns.Func(_SC("GetInvoker"), &Cmd_GetInvoker);
|
|
|
|
cmdns.Func(_SC("GetInvokerID"), &Cmd_GetInvokerID);
|
2016-02-20 23:25:00 +01:00
|
|
|
cmdns.Func(_SC("GetName"), &Cmd_GetCommand);
|
|
|
|
cmdns.Func(_SC("GetText"), &Cmd_GetArgument);
|
|
|
|
|
|
|
|
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)
|
2015-11-08 20:12:05 +01:00
|
|
|
);
|
2016-02-20 23:25:00 +01:00
|
|
|
|
|
|
|
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("ExecutionFailed"), CMDERR_EXECUTION_FAILED)
|
|
|
|
.Const(_SC("BufferOverflow"), CMDERR_BUFFER_OVERFLOW)
|
|
|
|
.Const(_SC("Max"), CMDERR_MAX)
|
2015-11-08 20:12:05 +01:00
|
|
|
);
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // Namespace:: SqMod
|