NLMISC::ICommand Class Reference

#include <command.h>

Inheritance diagram for NLMISC::ICommand:

NLMISC::IVariable NLMISC::CVariable< T > NLMISC::CVariablePtr< T >

Detailed Description

Create a function that can be call in realtime. Don't use this class directly but use the macro NLMISC_COMMAND
Author:
Vianney Lecroart

Nevrax France

Date:
2001

Definition at line 94 of file command.h.

Public Types

typedef std::map< std::string,
ICommand * > 
TCommand
enum  TType { Unknown, Command, Variable }

Public Member Functions

virtual bool execute (const std::vector< std::string > &args, NLMISC::CLog &log, bool quiet, bool human=true)=0
const std::string & getName () const
 ICommand (const char *commandName, const char *commandHelp, const char *commandArgs)
 Constructor.

virtual ~ICommand ()

Static Public Member Functions

void execute (const std::string &commandWithArgs, NLMISC::CLog &log, bool quiet=false, bool human=true)
bool exists (std::string &commandName)
 returns true if the command exists

void expand (std::string &commandName, NLMISC::CLog &log=*InfoLog)
bool isCommand (const std::string &str)
 if the string begin with an upper case, it s a variable, otherwise, it s a command

void serialCommands (IStream &f)

Data Fields

std::string CommandArgs
std::string HelpString
TType Type

Static Public Attributes

TCommandCommands
bool CommandsInit

Protected Attributes

std::string _CommandName

Friends

void cbVarChanged (CConfigFile::CVar &var)


Member Typedef Documentation

typedef std::map<std::string, ICommand *> NLMISC::ICommand::TCommand
 

Definition at line 116 of file command.h.

Referenced by ICommand().


Member Enumeration Documentation

enum NLMISC::ICommand::TType
 

Enumeration values:
Unknown 
Command 
Variable 

Definition at line 111 of file command.h.

00111 { Unknown, Command, Variable };


Constructor & Destructor Documentation

NLMISC::ICommand::ICommand const char *  commandName,
const char *  commandHelp,
const char *  commandArgs
 

Constructor.

Definition at line 38 of file command.cpp.

References _CommandName, Command, CommandArgs, Commands, CommandsInit, HelpString, nlstopex, and TCommand.

00039 {
00040         // self registration
00041 
00042         if (!CommandsInit)
00043         {
00044                 //nlinfo ("create map");
00045                 Commands = new TCommand;
00046                 CommandsInit = true;
00047         }
00048 
00049         TCommand::iterator comm = (*Commands).find(commandName);
00050 
00051         if (comm != (*Commands).end ())
00052         {
00053                 // 2 commands have the same name
00054                 nlstopex (("There are 2 commands that have the same name in the project (command name '%s'), skip the second definition", commandName));
00055         }
00056         else
00057         {
00058                 // insert the new command in the map
00059                 //nlinfo ("add command '%s'", commandName);
00060                 HelpString = commandHelp;
00061                 CommandArgs = commandArgs;
00062                 _CommandName = commandName;
00063                 Type = Command;
00064                 (*Commands)[commandName] = this;
00065         }
00066 }

NLMISC::ICommand::~ICommand  )  [virtual]
 

Definition at line 68 of file command.cpp.

References Commands, CommandsInit, and nlstop.

00069 {
00070         // self deregistration
00071 
00072         if (!CommandsInit)
00073         {
00074                 // should never happen
00075                 nlstop;
00076                 return;
00077         }
00078 
00079         // find the command
00080 
00081         for (TCommand::iterator comm = (*Commands).begin(); comm != (*Commands).end(); comm++)
00082         {
00083                 if ((*comm).second == this)
00084                 {
00085                         //printf("remove command\n");
00086                         (*Commands).erase (comm);
00087 
00088                         if ((*Commands).size() == 0)
00089                         {
00090                                 // if the commands map is empty, destroy it
00091                                 //printf("delete map\n");
00092                                 delete Commands;
00093                                 CommandsInit = false;
00094                         }
00095                         
00096                         return;
00097                 }
00098         }
00099         // commands is not found
00100         nlstop;
00101 }


Member Function Documentation

void NLMISC::ICommand::execute const std::string &  commandWithArgs,
NLMISC::CLog log,
bool  quiet = false,
bool  human = true
[static]
 

Executes the command and display output to the log

Parameters:
quiet true if you don't want to display the "executing the command ..."

Definition at line 103 of file command.cpp.

References NLMISC::CLog::displayNL(), and uint.

00104 {
00105         if (!quiet) log.displayNL ("Executing command : '%s'", commandWithArgs.c_str());
00106 
00107         // convert the buffer into string vector
00108         vector<pair<string, vector<string> > > commands;
00109         
00110         bool firstArg = true;
00111         uint i = 0;
00112         while (true)
00113         {
00114                 // skip whitespace
00115                 while (true)
00116                 {
00117                         if (i == commandWithArgs.size())
00118                         {
00119                                 goto end;
00120                         }
00121                         if (commandWithArgs[i] != ' ' && commandWithArgs[i] != '\t' && commandWithArgs[i] != '\n' && commandWithArgs[i] != '\r')
00122                         {
00123                                 break;
00124                         }
00125                         i++;
00126                 }
00127                 
00128                 // get param
00129                 string arg;
00130                 if (commandWithArgs[i] == '\"')
00131                 {
00132                         // starting with a quote "
00133                         i++;
00134                         while (true)
00135                         {
00136                                 if (i == commandWithArgs.size())
00137                                 {
00138                                         if (!quiet) log.displayNL ("Missing end quote character \"");
00139                                         return;
00140                                 }
00141                                 if (commandWithArgs[i] == '"')
00142                                 {
00143                                         i++;
00144                                         break;
00145                                 }
00146                                 if (commandWithArgs[i] == '\\')
00147                                 {
00148                                         // manage escape char backslash
00149                                         i++;
00150                                         if (i == commandWithArgs.size())
00151                                         {
00152                                                 if (!quiet) log.displayNL ("Missing character after the backslash \\ character");
00153                                                 return;
00154                                         }
00155                                         switch (commandWithArgs[i])
00156                                         {
00157                                                 case '\\':      arg += '\\'; break; // double backslash
00158                                                 case 'n':       arg += '\n'; break; // new line
00159                                                 case '"':       arg += '"'; break; // "
00160                                                 default:
00161                                                         if (!quiet) log.displayNL ("Unknown escape code '\\%c'", commandWithArgs[i]);
00162                                                         return;
00163                                         }
00164                                         i++;
00165                                 }
00166                                 else
00167                                 {
00168                                         arg += commandWithArgs[i++];
00169                                 }
00170                         }
00171                 }
00172                 else
00173                 {
00174                         // normal word
00175                         while (true)
00176                         {
00177                                 if (commandWithArgs[i] == '\\')
00178                                 {
00179                                         // manage escape char backslash
00180                                         i++;
00181                                         if (i == commandWithArgs.size())
00182                                         {
00183                                                 if (!quiet) log.displayNL ("Missing character after the backslash \\ character");
00184                                                 return;
00185                                         }
00186                                         switch (commandWithArgs[i])
00187                                         {
00188                                                 case '\\':      arg += '\\'; break; // double backslash
00189                                                 case 'n':       arg += '\n'; break; // new line
00190                                                 case '"':       arg += '"'; break; // "
00191                                                 case ';':       arg += ';'; break; // ;
00192                                                 default:
00193                                                         if (!quiet) log.displayNL ("Unknown escape code '\\%c'", commandWithArgs[i]);
00194                                                         return;
00195                                         }
00196                                 }
00197                                 else if (commandWithArgs[i] == ';')
00198                                 {
00199                                         // command separator
00200                                         break;
00201                                 }
00202                                 else
00203                                 {
00204                                         arg += commandWithArgs[i];
00205                                 }
00206 
00207                                 i++;
00208 
00209                                 if (i == commandWithArgs.size() || commandWithArgs[i] == ' ' || commandWithArgs[i] == '\t' || commandWithArgs[i] == '\n' || commandWithArgs[i] == '\r')
00210                                 {
00211                                         break;
00212                                 }
00213                         }
00214                 }
00215 
00216                 if (!arg.empty())
00217                 {
00218                         if (firstArg)
00219                         {
00220                                 commands.push_back (make_pair(arg, vector<string> () ));
00221                                 firstArg = false;
00222                         }
00223                         else
00224                         {
00225                                 commands[commands.size()-1].second.push_back (arg);
00226                         }
00227                 }
00228 
00229                 // separator
00230                 if (i < commandWithArgs.size() && commandWithArgs[i] == ';')
00231                 {
00232                         firstArg = true;
00233                         i++;
00234                 }
00235         }
00236 end:
00237 
00238 // displays args for debug purpose
00239 /*      for (uint u = 0; u < commands.size (); u++)
00240         {
00241                 nlinfo ("c '%s'", commands[u].first.c_str());
00242                 for (uint t = 0; t < commands[u].second.size (); t++)
00243                 {
00244                         nlinfo ("p%d '%s'", t, commands[u].second[t].c_str());
00245                 }
00246         }
00247 */
00248 
00249         for (uint u = 0; u < commands.size (); u++)
00250         {
00251                 // find the command     
00252                 TCommand::iterator comm = (*Commands).find(commands[u].first);
00253                 if (comm == (*Commands).end ())
00254                 {
00255                         // the command doesn't exist
00256                         if (!quiet) log.displayNL("Command '%s' not found, try 'help'", commands[u].first.c_str());
00257                 }
00258                 else
00259                 {
00260                         //nlinfo("execute command '%s'", commands[u].first.c_str());
00261                         if (!(*comm).second->execute (commands[u].second, log, quiet, human))
00262                         {
00263                                 if (!quiet) log.displayNL("Bad command usage, try 'help %s'", commands[u].first.c_str());
00264                         }
00265                 }
00266         }
00267 }

virtual bool NLMISC::ICommand::execute const std::vector< std::string > &  args,
NLMISC::CLog log,
bool  quiet,
bool  human = true
[pure virtual]
 

Implemented in NLMISC::IVariable, NLMISC::CVariable< T >, NLMISC::CVariable< uint16 >, and NLMISC::CVariable< std::string >.

bool NLMISC::ICommand::exists std::string &  commandName  )  [static]
 

returns true if the command exists

Definition at line 384 of file command.cpp.

00385 {
00386         return ((*Commands).find(commandName) != (*Commands).end ());
00387 }

void NLMISC::ICommand::expand std::string &  commandName,
NLMISC::CLog log = *InfoLog
[static]
 

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.

Definition at line 275 of file command.cpp.

References NLMISC::CLog::displayNL(), NLMISC::strlwr(), uint, and uint32.

00276 {
00277         // Take out the string before the last separator and remember it as a prefix
00278         uint32 lastseppos = commandName.find_last_of( " " );
00279         string prefix;
00280         bool useprefix;
00281         if ( lastseppos != string::npos )
00282         {
00283                 prefix = commandName.substr( 0, lastseppos+1 );
00284                 commandName.erase( 0, lastseppos+1 );
00285                 useprefix = true;
00286         }
00287         else
00288         {
00289                 useprefix = false;
00290         }
00291 
00292         string lowerCommandName = strlwr(const_cast<const string &>(commandName));
00293         // Build the list of matching command names
00294         vector<string> matchingnames;
00295         for (TCommand::iterator comm = (*Commands).begin(); comm != (*Commands).end(); comm++)
00296         {
00297                 string first = strlwr(const_cast<const string &>((*comm).first));
00298                 if (first.find( lowerCommandName ) == 0)
00299                 {
00300                         matchingnames.push_back( (*comm).first );
00301                 }
00302         }
00303 
00304         // Do not complete if there is no result
00305         if ( matchingnames.empty() )
00306         {
00307                 log.displayNL( "No matching command" );
00308                 goto returnFromExpand;
00309         }
00310 
00311         // Complete if there is a single result
00312         if ( matchingnames.size() == 1 )
00313         {
00314                 commandName = matchingnames.front() + " ";
00315                 goto returnFromExpand;
00316         }
00317 
00318         // Try to complete to the common part if there are several results
00319         {
00320                 // Stop loop when a name size is i or names[i] are different
00321                 string commonstr = commandName;
00322                 uint i = commandName.size();
00323                 while ( true )
00324                 {
00325                         char letter = 0;
00326                         vector<string>::iterator imn;
00327                         for ( imn=matchingnames.begin(); imn!=matchingnames.end(); ++imn )
00328                         {
00329                                 // Return common string if the next letter is not the same in all matching names
00330                                 if ( ((*imn).size() == i) || ( (letter!=0) && ((*imn)[i] != letter) ) )
00331                                 {
00332                                         log.displayNL( "(Matching command not unique)" );
00333                                         static string lastCommandName;
00334                                         commandName = commonstr;
00335                                         if ( lastCommandName == commandName )
00336                                         {
00337                                                 // Display all the matching names 
00338                                                 vector<string>::iterator imn2;
00339                                                 //stringstream ss;
00340                                                 string str;
00341                                                 //ss << "Matching commands:" << endl;
00342                                                 str += "Matching commands:\n";
00343                                                 for ( imn2=matchingnames.begin(); imn2!=matchingnames.end(); ++imn2 )
00344                                                 {
00345                                                         //ss << " " << (*imn2);
00346                                                         str += " " + (*imn2);
00347                                                 }
00348                                                 log.displayNL( "%s", str.c_str() );
00349                                         }
00350                                         lastCommandName = commandName;
00351                                         goto returnFromExpand;
00352                                 }
00353                                 // Add the next letter to the common string if it is the same in all matching names
00354                                 else if ( letter == 0 )
00355                                 {
00356                                         letter = (*imn)[i];
00357                                 }
00358                         }
00359                         commonstr += letter;
00360                         ++i;
00361                 }
00362         }
00363 
00364 returnFromExpand:
00365 
00366         // Put back the prefix
00367         if ( useprefix )
00368         {
00369                 commandName = prefix + commandName;
00370         }
00371 }

const std::string& NLMISC::ICommand::getName void   )  const [inline]
 

Definition at line 145 of file command.h.

References _CommandName.

Referenced by NLNET::cbDirectoryChanged().

00145 { return _CommandName; }

bool NLMISC::ICommand::isCommand const std::string &  str  )  [inline, static]
 

if the string begin with an upper case, it s a variable, otherwise, it s a command

Definition at line 137 of file command.h.

00138         {
00139                 if (str.empty())
00140                         return false;
00141                 
00142                 return isupper(str[0]) == 0;
00143         }

void NLMISC::ICommand::serialCommands IStream f  )  [static]
 

Definition at line 374 of file command.cpp.

References NLMISC::IStream::serialCont().

00375 {
00376         vector<CSerialCommand> cmd;
00377         for (TCommand::iterator comm = (*Commands).begin(); comm != (*Commands).end(); comm++)
00378         {
00379                 cmd.push_back (CSerialCommand ((*comm).first, (*comm).second->Type));
00380         }
00381         f.serialCont (cmd);
00382 }


Friends And Related Function Documentation

void cbVarChanged CConfigFile::CVar var  )  [friend]
 

Definition at line 36 of file variable.cpp.

00037 {
00038         for (ICommand::TCommand::iterator comm = (*ICommand::Commands).begin(); comm != (*ICommand::Commands).end(); comm++)
00039         {
00040                 if ((*comm).second->Type == ICommand::Variable && (*comm).second->_CommandName == cvar.Name)
00041                 {
00042                         IVariable *var = (IVariable *)((*comm).second);
00043                         string val = cvar.asString();
00044                         nlinfo ("VAR: Setting variable '%s' with value '%s' from config file", cvar.Name.c_str(), val.c_str());
00045                         var->fromString(val, true);
00046                 }
00047         }
00048 }


Field Documentation

std::string NLMISC::ICommand::_CommandName [protected]
 

Definition at line 149 of file command.h.

Referenced by getName(), ICommand(), and NLMISC::IVariable::init().

std::string NLMISC::ICommand::CommandArgs
 

Definition at line 108 of file command.h.

Referenced by ICommand().

ICommand::TCommand * NLMISC::ICommand::Commands [static]
 

Definition at line 35 of file command.cpp.

Referenced by ICommand(), and ~ICommand().

bool NLMISC::ICommand::CommandsInit [static]
 

Definition at line 36 of file command.cpp.

Referenced by ICommand(), and ~ICommand().

std::string NLMISC::ICommand::HelpString
 

Definition at line 107 of file command.h.

Referenced by ICommand().

TType NLMISC::ICommand::Type
 

Definition at line 112 of file command.h.


The documentation for this class was generated from the following files:
Generated on Tue Mar 16 13:45:24 2004 for NeL by doxygen 1.3.6