Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Sep 11, 2010, 12:34:00 AM (14 years ago)
Author:
landauf
Message:

merged doc branch back to trunk

Location:
code/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/libraries/core/command/CommandEvaluation.cc

    r7286 r7401  
    2727 */
    2828
     29/**
     30    @file
     31    @brief Implementation of CommandEvaluation
     32*/
     33
    2934#include "CommandEvaluation.h"
    3035
     
    3540namespace orxonox
    3641{
     42    /**
     43        @brief Constructor: Initializes the command evaluation with an empty command.
     44    */
    3745    CommandEvaluation::CommandEvaluation()
    3846    {
     
    4048    }
    4149
     50    /**
     51        @brief Initializes all values.
     52    */
    4253    void CommandEvaluation::initialize(const std::string& command)
    4354    {
     
    4960        this->bPossibleArgumentsRetrieved_ = false;
    5061        this->possibleArguments_.clear();
    51         this->bEvaluatedParams_ = false;
    52         this->bTriedToEvaluatedParams_ = false;
    53         this->numberOfEvaluatedParams_ = 0;
    54 
     62        this->bEvaluatedArguments_ = false;
     63        this->bTriedToEvaluatedArguments_ = false;
     64        this->numberOfEvaluatedArguments_ = 0;
     65
     66        // split the command into tokens
    5567        this->tokens_.split(command, " ", SubString::WhiteSpaces, false, '\\', true, '"', true, '{', '}', true, '\0');
    5668    }
    5769
     70    /**
     71        @brief Returns the number of tokens according to the definition of CommandExecutor (which counts also an empty argument at the end of the string).
     72    */
    5873    unsigned int CommandEvaluation::getNumberOfArguments() const
    5974    {
    6075        unsigned int count = this->tokens_.size();
    61         if (count > 0 && this->string_[this->string_.size() - 1] != ' ')
     76
     77        // If the last char in the string is a space character (or the string is empty), add +1 to the number of tokens, because this counts as an additional (but empty) argument
     78        if (count == 0 || this->string_[this->string_.size() - 1] == ' ')
     79            return count + 1;
     80        else
    6281            return count;
     82    }
     83
     84    /**
     85        @brief Returns the last argument (which is the one the user currently enters into the shell).
     86    */
     87    const std::string& CommandEvaluation::getLastArgument() const
     88    {
     89        // the string is empty or ends with a space character, the user is just about to enter a new argument (but its still empty). return a blank string in this case.
     90        if (this->tokens_.size() == 0 || this->string_[this->string_.size() - 1] == ' ')
     91            return BLANKSTRING;
    6392        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] != ' ')
    7093            return this->tokens_.back();
    71         else
    72             return BLANKSTRING;
    73     }
    74 
     94    }
     95
     96    /**
     97        @brief Returns the token with the given index (or a blank string if it doesn't exist).
     98    */
    7599    const std::string& CommandEvaluation::getToken(unsigned int i) const
    76100    {
     
    81105    }
    82106
     107    /**
     108        @brief Executes the command which was evaluated by this object.
     109        @return Returns the error code (see @ref CommandExecutorErrorCodes "CommandExecutor error codes")
     110    */
    83111    int CommandEvaluation::execute()
    84112    {
     
    88116    }
    89117
     118    /**
     119        @brief Executes the command which was evaluated by this object and returns its return-value.
     120        @param error A pointer to an integer (or NULL) which will be used to write error codes to (see @ref CommandExecutorErrorCodes "CommandExecutor error codes")
     121        @return Returns the result of the command (or MT_Type::Null if there is no return value)
     122    */
    90123    MultiType CommandEvaluation::query(int* error)
    91124    {
     125        // check if an error value was passed by reference
    92126        if (error)
    93127        {
     128            // Determine the error-code and return if it is not Success
     129
    94130            *error = CommandExecutor::Success;
    95131
     
    105141        }
    106142
     143        // check if it's possible to execute the command
    107144        if (this->execCommand_ && this->execCommand_->isActive() && this->execCommand_->hasAccess())
    108145        {
    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_)
     146            // if the arguments weren't evaluated yet, do it now.
     147            if (!this->bTriedToEvaluatedArguments_)
     148                this->evaluateArguments(false);
     149
     150            // check if the argument evaluation succeded
     151            if (this->bEvaluatedArguments_)
     152            {
     153                COUT(6) << "CE_execute (evaluation): " << this->execCommand_->getName() << " with " << this->numberOfEvaluatedArguments_ << " arguments: " << this->arguments_[0] << ' ' << this->arguments_[1] << ' ' << this->arguments_[2] << ' ' << this->arguments_[3] << ' ' << this->arguments_[4] << std::endl;
     154
     155                // pass as many arguments to the executor as were evaluated (thus the executor can still use additional default values)
     156                switch (this->numberOfEvaluatedArguments_)
    116157                {
    117158                    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]);
     159                    case 1:  return (*this->execCommand_->getExecutor())(this->arguments_[0]);
     160                    case 2:  return (*this->execCommand_->getExecutor())(this->arguments_[0], this->arguments_[1]);
     161                    case 3:  return (*this->execCommand_->getExecutor())(this->arguments_[0], this->arguments_[1], this->arguments_[2]);
     162                    case 4:  return (*this->execCommand_->getExecutor())(this->arguments_[0], this->arguments_[1], this->arguments_[2], this->arguments_[3]);
    122163                    case 5:
    123                     default: return (*this->execCommand_->getExecutor())(this->param_[0], this->param_[1], this->param_[2], this->param_[3], this->param_[4]);
     164                    default: return (*this->execCommand_->getExecutor())(this->arguments_[0], this->arguments_[1], this->arguments_[2], this->arguments_[3], this->arguments_[4]);
    124165                }
    125166            }
     
    128169        }
    129170
     171        // return a null value in case of an error
    130172        return MT_Type::Null;
    131173    }
    132174
    133     int CommandEvaluation::evaluateParams(bool bPrintError)
    134     {
    135         this->bTriedToEvaluatedParams_ = true;
    136 
     175    /**
     176        @brief Evaluates the arguments of the command.
     177        @param bPrintError If true, the function prints an error message if it doesn't succeed
     178        @return Returns the error code (see @ref CommandExecutorErrorCodes "CommandExecutor error codes")
     179    */
     180    int CommandEvaluation::evaluateArguments(bool bPrintError)
     181    {
     182        this->bTriedToEvaluatedArguments_ = true;
     183
     184        // check if there's a command to execute
    137185        if (!this->execCommand_)
    138186        {
    139187            if (bPrintError)
    140                 COUT(1) << "Error: Can't evaluate params, no console command assigned." << std::endl;
     188                COUT(1) << "Error: Can't evaluate arguments, no console command assigned." << std::endl;
    141189            return CommandExecutor::Error;
    142190        }
    143191
    144192        int error;
    145         this->numberOfEvaluatedParams_ = this->execCommand_->getExecutor()->evaluateParams(this->tokens_.subSet(this->execArgumentsOffset_), this->param_, &error, " ");
     193
     194        // try to evaluate the arguments using the executor of the evaluated command.
     195        // the arguments are currently stored as strings in token_, but afterwards they will be converted to the right type and stored in arguments_
     196        this->numberOfEvaluatedArguments_ = this->execCommand_->getExecutor()->evaluateArguments(this->tokens_.subSet(this->execArgumentsOffset_), this->arguments_, &error, " ");
     197
     198        // check if an error occurred
    146199        if (!error)
    147             this->bEvaluatedParams_ = true;
     200            this->bEvaluatedArguments_ = true;
    148201        else if (bPrintError)
    149             COUT(1) << "Error: Can't evaluate params, not enough arguments given." << std::endl;
     202            COUT(1) << "Error: Can't evaluate arguments, not enough arguments given." << std::endl;
    150203
    151204        return error;
    152205    }
    153206
    154     void CommandEvaluation::setEvaluatedParameter(unsigned int index, const MultiType& param)
     207    /**
     208        @brief Replaces an evaluated argument with a new value.
     209        @param index The index of the parameter (the first argument has index 0)
     210        @param arg The new value of the parameter
     211    */
     212    void CommandEvaluation::setEvaluatedArgument(unsigned int index, const MultiType& arg)
    155213    {
    156214        if (index < MAX_FUNCTOR_ARGUMENTS)
    157             this->param_[index] = param;
    158     }
    159 
    160     MultiType CommandEvaluation::getEvaluatedParameter(unsigned int index) const
     215            this->arguments_[index] = arg;
     216    }
     217
     218    /**
     219        @brief Returns the evaluated argument with given index.
     220        @param index The index of the argument (the first argument has index 0)
     221    */
     222    MultiType CommandEvaluation::getEvaluatedArgument(unsigned int index) const
    161223    {
    162224        if (index < MAX_FUNCTOR_ARGUMENTS)
    163             return this->param_[index];
     225            return this->arguments_[index];
    164226
    165227        return MT_Type::Null;
    166228    }
    167229
     230    /**
     231        @brief Completes the given command string using the list of possible arguments.
     232        @return Returns the completed command string
     233
     234        This is called by the shell if the user presses the @a tab key. The currently entered
     235        argument will be completed as good as possible by using the argument completion list
     236        of the evaluated command.
     237    */
    168238    std::string CommandEvaluation::complete()
    169239    {
     240        // check if it's possible to complete the command
    170241        if (!this->hintCommand_ || !this->hintCommand_->isActive())
    171242            return this->string_;
    172243
     244        // get the list of possible arguments
    173245        if (!this->bPossibleArgumentsRetrieved_)
    174246            this->retrievePossibleArguments();
    175247
     248        // if the list is empty, return the current command string
    176249        if (CommandEvaluation::getSize(this->possibleArguments_) == 0)
    177250        {
     
    180253        else
    181254        {
     255            // get the first part of the command string from the beginning up to the last space character
    182256            std::string output = this->string_.substr(0, this->string_.find_last_of(' ') + 1);
     257
     258            // add the common begin of all possible arguments
    183259            output += CommandEvaluation::getCommonBegin(this->possibleArguments_);
     260
     261            // return the resulting string
    184262            return output;
    185263        }
    186264    }
    187265
     266    /**
     267        @brief Returns a string containing hints or possible arguments for the evaluated command.
     268
     269        This is called by the shell if the user presses the @a tab key. It prints a list of
     270        possible arguments or other hints, returned by the argument completion list of the
     271        evaluated command. If there's no such list, the syntax of the command is returned.
     272    */
    188273    std::string CommandEvaluation::hint()
    189274    {
     275        // check if it's possible to get hints for this command
    190276        if (!this->hintCommand_ || !this->hintCommand_->isActive())
    191277            return "";
    192278
     279        // get the list of possible arguments
    193280        if (!this->bPossibleArgumentsRetrieved_)
    194281            this->retrievePossibleArguments();
    195282
     283        // return the list of possible arguments if:
     284        //   a) it contains at least one non-empty argument
     285        //   b) it contains an entry that may be empty (not an actual argument, just a helping text) AND the command is valid
    196286        if (CommandEvaluation::getSize(this->possibleArguments_) > 0 || (!this->possibleArguments_.empty() && this->isValid()))
    197287            return CommandEvaluation::dump(this->possibleArguments_);
    198288
     289        // at this point there's no valid argument in the list, so check if the command is actually valid
    199290        if (this->isValid())
    200291        {
     292            // yes it is - return the syntax of the command
    201293            return CommandEvaluation::dump(this->hintCommand_);
    202294        }
    203295        else
    204296        {
     297            // no the command is not valid
    205298            if (this->getNumberOfArguments() > 2)
    206299            {
     300                // the user typed 2+ arguments, but they don't name a command - print an error
    207301                return std::string("Error: There is no command with name \"") + this->getToken(0) + " " + this->getToken(1) + "\".";
    208302            }
    209303            else
    210304            {
     305                // the user typed 1-2 arguments, check what he tried to type and print a suitable error
    211306                std::string groupLC = getLowercase(this->getToken(0));
    212307                for (std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommandsLC().begin(); it_group != ConsoleCommand::getCommandsLC().end(); ++it_group)
     
    219314    }
    220315
     316    /**
     317        @brief If the command couln't be evaluated because it doesn't exist, print a suggestion for
     318        a command that looks close to the entered command (useful if the user mistyped the command).
     319    */
    221320    std::string CommandEvaluation::getCommandSuggestion() const
    222321    {
     
    227326        unsigned int nearestDistance = (unsigned int)-1;
    228327
     328        // iterate through all groups and their commands and calculate the distance to the current command. keep the best.
    229329        for (std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommandsLC().begin(); it_group != ConsoleCommand::getCommandsLC().end(); ++it_group)
    230330        {
     
    244344        }
    245345
     346        // now also iterate through all shortcuts and keep the best if it's better than the one found above.
    246347        std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommandsLC().find("");
    247348        if (it_group !=  ConsoleCommand::getCommandsLC().end())
     
    259360        }
    260361
     362        // return the command that's closest to the current one.
    261363        return nearestCommand;
    262364    }
    263365
     366    /**
     367        @brief Gets the possible arguments for the command in its current state.
     368    */
    264369    void CommandEvaluation::retrievePossibleArguments()
    265370    {
    266371        this->bPossibleArgumentsRetrieved_ = true;
     372
     373        // we use the hintCommand_ to get possible arguments. get the index of the last argument. limit the index if its greater than the number of arguments supported by the command.
    267374        unsigned int argumentID = std::min(this->getNumberOfArguments() - this->hintArgumentsOffset_, this->hintCommand_->getExecutor()->getParamCount());
     375
     376        // get the argument completer for the given argument index
    268377        ArgumentCompleter* ac = this->hintCommand_->getArgumentCompleter(argumentID - 1);
    269378
     379        // check if an argument completer exists
    270380        if (ac)
    271381        {
    272             MultiType param[MAX_FUNCTOR_ARGUMENTS];
    273 
     382            MultiType arg[MAX_FUNCTOR_ARGUMENTS];
     383
     384            // the index of the last argument in the command string that is supported by this argument completer
    274385            size_t max = this->hintArgumentsOffset_ + this->hintCommand_->getExecutor()->getParamCount();
    275386
     387            // write the argument strings to the argument array (in reversed order, as required by the argument completion function)
    276388            for (size_t i = 0; i < argumentID; ++i)
    277                 param[i] = this->getToken(std::min(this->getNumberOfArguments(), (unsigned int)max) - i - 1);
    278 
     389                arg[i] = this->getToken(std::min(this->getNumberOfArguments(), (unsigned int)max) - i - 1);
     390
     391            // check if there are more arguments given by the user than supported
    279392            if (this->getNumberOfArguments() > max)
    280393            {
     394                // yes - now check if multiple words are supported by the argument completer
    281395                if (ac->useMultipleWords())
    282396                {
     397                    // yes - join the surplus arguments
    283398                    std::string surplusArguments = this->tokens_.subSet(max - 1).join();
    284399                    if (this->string_[this->string_.size() - 1] == ' ')
    285400                        surplusArguments += ' ';
    286401
    287                     this->possibleArguments_ = (*ac)(surplusArguments, param[1], param[2], param[3], param[4]);
     402                    // pass all surplus arguments as the first argument to the argument completer
     403                    this->possibleArguments_ = (*ac)(surplusArguments, arg[1], arg[2], arg[3], arg[4]);
     404
     405                    // strip the list using the last argument
    288406                    CommandEvaluation::strip(this->possibleArguments_, this->getToken(this->getNumberOfArguments() - 1));
    289407                }
     408                else
     409                {
     410                    // no - the user typed more arguments than supported, no action
     411                }
    290412            }
    291413            else
    292414            {
    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 
     415                // no - so simply call the argument completer and get the list of arguments
     416                this->possibleArguments_ = (*ac)(arg[0], arg[1], arg[2], arg[3], arg[4]);
     417
     418                // strip the list using the last argument (stored arg[0])
     419                CommandEvaluation::strip(this->possibleArguments_, arg[0]);
     420            }
     421        }
     422    }
     423
     424    /**
     425        @brief Returns the size of an argument completion list - empty ("") arguments are not counted.
     426    */
    299427    /* static */ size_t CommandEvaluation::getSize(const ArgumentCompletionList& list)
    300428    {
     
    306434    }
    307435
     436    /**
     437        @brief Removes all elements from the list that don't start with @a fragment.
     438        @param list The argument completion list
     439        @param fragment The argument that is currently entered by the user and that needs to be completed
     440    */
    308441    /* static */ void CommandEvaluation::strip(ArgumentCompletionList& list, const std::string& fragment)
    309442    {
    310443        std::string fragmentLC = getLowercase(fragment);
    311444
     445        // iterate through the list
    312446        for (ArgumentCompletionList::iterator it = list.begin(); it != list.end(); )
    313447        {
    314448            const std::string& entry = it->getComparable();
    315449
     450            // check if the argument is empty - if yes, keep it always in the list
    316451            if (entry == "")
    317452            {
     
    320455            }
    321456
     457            // check the length of the argument - arguments smaller than 'fragment' are always erased
    322458            if (entry.size() < fragmentLC.size())
    323459            {
     
    326462            else
    327463            {
     464                // compare the argument char by char with 'fragment'
    328465                bool bErase = false;
    329466                for (size_t i = 0; i < fragmentLC.size(); ++i)
     
    344481    }
    345482
     483    /**
     484        @brief Returns the commond begin of all arguments in the list.
     485    */
    346486    /* static */ std::string CommandEvaluation::getCommonBegin(const ArgumentCompletionList& list)
    347487    {
    348488        if (CommandEvaluation::getSize(list) == 0)
    349489        {
     490            // no (non-empty) values in the list, return an empty string
    350491            return "";
    351492        }
    352493        else if (CommandEvaluation::getSize(list) == 1)
    353494        {
     495            // only one (non-empty) value in the list - search it and return it
    354496            for (ArgumentCompletionList::const_iterator it = list.begin(); it != list.end(); ++it)
    355497            {
    356498                if (it->getComparable() != "")
    357499                {
     500                    // arguments that have a separate string to be displayed need a little more care - just return them without modification. add a space character to the others.
    358501                    if (it->hasDisplay())
    359502                        return (it->getString());
     
    367510        else
    368511        {
     512            // multiple arguments in the list - iterate through it and find the common begin of all arguments
    369513            std::string output;
    370514            for (unsigned int i = 0; true; i++)
    371515            {
    372                 char tempComparable = 0;
    373                 char temp = 0;
     516                char tempComparable = '\0';
     517                char temp = '\0';
    374518                for (ArgumentCompletionList::const_iterator it = list.begin(); it != list.end(); ++it)
    375519                {
     
    377521                    const std::string& argument = it->getString();
    378522
     523                    // ignore empty arguments
    379524                    if (argumentComparable == "")
    380525                        continue;
     
    382527                    if (argument.size() > i)
    383528                    {
    384                         if (tempComparable == 0)
     529                        if (tempComparable == '\0')
    385530                        {
     531                            // the first entry is always taken
    386532                            tempComparable = argumentComparable[i];
    387533                            temp = argument[i];
     
    389535                        else
    390536                        {
     537                            // all other entries need comparison to the first entry
    391538                            if (tempComparable != argumentComparable[i])
    392539                                return output;
    393                             else if (temp != argument[i])
     540                            else if (temp != argument[i]) // the comparables match, but the normal chars don't - switch to comparable only
    394541                                temp = tempComparable;
    395542                        }
     
    406553    }
    407554
     555    /**
     556        @brief Joins the elements of the given list to a string.
     557    */
    408558    /* static */ std::string CommandEvaluation::dump(const ArgumentCompletionList& list)
    409559    {
     
    413563            output += it->getDisplay();
    414564
     565            // add a space character between two elements for all non-empty arguments
    415566            if (it->getComparable() != "")
    416567                output += ' ';
     
    419570    }
    420571
     572    /**
     573        @brief Returns a string that explains the syntax of the given command.
     574    */
    421575    /* static */ std::string CommandEvaluation::dump(const ConsoleCommand* command)
    422576    {
     577        // get the name of the command
    423578        std::string output = command->getName();
     579
     580        // check if there are parameters
    424581        if (command->getExecutor()->getParamCount() > 0)
    425582            output += ": ";
    426583
     584        // iterate through the parameters
    427585        for (unsigned int i = 0; i < command->getExecutor()->getParamCount(); i++)
    428586        {
     587            // separate the parameters with a space character
    429588            if (i != 0)
    430589                output += ' ';
    431590
     591            // print default values in [], others in {} braces
    432592            if (command->getExecutor()->defaultValueSet(i))
    433593                output += '[';
     
    435595                output += '{';
    436596
     597            // add the type-name of the parameter
    437598            output += command->getExecutor()->getTypenameParam(i);
    438599
     600            // print the default value if available
    439601            if (command->getExecutor()->defaultValueSet(i))
    440602                output += '=' + command->getExecutor()->getDefaultValue(i).getString() + ']';
Note: See TracChangeset for help on using the changeset viewer.