From 62489f52a31da92eba898950b6b3688606d9079e Mon Sep 17 00:00:00 2001 From: Anonymous Date: Tue, 14 Jan 2014 22:03:23 -0700 Subject: [PATCH] Added sharedCommandParser library --- engine/shared/library/CMakeLists.txt | 1 + .../sharedCommandParser/CMakeLists.txt | 11 + .../sharedCommandParser/CommandParser.h | 1 + .../CommandParserHistory.h | 1 + .../CommandPermissionManager.h | 1 + .../FirstSharedCommandParser.h | 1 + .../sharedCommandParser/src/CMakeLists.txt | 35 + .../src/shared/CommandParser.cpp | 750 ++++++++++++++++++ .../src/shared/CommandParser.h | 347 ++++++++ .../src/shared/CommandParserHistory.cpp | 110 +++ .../src/shared/CommandParserHistory.h | 75 ++ .../src/shared/CommandPermissionManager.cpp | 23 + .../src/shared/CommandPermissionManager.h | 34 + .../src/shared/FirstSharedCommandParser.h | 17 + .../src/win32/FirstSharedCommandParser.cpp | 8 + 15 files changed, 1415 insertions(+) create mode 100644 engine/shared/library/sharedCommandParser/CMakeLists.txt create mode 100644 engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandParser.h create mode 100644 engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandParserHistory.h create mode 100644 engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandPermissionManager.h create mode 100644 engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/FirstSharedCommandParser.h create mode 100644 engine/shared/library/sharedCommandParser/src/CMakeLists.txt create mode 100644 engine/shared/library/sharedCommandParser/src/shared/CommandParser.cpp create mode 100644 engine/shared/library/sharedCommandParser/src/shared/CommandParser.h create mode 100644 engine/shared/library/sharedCommandParser/src/shared/CommandParserHistory.cpp create mode 100644 engine/shared/library/sharedCommandParser/src/shared/CommandParserHistory.h create mode 100644 engine/shared/library/sharedCommandParser/src/shared/CommandPermissionManager.cpp create mode 100644 engine/shared/library/sharedCommandParser/src/shared/CommandPermissionManager.h create mode 100644 engine/shared/library/sharedCommandParser/src/shared/FirstSharedCommandParser.h create mode 100644 engine/shared/library/sharedCommandParser/src/win32/FirstSharedCommandParser.cpp diff --git a/engine/shared/library/CMakeLists.txt b/engine/shared/library/CMakeLists.txt index f452f33d..aff2f340 100644 --- a/engine/shared/library/CMakeLists.txt +++ b/engine/shared/library/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(sharedCollision) +add_subdirectory(sharedCommandParser) add_subdirectory(sharedCompression) add_subdirectory(sharedDebug) add_subdirectory(sharedFile) diff --git a/engine/shared/library/sharedCommandParser/CMakeLists.txt b/engine/shared/library/sharedCommandParser/CMakeLists.txt new file mode 100644 index 00000000..fc240e2f --- /dev/null +++ b/engine/shared/library/sharedCommandParser/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.8) + +project(sharedCommandParser) + +if(WIN32) + add_definitions(/D_CRT_SECURE_NO_WARNINGS) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public) + +add_subdirectory(src) diff --git a/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandParser.h b/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandParser.h new file mode 100644 index 00000000..3d160f76 --- /dev/null +++ b/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandParser.h @@ -0,0 +1 @@ +#include "../../src/shared/CommandParser.h" diff --git a/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandParserHistory.h b/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandParserHistory.h new file mode 100644 index 00000000..b0bf66c0 --- /dev/null +++ b/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandParserHistory.h @@ -0,0 +1 @@ +#include "../../src/shared/CommandParserHistory.h" diff --git a/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandPermissionManager.h b/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandPermissionManager.h new file mode 100644 index 00000000..fd93ee3d --- /dev/null +++ b/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/CommandPermissionManager.h @@ -0,0 +1 @@ +#include "../../src/shared/CommandPermissionManager.h" diff --git a/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/FirstSharedCommandParser.h b/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/FirstSharedCommandParser.h new file mode 100644 index 00000000..1fd012ad --- /dev/null +++ b/engine/shared/library/sharedCommandParser/include/public/sharedCommandParser/FirstSharedCommandParser.h @@ -0,0 +1 @@ +#include "../../src/shared/FirstSharedCommandParser.h" diff --git a/engine/shared/library/sharedCommandParser/src/CMakeLists.txt b/engine/shared/library/sharedCommandParser/src/CMakeLists.txt new file mode 100644 index 00000000..d36b0fdd --- /dev/null +++ b/engine/shared/library/sharedCommandParser/src/CMakeLists.txt @@ -0,0 +1,35 @@ + +set(SHARED_SOURCES + shared/CommandParser.cpp + shared/CommandParser.h + shared/CommandParserHistory.cpp + shared/CommandParserHistory.h + shared/CommandPermissionManager.cpp + shared/CommandPermissionManager.h + shared/FirstSharedCommandParser.h +) + +if(WIN32) + set(PLATFORM_SOURCES + win32/FirstSharedCommandParser.cpp + ) + + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32) +else() + set(PLATFORM_SOURCES "") +endif() + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/shared + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedSynchronization/include/public + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include +) + +add_library(sharedCommandParser STATIC + ${SHARED_SOURCES} + ${PLATFORM_SOURCES} +) diff --git a/engine/shared/library/sharedCommandParser/src/shared/CommandParser.cpp b/engine/shared/library/sharedCommandParser/src/shared/CommandParser.cpp new file mode 100644 index 00000000..383043ab --- /dev/null +++ b/engine/shared/library/sharedCommandParser/src/shared/CommandParser.cpp @@ -0,0 +1,750 @@ +// ====================================================================== +// +// CommandParser.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedCommandParser/FirstSharedCommandParser.h" +#include "sharedCommandParser/CommandParser.h" +#include "sharedCommandParser/CommandPermissionManager.h" + +#include "sharedFoundation/NetworkId.h" +#include "UnicodeUtils.h" + +#include +#include +#include +#include +#include + +// ====================================================================== + +//- TODO: load these messages from the StringTable to localize the commandparser - jww + +static const CommandParser::ErrorInfoData errors[static_cast(CommandParser::ERR_NUM_ERRS)+1] = +{ + {CommandParser::ERR_NONE, "None - error!"}, + {CommandParser::ERR_SUCCESS, "Command completed succesfully."}, + {CommandParser::ERR_FAIL, "Command failed!"}, + {CommandParser::ERR_NO_ERROR_MSG, "No error message available!"}, + {CommandParser::ERR_CMD_NOT_FOUND, "Command not found."}, + {CommandParser::ERR_SUBCMD_NOT_FOUND, "Subcommand not found."}, + {CommandParser::ERR_NO_HANDLER, "No handler for this command."}, + {CommandParser::ERR_NO_SCENE, "No scene available."}, + {CommandParser::ERR_SCENE_INVALID_OPERATION, "Scene does not support this operation."}, + {CommandParser::ERR_INVALID_ARGUMENTS, "Invalid arguments."}, + {CommandParser::ERR_NOT_ENOUGH_ARGUMENTS, "Not enough arguments."}, + {CommandParser::ERR_NO_AVATAR, "No avatar found!"}, + {CommandParser::ERR_SENDING_COMMAND_TO_SERVER, "Sending command to server."}, + {CommandParser::ERR_NO_CONTROLLER, "No controller found!"}, + {CommandParser::ERR_NO_NODES, "No CommandParser nodes attached."}, + {CommandParser::ERR_NO_SUBCOMMAND_SPECIFIED, "No subcommand specified. Subcommands:\n"}, + {CommandParser::ERR_NO_PARSER_IMPLEMENTED, "No parser implemented!"}, + {CommandParser::ERR_INVALID_OBJECT, "Invalid object."}, + {CommandParser::ERR_INVALID_SCRIPT, "Invalid script name or other error."}, + {CommandParser::ERR_INVALID_TRIGGER, "Invalid trigger id."}, + {CommandParser::ERR_NOT_SKUFREE_TEMPLATE, "Can't create a non skufree asset in a free trial area."}, + {CommandParser::ERR_SCRIPT_CONTINUE, "Trigger returns SCRIPT_CONTINUE"}, + {CommandParser::ERR_SCRIPT_OVERRIDE, "Trigger returns SCRIPT_OVERRIDE"}, + {CommandParser::ERR_UNSUPPORTED_TRIGGER, "Cannot invoke trigger from the command line."}, + {CommandParser::ERR_INVALID_PARAMETER_COUNT, "Wrong number of parameters for trigger, needed "}, + {CommandParser::ERR_INVALID_OBJVAR, "Cannot find objvar."}, + {CommandParser::ERR_LIST_OBJVAR_NOT_SUPPORTED, "Objvar type = list, function not supported."}, + {CommandParser::ERR_INVALID_INT_OBJVAR, "Invalid data for int objvar."}, + {CommandParser::ERR_INVALID_REAL_OBJVAR, "Invalid data for real objvar."}, + {CommandParser::ERR_PERMISSION_DENIED, "Permission denied."}, + {CommandParser::ERR_NO_TERRAIN, "Scene does not have a terrain."}, + {CommandParser::ERR_TERRAIN_GENERATION, "Could not generate terrain at these coords."}, + {CommandParser::ERR_INVALID_USER, "The user issuing the command was not found."}, + {CommandParser::ERR_NO_TARGET_OBJECT, "The target given was not found."}, + {CommandParser::ERR_BAD_ATTACKER, "The attacker is not a tangible object."}, + {CommandParser::ERR_BAD_DEFENDER, "The target is not a tangible object."}, + {CommandParser::ERR_QUEUE_COMMAND_FAIL, "Failed to queue command."}, + {CommandParser::ERR_CANNOT_XFER_AUTH, "Request to transfer authority denied."}, + {CommandParser::ERR_INVALID_TEMPLATE, "Invalid Object template specified."}, + {CommandParser::ERR_INVALID_CONTAINER_TRANSFER, "Invalid Container Transfer."}, + {CommandParser::ERR_FILE_NOT_FOUND, "File not found."}, + {CommandParser::ERR_INVALID_INGREDIENT, "Invalid ingredient."}, + {CommandParser::ERR_INVALID_STATION, "Object not a crafting station."}, + {CommandParser::ERR_STATION_IN_USE, "Crafting station in use."}, + {CommandParser::ERR_FILLSLOT_FAIL, "Error filling the schematic slot."}, + {CommandParser::ERR_CUSTOMIZE_FAIL, "Error setting customization property."}, + {CommandParser::ERR_TEMPLATE_NOT_LOADED, "Template Not Loaded"}, + {CommandParser::ERR_ACTIVE_MANF_STATION, "Manufacturing station active, please turn off."}, + {CommandParser::ERR_SCRIPTING_ENABLED, "Scripting is enabled."}, + {CommandParser::ERR_SCRIPTING_DISABLED, "Scripting is disabled."}, + {CommandParser::ERR_NUM_ERRS, ""} + +}; + +//---------------------------------------------------------------------- + +namespace +{ + const Unicode::String s_alias_cmd = Unicode::narrowToWide ("alias"); + const Unicode::String s_alias_cmd_slash = Unicode::narrowToWide ("/") + s_alias_cmd; +}; + +//----------------------------------------------------------------- + +CommandParser::String_t * CommandParser::ms_ERR_NO_ERROR_MSG_MSG; +CommandParser::ErrorMsgMap_t * CommandParser::ms_errorMsgMap; +size_t CommandParser::ms_instanceCount; +const CommandPermissionManager * CommandParser::ms_permissionManager; + +//----------------------------------------------------------------- + +CommandParser::CommandParser (const String_t & cmd, + size_t minArgs, + const String_t & args, + const String_t & help, + CommandParser * delegate) : +m_cmd (cmd), +m_minArgs (minArgs), +m_args (args), +m_help (help), +m_default (false), +m_parent (0), +m_delegate (delegate), +m_subCommands (NON_NULL (new CommandParserSet_t)) +{ + ++ms_instanceCount; + initStatics (); +} + +//----------------------------------------------------------------- + +CommandParser::CommandParser (const char * const cmd, + size_t minArgs, + const char * const args, + const char * const help, + CommandParser * delegate) : +m_cmd (), +m_minArgs (minArgs), +m_args (), +m_help (), +m_default (false), +m_parent (0), +m_delegate (delegate), +m_subCommands (NON_NULL (new CommandParserSet_t)) +{ + ++ms_instanceCount; + initStatics (); + + std::string cmd_narrow (cmd); + m_cmd.append (cmd_narrow.begin (), cmd_narrow.end ()); + + std::string args_narrow (args); + m_args.append (args_narrow.begin (), args_narrow.end ()); + + std::string help_narrow (help); + m_help.append (help_narrow.begin (), help_narrow.end ()); +} + +//----------------------------------------------------------------- + +CommandParser::CommandParser (const CommandParser::CmdInfo & info, CommandParser * delegate) : +m_cmd (Unicode::narrowToWide (info.m_cmd)), +m_minArgs (info.m_minArgs), +m_args (Unicode::narrowToWide (info.m_args)), +m_help (Unicode::narrowToWide (info.m_help)), +m_default (false), +m_parent (0), +m_delegate (delegate), +m_subCommands (NON_NULL (new CommandParserSet_t)) +{ + ++ms_instanceCount; + initStatics (); +} + +//----------------------------------------------------------------- + +void CommandParser::initStatics (void) +{ + if (ms_errorMsgMap == 0) + { + ms_errorMsgMap = new ErrorMsgMap_t; + + for (int i = 0; ; ++i) + { + const CommandParser::ErrorInfoData & infoData = errors [i]; + + if (infoData.m_type == ERR_NUM_ERRS) + break; + + const Unicode::String str (Unicode::narrowToWide (infoData.m_msg)); + const std::pair retval = + ms_errorMsgMap->insert (std::make_pair (static_cast(infoData.m_type), str)); + + DEBUG_FATAL (!retval.second, ("error adding error message.\n")); + UNREF (retval); + } + + ms_ERR_NO_ERROR_MSG_MSG = new String_t ((*ms_errorMsgMap)[static_cast(ERR_NO_ERROR_MSG)]); + } +} + +//---------------------------------------------------------------------- + +void CommandParser::deleteSubCommands () +{ + for (CommandParserSet_t::iterator iter = m_subCommands->begin (); iter != m_subCommands->end (); ++iter) + { + delete *iter; + } + + m_subCommands->clear (); +} + +//----------------------------------------------------------------- + +CommandParser::~CommandParser () +{ + m_delegate = 0; + m_parent = 0; + + for (CommandParserSet_t::iterator iter = m_subCommands->begin (); iter != m_subCommands->end (); ++iter) + { + delete *iter; + } + + m_subCommands->clear (); + delete m_subCommands; + m_subCommands = 0; + + DEBUG_FATAL (ms_instanceCount == 0, ("CommandParser instanceCount went negative... bogus constructors?\n")); + + --ms_instanceCount; + + if (ms_instanceCount == 0) + { + delete ms_errorMsgMap; + ms_errorMsgMap = 0; + delete ms_ERR_NO_ERROR_MSG_MSG; + ms_ERR_NO_ERROR_MSG_MSG = 0; + } +} + +//---------------------------------------------------------------------- + +void CommandParser::chopInputStrings (const String_t & str, StringVector_t & sv) +{ + size_t pos = 0; + size_t endpos = 0; + Unicode::String commandPart; + + const static Unicode::unicode_char_t sep [2] = { ';', 0 }; + + while (Unicode::getFirstToken (str, pos, endpos, commandPart, sep)) + { + Unicode::trim (commandPart); + + if (!commandPart.empty ()) + { + //-- if this is the magic alias command, stop choppin + if (isAbbrev (s_alias_cmd, commandPart) || isAbbrev (s_alias_cmd_slash, commandPart)) + { + commandPart = str.substr (pos); + Unicode::trim (commandPart); + endpos = static_cast(str.npos); + } + + sv.push_back (commandPart); + } + + if (endpos == Unicode::String::npos) + break; + + pos = endpos + 1; + } +} + +//----------------------------------------------------------------- + +CommandParser::ErrorType CommandParser::parse (const NetworkId & userId, const String_t & str, String_t & result) +{ + //---------------------------------------------------------------------- + //- first break the string into parts via semicolons, then + //- tokenize each portion of the string. + + ErrorType last_retval = ERR_NONE; + + StringVector_t sv; + + chopInputStrings (str, sv); + + for (StringVector_t::const_iterator it = sv.begin (); it != sv.end (); ++it) + { + const Unicode::String & commandPart = *it; + + if (!result.empty () && result [result.size () - 1] != '\n') + IGNORE_RETURN (result.append (1, '\n')); + + size_t dummy; + StringVector_t v; + Unicode::tokenize (commandPart, v, 0, dummy, dummy, dummy); + + last_retval = parse (userId, v, 0, str, result); + } + + return last_retval; +} + + +//----------------------------------------------------------------- + +CommandParser * CommandParser::findParser (const StringVector_t & argv, const size_t tokenNum) +{ + if (tokenNum >= argv.size ()) + return this; + + // look for the appropriate subcommand + const String_t & cur_cmd = argv [tokenNum]; + + CommandParserSet_t::iterator find_iter = std::find_if (m_subCommands->begin (), m_subCommands->end (), EqualsAbbrevNoCase (cur_cmd)); + + if (find_iter == m_subCommands->end ()) + { + return 0; + } + + // more arguments are available, so descend the command parser tree + + CommandParser & cmd = **find_iter; + return cmd.findParser (argv, tokenNum + 1); +} + +//----------------------------------------------------------------- + +/** +* Note: tokenNum can exceed the capacity of argv +* @param originalCommand +*/ + +CommandParser::ErrorType CommandParser::parse (const NetworkId & userId, const StringVector_t & argv, const size_t tokenNum, const String_t & originalCommand, String_t & result) +{ + // this command is a leaf node, thus it is capable of perfoming the interpret + if (m_subCommands->size () == 0) + { + // performInterpret () does not get called on the root node + if (m_parent == 0) + { + result += getErrorMessage (ERR_NO_NODES); + return ERR_NO_NODES; + } + + // not enough arguments + if (m_minArgs > (argv.size () - tokenNum)) + { + result += getNotEnoughArgumentsMessage (); + return ERR_NOT_ENOUGH_ARGUMENTS; + } + + //-- check for adequate permissions + if (ms_permissionManager) + { + Unicode::String path; + static const Unicode::unicode_char_t pathSep = '.'; + + const CommandParser * cmd = this; + + while (cmd && cmd->m_parent) + { + if (path.empty ()) + path = cmd->getCmd (); + else + { + path = cmd->getCmd () + pathSep + path; + } + cmd = cmd->m_parent; + } + + if (ms_permissionManager->isCommandAllowed (userId, path) == false) + { + result += getErrorMessage (getCmd (), ERR_PERMISSION_DENIED); + return ERR_PERMISSION_DENIED; + } + } + + // construct the truncated string vector the the performInterpret () method + StringVector_t passArgv; + passArgv.reserve (argv.size () - tokenNum + 1); + + DEBUG_FATAL (tokenNum == 0, ("tokenNum == 0 and no subCommands -- error.\n")); + + { + passArgv.push_back (m_cmd); + + for (size_t i = tokenNum; i < argv.size (); ++i) + passArgv.push_back (argv [i]); + } + + CommandParser * handler = m_delegate ? m_delegate : this; + + if (handler->performParsing(userId, passArgv, originalCommand, result, this)) + return ERR_SUCCESS; + + return ERR_NO_HANDLER; + } + + // no more arguments, this is not a fully qualified command line + if (tokenNum >= argv.size ()) + { + + // use default command if applicable + + CommandParserSet_t::iterator default_iter = std::find_if (m_subCommands->begin (), m_subCommands->end (), IsDefault ()); + + if (default_iter != m_subCommands->end ()) + { + CommandParser & cmd = **default_iter; + + // we need a modifed argument vector with the default argument on it + StringVector_t vect = argv; + vect.push_back (cmd.m_cmd); + + return cmd.parse (userId, vect, tokenNum + 1, originalCommand, result); + } + + // list possible subcommands + + result += getErrorMessage (constructFullPath (), ERR_NO_SUBCOMMAND_SPECIFIED); + + showHelp (result); + + return ERR_SUCCESS; + } + + // look for the appropriate subcommand + const String_t & cur_cmd = argv [tokenNum]; + + CommandParserSet_t::iterator find_iter = std::find_if (m_subCommands->begin (), m_subCommands->end (), EqualsAbbrevNoCase (cur_cmd)); + + if (find_iter == m_subCommands->end ()) + { + const ErrorType etype = m_parent ? ERR_SUBCMD_NOT_FOUND : ERR_CMD_NOT_FOUND; + result += getErrorMessage (constructFullPath (argv [tokenNum]), etype); + return etype; + } + + // more arguments are available, so descend the command parser tree + + CommandParser & cmd = **find_iter; + return cmd.parse (userId, argv, tokenNum + 1, originalCommand, result); +} + +//----------------------------------------------------------------- + +bool CommandParser::tabCompleteToken (const String_t & str, const size_t tokenPos, StringVector_t & results, size_t & token_start, size_t & token_end) +{ + StringVector_t v; + size_t whichToken; + Unicode::tokenize (str, v, tokenPos, whichToken, token_start, token_end); + + // ends with space, add an empty token + if (whichToken == (v.size () - 1) && tokenPos > 0 && str [tokenPos-1] == ' ') + { + v.push_back (String_t ()); + ++whichToken; + token_start = tokenPos; + token_end = tokenPos; + } + + return tabCompleteToken (v, 0, whichToken, results); +} + +//----------------------------------------------------------------- + +bool CommandParser::tabCompleteToken (const StringVector_t & argv, const size_t tokenNum, const size_t whichToken, StringVector_t & results) +{ + if (tokenNum > whichToken) + return true; + +// DEBUG_FATAL (argv.empty (), ("argv is empty in tab complete\n")); + + // look for the appropriate subcommand + const String_t empty; + const String_t & cur_cmd = argv.empty () ? empty : argv [tokenNum]; + + // this command(s) should be under this node + if (whichToken == tokenNum) + { + for (CommandParserSet_t::const_iterator iter = m_subCommands->begin (); iter != m_subCommands->end (); ++iter) + { + const CommandParser & sub_cmd = **iter; + + if (sub_cmd.isAbbrev (cur_cmd)) + results.push_back (sub_cmd.m_cmd); + } + + return true; + } + + CommandParserSet_t::iterator find_iter = std::find_if (m_subCommands->begin (), m_subCommands->end (), EqualsAbbrevNoCase (cur_cmd)); + + if (find_iter == m_subCommands->end ()) + { + return true; + } + + // more arguments are available, so descend the command parser tree + + CommandParser & cmd = **find_iter; + return cmd.tabCompleteToken (argv, tokenNum + 1, whichToken, results); +} + +//----------------------------------------------------------------- + +void CommandParser::showHelp (String_t & result) const +{ + if (m_subCommands->size () > 0) + { + result += + Unicode::narrowToWide ("\\#ffffffCommands:\n" + "-------------------------------------------------------\n\n"); + + if (m_parent) + { + result.append (m_cmd); + result.append (Unicode::narrowToWide ("\\%030\\#00ff00")); + result.append (m_args); + result.append (Unicode::narrowToWide ("\\#ffffff\n\\>000")); + result.append (m_help); + result.append (Unicode::narrowToWide ("\\>000")); + result.append (1, '\n'); + } + + for (CommandParserSet_t::const_iterator iter = m_subCommands->begin (); iter != m_subCommands->end (); ++iter) + { + const CommandParser & sub_cmd = **iter; + result.append (2, ' '); + result.append (sub_cmd.m_cmd); + result.append (Unicode::narrowToWide ("\\%030\\#00ff00")); + result.append (sub_cmd.m_args); + result.append (Unicode::narrowToWide ("\\#ffffff\n\\>000")); + result.append (sub_cmd.m_help); + result.append (Unicode::narrowToWide ("\\>000")); + result.append (1, '\n'); + } + } + else + { + result += Unicode::narrowToWide ("Usage: "); + result.append (m_cmd); + result.append (1, ' '); + result.append (m_args); + result.append (Unicode::narrowToWide (" : ")); + result.append (m_help); + result.append (1, '\n'); + } +} + +//----------------------------------------------------------------- + +bool CommandParser::performParsing (const NetworkId & userId, const StringVector_t & argv, const String_t & originalCommand, String_t & result, const CommandParser * node) +{ + UNREF (userId); + UNREF (argv); + UNREF (originalCommand); + UNREF (node); + + if (!result.empty () && result [result.size () - 1] != '\n') + IGNORE_RETURN (result.append (1, '\n')); + + result += getErrorMessage (constructFullPath (), ERR_NO_PARSER_IMPLEMENTED); + return true; +} + +//----------------------------------------------------------------- +/** +* overwrite any existing subnode +*/ +CommandParser * CommandParser::addSubCommand (CommandParser * node) +{ + CommandParserSet_t::iterator find_iter = std::find_if (m_subCommands->begin (), m_subCommands->end (), EqualsCmdString (node->m_cmd)); + + // remove existing + if (find_iter != m_subCommands->end ()) + { + delete *find_iter; + m_subCommands->erase (find_iter); + } + + std::pair retval = m_subCommands->insert (node); + + DEBUG_FATAL (retval.second == false, ("Error in command parser.\n")); + UNREF (retval); + + node->m_parent = this; + return node; +} + + +//----------------------------------------------------------------- + +bool CommandParser::removeParser (CommandParser * const parser) +{ + CommandParserSet_t::iterator iter = m_subCommands->find (parser); + + if (iter == m_subCommands->end ()) + { + return false; + } + else + { + m_subCommands->erase (iter); + return true; + } +} + +//----------------------------------------------------------------- + +const CommandParser::String_t & CommandParser::getErrorMessage (CommandParser::ErrorType code) const +{ + ErrorMsgMap_t::const_iterator iter = ms_errorMsgMap->find (static_cast(code)); + + if (iter == ms_errorMsgMap->end ()) + { + return *ms_ERR_NO_ERROR_MSG_MSG; + } + else + return iter->second; +} + +//----------------------------------------------------------------- + +CommandParser::String_t CommandParser::getErrorMessage (const CommandParser::String_t & prefix, CommandParser::ErrorType code) const +{ + return prefix + Unicode::narrowToWide (": ") + getErrorMessage (code); +} + +//----------------------------------------------------------------- + +CommandParser::String_t CommandParser::getFullErrorMessage (CommandParser::ErrorType code) const +{ + return getErrorMessage (constructFullPath (), code); +} + +//----------------------------------------------------------------- + +CommandParser::String_t CommandParser::getNotEnoughArgumentsMessage (void) const +{ + return (constructFullPath () + Unicode::narrowToWide(": ") + getErrorMessage (ERR_NOT_ENOUGH_ARGUMENTS) + Unicode::narrowToWide ("\nUsage: ") + m_cmd).append (1, ' ') + m_args; +} + +//----------------------------------------------------------------- +/** +* createDelegateCommands takes an array of CmdInfo objects, terminated with a CmdInfo with an empty m_cmd +*/ + +void CommandParser::createDelegateCommands (const CmdInfo cmds[]) +{ + for (int i = 0; ; ++i) + { + const CommandParser::CmdInfo & info = cmds [i]; + + if (*info.m_cmd == 0) + break; + + addSubCommand (new CommandParser (info, this)); + } +} + +//---------------------------------------------------------------------- + +bool CommandParser::isAbbrev (const String_t & str, const String_t & wholeStr) +{ + if (wholeStr.length () < str.length ()) + return false; + + if (str.empty ()) + return true; + + return Unicode::caseInsensitiveCompare (str, wholeStr, 0, str.length ()); +} + +//---------------------------------------------------------------------- + +void CommandParser::reconstructString (const StringVector_t & args, size_t startToken, size_t endToken, bool quote, Unicode::String & result) +{ + endToken = std::min (endToken, args.size ()); + + result.clear (); + + for (size_t i = startToken; i < endToken; ++i) + { + if (i != startToken) + result.append (1, ' '); + + const Unicode::String & str = args [i]; + + if (quote && str.find ('\"') != str.npos) + { + result.append (1, '\"'); + result += str; + result.append (1, '\"'); + } + else + result += str; + } +} + +//---------------------------------------------------------------------- + +CommandParser::String_t CommandParser::constructFullPath (const String_t & subCmd) const +{ + String_t p (constructFullPath()); + + if (!subCmd.empty ()) + { + if (!p.empty ()) + p.append (1, ' '); + + p.append (subCmd); + } + + return p; +} + +//---------------------------------------------------------------------- + +CommandParser::String_t CommandParser::constructFullPath () const +{ + String_t p; + + if (m_parent) + p = m_parent->constructFullPath(); + + if (!p.empty ()) + p.append (1, ' '); + + p.append (m_cmd); + + return p; +} + +//----------------------------------------------------------------- +//-- this method is very inefficient +// + +bool CommandParser::isAbbrev (const String_t & str, const char * const wholeWord) +{ + return isAbbrev (str, Unicode::narrowToWide (wholeWord)); +} + +//---------------------------------------------------------------------- + +bool CommandParser::isCommand (const String_t & str, const char * cmd) +{ + return str == Unicode::narrowToWide (cmd); +} + +//---------------------------------------------------------------------- + +CommandParser * CommandParser::getDelegate() const +{ + return m_delegate; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedCommandParser/src/shared/CommandParser.h b/engine/shared/library/sharedCommandParser/src/shared/CommandParser.h new file mode 100644 index 00000000..50922e1d --- /dev/null +++ b/engine/shared/library/sharedCommandParser/src/shared/CommandParser.h @@ -0,0 +1,347 @@ +// ====================================================================== +// +// CommandParser.h +// copyright (c) 2001 Sony Online Entertainment +// +// jwatson +// +// ====================================================================== + +#ifndef INCLUDED_CommandParser_H +#define INCLUDED_CommandParser_H + +#include "Unicode.h" + +class CommandPermissionManager; +class NetworkId; + +// ====================================================================== + +/** +* CommandParser is a generic class for parsing command lines. +* A CommandParser instance is simply a node in a hierarchical tree of +* commands and subcommands. +* +* A command node may be constructed in 2 ways: +* +* 1. Subclass the CommandParser to handle the command. The command is handled +* by the performParsing () method, which subclasses should ovverride. Attach +* an instance of your subclass to the appropriate node of your command tree. +* +* 2. Simply create an instance of CommandParser, with its delegate set to be +* any other CommandParser instance. The delegate's performParsing () will +* get called when your new command gets invoked. argv[0] in performParsing +* will be the command that corresponds to your new node. This technique is +* useful for adding small, lightweight subcommands to a command node, where +* creating subclasses would be overkill and annoying. +* +* performParsing () is the only method that must be overridden by subclasses. +* +* One of the parse () methods and one of the tabCompleTokens () are the entry +* points into the tree to parse a command or tab complete a command, respectively. +* +* Examples of how to use this system may be found in the SWUI project. +* +*/ + +class CommandParser +{ +public: + + typedef Unicode::String String_t; + typedef stdvector::fwd StringVector_t; + + enum ErrorType + { + ERR_NONE, + ERR_SUCCESS, + ERR_FAIL, + ERR_NO_ERROR_MSG, + ERR_CMD_NOT_FOUND, + ERR_SUBCMD_NOT_FOUND, + ERR_NO_HANDLER, + ERR_NO_SCENE, + ERR_SCENE_INVALID_OPERATION, + ERR_NO_AVATAR, + ERR_NO_CONTROLLER, + ERR_INVALID_ARGUMENTS, + ERR_NOT_ENOUGH_ARGUMENTS, + ERR_SENDING_COMMAND_TO_SERVER, + ERR_NO_NODES, + ERR_NO_SUBCOMMAND_SPECIFIED, + ERR_NO_PARSER_IMPLEMENTED, + ERR_INVALID_OBJECT, + ERR_INVALID_SCRIPT, + ERR_INVALID_TRIGGER, + ERR_NOT_SKUFREE_TEMPLATE, + ERR_SCRIPT_CONTINUE, + ERR_SCRIPT_OVERRIDE, + ERR_UNSUPPORTED_TRIGGER, + ERR_INVALID_PARAMETER_COUNT, + ERR_INVALID_OBJVAR, + ERR_LIST_OBJVAR_NOT_SUPPORTED, + ERR_INVALID_INT_OBJVAR, + ERR_INVALID_REAL_OBJVAR, + ERR_PERMISSION_DENIED, + ERR_NO_TERRAIN, + ERR_TERRAIN_GENERATION, + ERR_INVALID_USER, + ERR_NO_USER_OBJECT, + ERR_NO_TARGET_OBJECT, + ERR_BAD_ATTACKER, + ERR_BAD_DEFENDER, + ERR_QUEUE_COMMAND_FAIL, + ERR_CANNOT_XFER_AUTH, + ERR_INVALID_TEMPLATE, + ERR_INVALID_CONTAINER_TRANSFER, + ERR_FILE_NOT_FOUND, + ERR_INVALID_INGREDIENT, + ERR_INVALID_STATION, + ERR_STATION_IN_USE, + ERR_FILLSLOT_FAIL, + ERR_CUSTOMIZE_FAIL, + ERR_TEMPLATE_NOT_LOADED, + ERR_ACTIVE_MANF_STATION, + ERR_SCRIPTING_ENABLED, + ERR_SCRIPTING_DISABLED, + + + ERR_NUM_ERRS + }; + + struct ErrorInfoData + { + ErrorType m_type; + const char * m_msg; + }; + + struct CmdInfo + { + const char * m_cmd; + size_t m_minArgs; + const char * m_args; + const char * m_help; + }; + +public: + + CommandParser (const CmdInfo & info, CommandParser * delegate); + CommandParser (const String_t & cmd, size_t minArgs, const String_t & args, const String_t & help, CommandParser * delegate); + CommandParser (const char * cmd, size_t minArgs, const char * args, const char * help, CommandParser * delegate); + virtual ~CommandParser (); + + const String_t & getCmd () const; + const String_t & getArgs () const; + const String_t & getHelp () const; + const size_t getMinArgs () const; + + ErrorType parse (const NetworkId & userId, const String_t & str, String_t & result); + + ErrorType parse (const NetworkId & userId, const StringVector_t & argv, size_t tokenNum, const String_t & originalCommand, String_t & result); + + bool tabCompleteToken (const String_t & str, size_t tokenPos, StringVector_t & results, size_t & token_start, size_t & token_end); + bool tabCompleteToken (const StringVector_t & argv, size_t tokenNum, size_t whichToken, StringVector_t & results); + + virtual bool performParsing (const NetworkId & userId, const StringVector_t & argv, const String_t & originalCommand, String_t & result, const CommandParser * node); + + void showHelp (String_t & result) const; + + CommandParser * addSubCommand (CommandParser * node); + + bool isAbbrev (const String_t & str) const; + + const String_t & getErrorMessage (ErrorType code) const; + String_t getErrorMessage (const String_t & prefix, ErrorType code) const; + String_t getFullErrorMessage (ErrorType code) const; + String_t getNotEnoughArgumentsMessage () const; + bool isDefault () const; + void setDefault (bool b); + + static bool isAbbrev (const String_t & str, const String_t & wholeWord); + static bool isAbbrev (const String_t & str, const char * wholeWord); + + static bool isCommand (const String_t & str, const char * cmd); + + static void setPermissionManager (const CommandPermissionManager * permissionManager); + + static void reconstructString (const StringVector_t & args, size_t startToken, size_t endToken, bool quote, Unicode::String & result); + + static void chopInputStrings (const String_t & str, StringVector_t & sv); + + String_t constructFullPath () const; + String_t constructFullPath (const String_t & subCmd) const; + + CommandParser * getDelegate() const; + + CommandParser * findParser (const StringVector_t & argv, size_t tokenNum); + +protected: + + void createDelegateCommands (const CmdInfo cmds[]); + bool removeParser (CommandParser * parser); + void deleteSubCommands (); + +private: + CommandParser (); + CommandParser (const CommandParser & rhs); + CommandParser & operator= (const CommandParser & rhs); + + static void initStatics (); + +private: + + String_t m_cmd; + size_t m_minArgs; + String_t m_args; + String_t m_help; + bool m_default; + + const CommandParser * m_parent; + CommandParser * m_delegate; + + typedef stdmap::fwd ErrorMsgMap_t; + + static size_t ms_instanceCount; + static String_t * ms_ERR_NO_ERROR_MSG_MSG; + static ErrorMsgMap_t * ms_errorMsgMap; + + const static CommandPermissionManager * ms_permissionManager; + + /** + * Comparator for sorting the set of commands + */ + + struct Comparator + { + bool operator () (const CommandParser * a, const CommandParser * b) const; + }; + + typedef stdset::fwd CommandParserSet_t; + + CommandParserSet_t * m_subCommands; + + /** + * Predicate for searching for a command by abbreviation. + */ + + struct EqualsAbbrevNoCase + { + const String_t & m_str; + + explicit EqualsAbbrevNoCase (const String_t & theStr) : m_str (theStr) {} + + inline bool operator() (const CommandParser * t) const + { + return t->isAbbrev (m_str); + } + + EqualsAbbrevNoCase (const EqualsAbbrevNoCase & rhs) : m_str (rhs.m_str) {} + + private: + EqualsAbbrevNoCase & operator= (const EqualsAbbrevNoCase & rhs); //lint !e754 + EqualsAbbrevNoCase (); + }; + + /** + * Predicate for searching for a command by full name. + */ + + struct EqualsCmdString + { + const String_t & m_str; + + explicit EqualsCmdString (const String_t & theStr) : m_str (theStr) {} + + inline bool operator() (const CommandParser * t) const + { + return t->getCmd () == m_str; + } + + EqualsCmdString (const EqualsCmdString & rhs) : m_str (rhs.m_str) {} + + private: + EqualsCmdString & operator= (const EqualsCmdString & rhs); //lint !e754 + EqualsCmdString (); + }; + + /** + * Predicate for searching for a default command. + */ + + struct IsDefault + { + inline bool operator() (const CommandParser * t) const + { + return t->isDefault (); + } + }; +}; + + +// ====================================================================== + + +inline const CommandParser::String_t & CommandParser::getCmd () const +{ + return m_cmd; +} + +//----------------------------------------------------------------- + +inline const CommandParser::String_t & CommandParser::getArgs () const +{ + return m_args; +} + +//----------------------------------------------------------------- + +inline const CommandParser::String_t & CommandParser::getHelp () const +{ + return m_help; +} + +//----------------------------------------------------------------- + +inline const size_t CommandParser::getMinArgs () const +{ + return m_minArgs; +} + +//----------------------------------------------------------------- + +inline bool CommandParser::isDefault () const +{ + return m_default; +} + +//----------------------------------------------------------------- + +inline void CommandParser::setDefault (const bool b) +{ + m_default = b; +} + +//----------------------------------------------------------------- + +inline bool CommandParser::Comparator::operator () (const CommandParser * a, const CommandParser * b) const +{ + return a->getCmd () < b->getCmd (); +}; + +//----------------------------------------------------------------- + +inline bool CommandParser::isAbbrev (const String_t & abbrev) const +{ + return isAbbrev (abbrev, m_cmd); +} + +//----------------------------------------------------------------- + +inline void CommandParser::setPermissionManager (const CommandPermissionManager * permissionManager) +{ + ms_permissionManager = permissionManager; +} + +//----------------------------------------------------------------- + +#endif diff --git a/engine/shared/library/sharedCommandParser/src/shared/CommandParserHistory.cpp b/engine/shared/library/sharedCommandParser/src/shared/CommandParserHistory.cpp new file mode 100644 index 00000000..65330576 --- /dev/null +++ b/engine/shared/library/sharedCommandParser/src/shared/CommandParserHistory.cpp @@ -0,0 +1,110 @@ +// ====================================================================== +// +// CommandParserHistory.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedCommandParser/FirstSharedCommandParser.h" +#include "sharedCommandParser/CommandParserHistory.h" + +#include +#include + +// ====================================================================== + +CommandParserHistory::CommandParserHistory () : +m_index (-1), +m_history (NON_NULL (new HistoryList_t)), +m_maxSize (50) +{ +} + +//---------------------------------------------------------------------- + +CommandParserHistory::~CommandParserHistory () +{ + delete m_history; + m_history = 0; +} + +//----------------------------------------------------------------- + +bool CommandParserHistory::back (Unicode::String & result) +{ + if (static_cast (m_index + 1) >= m_history->size ()) + return false; + + ++m_index; + + result = (*m_history) [static_cast (m_index)]; + + return true; + +} +//----------------------------------------------------------------- + +bool CommandParserHistory::forward (Unicode::String & result) +{ + if (m_index - 1 < -1) + return false; + + if (--m_index < 0) + return false; + + result = (*m_history) [static_cast (m_index)]; + + return true; +} + +//----------------------------------------------------------------- + +void CommandParserHistory::push (const Unicode::String & cmd) +{ + //-- don't push identical commands back-to-back + if (!m_history->empty ()) + { + if (m_history->front () == cmd) + { + m_index = -1; + return; + } + } + + m_history->push_front (cmd); + if (m_history->size () > m_maxSize) + m_history->pop_back (); + + m_index = -1; +} + +//----------------------------------------------------------------- + +bool CommandParserHistory::getHistoryCommandByAbbrev (const Unicode::String & abbrev, Unicode::String & cmd) const +{ + const size_t len = abbrev.length (); + const HistoryList_t::const_iterator end = m_history->end (); + + for (HistoryList_t::const_iterator it = m_history->begin (); it != end; ++it) + { + if ((*it).compare (0, len, abbrev) == 0) + { + cmd = (*it); + return true; + } + } + return false; +} + +//----------------------------------------------------------------- + +bool CommandParserHistory::front (Unicode::String & cmd) +{ + if (m_history->empty ()) + return false; + + cmd = (*m_history) [0]; + return true; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedCommandParser/src/shared/CommandParserHistory.h b/engine/shared/library/sharedCommandParser/src/shared/CommandParserHistory.h new file mode 100644 index 00000000..787cb59f --- /dev/null +++ b/engine/shared/library/sharedCommandParser/src/shared/CommandParserHistory.h @@ -0,0 +1,75 @@ +// ====================================================================== +// +// CommandParserHistory.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_CommandParserHistory_H +#define INCLUDED_CommandParserHistory_H + +// ====================================================================== + +class CommandParserHistory +{ +public: + + typedef stddeque::fwd HistoryList_t; + + CommandParserHistory (); + ~CommandParserHistory (); + + bool back (Unicode::String & result); + bool forward (Unicode::String & result); + + size_t getMaxSize () const; + void setMaxSize (size_t newSize); + void resetIndex (); + + void push (const Unicode::String & cmd); + bool front (Unicode::String & cmd); + + const HistoryList_t & getHistoryList () const; + + bool getHistoryCommandByAbbrev (const Unicode::String & abbrev, Unicode::String & cmd) const; + + +private: + CommandParserHistory (const CommandParserHistory & rhs); + CommandParserHistory & operator= (const CommandParserHistory & rhs); + +private: + + /** -1 means no index into history, 0 is most recent command */ + + int m_index; + HistoryList_t * m_history; + size_t m_maxSize; + +}; +//----------------------------------------------------------------- + +inline size_t CommandParserHistory::getMaxSize (void) const +{ + return m_maxSize; +} +//----------------------------------------------------------------- +inline void CommandParserHistory::setMaxSize (const size_t size) +{ + m_maxSize = size; +} +//----------------------------------------------------------------- +inline void CommandParserHistory::resetIndex (void) +{ + m_index = -1; +} +//----------------------------------------------------------------- + +inline const CommandParserHistory::HistoryList_t & CommandParserHistory::getHistoryList () const +{ + NOT_NULL (m_history); + return *m_history; +} +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedCommandParser/src/shared/CommandPermissionManager.cpp b/engine/shared/library/sharedCommandParser/src/shared/CommandPermissionManager.cpp new file mode 100644 index 00000000..9dfe10b9 --- /dev/null +++ b/engine/shared/library/sharedCommandParser/src/shared/CommandPermissionManager.cpp @@ -0,0 +1,23 @@ +// ====================================================================== +// +// CommandPermissionManager.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedCommandParser/FirstSharedCommandParser.h" +#include "sharedCommandParser/CommandPermissionManager.h" + +// ====================================================================== + +CommandPermissionManager::CommandPermissionManager () +{ +} + +//------------------------------------------------------------------------------------------ + +CommandPermissionManager::~CommandPermissionManager () +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedCommandParser/src/shared/CommandPermissionManager.h b/engine/shared/library/sharedCommandParser/src/shared/CommandPermissionManager.h new file mode 100644 index 00000000..c3308e5b --- /dev/null +++ b/engine/shared/library/sharedCommandParser/src/shared/CommandPermissionManager.h @@ -0,0 +1,34 @@ +// ====================================================================== +// +// CommandPermissionManager.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_CommandPermissionManager_H +#define INCLUDED_CommandPermissionManager_H + +class NetworkId; + +// ====================================================================== +class CommandPermissionManager +{ +public: + + virtual ~CommandPermissionManager () = 0; + + /** + * the commandPath is a period-seperated path down through the command tree + */ + + virtual bool isCommandAllowed (const NetworkId & userId, const Unicode::String & commandPath) const = 0; + +protected: + CommandPermissionManager (); + CommandPermissionManager (const CommandPermissionManager & rhs); + CommandPermissionManager & operator= (const CommandPermissionManager & rhs); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedCommandParser/src/shared/FirstSharedCommandParser.h b/engine/shared/library/sharedCommandParser/src/shared/FirstSharedCommandParser.h new file mode 100644 index 00000000..7fa0fa79 --- /dev/null +++ b/engine/shared/library/sharedCommandParser/src/shared/FirstSharedCommandParser.h @@ -0,0 +1,17 @@ +// ====================================================================== +// +// FirstCommandParser.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_FirstCommandParser_H +#define INCLUDED_FirstCommandParser_H + +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedCommandParser/src/win32/FirstSharedCommandParser.cpp b/engine/shared/library/sharedCommandParser/src/win32/FirstSharedCommandParser.cpp new file mode 100644 index 00000000..e07abaf5 --- /dev/null +++ b/engine/shared/library/sharedCommandParser/src/win32/FirstSharedCommandParser.cpp @@ -0,0 +1,8 @@ +// ====================================================================== +// +// FirstCommandParser.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedCommandParser/FirstSharedCommandParser.h"