Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/console/src/core/CommandExecutor.cc @ 1402

Last change on this file since 1402 was 1402, checked in by landauf, 16 years ago

backup-commit

File size: 24.9 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "CommandExecutor.h"
30#include "ConsoleCommand.h"
31#include "util/String.h"
32#include "util/Convert.h"
33#include "Identifier.h"
34#include "Language.h"
35#include "Debug.h"
36#include "TclBind.h"
37
38namespace orxonox
39{
40    CommandExecutor& CommandExecutor::getInstance()
41    {
42        static CommandExecutor instance;
43        return instance;
44    }
45
46    CommandEvaluation& CommandExecutor::getEvaluation()
47    {
48        return CommandExecutor::getInstance().evaluation_;
49    }
50
51    const CommandEvaluation& CommandExecutor::getLastEvaluation()
52    {
53        return CommandExecutor::getInstance().evaluation_;
54    }
55
56    ConsoleCommand& CommandExecutor::addConsoleCommandShortcut(ConsoleCommand* command)
57    {
58        std::map<std::string, ConsoleCommand*>::const_iterator it = CommandExecutor::getInstance().consoleCommandShortcuts_.find(command->getName());
59        if (it != CommandExecutor::getInstance().consoleCommandShortcuts_.end())
60        {
61            COUT(2) << "Warning: Overwriting console-command shortcut with name " << command->getName() << "." << std::endl;
62        }
63
64
65        CommandExecutor::getInstance().consoleCommandShortcuts_[command->getName()] = command;
66        CommandExecutor::getInstance().consoleCommandShortcuts_LC_[getLowercase(command->getName())] = command;
67        return (*command);
68    }
69
70    /**
71        @brief Returns the executor of a console command shortcut with given name.
72        @brief name The name of the requested console command shortcut
73        @return The executor of the requested console command shortcut
74    */
75    ConsoleCommand* CommandExecutor::getConsoleCommandShortcut(const std::string& name)
76    {
77        std::map<std::string, ConsoleCommand*>::const_iterator it = CommandExecutor::getInstance().consoleCommandShortcuts_.find(name);
78        if (it != CommandExecutor::getInstance().consoleCommandShortcuts_.end())
79            return (*it).second;
80        else
81            return 0;
82    }
83
84    /**
85        @brief Returns the executor of a console command shortcut with given name in lowercase.
86        @brief name The name of the requested console command shortcut in lowercase
87        @return The executor of the requested console command shortcut
88    */
89    ConsoleCommand* CommandExecutor::getLowercaseConsoleCommandShortcut(const std::string& name)
90    {
91        std::map<std::string, ConsoleCommand*>::const_iterator it = CommandExecutor::getInstance().consoleCommandShortcuts_LC_.find(name);
92        if (it != CommandExecutor::getInstance().consoleCommandShortcuts_LC_.end())
93            return (*it).second;
94        else
95            return 0;
96    }
97
98    bool CommandExecutor::execute(const std::string& command, bool useTcl)
99    {
100        if (useTcl)
101            return TclBind::eval(command);
102
103        CommandExecutor::parseIfNeeded(command);
104        return CommandExecutor::getEvaluation().execute();
105    }
106
107    std::string CommandExecutor::complete(const std::string& command)
108    {
109        CommandExecutor::parseIfNeeded(command);
110        return CommandExecutor::getEvaluation().complete();
111    }
112
113    std::string CommandExecutor::hint(const std::string& command)
114    {
115        CommandExecutor::parseIfNeeded(command);
116        return CommandExecutor::getEvaluation().hint();
117    }
118
119    CommandEvaluation CommandExecutor::evaluate(const std::string& command)
120    {
121        CommandExecutor::parse(command, true);
122        CommandExecutor::getEvaluation().evaluateParams();
123        return CommandExecutor::getEvaluation();
124    }
125
126    void CommandExecutor::parseIfNeeded(const std::string& command)
127    {
128        if ((CommandExecutor::getEvaluation().getCommand() != command) || (CommandExecutor::getEvaluation().getState() == CS_Uninitialized))
129            CommandExecutor::parse(command);
130        else if (!CommandExecutor::getEvaluation().isValid())
131        {
132            CommandExecutor::getEvaluation().setNewCommand(false);
133            CommandExecutor::parse(command, false);
134        }
135    }
136
137    void CommandExecutor::parse(const std::string& command, bool bInitialize)
138    {
139std::cout << "parse: command: >" << command << "<" << std::endl;
140        if (bInitialize)
141            CommandExecutor::getEvaluation().initialize(command);
142
143        CommandExecutor::getEvaluation().setTokens(command);
144        CommandExecutor::getEvaluation().setCommand(command);
145
146        switch (CommandExecutor::getEvaluation().getState())
147        {
148            case CS_Uninitialized:
149            {
150std::cout << "parse: state: CS_Uninitialized" << std::endl;
151                // Impossible
152                break;
153            }
154            case CS_Empty:
155            {
156std::cout << "parse: state: CS_Empty" << std::endl;
157                CommandExecutor::createListOfPossibleIdentifiers(CommandExecutor::getArgument(0));
158                CommandExecutor::createListOfPossibleFunctions(CommandExecutor::getArgument(0));
159
160                if (CommandExecutor::argumentsGiven() > 0)
161                {
162                    CommandExecutor::getEvaluation().setState(CS_ShortcutOrIdentifier);
163                    CommandExecutor::parse(command, false);
164                    return;
165                }
166                break;
167            }
168            case CS_ShortcutOrIdentifier:
169            {
170std::cout << "parse: state: CS_ShortcutOrIdentifier" << std::endl;
171                if (CommandExecutor::argumentsFinished() > 0 || !CommandExecutor::getEvaluation().isNewCommand())
172                {
173                    // There's already a finished first argument - check if it's function or a classname
174                    CommandExecutor::getEvaluation().setIdentifier(CommandExecutor::getPossibleIdentifier(CommandExecutor::getArgument(0)));
175                    CommandExecutor::getEvaluation().setFunction(CommandExecutor::getPossibleCommand(CommandExecutor::getArgument(0)));
176
177                    if (CommandExecutor::getEvaluation().getFunction())
178                    {
179                        // It's a shortcut - continue parsing
180                        CommandExecutor::getEvaluation().setState(CS_Shortcut_Params);
181                        if (CommandExecutor::argumentsFinished() > 0 )
182                            CommandExecutor::parse(command, false);
183                        else
184                            CommandExecutor::parse(command + " ", false);
185                        return;
186                    }
187                    else if (CommandExecutor::getEvaluation().getIdentifier())
188                    {
189                        // It's a classname - continue parsing
190                        CommandExecutor::getEvaluation().setState(CS_Function);
191                        if (CommandExecutor::argumentsFinished() > 0 )
192                            CommandExecutor::parse(command, false);
193                        else
194                            CommandExecutor::parse(command + " ", false);
195                        return;
196                    }
197                }
198
199                unsigned int numIdentifiers = CommandExecutor::getEvaluation().getListOfPossibleIdentifiers().size();
200                unsigned int numCommands = CommandExecutor::getEvaluation().getListOfPossibleFunctions().size();
201
202                if (CommandExecutor::argumentsFinished() == 0)
203                {
204                    // There is no finished first argument
205                    if (numCommands == 1 && numIdentifiers == 0)
206                    {
207                        // It must be this command
208                        const std::string* possibleCommand = (*CommandExecutor::getEvaluation().getListOfPossibleFunctions().begin()).second;
209                        CommandExecutor::getEvaluation().setState(CS_Shortcut_Params);
210                        CommandExecutor::getEvaluation().setFunction(CommandExecutor::getPossibleCommand(*possibleCommand));
211                        CommandExecutor::parse(*possibleCommand + " ", false);
212                        return;
213                    }
214                    else if (numIdentifiers == 1 && numCommands == 0)
215                    {
216                        // It must be this classname
217                        const std::string* possibleIdentifier = (*CommandExecutor::getEvaluation().getListOfPossibleIdentifiers().begin()).second;
218                        CommandExecutor::getEvaluation().setState(CS_Function);
219                        CommandExecutor::getEvaluation().setIdentifier(CommandExecutor::getPossibleIdentifier(*possibleIdentifier));
220                        CommandExecutor::parse(*possibleIdentifier + " ", false);
221                        return;
222                    }
223                }
224
225                if (numCommands == 0 && numIdentifiers == 0)
226                {
227                    // It's not a shortcut nor a classname
228                    CommandExecutor::getEvaluation().setState(CS_Error);
229                    AddLanguageEntry("commandexecutorunknownfirstargument", "is not a shortcut nor a classname");
230                    CommandExecutor::getEvaluation().setError("Error: " + CommandExecutor::getArgument(0) + " " + GetLocalisation("commandexecutorunknownfirstargument") + ".");
231                }
232                break;
233            }
234            case CS_Function:
235std::cout << "parse: state: CS_Function" << std::endl;
236            {
237                if (CommandExecutor::getEvaluation().getIdentifier() && CommandExecutor::argumentsGiven() > 0)
238                {
239                    if (CommandExecutor::argumentsFinished() > 1 || !CommandExecutor::getEvaluation().isNewCommand())
240                    {
241                        // There is already a second argument - check if it's a valid function
242                        CommandExecutor::getEvaluation().setFunction(CommandExecutor::getPossibleCommand(CommandExecutor::getArgument(1), CommandExecutor::getEvaluation().getIdentifier()));
243
244                        if (CommandExecutor::getEvaluation().getFunction())
245                        {
246                            // It's a shortcut - continue parsing
247                            CommandExecutor::getEvaluation().setState(CS_Function_Params);
248                            if (CommandExecutor::argumentsFinished() > 1 )
249                                CommandExecutor::parse(command, false);
250                            else
251                                CommandExecutor::parse(command + " ", false);
252                            return;
253                        }
254                        else if (CommandExecutor::argumentsFinished() > 1)
255                        {
256                            // It's not a function
257                            AddLanguageEntry("commandexecutorunknowncommand", "is not a valid commandname");
258                            CommandExecutor::getEvaluation().setError("Error: " + CommandExecutor::getArgument(1) + " " + GetLocalisation("commandexecutorunknowncommand") + ".");
259                            CommandExecutor::getEvaluation().setState(CS_Error);
260                        }
261                    }
262
263                    CommandExecutor::createListOfPossibleFunctions(CommandExecutor::getArgument(1), CommandExecutor::getEvaluation().getIdentifier());
264
265                    if (CommandExecutor::argumentsFinished() <= 1)
266                    {
267                        // There is no finished second argument
268                        unsigned int numFunctions = CommandExecutor::getEvaluation().getListOfPossibleFunctions().size();
269
270                        if (numFunctions == 1)
271                        {
272                            // It must be this command
273                            const std::string* possibleCommand = (*CommandExecutor::getEvaluation().getListOfPossibleFunctions().begin()).second;
274                            CommandExecutor::getEvaluation().setState(CS_Function_Params);
275                            CommandExecutor::getEvaluation().setFunction(CommandExecutor::getPossibleCommand(*possibleCommand, CommandExecutor::getEvaluation().getIdentifier()));
276                            CommandExecutor::parse(CommandExecutor::getArgument(0) + " " + *possibleCommand + " ", false);
277                            return;
278                        }
279                        else if (numFunctions == 0)
280                        {
281                            // It's not a function
282                            AddLanguageEntry("commandexecutorunknowncommand", "is not a valid commandname");
283                            CommandExecutor::getEvaluation().setError("Error: " + CommandExecutor::getArgument(1) + " " + GetLocalisation("commandexecutorunknowncommand") + ".");
284                            CommandExecutor::getEvaluation().setState(CS_Error);
285                        }
286                    }
287
288                    // It's ambiguous
289                    return;
290                }
291
292                // Bad state
293                CommandExecutor::getEvaluation().setState(CS_Error);
294                break;
295            }
296            case CS_Shortcut_Params:
297std::cout << "parse: state: CS_Shortcut_Params" << std::endl;
298            case CS_Function_Params:
299            {
300std::cout << "parse: state: CS_Function_Params" << std::endl;
301                if (CommandExecutor::getEvaluation().getFunction())
302                {
303std::cout << "1\n";
304                    unsigned int startindex = 0;
305                    if (CommandExecutor::getEvaluation().getState() == CS_Shortcut_Params)
306                        startindex = 1;
307                    else if (CommandExecutor::getEvaluation().getState() == CS_Function_Params)
308                        startindex = 2;
309std::cout << "2\n";
310
311                    if (CommandExecutor::argumentsGiven() >= startindex)
312                    {
313std::cout << "3\n";
314                        if (CommandExecutor::enoughArgumentsGiven(CommandExecutor::getEvaluation().getFunction()))
315                        {
316std::cout << "4\n";
317                            if (CommandExecutor::getEvaluation().getState() == CS_Shortcut_Params)
318                                CommandExecutor::getEvaluation().setState(CS_Shortcut_Finished);
319                            else if (CommandExecutor::getEvaluation().getState() == CS_Function_Params)
320                                CommandExecutor::getEvaluation().setState(CS_Function_Finished);
321
322                            return;
323                        }
324                        else
325                        {
326std::cout << "5\n";
327std::cout << "last argument: " << CommandExecutor::getLastArgument() << std::endl;
328std::cout << "function: " << CommandExecutor::getEvaluation().getFunction() << std::endl;
329std::cout << "functionname: " << CommandExecutor::getEvaluation().getFunction()->getName() << std::endl;
330std::cout << "param nr: " << CommandExecutor::getEvaluation().getTokens().size() - startindex << std::endl;
331                            CommandExecutor::createListOfPossibleArguments(CommandExecutor::getLastArgument(), CommandExecutor::getEvaluation().getFunction(), CommandExecutor::getEvaluation().getTokens().size() - startindex);
332std::cout << "6\n";
333                            unsigned int numArguments = CommandExecutor::getEvaluation().getListOfPossibleArguments().size();
334
335                            if (numArguments == 1)
336                            {
337std::cout << "7\n";
338                                // There is exactly one possible argument
339                                const std::string* possibleArgument = (*CommandExecutor::getEvaluation().getListOfPossibleArguments().begin()).second;
340                                CommandExecutor::parse(CommandExecutor::getEvaluation().getTokens().subSet(0, CommandExecutor::getEvaluation().getTokens().size() - 1 - startindex).join() + " " + (*possibleArgument) + " ");
341                                return;
342                            }
343
344std::cout << "8\n";
345                            if ((CommandExecutor::argumentsGiven() > CommandExecutor::argumentsFinished()) && (!CommandExecutor::getEvaluation().isNewCommand()))
346                            {
347std::cout << "9\n";
348                                // There is more than one argument, but the user wants to use this - check if there is a perfect match
349                                const std::string* possibleArgument = CommandExecutor::getPossibleArgument(CommandExecutor::getLastArgument(), CommandExecutor::getEvaluation().getFunction(), CommandExecutor::getEvaluation().getTokens().size() - startindex);
350                                if (possibleArgument)
351                                {
352std::cout << "10\n";
353                                    // There is such an argument - use it
354                                    CommandExecutor::parse(command + " ", false);
355                                    return;
356                                }
357std::cout << "11\n";
358                            }
359std::cout << "12\n";
360                        }
361std::cout << "13\n";
362
363                        // Nothing to do
364                        return;
365                    }
366                }
367
368                // Bad state
369                CommandExecutor::getEvaluation().setState(CS_Error);
370                break;
371            }
372            case CS_Shortcut_Finished:
373std::cout << "parse: state: CS_Shortcut_Finished" << std::endl;
374                break;
375            case CS_Function_Finished:
376std::cout << "parse: state: CS_Function_Finished" << std::endl;
377                break;
378            case CS_Error:
379std::cout << "parse: state: CS_Error" << std::endl;
380                break;
381        }
382    }
383
384    unsigned int CommandExecutor::argumentsFinished()
385    {
386        if (CommandExecutor::getEvaluation().getCommand().size() > 0)
387        {
388            if (CommandExecutor::getEvaluation().getCommand()[CommandExecutor::getEvaluation().getCommand().size() - 1] == ' ')
389                return CommandExecutor::getEvaluation().getTokens().size();
390            else if (CommandExecutor::getEvaluation().getTokens().size() > 0)
391                return CommandExecutor::getEvaluation().getTokens().size() - 1;
392        }
393        return 0;
394    }
395
396    unsigned int CommandExecutor::argumentsGiven()
397    {
398        return CommandExecutor::getEvaluation().getTokens().size();
399    }
400
401    bool CommandExecutor::enoughArgumentsGiven(ConsoleCommand* command)
402    {
403        if (CommandExecutor::getEvaluation().getIdentifier())
404            return (CommandExecutor::argumentsGiven() >= (2 + command->getParamCount()));
405        else
406            return (CommandExecutor::argumentsGiven() >= (1 + command->getParamCount()));
407    }
408
409    std::string CommandExecutor::getArgument(unsigned int index)
410    {
411        if ((index >= 0) && index < (CommandExecutor::getEvaluation().getTokens().size()))
412            return CommandExecutor::getEvaluation().getTokens()[index];
413        else
414            return "";
415    }
416
417    std::string CommandExecutor::getLastArgument()
418    {
419        if (CommandExecutor::getEvaluation().getTokens().size() > 0)
420            if (CommandExecutor::getEvaluation().getCommand().size() > 0 && CommandExecutor::getEvaluation().getCommand()[CommandExecutor::getEvaluation().getCommand().size() - 1] != ' ')
421                return CommandExecutor::getEvaluation().getTokens()[CommandExecutor::getEvaluation().getTokens().size() - 1];
422
423        return "";
424    }
425
426    void CommandExecutor::createListOfPossibleIdentifiers(const std::string& fragment)
427    {
428        std::string lowercase = getLowercase(fragment);
429        for (std::map<std::string, Identifier*>::const_iterator it = Identifier::getLowercaseIdentifierMapBegin(); it != Identifier::getLowercaseIdentifierMapEnd(); ++it)
430            if ((*it).second->hasConsoleCommands())
431                if ((*it).first.find(lowercase) == 0 || fragment == "")
432                    CommandExecutor::getEvaluation().getListOfPossibleIdentifiers().push_back(std::pair<const std::string*, const std::string*>(&(*it).first, &(*it).second->getName()));
433
434        CommandExecutor::getEvaluation().getListOfPossibleIdentifiers().sort(CommandExecutor::compareStringsInList);
435    }
436
437    void CommandExecutor::createListOfPossibleFunctions(const std::string& fragment, Identifier* identifier)
438    {
439        std::string lowercase = getLowercase(fragment);
440        if (!identifier)
441        {
442            for (std::map<std::string, ConsoleCommand*>::const_iterator it = CommandExecutor::getLowercaseConsoleCommandShortcutMapBegin(); it != CommandExecutor::getLowercaseConsoleCommandShortcutMapEnd(); ++it)
443                if ((*it).first.find(lowercase) == 0 || fragment == "")
444                    CommandExecutor::getEvaluation().getListOfPossibleFunctions().push_back(std::pair<const std::string*, const std::string*>(&(*it).first, &(*it).second->getName()));
445        }
446        else
447        {
448            for (std::map<std::string, ConsoleCommand*>::const_iterator it = identifier->getLowercaseConsoleCommandMapBegin(); it != identifier->getLowercaseConsoleCommandMapEnd(); ++it)
449                if ((*it).first.find(lowercase) == 0 || fragment == "")
450                    CommandExecutor::getEvaluation().getListOfPossibleFunctions().push_back(std::pair<const std::string*, const std::string*>(&(*it).first, &(*it).second->getName()));
451        }
452
453        CommandExecutor::getEvaluation().getListOfPossibleFunctions().sort(CommandExecutor::compareStringsInList);
454    }
455
456    void CommandExecutor::createListOfPossibleArguments(const std::string& fragment, ConsoleCommand* command, unsigned int param)
457    {
458std::cout << "2_1\n";
459        std::string lowercase = getLowercase(fragment);
460std::cout << "2_2\n";
461        for (std::list<std::pair<std::string, std::string> >::const_iterator it = command->getArgumentCompletionListBegin(param); it != command->getArgumentCompletionListEnd(param); ++it)
462        {
463std::cout << "2_3\n";
464            if ((*it).first.find(lowercase) == 0 || fragment == "")
465            {
466std::cout << "2_4\n";
467                CommandExecutor::getEvaluation().getListOfPossibleArguments().push_back(std::pair<const std::string*, const std::string*>(&(*it).first, &(*it).second));
468std::cout << "2_5\n";
469            }
470        }
471
472std::cout << "2_6\n";
473        CommandExecutor::getEvaluation().getListOfPossibleArguments().sort(CommandExecutor::compareStringsInList);
474std::cout << "2_7\n";
475    }
476
477    Identifier* CommandExecutor::getPossibleIdentifier(const std::string& name)
478    {
479        std::string lowercase = getLowercase(name);
480        std::map<std::string, Identifier*>::const_iterator it = Identifier::getLowercaseIdentifierMap().find(lowercase);
481        if ((it != Identifier::getLowercaseIdentifierMapEnd()) && (*it).second->hasConsoleCommands())
482            return (*it).second;
483
484        return 0;
485    }
486
487    ConsoleCommand* CommandExecutor::getPossibleCommand(const std::string& name, Identifier* identifier)
488    {
489        std::string lowercase = getLowercase(name);
490        if (!identifier)
491        {
492            std::map<std::string, ConsoleCommand*>::const_iterator it = CommandExecutor::getLowercaseConsoleCommandShortcutMap().find(lowercase);
493            if (it != CommandExecutor::getLowercaseConsoleCommandShortcutMapEnd())
494                return (*it).second;
495        }
496        else
497        {
498            std::map<std::string, ConsoleCommand*>::const_iterator it = identifier->getLowercaseConsoleCommandMap().find(lowercase);
499            if (it != identifier->getLowercaseConsoleCommandMapEnd())
500                return (*it).second;
501        }
502        return 0;
503    }
504
505    const std::string* CommandExecutor::getPossibleArgument(const std::string& name, ConsoleCommand* command, unsigned int param)
506    {
507        std::string lowercase = getLowercase(name);
508        for (std::list<std::pair<std::string, std::string> >::const_iterator it = command->getArgumentCompletionListBegin(param); it != command->getArgumentCompletionListEnd(param); ++it)
509            if ((*it).first == lowercase)
510                return &(*it).second;
511
512        return 0;
513    }
514
515    bool CommandExecutor::compareStringsInList(const std::pair<const std::string*, const std::string*>& first, const std::pair<const std::string*, const std::string*>& second)
516    {
517        return ((*first.first) < (*second.first));
518    }
519}
Note: See TracBrowser for help on using the repository browser.