Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/consolecommands3/src/libraries/core/command/CommandEvaluation.cc @ 7441

Last change on this file since 7441 was 7276, checked in by landauf, 14 years ago

until now we could group words and values in console commands and XML values using parentheses (…). now we have to use braces {…}, because that works better in connection with Tcl. in practice however this feature was never used before, so this change shouldn't affect anything.

  • Property svn:eol-style set to native
File size: 15.6 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 "CommandEvaluation.h"
30
31#include "util/StringUtils.h"
32#include "CommandExecutor.h"
33#include "ConsoleCommand.h"
34
35namespace orxonox
36{
37    CommandEvaluation::CommandEvaluation()
38    {
39        this->initialize("");
40    }
41
42    void CommandEvaluation::initialize(const std::string& command)
43    {
44        this->execCommand_ = 0;
45        this->hintCommand_ = 0;
46        this->string_ = command;
47        this->execArgumentsOffset_ = 0;
48        this->hintArgumentsOffset_ = 0;
49        this->bPossibleArgumentsRetrieved_ = false;
50        this->possibleArguments_.clear();
51        this->bEvaluatedParams_ = false;
52        this->bTriedToEvaluatedParams_ = false;
53        this->numberOfEvaluatedParams_ = 0;
54
55        this->tokens_.split(command, " ", SubString::WhiteSpaces, false, '\\', true, '"', true, '{', '}', true, '\0');
56    }
57
58    unsigned int CommandEvaluation::getNumberOfArguments() const
59    {
60        unsigned int count = this->tokens_.size();
61        if (count > 0 && this->string_[this->string_.size() - 1] != ' ')
62            return count;
63        else
64            return count + 1;
65    }
66
67    const std::string& CommandEvaluation::getLastArgument() const
68    {
69        if (this->tokens_.size() > 0 && this->string_[this->string_.size() - 1] != ' ')
70            return this->tokens_.back();
71        else
72            return BLANKSTRING;
73    }
74
75    const std::string& CommandEvaluation::getToken(unsigned int i) const
76    {
77        if (i < this->tokens_.size())
78            return this->tokens_[i];
79        else
80            return BLANKSTRING;
81    }
82
83    int CommandEvaluation::execute()
84    {
85        int error;
86        this->query(&error);
87        return error;
88    }
89
90    MultiType CommandEvaluation::query(int* error)
91    {
92        if (error)
93        {
94            *error = CommandExecutor::Success;
95
96            if (!this->execCommand_)
97                *error = CommandExecutor::Error;
98            else if (!this->execCommand_->isActive())
99                *error = CommandExecutor::Deactivated;
100            else if (!this->execCommand_->hasAccess())
101                *error = CommandExecutor::Denied;
102
103            if (*error != CommandExecutor::Success)
104                return MT_Type::Null;
105        }
106
107        if (this->execCommand_ && this->execCommand_->isActive() && this->execCommand_->hasAccess())
108        {
109            if (!this->bTriedToEvaluatedParams_)
110                this->evaluateParams(false);
111
112            if (this->bEvaluatedParams_)
113            {
114                COUT(6) << "CE_execute (evaluation): " << this->execCommand_->getName() << " with " << this->numberOfEvaluatedParams_ << " params: " << this->param_[0] << ' ' << this->param_[1] << ' ' << this->param_[2] << ' ' << this->param_[3] << ' ' << this->param_[4] << std::endl;
115                switch (this->numberOfEvaluatedParams_)
116                {
117                    case 0:  return (*this->execCommand_->getExecutor())();
118                    case 1:  return (*this->execCommand_->getExecutor())(this->param_[0]);
119                    case 2:  return (*this->execCommand_->getExecutor())(this->param_[0], this->param_[1]);
120                    case 3:  return (*this->execCommand_->getExecutor())(this->param_[0], this->param_[1], this->param_[2]);
121                    case 4:  return (*this->execCommand_->getExecutor())(this->param_[0], this->param_[1], this->param_[2], this->param_[3]);
122                    case 5:
123                    default: return (*this->execCommand_->getExecutor())(this->param_[0], this->param_[1], this->param_[2], this->param_[3], this->param_[4]);
124                }
125            }
126            else if (error)
127                *error = CommandExecutor::Incomplete;
128        }
129
130        return MT_Type::Null;
131    }
132
133    int CommandEvaluation::evaluateParams(bool bPrintError)
134    {
135        this->bTriedToEvaluatedParams_ = true;
136
137        if (!this->execCommand_)
138        {
139            if (bPrintError)
140                COUT(1) << "Error: Can't evaluate params, no console command assigned." << std::endl;
141            return CommandExecutor::Error;
142        }
143
144        int error;
145        this->numberOfEvaluatedParams_ = this->execCommand_->getExecutor()->evaluateParams(this->tokens_.subSet(this->execArgumentsOffset_), this->param_, &error, " ");
146        if (!error)
147            this->bEvaluatedParams_ = true;
148        else if (bPrintError)
149            COUT(1) << "Error: Can't evaluate params, not enough arguments given." << std::endl;
150
151        return error;
152    }
153
154    void CommandEvaluation::setEvaluatedParameter(unsigned int index, const MultiType& param)
155    {
156        if (index < MAX_FUNCTOR_ARGUMENTS)
157            this->param_[index] = param;
158    }
159
160    MultiType CommandEvaluation::getEvaluatedParameter(unsigned int index) const
161    {
162        if (index < MAX_FUNCTOR_ARGUMENTS)
163            return this->param_[index];
164
165        return MT_Type::Null;
166    }
167
168    std::string CommandEvaluation::complete()
169    {
170        if (!this->hintCommand_ || !this->hintCommand_->isActive())
171            return this->string_;
172
173        if (!this->bPossibleArgumentsRetrieved_)
174            this->retrievePossibleArguments();
175
176        if (CommandEvaluation::getSize(this->possibleArguments_) == 0)
177        {
178            return this->string_;
179        }
180        else
181        {
182            std::string output = this->string_.substr(0, this->string_.find_last_of(' ') + 1);
183            output += CommandEvaluation::getCommonBegin(this->possibleArguments_);
184            return output;
185        }
186    }
187
188    std::string CommandEvaluation::hint()
189    {
190        if (!this->hintCommand_ || !this->hintCommand_->isActive())
191            return "";
192
193        if (!this->bPossibleArgumentsRetrieved_)
194            this->retrievePossibleArguments();
195
196        if (CommandEvaluation::getSize(this->possibleArguments_) > 0 || (!this->possibleArguments_.empty() && this->isValid()))
197            return CommandEvaluation::dump(this->possibleArguments_);
198
199        if (this->isValid())
200        {
201            return CommandEvaluation::dump(this->hintCommand_);
202        }
203        else
204        {
205            if (this->getNumberOfArguments() > 2)
206            {
207                return std::string("Error: There is no command with name \"") + this->getToken(0) + " " + this->getToken(1) + "\".";
208            }
209            else
210            {
211                std::string groupLC = getLowercase(this->getToken(0));
212                for (std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommandsLC().begin(); it_group != ConsoleCommand::getCommandsLC().end(); ++it_group)
213                    if (it_group->first == groupLC)
214                        return std::string("Error: There is no command in group \"") + this->getToken(0) + "\" starting with \"" + this->getToken(1) + "\".";
215
216                return std::string("Error: There is no command starting with \"") + this->getToken(0) + "\".";
217            }
218        }
219    }
220
221    std::string CommandEvaluation::getCommandSuggestion() const
222    {
223        std::string token0_LC = getLowercase(this->getToken(0));
224        std::string token1_LC = getLowercase(this->getToken(1));
225
226        std::string nearestCommand;
227        unsigned int nearestDistance = (unsigned int)-1;
228
229        for (std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommandsLC().begin(); it_group != ConsoleCommand::getCommandsLC().end(); ++it_group)
230        {
231            if (it_group->first != "")
232            {
233                for (std::map<std::string, ConsoleCommand*>::const_iterator it_name = it_group->second.begin(); it_name != it_group->second.end(); ++it_name)
234                {
235                    std::string command = it_group->first + " " + it_name->first;
236                    unsigned int distance = getLevenshteinDistance(command, token0_LC + " " + token1_LC);
237                    if (distance < nearestDistance)
238                    {
239                        nearestCommand = command;
240                        nearestDistance = distance;
241                    }
242                }
243            }
244        }
245
246        std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommandsLC().find("");
247        if (it_group !=  ConsoleCommand::getCommandsLC().end())
248        {
249            for (std::map<std::string, ConsoleCommand*>::const_iterator it_name = it_group->second.begin(); it_name != it_group->second.end(); ++it_name)
250            {
251                std::string command = it_name->first;
252                unsigned int distance = getLevenshteinDistance(command, token0_LC);
253                if (distance < nearestDistance)
254                {
255                    nearestCommand = command;
256                    nearestDistance = distance;
257                }
258            }
259        }
260
261        return nearestCommand;
262    }
263
264    void CommandEvaluation::retrievePossibleArguments()
265    {
266        this->bPossibleArgumentsRetrieved_ = true;
267        unsigned int argumentID = std::min(this->getNumberOfArguments() - this->hintArgumentsOffset_, this->hintCommand_->getExecutor()->getParamCount());
268        ArgumentCompleter* ac = this->hintCommand_->getArgumentCompleter(argumentID - 1);
269
270        if (ac)
271        {
272            MultiType param[MAX_FUNCTOR_ARGUMENTS];
273
274            size_t max = this->hintArgumentsOffset_ + this->hintCommand_->getExecutor()->getParamCount();
275
276            for (size_t i = 0; i < argumentID; ++i)
277                param[i] = this->getToken(std::min(this->getNumberOfArguments(), max) - i - 1);
278
279            if (this->getNumberOfArguments() > max)
280            {
281                if (ac->useMultipleWords())
282                {
283                    std::string surplusArguments = this->tokens_.subSet(max - 1).join();
284                    if (this->string_[this->string_.size() - 1] == ' ')
285                        surplusArguments += ' ';
286
287                    this->possibleArguments_ = (*ac)(surplusArguments, param[1], param[2], param[3], param[4]);
288                    CommandEvaluation::strip(this->possibleArguments_, this->getToken(this->getNumberOfArguments() - 1));
289                }
290            }
291            else
292            {
293                this->possibleArguments_ = (*ac)(param[0], param[1], param[2], param[3], param[4]);
294                CommandEvaluation::strip(this->possibleArguments_, param[0]);
295            }
296        }
297    }
298
299    /* static */ size_t CommandEvaluation::getSize(const ArgumentCompletionList& list)
300    {
301        size_t count = 0;
302        for (ArgumentCompletionList::const_iterator it = list.begin(); it != list.end(); ++it)
303            if (it->getComparable() != "")
304                ++count;
305        return count;
306    }
307
308    /* static */ void CommandEvaluation::strip(ArgumentCompletionList& list, const std::string& fragment)
309    {
310        std::string fragmentLC = getLowercase(fragment);
311
312        for (ArgumentCompletionList::iterator it = list.begin(); it != list.end(); )
313        {
314            const std::string& entry = it->getComparable();
315
316            if (entry == "")
317            {
318                ++it;
319                continue;
320            }
321
322            if (entry.size() < fragmentLC.size())
323            {
324                list.erase(it++);
325            }
326            else
327            {
328                bool bErase = false;
329                for (size_t i = 0; i < fragmentLC.size(); ++i)
330                {
331                    if (fragmentLC[i] != entry[i])
332                    {
333                        bErase = true;
334                        break;
335                    }
336                }
337
338                if (bErase)
339                    list.erase(it++);
340                else
341                    ++it;
342            }
343        }
344    }
345
346    /* static */ std::string CommandEvaluation::getCommonBegin(const ArgumentCompletionList& list)
347    {
348        if (CommandEvaluation::getSize(list) == 0)
349        {
350            return "";
351        }
352        else if (CommandEvaluation::getSize(list) == 1)
353        {
354            for (ArgumentCompletionList::const_iterator it = list.begin(); it != list.end(); ++it)
355            {
356                if (it->getComparable() != "")
357                {
358                    if (it->hasDisplay())
359                        return (it->getString());
360                    else
361                        return (it->getString() + ' ');
362                }
363            }
364
365            return "";
366        }
367        else
368        {
369            std::string output;
370            for (unsigned int i = 0; true; i++)
371            {
372                char tempComparable = 0;
373                char temp = 0;
374                for (ArgumentCompletionList::const_iterator it = list.begin(); it != list.end(); ++it)
375                {
376                    const std::string& argumentComparable = it->getComparable();
377                    const std::string& argument = it->getString();
378
379                    if (argumentComparable == "")
380                        continue;
381
382                    if (argument.size() > i)
383                    {
384                        if (tempComparable == 0)
385                        {
386                            tempComparable = argumentComparable[i];
387                            temp = argument[i];
388                        }
389                        else
390                        {
391                            if (tempComparable != argumentComparable[i])
392                                return output;
393                            else if (temp != argument[i])
394                                temp = tempComparable;
395                        }
396                    }
397                    else
398                    {
399                        return output;
400                    }
401                }
402                output += temp;
403            }
404            return output;
405        }
406    }
407
408    /* static */ std::string CommandEvaluation::dump(const ArgumentCompletionList& list)
409    {
410        std::string output;
411        for (ArgumentCompletionList::const_iterator it = list.begin(); it != list.end(); ++it)
412        {
413            output += it->getDisplay();
414
415            if (it->getComparable() != "")
416                output += ' ';
417        }
418        return output;
419    }
420
421    /* static */ std::string CommandEvaluation::dump(const ConsoleCommand* command)
422    {
423        std::string output = command->getName();
424        if (command->getExecutor()->getParamCount() > 0)
425            output += ": ";
426
427        for (unsigned int i = 0; i < command->getExecutor()->getParamCount(); i++)
428        {
429            if (i != 0)
430                output += ' ';
431
432            if (command->getExecutor()->defaultValueSet(i))
433                output += '[';
434            else
435                output += '{';
436
437            output += command->getExecutor()->getTypenameParam(i);
438
439            if (command->getExecutor()->defaultValueSet(i))
440                output += '=' + command->getExecutor()->getDefaultValue(i).getString() + ']';
441            else
442                output += '}';
443        }
444        return output;
445    }
446}
Note: See TracBrowser for help on using the repository browser.