2012-05-29 13:31:11 +00:00
// 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 ( const 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>] " )
{
nlunreferenced ( rawCommandString ) ;
nlunreferenced ( quiet ) ;
nlunreferenced ( human ) ;
// 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