// ------------------------------------------------------------------------------------------------ #include "Command.hpp" #include "Core.hpp" #include "Entity/Player.hpp" // ------------------------------------------------------------------------------------------------ #include #include #include #include #include // ------------------------------------------------------------------------------------------------ namespace SqMod { // ------------------------------------------------------------------------------------------------ CmdManager * _Cmd = nullptr; // ------------------------------------------------------------------------------------------------ SQInteger CmdListener::Typename(HSQUIRRELVM vm) { static 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 (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"); } } // ------------------------------------------------------------------------------------------------ CmdManager::Guard::~Guard() { // Release the command instance _Cmd->m_Instance = nullptr; // Release the reference to the script object _Cmd->m_Object.Release(); } // ------------------------------------------------------------------------------------------------ CmdManager::CmdManager() : m_Buffer(512) , m_Commands() , m_Invoker(SQMOD_UNKNOWN) , m_Command(64, '\0') , m_Argument(512, '\0') , m_Instance(nullptr) , m_Object() , m_Argv() , m_Argc(0) , m_OnError() , m_OnAuth() { /* ... */ } // ------------------------------------------------------------------------------------------------ CmdManager::~CmdManager() { /* ... */ } // ------------------------------------------------------------------------------------------------ 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:%zu) already exists as (%s:%zu)", name.c_str(), hash, cmd.mName.c_str(), cmd.mHash); } } // 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; } // ------------------------------------------------------------------------------------------------ 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(); } // ------------------------------------------------------------------------------------------------ void CmdManager::Terminate() { // 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 script resources from this class m_Argv.clear(); // Release the global callbacks m_OnError.ReleaseGently(); m_OnAuth.ReleaseGently(); } // ------------------------------------------------------------------------------------------------ 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; } // Save the invoker identifier m_Invoker = invoker; // Skip white-space until the command name while (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 (!isspace(*split) && *split != '\0') ++split; // Are there any arguments specified? if (split != nullptr) { // Save the command name m_Command.assign(command, (split - command)); // Skip white space after command name while (isspace(*split)) ++split; // Save the command argument m_Argument.assign(split); } // No arguments specified else { // Save the command name m_Command.assign(command); // Leave argument empty m_Argument.assign(""); } // Do we have a valid command name? try { ValidateName(m_Command.c_str()); } 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; } // Make sure resources are released at the end of this function Guard g; // Attempt to find the specified command m_Object = FindByName(m_Command); // Have we found anything? if (m_Object.IsNull()) { // Tell the script callback to deal with the error SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), m_Command); // Execution failed! return -1; } // Save the command instance m_Instance = m_Object.Cast< CmdListener * >(); // Is the command instance valid? (just in case) if (!m_Instance) { // Tell the script callback to deal with the error SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), m_Command); // Execution failed! return -1; } // Attempt to execute the command try { return Exec(); } catch (...) { // Tell the script callback to deal with the error SqError(CMDERR_EXECUTION_FAILED, _SC("Exceptions occurred during execution"), m_Invoker); } // Execution failed return -1; } // ------------------------------------------------------------------------------------------------ Int32 CmdManager::Exec() { // Clear previous arguments m_Argv.clear(); // Reset the argument counter m_Argc = 0; // Make sure the invoker has enough authority to execute this command if (!m_Instance->AuthCheckID(m_Invoker)) { // Tell the script callback to deal with the error SqError(CMDERR_INSUFFICIENT_AUTH, _SC("Insufficient authority to execute command"), m_Invoker); // Execution failed! return -1; } // Make sure an executer was specified else if (m_Instance->GetOnExec().IsNull()) { // Tell the script callback to deal with the error SqError(CMDERR_MISSING_EXECUTER, _SC("No executer was specified for this command"), m_Invoker); // Execution failed! return -1; } // See if there are any arguments to parse else if (!m_Argument.empty() && !Parse()) { // The error message was reported while parsing return -1; } // Make sure we have enough arguments specified else if (m_Instance->GetMinArgC() > m_Argc) { // Tell the script callback to deal with the error SqError(CMDERR_INCOMPLETE_ARGS, _SC("Incomplete command arguments"), m_Instance->GetMinArgC()); // Execution failed! return -1; } // The check during the parsing may omit the last argument else if (m_Instance->GetMaxArgC() < m_Argc) { // Tell the script callback to deal with the error SqError(CMDERR_EXTRANEOUS_ARGS, _SC("Extraneous command arguments"), m_Instance->GetMaxArgC()); // Execution failed! return -1; } // Check argument types against the command specifiers for (Uint32 arg = 0; arg < m_Argc; ++arg) { if (!m_Instance->ArgCheck(arg, m_Argv[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 m_Buffer.At(0) = 0; // Whether the command execution failed bool failed = false; // Do we have to call the command with an associative container? if (m_Instance->m_Associate) { // 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 try { result = m_Instance->Execute(_Core->GetPlayer(m_Invoker).mObj, args); } catch (const Sqrat::Exception & e) { // Let's store the exception message m_Buffer.Write(0, e.Message().c_str(), e.Message().size()); // Specify that the command execution failed failed = true; } } 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 try { result = m_Instance->Execute(_Core->GetPlayer(m_Invoker).mObj, args); } catch (const Sqrat::Exception & e) { // Let's store the exception message m_Buffer.Write(0, e.Message().c_str(), e.Message().size()); // 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"), m_Buffer.Data()); // Is there a script callback that handles failures? if (!m_Instance->m_OnFail.IsNull()) { // Then attempt to relay the result to that function try { m_Instance->m_OnFail.Execute(_Core->GetPlayer(m_Invoker).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()); } } // 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 (!m_Instance->m_OnFail.IsNull()) { // Then attempt to relay the result to that function try { m_Instance->m_OnFail.Execute(_Core->GetPlayer(m_Invoker).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()); } } } // Is there a callback that must be executed after a successful execution? else if (!m_Instance->m_OnPost.IsNull()) { // Then attempt to relay the result to that function try { m_Instance->m_OnPost.Execute(_Core->GetPlayer(m_Invoker).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()); } } // Return the result return static_cast< Int32 >(result); } // ------------------------------------------------------------------------------------------------ bool CmdManager::Parse() { // Is there anything to parse? if (m_Argument.empty()) { return true; // Done parsing! } // Obtain the flags of the currently processed argument Uint8 arg_flags = m_Instance->m_ArgSpec[m_Argc]; // 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(); // Previous and currently processed character SQChar prev = 0, elem = 0; // Maximum arguments allowed to be processed const Uint8 max_arg = m_Instance->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 there's anything left to parse if (elem == 0) break; // Early check to prevent parsing extraneous arguments else if (m_Argc >= max_arg) { // Tell the script callback to deal with the error SqError(CMDERR_EXTRANEOUS_ARGS, _SC("Extraneous command arguments"), max_arg); // Parsing aborted good = false; // Stop parsing break; } // Is this a greedy argument? else if (arg_flags & CMDARG_GREEDY) { // Skip white-space characters while (itr != m_Argument.end() && isspace(*itr)) ++itr; // Anything left to copy to the argument? 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 and add it to the argument list along with it's type m_Argv.emplace_back(CMDARG_STRING, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack sq_pop(DefaultVM::Get(), 1); // 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 != '\\') { // Obtain the beginning and ending of the internal buffer SStr str = m_Buffer.Begin< SQChar >(); CSStr end = (m_Buffer.End< SQChar >()-1); // + null terminator // Save the closing quote type 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"), m_Argc); // 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"), m_Invoker); // Parsing aborted good = false; // Stop parsing break; } // Simply replicate the character to the internal buffer *(str++) = elem; // Advance to the next character ++itr; } // See if the argument was valid if (!good) // Propagate failure break; // 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 = static_cast< 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 = static_cast< 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 and add it to the argument list along with it's type m_Argv.emplace_back(CMDARG_STRING, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack sq_pop(DefaultVM::Get(), 1); // Advance to the next argument and obtain its flags arg_flags = m_Instance->m_ArgSpec[++m_Argc]; } // Ignore white-space characters until another valid character is found else if (!isspace(elem) && (isspace(prev) || prev == 0)) { // Find the first space character that marks the end of the argument String::iterator pos = std::find(String::iterator(itr), m_Argument.end(), ' '); // Copy all characters within range into the internal buffer 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; // Attempt to treat the value as an integer number if (!identified) { // 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 LongI value = strtol(m_Buffer.Data(), &next, 10); // See if this whole string was indeed an integer if (next == &m_Buffer.At< SQChar >(sz)) { // Transform it into a script object sq_pushinteger(DefaultVM::Get(), static_cast< SQInteger >(value)); // Get the object from the stack and add it to the argument list along with it's type m_Argv.emplace_back(CMDARG_INTEGER, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack sq_pop(DefaultVM::Get(), 1); // We identified the correct value identified = true; } } // Attempt to treat the value as an floating point number if (!identified) { // Let's us know if the whole argument was part of the resulted value CStr next = nullptr; // Attempt to extract the floating point value from the string #ifdef SQUSEDOUBLE Float64 value = strtod(m_Buffer.Data(), &next); #else Float32 value = strtof(m_Buffer.Data(), &next); #endif // SQUSEDOUBLE // See if this whole string was indeed an floating point if (next == &m_Buffer.At< SQChar >(sz)) { // Transform it into a script object sq_pushfloat(DefaultVM::Get(), static_cast< SQFloat >(value)); // Get the object from the stack and add it to the argument list along with it's type m_Argv.emplace_back(CMDARG_FLOAT, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack sq_pop(DefaultVM::Get(), 1); // We identified the correct value identified = true; } } // Attempt to treat the value as a boolean if possible if (!identified && sz <= 6) { // 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) 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 sq_pushbool(DefaultVM::Get(), true); // Get the object from the stack and add it to the argument list along with it's type m_Argv.emplace_back(CMDARG_BOOLEAN, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack sq_pop(DefaultVM::Get(), 1); // We identified the correct value identified = true; } // Is this a boolean false value? else if (strcmp(m_Buffer.Data(), "false") == 0 || strcmp(m_Buffer.Data(), "off") == 0) { // Transform it into a script object sq_pushbool(DefaultVM::Get(), false); // Get the object from the stack and add it to the argument list along with it's type m_Argv.emplace_back(CMDARG_BOOLEAN, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack sq_pop(DefaultVM::Get(), 1); // We identified the correct value identified = true; } } // If everything else failed then simply treat the value as a string if (!identified) { // 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) = static_cast< 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) = static_cast< 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 and add it to the argument list along with it's type m_Argv.emplace_back(CMDARG_STRING, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack sq_pop(DefaultVM::Get(), 1); } // Advance to the next argument and obtain its flags arg_flags = m_Instance->m_ArgSpec[++m_Argc]; } // Is there anything left to parse? if (itr >= m_Argument.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!) _Cmd->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 (_Cmd->Attached(this)) { STHROWF("Command is already attached"); } // Attempt to attach this command _Cmd->Attach(m_Name, this, false); } // ------------------------------------------------------------------------------------------------ void CmdListener::Detach() { // Detach this command _Cmd->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 (_Cmd->Attached(this)) { // Detach from the current name if necessary _Cmd->Detach(this); // Now it's safe to assign the new name m_Name.assign(name); // We know the new name is valid _Cmd->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 _Cmd->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->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 (!_Cmd->GetOnAuth().IsNull()) { // Ask the specified authority inspector if this execution should be allowed SharedPtr< bool > ret = _Cmd->GetOnAuth().Evaluate< bool, Object & >(_Core->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->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. */ Int32 RunCommand(Int32 invoker, CSStr command) { return _Cmd->Run(invoker, command); } /* ------------------------------------------------------------------------------------------------ * Forward the call to terminate the command system. */ void TerminateCommand() { _Cmd->Terminate(); } // ------------------------------------------------------------------------------------------------ static void Cmd_Sort() { _Cmd->Sort(); } // ------------------------------------------------------------------------------------------------ static Uint32 Cmd_Count() { return _Cmd->Count(); } // ------------------------------------------------------------------------------------------------ static const Object & Cmd_FindByName(CSStr name) { // Validate the specified name ValidateName(name); // Now perform the requested search return _Cmd->FindByName(name); } // ------------------------------------------------------------------------------------------------ static Function & Cmd_GetOnError() { return _Cmd->GetOnError(); } // ------------------------------------------------------------------------------------------------ static void Cmd_SetOnError(Object & env, Function & func) { _Cmd->SetOnError(env, func); } // ------------------------------------------------------------------------------------------------ static Function & Cmd_GetOnAuth() { return _Cmd->GetOnAuth(); } // ------------------------------------------------------------------------------------------------ static void Cmd_SetOnAuth(Object & env, Function & func) { _Cmd->SetOnAuth(env, func); } // ------------------------------------------------------------------------------------------------ static Object & Cmd_GetInvoker() { return _Core->GetPlayer(_Cmd->GetInvoker()).mObj; } // ------------------------------------------------------------------------------------------------ static Int32 Cmd_GetInvokerID() { return _Cmd->GetInvoker(); } // ------------------------------------------------------------------------------------------------ static const Object & Cmd_GetObject() { return _Cmd->GetObject(); } // ------------------------------------------------------------------------------------------------ static const String & Cmd_GetCommand() { return _Cmd->GetCommand(); } // ------------------------------------------------------------------------------------------------ static const String & Cmd_GetArgument() { return _Cmd->GetArgument(); } // ------------------------------------------------------------------------------------------------ Object & Cmd_Create(CSStr name) { return _Cmd->Create(name); } Object & Cmd_Create(CSStr name, CSStr spec) { return _Cmd->Create(name, spec); } Object & Cmd_Create(CSStr name, CSStr spec, Array & tags) { return _Cmd->Create(name, spec, tags); } Object & Cmd_Create(CSStr name, CSStr spec, Uint8 min, Uint8 max) { return _Cmd->Create(name,spec, min, max); } Object & Cmd_Create(CSStr name, CSStr spec, Array & tags, Uint8 min, Uint8 max) { return _Cmd->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")) /* Metamethods */ .Func(_SC("_cmp"), &CmdListener::Cmp) .SquirrelFunc(_SC("_typename"), &CmdListener::Typename) .Func(_SC("_tostring"), &CmdListener::ToString) /* 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) /* Functions */ .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("Sort"), &Cmd_Sort); cmdns.Func(_SC("Count"), &Cmd_Count); cmdns.Func(_SC("FindByName"), &Cmd_FindByName); cmdns.Func(_SC("GetOnError"), &Cmd_GetOnError); cmdns.Func(_SC("SetOnError"), &Cmd_SetOnError); cmdns.Func(_SC("BindError"), &Cmd_SetOnError); cmdns.Func(_SC("GetOnAuth"), &Cmd_GetOnAuth); cmdns.Func(_SC("SetOnAuth"), &Cmd_SetOnAuth); cmdns.Func(_SC("BindAuth"), &Cmd_SetOnAuth); 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