00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdmisc.h"
00027
00028 #include "nel/misc/command.h"
00029
00030 using namespace std;
00031 using namespace NLMISC;
00032
00033 namespace NLMISC {
00034
00035 ICommand::TCommand *ICommand::Commands;
00036 bool ICommand::CommandsInit;
00037
00038 ICommand::ICommand(const char *commandName, const char *commandHelp, const char *commandArgs)
00039 {
00040
00041
00042 if (!CommandsInit)
00043 {
00044
00045 Commands = new TCommand;
00046 CommandsInit = true;
00047 }
00048
00049 TCommand::iterator comm = (*Commands).find(commandName);
00050
00051 if (comm != (*Commands).end ())
00052 {
00053
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
00059
00060 HelpString = commandHelp;
00061 CommandArgs = commandArgs;
00062 _CommandName = commandName;
00063 Type = Command;
00064 (*Commands)[commandName] = this;
00065 }
00066 }
00067
00068 ICommand::~ICommand()
00069 {
00070
00071
00072 if (!CommandsInit)
00073 {
00074
00075 nlstop;
00076 return;
00077 }
00078
00079
00080
00081 for (TCommand::iterator comm = (*Commands).begin(); comm != (*Commands).end(); comm++)
00082 {
00083 if ((*comm).second == this)
00084 {
00085
00086 (*Commands).erase (comm);
00087
00088 if ((*Commands).size() == 0)
00089 {
00090
00091
00092 delete Commands;
00093 CommandsInit = false;
00094 }
00095
00096 return;
00097 }
00098 }
00099
00100 nlstop;
00101 }
00102
00103 void ICommand::execute (const std::string &commandWithArgs, CLog &log, bool quiet)
00104 {
00105 if (!quiet) log.displayNL ("Executing command : '%s'", commandWithArgs.c_str());
00106
00107
00108
00109 vector<string> args;
00110 string command;
00111
00112 bool firstArg = true;
00113 uint i = 0;
00114 while (true)
00115 {
00116
00117 while (true)
00118 {
00119 if (i == commandWithArgs.size())
00120 {
00121 goto end;
00122 }
00123 if (commandWithArgs[i] != ' ' && commandWithArgs[i] != '\t' && commandWithArgs[i] != '\n' && commandWithArgs[i] != '\r')
00124 {
00125 break;
00126 }
00127 i++;
00128 }
00129
00130
00131 string arg;
00132 if (commandWithArgs[i] == '\"')
00133 {
00134
00135 i++;
00136 while (true)
00137 {
00138 if (i == commandWithArgs.size())
00139 {
00140 if (!quiet) log.displayNL ("Missing end quote character \"");
00141 return;
00142 }
00143 if (commandWithArgs[i] == '"')
00144 {
00145 i++;
00146 break;
00147 }
00148 if (commandWithArgs[i] == '\\')
00149 {
00150
00151 i++;
00152 if (i == commandWithArgs.size())
00153 {
00154 if (!quiet) log.displayNL ("Missing character after the backslash \\ character");
00155 return;
00156 }
00157 switch (commandWithArgs[i])
00158 {
00159 case '\\': arg += '\\'; break;
00160 case 'n': arg += '\n'; break;
00161 case '"': arg += '"'; break;
00162 default:
00163 if (!quiet) log.displayNL ("Unknown escape code '\\%c'", commandWithArgs[i]);
00164 return;
00165 }
00166 i++;
00167 }
00168 else
00169 {
00170 arg += commandWithArgs[i++];
00171 }
00172 }
00173 }
00174 else
00175 {
00176
00177 while (true)
00178 {
00179 if (commandWithArgs[i] == '\\')
00180 {
00181
00182 i++;
00183 if (i == commandWithArgs.size())
00184 {
00185 if (!quiet) log.displayNL ("Missing character after the backslash \\ character");
00186 return;
00187 }
00188 switch (commandWithArgs[i])
00189 {
00190 case '\\': arg += '\\'; break;
00191 case 'n': arg += '\n'; break;
00192 case '"': arg += '"'; break;
00193 default:
00194 if (!quiet) log.displayNL ("Unknown escape code '\\%c'", commandWithArgs[i]);
00195 return;
00196 }
00197 i++;
00198 }
00199 else
00200 {
00201 arg += commandWithArgs[i++];
00202 }
00203 if (i == commandWithArgs.size() || commandWithArgs[i] == ' ' || commandWithArgs[i] == '\t' || commandWithArgs[i] == '\n' || commandWithArgs[i] == '\r')
00204 {
00205 break;
00206 }
00207 }
00208 }
00209 if (firstArg)
00210 {
00211 command = arg;
00212 firstArg = false;
00213 }
00214 else
00215 {
00216 args.push_back (arg);
00217 }
00218 }
00219 end:
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 TCommand::iterator comm = (*Commands).find(command.c_str());
00231 if (comm == (*Commands).end ())
00232 {
00233
00234 if (!quiet) log.displayNL("Command '%s' not found, try 'help'", command.c_str());
00235 }
00236 else
00237 {
00238
00239 if (!(*comm).second->execute (args, log))
00240 {
00241 if (!quiet) log.displayNL("Bad command usage, try 'help %s'", command.c_str());
00242 }
00243 }
00244 }
00245
00246
00247
00248
00249
00250
00251
00252 void ICommand::expand (std::string &commandName, NLMISC::CLog &log)
00253 {
00254
00255 uint32 lastseppos = commandName.find_last_of( " " );
00256 string prefix;
00257 bool useprefix;
00258 if ( lastseppos != string::npos )
00259 {
00260 prefix = commandName.substr( 0, lastseppos+1 );
00261 commandName.erase( 0, lastseppos+1 );
00262 useprefix = true;
00263 }
00264 else
00265 {
00266 useprefix = false;
00267 }
00268
00269 string lowerCommandName = strlwr(const_cast<const string &>(commandName));
00270
00271 vector<string> matchingnames;
00272 for (TCommand::iterator comm = (*Commands).begin(); comm != (*Commands).end(); comm++)
00273 {
00274 string first = strlwr(const_cast<const string &>((*comm).first));
00275 if (first.find( lowerCommandName ) == 0)
00276 {
00277 matchingnames.push_back( (*comm).first );
00278 }
00279 }
00280
00281
00282 if ( matchingnames.empty() )
00283 {
00284 log.displayNL( "No matching command" );
00285 goto returnFromExpand;
00286 }
00287
00288
00289 if ( matchingnames.size() == 1 )
00290 {
00291 commandName = matchingnames.front() + " ";
00292 goto returnFromExpand;
00293 }
00294
00295
00296 {
00297
00298 string commonstr = commandName;
00299 uint i = commandName.size();
00300 while ( true )
00301 {
00302 char letter = 0;
00303 vector<string>::iterator imn;
00304 for ( imn=matchingnames.begin(); imn!=matchingnames.end(); ++imn )
00305 {
00306
00307 if ( ((*imn).size() == i) || ( (letter!=0) && ((*imn)[i] != letter) ) )
00308 {
00309 log.displayNL( "(Matching command not unique)" );
00310 static string lastCommandName;
00311 commandName = commonstr;
00312 if ( lastCommandName == commandName )
00313 {
00314
00315 vector<string>::iterator imn2;
00316 stringstream ss;
00317 ss << "Matching commands:" << endl;
00318 for ( imn2=matchingnames.begin(); imn2!=matchingnames.end(); ++imn2 )
00319 {
00320 ss << " " << (*imn2);
00321 }
00322 log.displayNL( "%s", ss.str().c_str() );
00323 }
00324 lastCommandName = commandName;
00325 goto returnFromExpand;
00326 }
00327
00328 else if ( letter == 0 )
00329 {
00330 letter = (*imn)[i];
00331 }
00332 }
00333 commonstr += letter;
00334 ++i;
00335 }
00336 }
00337
00338 returnFromExpand:
00339
00340
00341 if ( useprefix )
00342 {
00343 commandName = prefix + commandName;
00344 }
00345 }
00346
00347
00348 void ICommand::serialCommands (IStream &f)
00349 {
00350 vector<CSerialCommand> cmd;
00351 for (TCommand::iterator comm = (*Commands).begin(); comm != (*Commands).end(); comm++)
00352 {
00353 cmd.push_back (CSerialCommand ((*comm).first, (*comm).second->Type));
00354 }
00355 f.serialCont (cmd);
00356 }
00357
00358
00359 NLMISC_COMMAND(help,"display help on a specific variable/commands or on all variables and commands", "[<variable>|<command>]")
00360 {
00361 if (args.size() == 0)
00362 {
00363
00364 for (TCommand::iterator comm = (*Commands).begin(); comm != (*Commands).end(); comm++)
00365 {
00366 log.displayNL("%-15s: %s", (*comm).first.c_str(), (*comm).second->HelpString.c_str());
00367 }
00368 }
00369 else if (args.size() == 1)
00370 {
00371
00372 TCommand::iterator comm = (*Commands).find(args[0].c_str());
00373 if (comm == (*Commands).end ())
00374 {
00375 log.displayNL("command '%s' not found", args[0].c_str());
00376 }
00377 else
00378 {
00379 log.displayNL("%s", (*comm).second->HelpString.c_str());
00380 log.displayNL("usage: %s %s", (*comm).first.c_str(), (*comm).second->CommandArgs.c_str(), (*comm).second->HelpString.c_str());
00381 }
00382 }
00383 else
00384 {
00385 return false;
00386 }
00387 return true;
00388 }
00389
00390 }