Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / misc / command.cpp
blob0f9d84c293ed3e7b0b94af9afb5e6ff254fd2b67
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdmisc.h"
22 #include "nel/misc/command.h"
23 #include "nel/misc/algo.h"
25 using namespace std;
26 using namespace NLMISC;
28 #ifdef DEBUG_NEW
29 #define new DEBUG_NEW
30 #endif
32 namespace NLMISC {
34 //ICommand::TCategorySet* ICommand::_Categories;
35 ICommand::TCommand *ICommand::LocalCommands = NULL;
36 bool ICommand::LocalCommandsInit = false;
37 //set<std::string> ICommand::_CommandsDisablingControlChar;
39 NLMISC_SAFE_SINGLETON_IMPL(CCommandRegistry);
41 ICommand::ICommand(const char *categoryName, const char *commandName, const char *commandHelp, const char *commandArgs)
43 // self registration
45 if (!LocalCommandsInit)
47 LocalCommands = new TCommand;
48 LocalCommandsInit = true;
51 TCommand::iterator comm = LocalCommands->find(commandName);
53 if (comm != LocalCommands->end ())
55 nlinfo("command with same name: %s", commandName);
56 // 2 commands have the same name
57 // nlstopex (("There are 2 commands that have the same name in the project (command name '%s'), skip the second definition", commandName));
59 else
61 // insert the new command in the map
62 //nlinfo ("add command '%s'", commandName);
63 CategoryName = categoryName;
64 HelpString = commandHelp;
65 CommandArgs = commandArgs;
66 _CommandName = commandName;
67 Type = Command;
68 (*LocalCommands)[commandName] = this;
71 if (INelContext::isContextInitialised())
73 // directly register this command
74 CCommandRegistry::getInstance().registerCommand(this);
78 ICommand::~ICommand()
80 // self deregistration
82 // find the command
84 for (TCommand::iterator comm = LocalCommands->begin(); comm != LocalCommands->end(); comm++)
86 if ((*comm).second == this)
88 //printf("remove command\n");
89 LocalCommands->erase (comm);
91 // delete local commands if all gone
92 if (!LocalCommands->size())
94 delete LocalCommands;
95 LocalCommands = NULL;
96 LocalCommandsInit = false;
99 // Yoyo: if no nlinfo()/nlwarning() (thus no createDebug(), thus no new CApplicationContext)
100 // done in the .dll, it is possible that the nel context is never initialized
101 if (INelContext::isContextInitialised())
103 CCommandRegistry::getInstance().unregisterCommand(this);
107 return;
110 // commands is not found
111 // nlstop;
114 void CCommandRegistry::registerCommand(ICommand *command)
116 if (_Commands.find(command->getName()) != _Commands.end())
118 // nlwarning("There are 2 commands that have the same name in the project (command name '%s'), skip the second definition", command->getName().c_str());
119 return;
121 _Commands[command->getName()] = command;
122 _Categories.insert(command->CategoryName);
125 void CCommandRegistry::unregisterCommand(ICommand *command)
127 for (TCommand::iterator comm = _Commands.begin(); comm != _Commands.end(); ++comm)
129 if (comm->second == command)
131 //printf("remove command\n");
132 _Commands.erase (comm);
133 return;
136 //nlwarning("CCommandRegistry::unregisterCommand : the command '%s' is not registered", command->getName().c_str());
139 void CCommandRegistry::registerNamedCommandHandler(ICommandsHandler *handler, const std::string &className)
141 const std::string &name = handler->getCommandHandlerName();
142 if (_CommandsHandlers.getB(name) != NULL)
144 nlwarning("CCommandRegistry : a commands handler with the name '%s' already exist, ignoring new candidat", name.c_str());
145 return;
147 _CommandsHandlers.add(name, handler);
149 TCommandsHandlersClass::iterator it = _CommandsHandlersClass.find(className);
151 if (it == _CommandsHandlersClass.end())
153 nlinfo("CCommandRegistry : adding commands handler for class '%s'", className.c_str());
156 // register the class and commands name
157 TCommandHandlerClassInfo &chci = _CommandsHandlersClass[className];
159 // add an instance to the counter
160 ++chci.InstanceCount;
161 // store the command list
162 TCommandHandlerClassInfo::TCommandsInfo commands;
163 handler->fillCommandsHandlerList(commands);
164 nlassert(chci._Commands.empty() || chci._Commands == commands);
166 if (chci._Commands.empty())
167 std::swap(chci._Commands, commands);
171 void CCommandRegistry::unregisterNamedCommandHandler(ICommandsHandler *handler, const std::string &className)
173 if (_CommandsHandlers.getA(handler) == NULL)
174 return;
176 _CommandsHandlers.removeWithB(handler);
178 // update the handler class commands tables
179 TCommandsHandlersClass::iterator it = _CommandsHandlersClass.find(className);
180 if (it != _CommandsHandlersClass.end())
182 --(it->second.InstanceCount);
184 if (it->second.InstanceCount == 0)
186 nlinfo("CCommandRegistry : removing commands handler for class '% s'", className.c_str());
187 _CommandsHandlersClass.erase(it);
193 bool ICommand::execute (const std::string &commandWithArgs, CLog &log, bool quiet, bool human)
197 return CCommandRegistry::getInstance().execute(commandWithArgs, log, quiet, human);
199 catch(const exception &e)
201 log.displayNL("Command '%s' thrown an exception :", commandWithArgs.c_str());
202 log.displayNL(e.what());
204 return false;
208 struct TCommandParams
210 string CommandName;
211 string RawCommandString;
212 vector<string> CommandArgs;
215 bool CCommandRegistry::execute (const std::string &commandWithArgs, CLog &log, bool quiet, bool human)
217 if (!quiet)
219 log.displayNL ("Executing command : '%s'", commandWithArgs.c_str());
222 // true to indicate that '"', ';' and '\' are special character sequence control
223 bool allowControlChar= true;
224 // Start of each command in the command line
225 string::size_type commandBegin = 0;
227 // convert the buffer into string vector
228 vector<TCommandParams> commands;
229 bool firstArg = true;
230 uint i = 0;
231 for(;;)
233 // skip whitespace
234 for(;;)
236 if (i == commandWithArgs.size())
238 goto end;
240 if (commandWithArgs[i] != ' ' && commandWithArgs[i] != '\t' && commandWithArgs[i] != '\n' && commandWithArgs[i] != '\r')
242 break;
244 i++;
247 // get param
248 string arg;
249 if (allowControlChar && commandWithArgs[i] == '\"')
251 // starting with a quote "
252 i++;
253 for(;;)
255 if (i == commandWithArgs.size())
257 if (!quiet) log.displayNL ("Missing end quote character \"");
258 return false;
260 if (commandWithArgs[i] == '"')
262 i++;
263 break;
265 if (commandWithArgs[i] == '\\')
267 // manage escape char backslash
268 i++;
269 if (i == commandWithArgs.size())
271 if (!quiet) log.displayNL ("Missing character after the backslash \\ character");
272 return false;
274 switch (commandWithArgs[i])
276 case '\\': arg += '\\'; break; // double backslash
277 case 'n': arg += '\n'; break; // new line
278 case '"': arg += '"'; break; // "
279 default:
280 if (!quiet) log.displayNL ("Unknown escape code '\\%c'", commandWithArgs[i]);
281 return false;
283 i++;
285 else
287 arg += commandWithArgs[i++];
291 else
293 // normal word
294 for(;;)
296 if (allowControlChar && commandWithArgs[i] == '\\')
298 // manage escape char backslash
299 i++;
300 if (i == commandWithArgs.size())
302 if (!quiet) log.displayNL ("Missing character after the backslash \\ character");
303 return false;
305 switch (commandWithArgs[i])
307 case '\\': arg += '\\'; break; // double backslash
308 case 'n': arg += '\n'; break; // new line
309 case '"': arg += '"'; break; // "
310 case ';': arg += ';'; break; // ;
311 default:
312 if (!quiet) log.displayNL ("Unknown escape code '\\%c'", commandWithArgs[i]);
313 return false;
316 else if (allowControlChar && commandWithArgs[i] == ';')
318 // command separator
319 break;
321 else
323 arg += commandWithArgs[i];
326 i++;
328 if (i == commandWithArgs.size() || commandWithArgs[i] == ' ' || commandWithArgs[i] == '\t' || commandWithArgs[i] == '\n' || commandWithArgs[i] == '\r')
330 break;
335 if (!arg.empty())
337 if (firstArg)
339 // the first arg is the command
340 TCommandParams cp;
341 cp.CommandName = arg;
342 commands.push_back(cp);
343 firstArg = false;
345 // does this command disable control char for remaining params?
346 if(!isControlCharForCommandEnabled(arg))
347 allowControlChar= false;
349 else
351 commands[commands.size()-1].CommandArgs.push_back (arg);
355 // separator
356 if (i < commandWithArgs.size() && allowControlChar && commandWithArgs[i] == ';')
358 // store the raw command
359 if (!commands.empty() && commands.back().RawCommandString.empty())
360 commands.back().RawCommandString = string(commandWithArgs.begin()+commandBegin, commandWithArgs.begin()+i);
361 firstArg = true;
362 i++;
363 commandBegin = i;
366 end:
367 // store the last raw command string
368 if (!commands.empty() && commands.back().RawCommandString.empty())
369 commands.back().RawCommandString = string(commandWithArgs.begin()+commandBegin, commandWithArgs.begin()+i);
371 bool ret = true;
373 for (uint u = 0; u < commands.size (); u++)
375 TCommandParams &cp = commands[u];
376 // find the command
377 // check for object name
378 string::size_type pos = cp.CommandName.find(".");
379 if (pos != string::npos)
381 // there is an object name, separate it and look in the object registry
382 string objectName = cp.CommandName.substr(0, pos);
383 string commandName = cp.CommandName.substr(pos+1);
384 ICommandsHandler *const *ppch = _CommandsHandlers.getB(objectName);
385 if (ppch != NULL)
387 // ok, we found the object
388 ret = ret && (*ppch)->execute(commands[u].RawCommandString, commandName, commands[u].CommandArgs, log, quiet, human);
390 else
392 if (!quiet)
393 log.displayNL("Command '%s' : can't found object named '%s'",
394 cp.CommandName.c_str(),
395 objectName.c_str());
398 else
400 // this is a global command
401 TCommand::iterator comm = _Commands.find(commands[u].CommandName);
402 if (comm == _Commands.end ())
404 // the command doesn't exist
405 ret = false;
406 if (!quiet)
407 log.displayNL("Command '%s' not found, try 'help'", commands[u].CommandName.c_str());
409 else
411 bool res = comm->second->execute (commands[u].RawCommandString, commands[u].CommandArgs, log, quiet, human);
412 ret = ret & res;
413 if (!res)
415 if (!quiet)
416 log.displayNL("Bad command usage, try 'help %s'", commands[u].CommandName.c_str());
422 // false if at least one command returned false
423 return ret;
428 * Command name completion.
429 * Case-sensitive. Displays the list after two calls with the same non-unique completion.
430 * Completes commands used with prefixes (such as "help " for example) as well.
432 void ICommand::expand (std::string &commandName, NLMISC::CLog &log)
434 // forward to command registry
435 CCommandRegistry::getInstance().expand(commandName, log);
438 void CCommandRegistry::expand (std::string &commandName, NLMISC::CLog &log)
440 // Take out the string before the last separator and remember it as a prefix
441 string objectName;
442 string::size_type lastseppos = commandName.find_last_of( " " );
444 // eventually use the last dot as separator
445 string::size_type lastDot = commandName.find_last_of( "." );
446 if (lastDot != string::npos
447 && (lastseppos == string::npos || lastDot > lastseppos))
449 lastseppos = lastDot;
450 // store the object name to limit the matching scope
451 string::size_type spcPos = commandName.find_last_of(" ", lastDot);
452 if (spcPos == string::npos)
453 spcPos = 0;
454 else
455 spcPos++;
456 objectName = commandName.substr(spcPos, lastDot-spcPos);
459 string prefix;
460 bool useprefix;
461 if ( lastseppos != string::npos )
463 prefix = commandName.substr( 0, lastseppos+1 );
464 commandName.erase( 0, lastseppos+1 );
465 useprefix = true;
467 else
469 useprefix = false;
472 string lowerCommandName = toLowerAscii(commandName);
473 // Build the list of matching command names
474 vector<string> matchingnames;
476 if (objectName.empty())
478 // list of global commands
479 for (TCommand::iterator comm = _Commands.begin(); comm != _Commands.end(); comm++)
481 string first = toLowerAscii((*comm).first);
482 if (first.find( lowerCommandName ) == 0)
484 matchingnames.push_back( (*comm).first );
488 // list of object instance
489 for (TCommandsHandlers::TAToBMap::const_iterator it(_CommandsHandlers.getAToBMap().begin()); it != _CommandsHandlers.getAToBMap().end(); ++it)
491 string first = toLowerAscii(it->first);
492 if (first.find( lowerCommandName ) == 0)
494 matchingnames.push_back( it->first );
498 else
500 ICommandsHandler *const *pch = _CommandsHandlers.getB(objectName);
501 if (pch != NULL)
503 // ok, an object of this name exist, lookup the class
504 TCommandsHandlersClass::iterator it = _CommandsHandlersClass.find((*pch)->getCommandHandlerClassName());
506 // list of class commands
507 if (it != _CommandsHandlersClass.end())
509 TCommandHandlerClassInfo &chci = it->second;
511 for (TCommandHandlerClassInfo::TCommandsInfo::iterator it(chci._Commands.begin()); it != chci._Commands.end(); ++it)
513 string first = toLowerAscii(it->first);
514 if (first.find( lowerCommandName ) == 0)
516 matchingnames.push_back( it->first );
525 // Do not complete if there is no result
526 if ( matchingnames.empty() )
528 log.displayNL( "No matching command" );
529 goto returnFromExpand;
532 // Complete if there is a single result
533 if ( matchingnames.size() == 1 )
535 if (_CommandsHandlers.getAToBMap().find(matchingnames.front()) != _CommandsHandlers.getAToBMap().end())
537 // this is an object, complete with '.'
538 commandName = matchingnames.front() + ".";
540 else
541 commandName = matchingnames.front() + " ";
542 goto returnFromExpand;
545 // Try to complete to the common part if there are several results
547 // Stop loop when a name size is i or names[i] are different
548 string commonstr = commandName;
549 size_t i = commandName.size();
550 while ( true )
552 char letter = 0;
553 vector<string>::iterator imn;
554 for ( imn=matchingnames.begin(); imn!=matchingnames.end(); ++imn )
556 // Return common string if the next letter is not the same in all matching names
557 if ( ((*imn).size() == i) || ( (letter!=0) && ((*imn)[i] != letter) ) )
559 log.displayNL( "(Matching command not unique)" );
560 static string lastCommandName;
561 commandName = commonstr;
562 if ( lastCommandName == commandName )
564 // Display all the matching names
565 vector<string>::iterator imn2;
566 //stringstream ss;
567 string str;
568 //ss << "Matching commands:" << endl;
569 str += "Matching commands:\n";
570 for ( imn2=matchingnames.begin(); imn2!=matchingnames.end(); ++imn2 )
572 //ss << " " << (*imn2);
573 str += " " + (*imn2);
575 log.displayNL( "%s", str.c_str() );
577 lastCommandName = commandName;
578 goto returnFromExpand;
580 // Add the next letter to the common string if it is the same in all matching names
581 else if ( letter == 0 )
583 letter = (*imn)[i];
586 commonstr += letter;
587 ++i;
591 returnFromExpand:
593 // Put back the prefix
594 if ( useprefix )
596 commandName = prefix + commandName;
601 void ICommand::serialCommands (IStream &f)
603 CCommandRegistry::getInstance().serialCommands(f);
606 void CCommandRegistry::serialCommands (IStream &f)
608 vector<CSerialCommand> cmd;
609 for (TCommand::iterator comm = _Commands.begin(); comm != _Commands.end(); comm++)
611 cmd.push_back (CSerialCommand ((*comm).first, (*comm).second->Type));
613 f.serialCont (cmd);
616 bool ICommand::exists (std::string const &commandName)
618 return CCommandRegistry::getInstance().exists(commandName);
620 bool CCommandRegistry::exists (std::string const &commandName)
622 return (_Commands.find(commandName) != _Commands.end ());
625 bool CCommandRegistry::isNamedCommandHandler(const std::string &handlerName)
627 return _CommandsHandlers.getB(handlerName) != NULL;
630 bool ICommand::isCommand (const std::string &str)
632 return CCommandRegistry::getInstance().isCommand(str);
635 bool CCommandRegistry::isCommand (const std::string &str)
637 if (str.empty())
638 return false;
640 return isupper(str[0]) == 0;
643 ICommand *ICommand::getCommand(const std::string &commandName)
645 return CCommandRegistry::getInstance().getCommand(commandName);
648 ICommand *CCommandRegistry::getCommand(const std::string &commandName)
650 TCommand::iterator it(_Commands.find(commandName));
652 if (it == _Commands.end())
653 return NULL;
654 else
655 return it->second;
659 NLMISC_CATEGORISED_COMMAND(nel,help,"display help on a specific variable/commands or on all variables and commands", "[<variable>|<command>]")
661 nlunreferenced(rawCommandString);
662 nlunreferenced(quiet);
663 nlunreferenced(human);
664 // nlassert (_Commands != NULL);
666 // make sure we have a valid number of parameters
667 if (args.size()>1)
668 return false;
670 CCommandRegistry &cr = CCommandRegistry::getInstance();
672 // treat the case where we have no parameters
673 if (args.empty())
675 // display a list of all command categories
676 log.displayNL("Help commands:");
677 log.displayNL("- help all");
678 for (CCommandRegistry::TCategorySet::iterator it=cr._Categories.begin();it!=cr._Categories.end();++it)
680 log.displayNL("- help %s",it->c_str());
682 log.displayNL("- help <wildcard>");
683 log.displayNL("- help <command name>");
684 return true;
687 // treat the case where the supplied parameter is "all"
688 if (args[0]=="all")
690 // display all commands
691 log.displayNL("Displaying all %d variables and commands: ", cr._Commands.size());
692 uint i = 0;
693 for (TCommand::iterator comm = cr._Commands.begin(); comm != cr._Commands.end(); ++comm, i++)
695 log.displayNL("%2d %-15s: %s", i, comm->first.c_str(), comm->second->HelpString.c_str());
698 // display the class commands
700 CCommandRegistry::TCommandsHandlersClass::iterator first(cr._CommandsHandlersClass.begin()), last(cr._CommandsHandlersClass.end());
701 for (; first != last; ++first)
703 log.displayNL("%-15s :", first->first.c_str());
704 TCommandHandlerClassInfo &chci = first->second;
706 TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
707 for (;first != last; ++first)
709 log.displayNL(" %-15s: %s", first->first.c_str(), first->second.CommandHelp.c_str());
715 // display the named instance instance
717 log.displayNL("Listing named object instance : <name> : <className>");
718 CCommandRegistry::TCommandsHandlers::TAToBMap::const_iterator first(cr._CommandsHandlers.getAToBMap().begin()), last(cr._CommandsHandlers.getAToBMap().end());
719 for (; first != last; ++first)
721 log.displayNL(" %-15s: %s",
722 first->first.c_str(),
723 first->second->getCommandHandlerClassName().c_str());
726 return true;
729 // treat the case where the supplied parameter is a category name
731 if (cr._Categories.find(args[0])!=cr._Categories.end())
733 log.displayNL("Displaying commands and variables from category: %s", args[0].c_str());
734 uint i = 0;
735 for (TCommand::iterator comm = cr._Commands.begin(); comm != cr._Commands.end(); ++comm)
737 if (comm->second->CategoryName == args[0])
739 log.displayNL("%2d %-15s: %s", i, comm->first.c_str(), comm->second->HelpString.c_str());
740 i++;
743 return true;
746 // treat the case where the supplied parameter is a class name
748 string className = args[0].substr(0, args[0].find("."));
749 if (cr._CommandsHandlersClass.find(className) != cr._CommandsHandlersClass.end())
751 TCommandHandlerClassInfo &chci = cr._CommandsHandlersClass[className];
752 if (className != args[0])
754 string cmdName = args[0].substr(className.size()+1);
755 // we are looking for a particular command in this class
756 TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
757 for (;first != last; ++first)
759 if (first->first == cmdName)
761 log.displayNL("%s::%s", className.c_str(), cmdName.c_str());
762 log.displayNL("usage: <instanceName>.%s %s : %s",
763 cmdName.c_str(),
764 first->second.CommandArgs.c_str(),
765 first->second.CommandHelp.c_str());
766 // log.displayNL(" %s::%-15s: %s", className.c_str(), cmdName.c_str(), first->second.CommandHelp.c_str());
767 return true;
772 else
774 log.displayNL("%-15s :", args[0].c_str());
776 TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
777 for (;first != last; ++first)
779 log.displayNL(" %-15s: %s", first->first.c_str(), first->second.CommandHelp.c_str());
783 // list the instance of this class
784 log.displayNL(" Here is a list of the %u named instance of this class", chci.InstanceCount);
785 for (CCommandRegistry::TCommandsHandlers::TAToBMap::const_iterator it=cr._CommandsHandlers.getAToBMap().begin(); it != cr._CommandsHandlers.getAToBMap().end(); ++it)
787 if (it->second->getCommandHandlerClassName() == args[0])
789 log.displayNL(" %-15s", it->first.c_str());
792 return true;
796 // treat the case where the supplied parameter is an object name
798 string objName = args[0].substr(0, args[0].find("."));
800 if (cr._CommandsHandlers.getB(objName) != NULL)
802 const string &className = (*(cr._CommandsHandlers.getB(objName)))->getCommandHandlerClassName();
803 if (cr._CommandsHandlersClass.find(className) != cr._CommandsHandlersClass.end())
805 TCommandHandlerClassInfo &chci = cr._CommandsHandlersClass[className];
806 if (objName != args[0])
808 // only display a particular command of this class instance
809 string cmdName = args[0].substr(objName.size()+1);
810 TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
811 for (;first != last; ++first)
813 if (first->first == cmdName)
815 log.displayNL("%s.%s", objName.c_str(), cmdName.c_str());
816 log.displayNL("usage: %s.%s %s : %s",
817 objName.c_str(),
818 cmdName.c_str(),
819 first->second.CommandArgs.c_str(),
820 first->second.CommandHelp.c_str());
821 // log.displayNL(" %s.%-15s: %s", className.c_str(), cmdName.c_str(), first->second.CommandHelp.c_str());
822 return true;
826 else
828 TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
829 for (;first != last; ++first)
831 log.displayNL(" %-15s: %s", first->first.c_str(), first->second.CommandHelp.c_str());
834 return true;
840 // treat the case where the supplied parameter is a wildcard
841 if (args[0].find('*')!=std::string::npos || args[0].find('?')!=std::string::npos)
843 log.displayNL("Displaying commands, variables and objects matching wildcard: '%s'", args[0].c_str());
844 log.displayNL(" Global commands and variables :");
845 uint i = 0;
846 for (TCommand::iterator comm = cr._Commands.begin(); comm != cr._Commands.end(); ++comm)
848 if (testWildCard(comm->first,args[0]))
850 log.displayNL("%2d %-15s: %s", i, comm->first.c_str(), comm->second->HelpString.c_str());
851 i++;
855 // display the named instance instance that match
857 log.displayNL(" Named objects instances : <name> : <className>");
858 CCommandRegistry::TCommandsHandlers::TAToBMap::const_iterator first(cr._CommandsHandlers.getAToBMap().begin()), last(cr._CommandsHandlers.getAToBMap().end());
859 for (; first != last; ++first)
861 if (testWildCard(first->first, args[0]))
863 log.displayNL(" %-15s: '%s'",
864 first->first.c_str(),
865 first->second->getCommandHandlerClassName().c_str());
870 // display the class commands that match
872 log.displayNL(" Class commands :");
873 CCommandRegistry::TCommandsHandlersClass::iterator first(cr._CommandsHandlersClass.begin()), last(cr._CommandsHandlersClass.end());
874 for (; first != last; ++first)
876 const string &className = first->first;
877 TCommandHandlerClassInfo &chci = first->second;
879 TCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());
880 for (;first != last; ++first)
882 if (testWildCard(first->first, args[0]))
884 log.displayNL(" %s::%-15s: %s",
885 className.c_str(),
886 first->first.c_str(),
887 first->second.CommandHelp.c_str());
894 return true;
897 // treat the case where we're looking at help on a given command
899 // look in global commands
900 if (cr._Commands.find(args[0]) != cr._Commands.end())
902 TCommand::iterator comm = cr._Commands.find(args[0]);
903 log.displayNL("%s", comm->second->HelpString.c_str());
905 std::vector<std::string> commandArgs;
906 splitString(comm->second->CommandArgs, "\n", commandArgs);
908 log.displayNL("usage: %s %s",
909 comm->first.c_str(),
910 commandArgs.empty() ? "":commandArgs.front().c_str());
912 for(uint i = 1; i < commandArgs.size(); ++i)
913 log.displayNL("%s", commandArgs[i].c_str());
915 return true;
917 // look in the class commands
919 CCommandRegistry::TCommandsHandlersClass::iterator first(cr._CommandsHandlersClass.begin()), last(cr._CommandsHandlersClass.end());
920 for (; first != last; ++first)
922 TCommandHandlerClassInfo &chci = first->second;
924 TCommandHandlerClassInfo::TCommandsInfo::iterator it = chci._Commands.find(args[0]);
925 if (it != chci._Commands.end())
927 log.displayNL("%s", it->second.CommandHelp.c_str());
929 std::vector<std::string> commandArgs;
930 splitString(it->second.CommandArgs, "\n", commandArgs);
932 log.displayNL("usage: %s %s",
933 it->first.c_str(),
934 commandArgs.empty() ? "":commandArgs.front().c_str());
936 for(uint i = 1; i < commandArgs.size(); ++i)
937 log.displayNL("%s", commandArgs[i].c_str());
939 return true;
947 // we've failed to find a case that works so display an error message and prompt the player
948 log.displayNL("'%s' is not a command, category or wildcard. Type 'help' for more information", args[0].c_str());
949 return true;
952 // ***************************************************************************
953 void ICommand::enableControlCharForCommand(const std::string &commandName, bool state)
955 CCommandRegistry::getInstance().enableControlCharForCommand(commandName, state);
957 void CCommandRegistry::enableControlCharForCommand(const std::string &commandName, bool state)
959 if(state)
960 // allow, so erase from the set of those who disable
961 _CommandsDisablingControlChar.erase(commandName);
962 else
963 // disable, so insert in the set of those who disable
964 _CommandsDisablingControlChar.insert(commandName);
967 // ***************************************************************************
968 bool ICommand::isControlCharForCommandEnabled(const std::string &commandName)
970 return CCommandRegistry::getInstance().isControlCharForCommandEnabled(commandName);
972 bool CCommandRegistry::isControlCharForCommandEnabled(const std::string &commandName)
974 // true if not in the set
975 return _CommandsDisablingControlChar.find(commandName)==_CommandsDisablingControlChar.end();
978 ICommandsHandler::ICommandsHandler()
979 : _ClassName(NULL)
983 void ICommandsHandler::registerCommandsHandler()
985 if (_ClassName == NULL)
987 // store the class name for unregistering during destruction
988 _ClassName = &getCommandHandlerClassName();
989 CCommandRegistry::getInstance().registerNamedCommandHandler(this, *_ClassName);
993 void ICommandsHandler::unregisterCommandsHandler()
995 if (_ClassName != NULL)
997 CCommandRegistry::getInstance().unregisterNamedCommandHandler(this, *_ClassName);
998 _ClassName = NULL;
1003 ICommandsHandler::~ICommandsHandler()
1005 unregisterCommandsHandler();
1009 } // NLMISC