You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ryzom-core/code/nel/src/misc/command.cpp

999 lines
29 KiB
C++

15 years ago
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdmisc.h"
#include "nel/misc/command.h"
#include "nel/misc/algo.h"
using namespace std;
using namespace NLMISC;
namespace NLMISC {
//ICommand::TCategorySet* ICommand::_Categories;
ICommand::TCommand *ICommand::LocalCommands = NULL;
bool ICommand::LocalCommandsInit = false;
//set<std::string> ICommand::_CommandsDisablingControlChar;
NLMISC_SAFE_SINGLETON_IMPL(CCommandRegistry);
ICommand::ICommand(const char *categoryName, const char *commandName, const char *commandHelp, const char *commandArgs)
{
// self registration
if (!LocalCommandsInit)
{
LocalCommands = new TCommand;
LocalCommandsInit = true;
}
TCommand::iterator comm = LocalCommands->find(commandName);
if (comm != LocalCommands->end ())
{
// 2 commands have the same name
nlstopex (("There are 2 commands that have the same name in the project (command name '%s'), skip the second definition", commandName));
}
else
{
// insert the new command in the map
//nlinfo ("add command '%s'", commandName);
CategoryName = categoryName;
HelpString = commandHelp;
CommandArgs = commandArgs;
_CommandName = commandName;
Type = Command;
(*LocalCommands)[commandName] = this;
}
if (INelContext::isContextInitialised())
{
// directly register this command
CCommandRegistry::getInstance().registerCommand(this);
}
}
ICommand::~ICommand()
{
// self deregistration
// find the command
for (TCommand::iterator comm = LocalCommands->begin(); comm != LocalCommands->end(); comm++)
{
if ((*comm).second == this)
{
//printf("remove command\n");
LocalCommands->erase (comm);
// delete local commands if all gone
if (!LocalCommands->size())
{
delete LocalCommands;
LocalCommands = NULL;
LocalCommandsInit = false;
}
// Yoyo: if no nlinfo()/nlwarning() (thus no createDebug(), thus no new CApplicationContext)
// done in the .dll, it is possible that the nel context is never initialized
if (INelContext::isContextInitialised())
{
CCommandRegistry::getInstance().unregisterCommand(this);
}
return;
}
}
// commands is not found
// nlstop;
}
void CCommandRegistry::registerCommand(ICommand *command)
{
if (_Commands.find(command->getName()) != _Commands.end())
{
// nlwarning("There are 2 commands that have the same name in the project (command name '%s'), skip the second definition", command->getName().c_str());
return;
}
_Commands[command->getName()] = command;
_Categories.insert(command->CategoryName);
}
void CCommandRegistry::unregisterCommand(ICommand *command)
{
for (TCommand::iterator comm = _Commands.begin(); comm != _Commands.end(); ++comm)
{
if (comm->second == command)
{
//printf("remove command\n");
_Commands.erase (comm);
return;
}
}
//nlwarning("CCommandRegistry::unregisterCommand : the command '%s' is not registered", command->getName().c_str());
}
void CCommandRegistry::registerNamedCommandHandler(ICommandsHandler *handler, const std::string &className)
{
const std::string &name = handler->getCommandHandlerName();
if (_CommandsHandlers.getB(name) != NULL)
{
nlwarning("CCommandRegistry : a commands handler with the name '%s' already exist, ignoring new candidat", name.c_str());
return;
}
_CommandsHandlers.add(name, handler);
TCommandsHandlersClass::iterator it = _CommandsHandlersClass.find(className);
if (it == _CommandsHandlersClass.end())
{
nlinfo("CCommandRegistry : adding commands handler for class '%s'", className.c_str());
}
// register the class and commands name
TCommandHandlerClassInfo &chci = _CommandsHandlersClass[className];
// add an instance to the counter
++chci.InstanceCount;
// store the command list
TCommandHandlerClassInfo::TCommandsInfo commands;
handler->fillCommandsHandlerList(commands);
nlassert(chci._Commands.empty() || chci._Commands == commands);
if (chci._Commands.empty())
std::swap(chci._Commands, commands);
}
void CCommandRegistry::unregisterNamedCommandHandler(ICommandsHandler *handler, const std::string &className)
{
if (_CommandsHandlers.getA(handler) == NULL)
return;
_CommandsHandlers.removeWithB(handler);
// update the handler class commands tables
TCommandsHandlersClass::iterator it = _CommandsHandlersClass.find(className);
if (it != _CommandsHandlersClass.end())
{
--(it->second.InstanceCount);
if (it->second.InstanceCount == 0)
{
nlinfo("CCommandRegistry : removing commands handler for class '% s'", className.c_str());
_CommandsHandlersClass.erase(it);
}
}
}
bool ICommand::execute (const std::string &commandWithArgs, CLog &log, bool quiet, bool human)
{
try
{
return CCommandRegistry::getInstance().execute(commandWithArgs, log, quiet, human);
}
catch(exception e)
{
log.displayNL("Command '%s' thrown an exception :", commandWithArgs.c_str());
log.displayNL(e.what());
return false;
}
}
struct TCommandParams
{
string CommandName;
string RawCommandString;
vector<string> CommandArgs;
};
bool CCommandRegistry::execute (const std::string &commandWithArgs, CLog &log, bool quiet, bool human)
{
if (!quiet)
{
log.displayNL ("Executing command : '%s'", commandWithArgs.c_str());
}
// true to indicate that '"', ';' and '\' are special character sequence control
bool allowControlChar= true;
// Start of each command in the command line
string::size_type commandBegin = 0;
// convert the buffer into string vector
vector<TCommandParams> commands;
bool firstArg = true;
uint i = 0;
for(;;)
{
// skip whitespace
for(;;)
{
if (i == commandWithArgs.size())
{
goto end;
}
if (commandWithArgs[i] != ' ' && commandWithArgs[i] != '\t' && commandWithArgs[i] != '\n' && commandWithArgs[i] != '\r')
{
break;
}
i++;
}
// get param
string arg;
if (allowControlChar && commandWithArgs[i] == '\"')
{
// starting with a quote "
i++;
for(;;)
{
if (i == commandWithArgs.size())
{
if (!quiet) log.displayNL ("Missing end quote character \"");
return false;
}
if (commandWithArgs[i] == '"')
{
i++;
break;
}
if (commandWithArgs[i] == '\\')
{
// manage escape char backslash
i++;
if (i == commandWithArgs.size())
{
if (!quiet) log.displayNL ("Missing character after the backslash \\ character");
return false;
}
switch (commandWithArgs[i])
{
case '\\': arg += '\\'; break; // double backslash
case 'n': arg += '\n'; break; // new line
case '"': arg += '"'; break; // "
default:
if (!quiet) log.displayNL ("Unknown escape code '\\%c'", commandWithArgs[i]);
return false;
}
i++;
}
else
{
arg += commandWithArgs[i++];
}
}
}
else
{
// normal word
for(;;)
{
if (allowControlChar && commandWithArgs[i] == '\\')
{
// manage escape char backslash
i++;
if (i == commandWithArgs.size())
{
if (!quiet) log.displayNL ("Missing character after the backslash \\ character");
return false;
}
switch (commandWithArgs[i])
{
case '\\': arg += '\\'; break; // double backslash
case 'n': arg += '\n'; break; // new line
case '"': arg += '"'; break; // "
case ';': arg += ';'; break; // ;
default:
if (!quiet) log.displayNL ("Unknown escape code '\\%c'", commandWithArgs[i]);
return false;
}
}
else if (allowControlChar && commandWithArgs[i] == ';')
{
// command separator
break;
}
else
{
arg += commandWithArgs[i];
}
i++;
if (i == commandWithArgs.size() || commandWithArgs[i] == ' ' || commandWithArgs[i] == '\t' || commandWithArgs[i] == '\n' || commandWithArgs[i] == '\r')
{
break;
}
}
}
if (!arg.empty())
{
if (firstArg)
{
// the first arg is the command
TCommandParams cp;
cp.CommandName = arg;
commands.push_back(cp);
firstArg = false;
// does this command disable control char for remaining params?
if(!isControlCharForCommandEnabled(arg))
allowControlChar= false;
}
else
{
commands[commands.size()-1].CommandArgs.push_back (arg);
}
}
// separator
if (i < commandWithArgs.size() && allowControlChar && commandWithArgs[i] == ';')
{
// store the raw command
if (!commands.empty() && commands.back().RawCommandString.empty())
commands.back().RawCommandString = string(commandWithArgs.begin()+commandBegin, commandWithArgs.begin()+i);
firstArg = true;
i++;
commandBegin = i;
}
}
end:
// store the last raw command string
if (!commands.empty() && commands.back().RawCommandString.empty())
commands.back().RawCommandString = string(commandWithArgs.begin()+commandBegin, commandWithArgs.begin()+i);
bool ret = true;
for (uint u = 0; u < commands.size (); u++)
{
TCommandParams &cp = commands[u];
// find the command
// check for object name
string::size_type pos = cp.CommandName.find(".");
if (pos != string::npos)
{
// there is an object name, separate it and look in the object registry
string objectName = cp.CommandName.substr(0, pos);
string commandName = cp.CommandName.substr(pos+1);
ICommandsHandler *const *ppch = _CommandsHandlers.getB(objectName);
if (ppch != NULL)
{
// ok, we found the object
ret = ret && (*ppch)->execute(commands[u].RawCommandString, commandName, commands[u].CommandArgs, log, quiet, human);
}
else
{
if (!quiet)
log.displayNL("Command '%s' : can't found object named '%s'",
cp.CommandName.c_str(),
objectName.c_str());
}
}
else
{
// this is a global command
TCommand::iterator comm = _Commands.find(commands[u].CommandName);
if (comm == _Commands.end ())
{
// the command doesn't exist
ret = false;
if (!quiet)
log.displayNL("Command '%s' not found, try 'help'", commands[u].CommandName.c_str());
}
else
{
bool res = comm->second->execute (commands[u].RawCommandString, commands[u].CommandArgs, log, quiet, human);
ret = ret & res;
if (!res)
{
if (!quiet)
log.displayNL("Bad command usage, try 'help %s'", commands[u].CommandName.c_str());
}
}
}
}
// false if at least one command returned false
return ret;
}
/*
* Command name completion.
* Case-sensitive. Displays the list after two calls with the same non-unique completion.
* Completes commands used with prefixes (such as "help " for example) as well.
*/
void ICommand::expand (std::string &commandName, NLMISC::CLog &log)
{
// forward to command registry
CCommandRegistry::getInstance().expand(commandName, log);
}
void CCommandRegistry::expand (std::string &commandName, NLMISC::CLog &log)
{
// Take out the string before the last separator and remember it as a prefix
string objectName;
string::size_type lastseppos = commandName.find_last_of( " " );
{
// eventually use the last dot as separator
string::size_type lastDot = commandName.find_last_of( "." );
if (lastDot != string::npos
&& (lastseppos == string::npos || lastDot > lastseppos))
{
lastseppos = lastDot;
// store the object name to limit the matching scope
string::size_type spcPos = commandName.find_last_of(" ", lastDot);
if (spcPos == string::npos)
spcPos = 0;
else
spcPos++;
objectName = commandName.substr(spcPos, lastDot-spcPos);
}
}
string prefix;
bool useprefix;
if ( lastseppos != string::npos )
{
prefix = commandName.substr( 0, lastseppos+1 );
commandName.erase( 0, lastseppos+1 );
useprefix = true;
}
else
{
useprefix = false;
}
string lowerCommandName = toLower(commandName);
// Build the list of matching command names
vector<string> matchingnames;
{
if (objectName.empty())
{
// list of global commands
for (TCommand::iterator comm = _Commands.begin(); comm != _Commands.end(); comm++)
{
string first = toLower((*comm).first);
if (first.find( lowerCommandName ) == 0)
{
matchingnames.push_back( (*comm).first );
}
}
// list of object instance
for (TCommandsHandlers::TAToBMap::const_iterator it(_CommandsHandlers.getAToBMap().begin()); it != _CommandsHandlers.getAToBMap().end(); ++it)
{
string first = toLower(it->first);
if (first.find( lowerCommandName ) == 0)
{
matchingnames.push_back( it->first );
}
}
}
else
{
ICommandsHandler *const *pch = _CommandsHandlers.getB(objectName);
if (pch != NULL)
{
// ok, an object of this name exist, lookup the class
TCommandsHandlersClass::iterator it = _CommandsHandlersClass.find((*pch)->getCommandHandlerClassName());
// list of class commands
if (it != _CommandsHandlersClass.end())
{
TCommandHandlerClassInfo &chci = it->second;
for (TCommandHandlerClassInfo::TCommandsInfo::iterator it(chci._Commands.begin()); it != chci._Commands.end(); ++it)
{
string first = toLower(it->first);
if (first.find( lowerCommandName ) == 0)
{
matchingnames.push_back( it->first );
}
}
}
}
}
}
// Do not complete if there is no result
if ( matchingnames.empty() )
{
log.displayNL( "No matching command" );
goto returnFromExpand;
}
// Complete if there is a single result
if ( matchingnames.size() == 1 )
{
if (_CommandsHandlers.getAToBMap().find(matchingnames.front()) != _CommandsHandlers.getAToBMap().end())
{
// this is an object, complete with '.'
commandName = matchingnames.front() + ".";
}
else
commandName = matchingnames.front() + " ";
goto returnFromExpand;
}
// Try to complete to the common part if there are several results
{
// Stop loop when a name size is i or names[i] are different
string commonstr = commandName;
size_t i = commandName.size();
while ( true )
{
char letter = 0;
vector<string>::iterator imn;
for ( imn=matchingnames.begin(); imn!=matchingnames.end(); ++imn )
{
// Return common string if the next letter is not the same in all matching names
if ( ((*imn).size() == i) || ( (letter!=0) && ((*imn)[i] != letter) ) )
{
log.displayNL( "(Matching command not unique)" );
static string lastCommandName;
commandName = commonstr;
if ( lastCommandName == commandName )
{
// Display all the matching names
vector<string>::iterator imn2;
//stringstream ss;
string str;
//ss << "Matching commands:" << endl;
str += "Matching commands:\n";
for ( imn2=matchingnames.begin(); imn2!=matchingnames.end(); ++imn2 )
{
//ss << " " << (*imn2);
str += " " + (*imn2);
}
log.displayNL( "%s", str.c_str() );
}
lastCommandName = commandName;
goto returnFromExpand;
}
// Add the next letter to the common string if it is the same in all matching names
else if ( letter == 0 )
{
letter = (*imn)[i];
}
}
commonstr += letter;
++i;
}
}
returnFromExpand:
// Put back the prefix
if ( useprefix )
{
commandName = prefix + commandName;
}
}
void ICommand::serialCommands (IStream &f)
{
CCommandRegistry::getInstance().serialCommands(f);
}
void CCommandRegistry::serialCommands (IStream &f)
{
vector<CSerialCommand> cmd;
for (TCommand::iterator comm = _Commands.begin(); comm != _Commands.end(); comm++)
{
cmd.push_back (CSerialCommand ((*comm).first, (*comm).second->Type));
}
f.serialCont (cmd);
}
bool ICommand::exists (std::string const &commandName)
{
return CCommandRegistry::getInstance().exists(commandName);
}
bool CCommandRegistry::exists (std::string const &commandName)
{
return (_Commands.find(commandName) != _Commands.end ());
}
bool CCommandRegistry::isNamedCommandHandler(const std::string &handlerName)
{
return _CommandsHandlers.getB(handlerName) != NULL;
}
bool ICommand::isCommand (const std::string &str)
{
return CCommandRegistry::getInstance().isCommand(str);
}
bool CCommandRegistry::isCommand (const std::string &str)
{
if (str.empty())
return false;
return isupper(str[0]) == 0;
}
ICommand *ICommand::getCommand(const std::string &commandName)
{
return CCommandRegistry::getInstance().getCommand(commandName);
}
ICommand *CCommandRegistry::getCommand(const std::string &commandName)
{
TCommand::iterator it(_Commands.find(commandName));
if (it == _Commands.end())
return NULL;
else
return it->second;
}
NLMISC_CATEGORISED_COMMAND(nel,help,"display help on a specific variable/commands or on all variables and commands", "[<variable>|<command>]")
{
// nlassert (_Commands != NULL);
// make sure we have a valid number of parameters
if (args.size()>1)
return false;
CCommandRegistry &cr = CCommandRegistry::getInstance();
// treat the case where we have no parameters
if (args.size() == 0)
{
// display a list of all command categories
log.displayNL("Help commands:");
log.displayNL("- help all");
for (CCommandRegistry::TCategorySet::iterator it=cr._Categories.begin();it!=cr._Categories.end();++it)
{
log.displayNL("- help %s",it->c_str());
}
log.displayNL("- help <wildcard>");
log.displayNL("- help <command name>");
return true;
}
// treat the case where the supplied parameter is "all"
if (args[0]=="all")
{
// display all commands
log.displayNL("Displaying all %d variables and commands: ", cr._Commands.size());
uint i = 0;
for (TCommand::iterator comm = cr._Commands.begin(); comm != cr._Commands.end(); ++comm, i++)
{
log.displayNL("%2d %-15s: %s", i, comm->first.c_str(), comm->second->HelpString.c_str());
}
// display the class commands
{
CCommandRegistry::TCommandsHandlersClass::iterator first(cr._CommandsHandlersClass.begin()), last(cr._CommandsHandlersClass.end());
for (; first != last; ++first)
{
log.displayNL("%-15s :", first->first.c_str());
TCommandHandlerClassInfo &chci = first->second;
{
TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
for (;first != last; ++first)
{
log.displayNL(" %-15s: %s", first->first.c_str(), first->second.CommandHelp.c_str());
}
}
}
}
// display the named instance instance
{
log.displayNL("Listing named object instance : <name> : <className>");
CCommandRegistry::TCommandsHandlers::TAToBMap::const_iterator first(cr._CommandsHandlers.getAToBMap().begin()), last(cr._CommandsHandlers.getAToBMap().end());
for (; first != last; ++first)
{
log.displayNL(" %-15s: %s",
first->first.c_str(),
first->second->getCommandHandlerClassName().c_str());
}
}
return true;
}
// treat the case where the supplied parameter is a category name
{
if (cr._Categories.find(args[0])!=cr._Categories.end())
{
log.displayNL("Displaying commands and variables from category: %s", args[0].c_str());
uint i = 0;
for (TCommand::iterator comm = cr._Commands.begin(); comm != cr._Commands.end(); ++comm)
{
if (comm->second->CategoryName == args[0])
{
log.displayNL("%2d %-15s: %s", i, comm->first.c_str(), comm->second->HelpString.c_str());
i++;
}
}
return true;
}
}
// treat the case where the supplied parameter is a class name
{
string className = args[0].substr(0, args[0].find("."));
if (cr._CommandsHandlersClass.find(className) != cr._CommandsHandlersClass.end())
{
TCommandHandlerClassInfo &chci = cr._CommandsHandlersClass[className];
if (className != args[0])
{
string cmdName = args[0].substr(className.size()+1);
// we are looking for a particular command in this class
TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
for (;first != last; ++first)
{
if (first->first == cmdName)
{
log.displayNL("%s::%s", className.c_str(), cmdName.c_str());
log.displayNL("usage: <instanceName>.%s %s : %s",
cmdName.c_str(),
first->second.CommandArgs.c_str(),
first->second.CommandHelp.c_str());
// log.displayNL(" %s::%-15s: %s", className.c_str(), cmdName.c_str(), first->second.CommandHelp.c_str());
return true;
}
}
}
else
{
log.displayNL("%-15s :", args[0].c_str());
{
TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
for (;first != last; ++first)
{
log.displayNL(" %-15s: %s", first->first.c_str(), first->second.CommandHelp.c_str());
}
}
// list the instance of this class
log.displayNL(" Here is a list of the %u named instance of this class", chci.InstanceCount);
for (CCommandRegistry::TCommandsHandlers::TAToBMap::const_iterator it=cr._CommandsHandlers.getAToBMap().begin(); it != cr._CommandsHandlers.getAToBMap().end(); ++it)
{
if (it->second->getCommandHandlerClassName() == args[0])
{
log.displayNL(" %-15s", it->first.c_str());
}
}
return true;
}
}
}
// treat the case where the supplied parameter is an object name
{
string objName = args[0].substr(0, args[0].find("."));
if (cr._CommandsHandlers.getB(objName) != NULL)
{
const string &className = (*(cr._CommandsHandlers.getB(objName)))->getCommandHandlerClassName();
if (cr._CommandsHandlersClass.find(className) != cr._CommandsHandlersClass.end())
{
TCommandHandlerClassInfo &chci = cr._CommandsHandlersClass[className];
if (objName != args[0])
{
// only display a particular command of this class instance
string cmdName = args[0].substr(objName.size()+1);
TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
for (;first != last; ++first)
{
if (first->first == cmdName)
{
log.displayNL("%s.%s", objName.c_str(), cmdName.c_str());
log.displayNL("usage: %s.%s %s : %s",
objName.c_str(),
cmdName.c_str(),
first->second.CommandArgs.c_str(),
first->second.CommandHelp.c_str());
// log.displayNL(" %s.%-15s: %s", className.c_str(), cmdName.c_str(), first->second.CommandHelp.c_str());
return true;
}
}
}
else
{
TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
for (;first != last; ++first)
{
log.displayNL(" %-15s: %s", first->first.c_str(), first->second.CommandHelp.c_str());
}
return true;
}
}
}
}
// treat the case where the supplied parameter is a wildcard
if (args[0].find('*')!=std::string::npos || args[0].find('?')!=std::string::npos)
{
log.displayNL("Displaying commands, variables and objects matching wildcard: '%s'", args[0].c_str());
log.displayNL(" Global commands and variables :");
uint i = 0;
for (TCommand::iterator comm = cr._Commands.begin(); comm != cr._Commands.end(); ++comm)
{
if (testWildCard(comm->first,args[0]))
{
log.displayNL("%2d %-15s: %s", i, comm->first.c_str(), comm->second->HelpString.c_str());
i++;
}
}
// display the named instance instance that match
{
log.displayNL(" Named objects instances : <name> : <className>");
CCommandRegistry::TCommandsHandlers::TAToBMap::const_iterator first(cr._CommandsHandlers.getAToBMap().begin()), last(cr._CommandsHandlers.getAToBMap().end());
for (; first != last; ++first)
{
if (testWildCard(first->first, args[0]))
{
log.displayNL(" %-15s: '%s'",
first->first.c_str(),
first->second->getCommandHandlerClassName().c_str());
}
}
}
// display the class commands that match
{
log.displayNL(" Class commands :");
CCommandRegistry::TCommandsHandlersClass::iterator first(cr._CommandsHandlersClass.begin()), last(cr._CommandsHandlersClass.end());
for (; first != last; ++first)
{
const string &className = first->first;
TCommandHandlerClassInfo &chci = first->second;
{
TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
for (;first != last; ++first)
{
if (testWildCard(first->first, args[0]))
{
log.displayNL(" %s::%-15s: %s",
className.c_str(),
first->first.c_str(),
first->second.CommandHelp.c_str());
}
}
}
}
}
return true;
}
// treat the case where we're looking at help on a given command
{
// look in global commands
if (cr._Commands.find(args[0]) != cr._Commands.end())
{
TCommand::iterator comm = cr._Commands.find(args[0]);
log.displayNL("%s", comm->second->HelpString.c_str());
std::vector<std::string> commandArgs;
splitString(comm->second->CommandArgs, "\n", commandArgs);
log.displayNL("usage: %s %s",
comm->first.c_str(),
commandArgs.empty() ? "":commandArgs.front().c_str());
for(uint i = 1; i < commandArgs.size(); ++i)
log.displayNL("%s", commandArgs[i].c_str());
return true;
}
// look in the class commands
{
CCommandRegistry::TCommandsHandlersClass::iterator first(cr._CommandsHandlersClass.begin()), last(cr._CommandsHandlersClass.end());
for (; first != last; ++first)
{
TCommandHandlerClassInfo &chci = first->second;
{
TCommandHandlerClassInfo::TCommandsInfo::iterator it = chci._Commands.find(args[0]);
if (it != chci._Commands.end())
{
log.displayNL("%s", it->second.CommandHelp.c_str());
std::vector<std::string> commandArgs;
splitString(it->second.CommandArgs, "\n", commandArgs);
log.displayNL("usage: %s %s",
it->first.c_str(),
commandArgs.empty() ? "":commandArgs.front().c_str());
for(uint i = 1; i < commandArgs.size(); ++i)
log.displayNL("%s", commandArgs[i].c_str());
return true;
}
}
}
}
}
// we've failed to find a case that works so display an error message and prompt the player
log.displayNL("'%s' is not a command, category or wildcard. Type 'help' for more information", args[0].c_str());
return true;
}
// ***************************************************************************
void ICommand::enableControlCharForCommand(const std::string &commandName, bool state)
{
CCommandRegistry::getInstance().enableControlCharForCommand(commandName, state);
}
void CCommandRegistry::enableControlCharForCommand(const std::string &commandName, bool state)
{
if(state)
// allow, so erase from the set of those who disable
_CommandsDisablingControlChar.erase(commandName);
else
// disable, so insert in the set of those who disable
_CommandsDisablingControlChar.insert(commandName);
}
// ***************************************************************************
bool ICommand::isControlCharForCommandEnabled(const std::string &commandName)
{
return CCommandRegistry::getInstance().isControlCharForCommandEnabled(commandName);
}
bool CCommandRegistry::isControlCharForCommandEnabled(const std::string &commandName)
{
// true if not in the set
return _CommandsDisablingControlChar.find(commandName)==_CommandsDisablingControlChar.end();
}
ICommandsHandler::ICommandsHandler()
: _ClassName(NULL)
{
}
void ICommandsHandler::registerCommandsHandler()
{
if (_ClassName == NULL)
{
// store the class name for unregistering during destruction
_ClassName = &getCommandHandlerClassName();
CCommandRegistry::getInstance().registerNamedCommandHandler(this, *_ClassName);
}
}
void ICommandsHandler::unregisterCommandsHandler()
{
if (_ClassName != NULL)
{
CCommandRegistry::getInstance().unregisterNamedCommandHandler(this, *_ClassName);
_ClassName = NULL;
}
}
ICommandsHandler::~ICommandsHandler()
{
unregisterCommandsHandler();
}
} // NLMISC