Added sharedCommandParser library

This commit is contained in:
Anonymous
2014-01-14 22:03:23 -07:00
parent dcef2e89f3
commit 62489f52a3
15 changed files with 1415 additions and 0 deletions
@@ -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)
@@ -0,0 +1 @@
#include "../../src/shared/CommandParser.h"
@@ -0,0 +1 @@
#include "../../src/shared/CommandParserHistory.h"
@@ -0,0 +1 @@
#include "../../src/shared/CommandPermissionManager.h"
@@ -0,0 +1 @@
#include "../../src/shared/FirstSharedCommandParser.h"
@@ -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}
)
@@ -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 <algorithm>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
// ======================================================================
//- TODO: load these messages from the StringTable to localize the commandparser - jww
static const CommandParser::ErrorInfoData errors[static_cast<size_t>(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<ErrorMsgMap_t::iterator, bool> retval =
ms_errorMsgMap->insert (std::make_pair (static_cast<int>(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<int>(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<size_t>(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<CommandParserSet_t::iterator, bool> 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<int>(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;
}
// ======================================================================
@@ -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<String_t>::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<int, String_t>::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<CommandParser*, Comparator>::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
@@ -0,0 +1,110 @@
// ======================================================================
//
// CommandParserHistory.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedCommandParser/FirstSharedCommandParser.h"
#include "sharedCommandParser/CommandParserHistory.h"
#include <deque>
#include <string>
// ======================================================================
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<size_t> (m_index + 1) >= m_history->size ())
return false;
++m_index;
result = (*m_history) [static_cast<size_t> (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<size_t> (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;
}
// ======================================================================
@@ -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<Unicode::String>::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
@@ -0,0 +1,23 @@
// ======================================================================
//
// CommandPermissionManager.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedCommandParser/FirstSharedCommandParser.h"
#include "sharedCommandParser/CommandPermissionManager.h"
// ======================================================================
CommandPermissionManager::CommandPermissionManager ()
{
}
//------------------------------------------------------------------------------------------
CommandPermissionManager::~CommandPermissionManager ()
{
}
// ======================================================================
@@ -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
@@ -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
@@ -0,0 +1,8 @@
// ======================================================================
//
// FirstCommandParser.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedCommandParser/FirstSharedCommandParser.h"