- Timestamp:
- Sep 4, 2010, 11:33:02 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/doc/src/libraries/core/command/CommandEvaluation.cc
r7286 r7352 27 27 */ 28 28 29 /** 30 @file 31 @brief Implementation of CommandEvaluation 32 */ 33 29 34 #include "CommandEvaluation.h" 30 35 … … 35 40 namespace orxonox 36 41 { 42 /** 43 @brief Constructor: Initializes the command evaluation with an empty command. 44 */ 37 45 CommandEvaluation::CommandEvaluation() 38 46 { … … 40 48 } 41 49 50 /** 51 @brief Initializes all values. 52 */ 42 53 void CommandEvaluation::initialize(const std::string& command) 43 54 { … … 49 60 this->bPossibleArgumentsRetrieved_ = false; 50 61 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 55 67 this->tokens_.split(command, " ", SubString::WhiteSpaces, false, '\\', true, '"', true, '{', '}', true, '\0'); 56 68 } 57 69 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 */ 58 73 unsigned int CommandEvaluation::getNumberOfArguments() const 59 74 { 60 75 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 62 81 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; 63 92 else 64 return count + 1;65 }66 67 const std::string& CommandEvaluation::getLastArgument() const68 {69 if (this->tokens_.size() > 0 && this->string_[this->string_.size() - 1] != ' ')70 93 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 */ 75 99 const std::string& CommandEvaluation::getToken(unsigned int i) const 76 100 { … … 81 105 } 82 106 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 */ 83 111 int CommandEvaluation::execute() 84 112 { … … 88 116 } 89 117 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 */ 90 123 MultiType CommandEvaluation::query(int* error) 91 124 { 125 // check if an error value was passed by reference 92 126 if (error) 93 127 { 128 // Determine the error-code and return if it is not Success 129 94 130 *error = CommandExecutor::Success; 95 131 … … 105 141 } 106 142 143 // check if it's possible to execute the command 107 144 if (this->execCommand_ && this->execCommand_->isActive() && this->execCommand_->hasAccess()) 108 145 { 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_) 116 157 { 117 158 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]); 122 163 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]); 124 165 } 125 166 } … … 128 169 } 129 170 171 // return a null value in case of an error 130 172 return MT_Type::Null; 131 173 } 132 174 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 137 185 if (!this->execCommand_) 138 186 { 139 187 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; 141 189 return CommandExecutor::Error; 142 190 } 143 191 144 192 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 146 199 if (!error) 147 this->bEvaluated Params_ = true;200 this->bEvaluatedArguments_ = true; 148 201 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; 150 203 151 204 return error; 152 205 } 153 206 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) 155 213 { 156 214 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 161 223 { 162 224 if (index < MAX_FUNCTOR_ARGUMENTS) 163 return this-> param_[index];225 return this->arguments_[index]; 164 226 165 227 return MT_Type::Null; 166 228 } 167 229 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 */ 168 238 std::string CommandEvaluation::complete() 169 239 { 240 // check if it's possible to complete the command 170 241 if (!this->hintCommand_ || !this->hintCommand_->isActive()) 171 242 return this->string_; 172 243 244 // get the list of possible arguments 173 245 if (!this->bPossibleArgumentsRetrieved_) 174 246 this->retrievePossibleArguments(); 175 247 248 // if the list is empty, return the current command string 176 249 if (CommandEvaluation::getSize(this->possibleArguments_) == 0) 177 250 { … … 180 253 else 181 254 { 255 // get the first part of the command string from the beginning up to the last space character 182 256 std::string output = this->string_.substr(0, this->string_.find_last_of(' ') + 1); 257 258 // add the common begin of all possible arguments 183 259 output += CommandEvaluation::getCommonBegin(this->possibleArguments_); 260 261 // return the resulting string 184 262 return output; 185 263 } 186 264 } 187 265 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 */ 188 273 std::string CommandEvaluation::hint() 189 274 { 275 // check if it's possible to get hints for this command 190 276 if (!this->hintCommand_ || !this->hintCommand_->isActive()) 191 277 return ""; 192 278 279 // get the list of possible arguments 193 280 if (!this->bPossibleArgumentsRetrieved_) 194 281 this->retrievePossibleArguments(); 195 282 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 196 286 if (CommandEvaluation::getSize(this->possibleArguments_) > 0 || (!this->possibleArguments_.empty() && this->isValid())) 197 287 return CommandEvaluation::dump(this->possibleArguments_); 198 288 289 // at this point there's no valid argument in the list, so check if the command is actually valid 199 290 if (this->isValid()) 200 291 { 292 // yes it is - return the syntax of the command 201 293 return CommandEvaluation::dump(this->hintCommand_); 202 294 } 203 295 else 204 296 { 297 // no the command is not valid 205 298 if (this->getNumberOfArguments() > 2) 206 299 { 300 // the user typed 2+ arguments, but they don't name a command - print an error 207 301 return std::string("Error: There is no command with name \"") + this->getToken(0) + " " + this->getToken(1) + "\"."; 208 302 } 209 303 else 210 304 { 305 // the user typed 1-2 arguments, check what he tried to type and print a suitable error 211 306 std::string groupLC = getLowercase(this->getToken(0)); 212 307 for (std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommandsLC().begin(); it_group != ConsoleCommand::getCommandsLC().end(); ++it_group) … … 219 314 } 220 315 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 */ 221 320 std::string CommandEvaluation::getCommandSuggestion() const 222 321 { … … 227 326 unsigned int nearestDistance = (unsigned int)-1; 228 327 328 // iterate through all groups and their commands and calculate the distance to the current command. keep the best. 229 329 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 330 { … … 244 344 } 245 345 346 // now also iterate through all shortcuts and keep the best if it's better than the one found above. 246 347 std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommandsLC().find(""); 247 348 if (it_group != ConsoleCommand::getCommandsLC().end()) … … 259 360 } 260 361 362 // return the command that's closest to the current one. 261 363 return nearestCommand; 262 364 } 263 365 366 /** 367 @brief Gets the possible arguments for the command in its current state. 368 */ 264 369 void CommandEvaluation::retrievePossibleArguments() 265 370 { 266 371 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. 267 374 unsigned int argumentID = std::min(this->getNumberOfArguments() - this->hintArgumentsOffset_, this->hintCommand_->getExecutor()->getParamCount()); 375 376 // get the argument completer for the given argument index 268 377 ArgumentCompleter* ac = this->hintCommand_->getArgumentCompleter(argumentID - 1); 269 378 379 // check if an argument completer exists 270 380 if (ac) 271 381 { 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 274 385 size_t max = this->hintArgumentsOffset_ + this->hintCommand_->getExecutor()->getParamCount(); 275 386 387 // write the argument strings to the argument array (in reversed order, as required by the argument completion function) 276 388 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 279 392 if (this->getNumberOfArguments() > max) 280 393 { 394 // yes - now check if multiple words are supported by the argument completer 281 395 if (ac->useMultipleWords()) 282 396 { 397 // yes - join the surplus arguments 283 398 std::string surplusArguments = this->tokens_.subSet(max - 1).join(); 284 399 if (this->string_[this->string_.size() - 1] == ' ') 285 400 surplusArguments += ' '; 286 401 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 288 406 CommandEvaluation::strip(this->possibleArguments_, this->getToken(this->getNumberOfArguments() - 1)); 289 407 } 408 else 409 { 410 // no - the user typed more arguments than supported, no action 411 } 290 412 } 291 413 else 292 414 { 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 */ 299 427 /* static */ size_t CommandEvaluation::getSize(const ArgumentCompletionList& list) 300 428 { … … 306 434 } 307 435 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 */ 308 441 /* static */ void CommandEvaluation::strip(ArgumentCompletionList& list, const std::string& fragment) 309 442 { 310 443 std::string fragmentLC = getLowercase(fragment); 311 444 445 // iterate through the list 312 446 for (ArgumentCompletionList::iterator it = list.begin(); it != list.end(); ) 313 447 { 314 448 const std::string& entry = it->getComparable(); 315 449 450 // check if the argument is empty - if yes, keep it always in the list 316 451 if (entry == "") 317 452 { … … 320 455 } 321 456 457 // check the length of the argument - arguments smaller than 'fragment' are always erased 322 458 if (entry.size() < fragmentLC.size()) 323 459 { … … 326 462 else 327 463 { 464 // compare the argument char by char with 'fragment' 328 465 bool bErase = false; 329 466 for (size_t i = 0; i < fragmentLC.size(); ++i) … … 344 481 } 345 482 483 /** 484 @brief Returns the commond begin of all arguments in the list. 485 */ 346 486 /* static */ std::string CommandEvaluation::getCommonBegin(const ArgumentCompletionList& list) 347 487 { 348 488 if (CommandEvaluation::getSize(list) == 0) 349 489 { 490 // no (non-empty) values in the list, return an empty string 350 491 return ""; 351 492 } 352 493 else if (CommandEvaluation::getSize(list) == 1) 353 494 { 495 // only one (non-empty) value in the list - search it and return it 354 496 for (ArgumentCompletionList::const_iterator it = list.begin(); it != list.end(); ++it) 355 497 { 356 498 if (it->getComparable() != "") 357 499 { 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. 358 501 if (it->hasDisplay()) 359 502 return (it->getString()); … … 367 510 else 368 511 { 512 // multiple arguments in the list - iterate through it and find the common begin of all arguments 369 513 std::string output; 370 514 for (unsigned int i = 0; true; i++) 371 515 { 372 char tempComparable = 0;373 char temp = 0;516 char tempComparable = '\0'; 517 char temp = '\0'; 374 518 for (ArgumentCompletionList::const_iterator it = list.begin(); it != list.end(); ++it) 375 519 { … … 377 521 const std::string& argument = it->getString(); 378 522 523 // ignore empty arguments 379 524 if (argumentComparable == "") 380 525 continue; … … 382 527 if (argument.size() > i) 383 528 { 384 if (tempComparable == 0)529 if (tempComparable == '\0') 385 530 { 531 // the first entry is always taken 386 532 tempComparable = argumentComparable[i]; 387 533 temp = argument[i]; … … 389 535 else 390 536 { 537 // all other entries need comparison to the first entry 391 538 if (tempComparable != argumentComparable[i]) 392 539 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 394 541 temp = tempComparable; 395 542 } … … 406 553 } 407 554 555 /** 556 @brief Joins the elements of the given list to a string. 557 */ 408 558 /* static */ std::string CommandEvaluation::dump(const ArgumentCompletionList& list) 409 559 { … … 413 563 output += it->getDisplay(); 414 564 565 // add a space character between two elements for all non-empty arguments 415 566 if (it->getComparable() != "") 416 567 output += ' '; … … 419 570 } 420 571 572 /** 573 @brief Returns a string that explains the syntax of the given command. 574 */ 421 575 /* static */ std::string CommandEvaluation::dump(const ConsoleCommand* command) 422 576 { 577 // get the name of the command 423 578 std::string output = command->getName(); 579 580 // check if there are parameters 424 581 if (command->getExecutor()->getParamCount() > 0) 425 582 output += ": "; 426 583 584 // iterate through the parameters 427 585 for (unsigned int i = 0; i < command->getExecutor()->getParamCount(); i++) 428 586 { 587 // separate the parameters with a space character 429 588 if (i != 0) 430 589 output += ' '; 431 590 591 // print default values in [], others in {} braces 432 592 if (command->getExecutor()->defaultValueSet(i)) 433 593 output += '['; … … 435 595 output += '{'; 436 596 597 // add the type-name of the parameter 437 598 output += command->getExecutor()->getTypenameParam(i); 438 599 600 // print the default value if available 439 601 if (command->getExecutor()->defaultValueSet(i)) 440 602 output += '=' + command->getExecutor()->getDefaultValue(i).getString() + ']';
Note: See TracChangeset
for help on using the changeset viewer.