1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
22 #include "nel/misc/command.h"
23 #include "nel/misc/algo.h"
26 using 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
)
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));
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
;
68 (*LocalCommands
)[commandName
] = this;
71 if (INelContext::isContextInitialised())
73 // directly register this command
74 CCommandRegistry::getInstance().registerCommand(this);
80 // self deregistration
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())
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);
110 // commands is not found
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());
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
);
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());
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
)
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());
208 struct TCommandParams
211 string RawCommandString
;
212 vector
<string
> CommandArgs
;
215 bool CCommandRegistry::execute (const std::string
&commandWithArgs
, CLog
&log
, bool quiet
, bool human
)
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;
236 if (i
== commandWithArgs
.size())
240 if (commandWithArgs
[i
] != ' ' && commandWithArgs
[i
] != '\t' && commandWithArgs
[i
] != '\n' && commandWithArgs
[i
] != '\r')
249 if (allowControlChar
&& commandWithArgs
[i
] == '\"')
251 // starting with a quote "
255 if (i
== commandWithArgs
.size())
257 if (!quiet
) log
.displayNL ("Missing end quote character \"");
260 if (commandWithArgs
[i
] == '"')
265 if (commandWithArgs
[i
] == '\\')
267 // manage escape char backslash
269 if (i
== commandWithArgs
.size())
271 if (!quiet
) log
.displayNL ("Missing character after the backslash \\ character");
274 switch (commandWithArgs
[i
])
276 case '\\': arg
+= '\\'; break; // double backslash
277 case 'n': arg
+= '\n'; break; // new line
278 case '"': arg
+= '"'; break; // "
280 if (!quiet
) log
.displayNL ("Unknown escape code '\\%c'", commandWithArgs
[i
]);
287 arg
+= commandWithArgs
[i
++];
296 if (allowControlChar
&& commandWithArgs
[i
] == '\\')
298 // manage escape char backslash
300 if (i
== commandWithArgs
.size())
302 if (!quiet
) log
.displayNL ("Missing character after the backslash \\ character");
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; // ;
312 if (!quiet
) log
.displayNL ("Unknown escape code '\\%c'", commandWithArgs
[i
]);
316 else if (allowControlChar
&& commandWithArgs
[i
] == ';')
323 arg
+= commandWithArgs
[i
];
328 if (i
== commandWithArgs
.size() || commandWithArgs
[i
] == ' ' || commandWithArgs
[i
] == '\t' || commandWithArgs
[i
] == '\n' || commandWithArgs
[i
] == '\r')
339 // the first arg is the command
341 cp
.CommandName
= arg
;
342 commands
.push_back(cp
);
345 // does this command disable control char for remaining params?
346 if(!isControlCharForCommandEnabled(arg
))
347 allowControlChar
= false;
351 commands
[commands
.size()-1].CommandArgs
.push_back (arg
);
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
);
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
);
373 for (uint u
= 0; u
< commands
.size (); u
++)
375 TCommandParams
&cp
= commands
[u
];
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
);
387 // ok, we found the object
388 ret
= ret
&& (*ppch
)->execute(commands
[u
].RawCommandString
, commandName
, commands
[u
].CommandArgs
, log
, quiet
, human
);
393 log
.displayNL("Command '%s' : can't found object named '%s'",
394 cp
.CommandName
.c_str(),
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
407 log
.displayNL("Command '%s' not found, try 'help'", commands
[u
].CommandName
.c_str());
411 bool res
= comm
->second
->execute (commands
[u
].RawCommandString
, commands
[u
].CommandArgs
, log
, quiet
, human
);
416 log
.displayNL("Bad command usage, try 'help %s'", commands
[u
].CommandName
.c_str());
422 // false if at least one command returned false
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
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
)
456 objectName
= commandName
.substr(spcPos
, lastDot
-spcPos
);
461 if ( lastseppos
!= string::npos
)
463 prefix
= commandName
.substr( 0, lastseppos
+1 );
464 commandName
.erase( 0, lastseppos
+1 );
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
);
500 ICommandsHandler
*const *pch
= _CommandsHandlers
.getB(objectName
);
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() + ".";
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();
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
;
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 )
593 // Put back the prefix
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
));
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
)
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())
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
670 CCommandRegistry
&cr
= CCommandRegistry::getInstance();
672 // treat the case where we have no parameters
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>");
687 // treat the case where the supplied parameter is "all"
690 // display all commands
691 log
.displayNL("Displaying all %d variables and commands: ", cr
._Commands
.size());
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());
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());
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());
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",
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());
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());
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",
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());
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());
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 :");
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());
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",
886 first
->first
.c_str(),
887 first
->second
.CommandHelp
.c_str());
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",
910 commandArgs
.empty() ? "":commandArgs
.front().c_str());
912 for(uint i
= 1; i
< commandArgs
.size(); ++i
)
913 log
.displayNL("%s", commandArgs
[i
].c_str());
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",
934 commandArgs
.empty() ? "":commandArgs
.front().c_str());
936 for(uint i
= 1; i
< commandArgs
.size(); ++i
)
937 log
.displayNL("%s", commandArgs
[i
].c_str());
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());
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
)
960 // allow, so erase from the set of those who disable
961 _CommandsDisablingControlChar
.erase(commandName
);
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()
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
);
1003 ICommandsHandler::~ICommandsHandler()
1005 unregisterCommandsHandler();