diff options
| -rw-r--r-- | lldb/include/lldb/Interpreter/Args.h | 3 | ||||
| -rw-r--r-- | lldb/include/lldb/Interpreter/CommandInterpreter.h | 10 | ||||
| -rw-r--r-- | lldb/source/Commands/CommandObjectCommands.cpp | 133 | ||||
| -rw-r--r-- | lldb/source/Interpreter/Args.cpp | 22 | ||||
| -rw-r--r-- | lldb/source/Interpreter/CommandInterpreter.cpp | 478 |
5 files changed, 486 insertions, 160 deletions
diff --git a/lldb/include/lldb/Interpreter/Args.h b/lldb/include/lldb/Interpreter/Args.h index 4cde95f3dc9..3a62fdee42f 100644 --- a/lldb/include/lldb/Interpreter/Args.h +++ b/lldb/include/lldb/Interpreter/Args.h @@ -313,7 +313,8 @@ public: // and it builds up the option_arg_vector as it parses the options. void - ParseAliasOptions (Options &options, CommandReturnObject &result, OptionArgVector *option_arg_vector); + ParseAliasOptions (Options &options, CommandReturnObject &result, OptionArgVector *option_arg_vector, + std::string &raw_input_line); void ParseArgsForCompletion (Options &options, OptionElementVector &option_element_vector, uint32_t cursor_index); diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h index ada49c32a1d..865761ffaa8 100644 --- a/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -85,11 +85,21 @@ public: AddOrReplaceAliasOptions (const char *alias_name, OptionArgVectorSP &option_arg_vector_sp); bool + StripFirstWord (std::string &command_string, std::string &next_word); + + void + BuildAliasResult (const char *alias_name, std::string &raw_input_string, std::string &alias_result, + CommandObject *&alias_cmd_obj, CommandReturnObject &result); + + bool HandleCommand (const char *command_line, bool add_to_history, CommandReturnObject &result, ExecutionContext *override_context = NULL); + CommandObject * + GetCommandObjectForCommand (std::string &command_line); + // This handles command line completion. You are given a pointer to the command string buffer, to the current cursor, // and to the end of the string (in case it is not NULL terminated). // You also passed in an Args object to fill with the returns. diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp index 0ca50b0ff65..0d2c55c9567 100644 --- a/lldb/source/Commands/CommandObjectCommands.cpp +++ b/lldb/source/Commands/CommandObjectCommands.cpp @@ -239,6 +239,133 @@ public: { } + bool + WantsRawCommandString () + { + return true; + } + + bool + ExecuteRawCommandString (const char *raw_command_line, CommandReturnObject &result) + { + Args args (raw_command_line); + std::string raw_command_string (raw_command_line); + + size_t argc = args.GetArgumentCount(); + + if (argc < 2) + { + result.AppendError ("'alias' requires at least two arguments"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + // Get the alias command. + + const std::string alias_command = args.GetArgumentAtIndex (0); + + // Strip the new alias name off 'raw_command_string' (leave it on args, which gets passed to 'Execute', which + // does the stripping itself. + size_t pos = raw_command_string.find (alias_command); + if (pos == 0) + { + raw_command_string = raw_command_string.substr (alias_command.size()); + pos = raw_command_string.find_first_not_of (' '); + if ((pos != std::string::npos) && (pos > 0)) + raw_command_string = raw_command_string.substr (pos); + } + else + { + result.AppendError ("Error parsing command string. No alias created."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + + // Verify that the command is alias-able. + if (m_interpreter.CommandExists (alias_command.c_str())) + { + result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", + alias_command.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + // Get CommandObject that is being aliased. The command name is read from the front of raw_command_string. + // raw_command_string is returned with the name of the command object stripped off the front. + CommandObject *cmd_obj = m_interpreter.GetCommandObjectForCommand (raw_command_string); + + if (!cmd_obj) + { + result.AppendErrorWithFormat ("Invalid command given to 'alias'. '%s' does not begin with a valid command." + " No alias created.", raw_command_string.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; + } + else if (!cmd_obj->WantsRawCommandString ()) + { + // Note that args was initialized with the original command, and has not been updated to this point. + // Therefore can we pass it to the version of Execute that does not need/expect raw input in the alias. + return Execute (args, result); + } + else + { + // Verify & handle any options/arguments passed to the alias command + + OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); + OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); + + // Check to see if there's anything left in the input command string. + if (raw_command_string.size() > 0) + { + + // Check to see if the command being aliased can take any command options. + Options *options = cmd_obj->GetOptions(); + if (options) + { + // See if any options were specified as part of the alias; if so, handle them appropriately + options->ResetOptionValues (); + Args tmp_args (raw_command_string.c_str()); + args.Unshift ("dummy_arg"); + args.ParseAliasOptions (*options, result, option_arg_vector, raw_command_string); + args.Shift (); + if (result.Succeeded()) + options->VerifyPartialOptions (result); + if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted) + { + result.AppendError ("Unable to create requested alias.\n"); + return false; + } + } + // Anything remaining must be plain raw input. Push it in as a single raw input argument. + if (raw_command_string.size() > 0) + option_arg_vector->push_back (OptionArgPair ("<argument>", + OptionArgValue (-1, + raw_command_string))); + } + + // Create the alias + if (m_interpreter.AliasExists (alias_command.c_str()) + || m_interpreter.UserCommandExists (alias_command.c_str())) + { + OptionArgVectorSP temp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str())); + if (temp_option_arg_sp.get()) + { + if (option_arg_vector->size() == 0) + m_interpreter.RemoveAliasOptions (alias_command.c_str()); + } + result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", + alias_command.c_str()); + } + + CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false); + m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp); + if (option_arg_vector->size() > 0) + m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + return result.Succeeded(); + } bool Execute @@ -282,7 +409,7 @@ public: OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); - if (cmd_obj->IsMultiwordObject()) + while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0) { if (argc >= 3) { @@ -295,6 +422,7 @@ public: sub_cmd_obj = subcommand_obj_sp.get(); use_subcommand = true; args.Shift(); // Shift the sub_command word off the argument vector. + cmd_obj = sub_cmd_obj; } else { @@ -320,8 +448,9 @@ public: else options = cmd_obj->GetOptions(); options->ResetOptionValues (); + std::string empty_string; args.Unshift ("dummy_arg"); - args.ParseAliasOptions (*options, result, option_arg_vector); + args.ParseAliasOptions (*options, result, option_arg_vector, empty_string); args.Shift (); if (result.Succeeded()) options->VerifyPartialOptions (result); diff --git a/lldb/source/Interpreter/Args.cpp b/lldb/source/Interpreter/Args.cpp index 8bc7d97b582..b0e448ee9bd 100644 --- a/lldb/source/Interpreter/Args.cpp +++ b/lldb/source/Interpreter/Args.cpp @@ -849,7 +849,8 @@ Args::IsPositionalArgument (const char *arg) void Args::ParseAliasOptions (Options &options, CommandReturnObject &result, - OptionArgVector *option_arg_vector) + OptionArgVector *option_arg_vector, + std::string &raw_input_string) { StreamString sstr; int i; @@ -985,16 +986,33 @@ Args::ParseAliasOptions (Options &options, if (long_options_index >= 0) { // Find option in the argument list; also see if it was supposed to take an argument and if one was - // supplied. Remove option (and argument, if given) from the argument list. + // supplied. Remove option (and argument, if given) from the argument list. Also remove them from + // the raw_input_string, if one was passed in. size_t idx = FindArgumentIndexForOption (long_options, long_options_index); if (idx < GetArgumentCount()) { + if (raw_input_string.size() > 0) + { + const char *tmp_arg = GetArgumentAtIndex (idx); + size_t pos = raw_input_string.find (tmp_arg); + if (pos != std::string::npos) + raw_input_string.erase (pos, strlen (tmp_arg)); + } ReplaceArgumentAtIndex (idx, ""); if ((long_options[long_options_index].has_arg != no_argument) && (optarg != NULL) && (idx+1 < GetArgumentCount()) && (strcmp (optarg, GetArgumentAtIndex(idx+1)) == 0)) + { + if (raw_input_string.size() > 0) + { + const char *tmp_arg = GetArgumentAtIndex (idx+1); + size_t pos = raw_input_string.find (tmp_arg); + if (pos != std::string::npos) + raw_input_string.erase (pos, strlen (tmp_arg)); + } ReplaceArgumentAtIndex (idx+1, ""); + } } } diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index feb496332c1..4651ad93a47 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -494,30 +494,184 @@ CommandInterpreter::GetHelp (CommandReturnObject &result) result.AppendMessage("For more information on any particular command, try 'help <command-name>'."); } +CommandObject * +CommandInterpreter::GetCommandObjectForCommand (std::string &command_string) +{ + // This function finds the final, lowest-level, alias-resolved command object whose 'Execute' function will + // eventually be invoked by the given command line. + + CommandObject *cmd_obj = NULL; + std::string white_space (" \t\v"); + size_t start = command_string.find_first_not_of (white_space); + size_t end = 0; + bool done = false; + while (!done) + { + if (start != std::string::npos) + { + // Get the next word from command_string. + end = command_string.find_first_of (white_space, start); + if (end == std::string::npos) + end = command_string.size(); + std::string cmd_word = command_string.substr (start, end - start); + + if (cmd_obj == NULL) + // Since cmd_obj is NULL we are on our first time through this loop. Check to see if cmd_word is a valid + // command or alias. + cmd_obj = GetCommandObject (cmd_word.c_str()); + else if (cmd_obj->IsMultiwordObject ()) + { + // Our current object is a multi-word object; see if the cmd_word is a valid sub-command for our object. + CommandObject *sub_cmd_obj = + ((CommandObjectMultiword *) cmd_obj)->GetSubcommandObject (cmd_word.c_str()); + if (sub_cmd_obj) + cmd_obj = sub_cmd_obj; + else // cmd_word was not a valid sub-command word, so we are donee + done = true; + } + else + // We have a cmd_obj and it is not a multi-word object, so we are done. + done = true; + + // If we didn't find a valid command object, or our command object is not a multi-word object, or + // we are at the end of the command_string, then we are done. Otherwise, find the start of the + // next word. + + if (!cmd_obj || !cmd_obj->IsMultiwordObject() || end >= command_string.size()) + done = true; + else + start = command_string.find_first_not_of (white_space, end); + } + else + // Unable to find any more words. + done = true; + } + + if (end == command_string.size()) + command_string.clear(); + else + command_string = command_string.substr(end); + + return cmd_obj; +} + bool -CommandInterpreter::HandleCommand -( - const char *command_line, - bool add_to_history, - CommandReturnObject &result, - ExecutionContext *override_context -) +CommandInterpreter::StripFirstWord (std::string &command_string, std::string &word) { - LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMANDS)); - // FIXME: there should probably be a mutex to make sure only one thread can - // run the interpreter at a time. + std::string white_space (" \t\v"); + size_t start; + size_t end; + + start = command_string.find_first_not_of (white_space); + if (start != std::string::npos) + { + end = command_string.find_first_of (white_space, start); + if (end != std::string::npos) + { + word = command_string.substr (start, end - start); + command_string = command_string.substr (end); + size_t pos = command_string.find_first_not_of (white_space); + if ((pos != 0) && (pos != std::string::npos)) + command_string = command_string.substr (pos); + } + else + { + word = command_string.substr (start); + command_string.erase(); + } + + } + return true; +} + +void +CommandInterpreter::BuildAliasResult (const char *alias_name, std::string &raw_input_string, std::string &alias_result, + CommandObject *&alias_cmd_obj, CommandReturnObject &result) +{ + Args cmd_args (raw_input_string.c_str()); + alias_cmd_obj = GetCommandObject (alias_name); + StreamString result_str; + + if (alias_cmd_obj) + { + std::string alias_name_str = alias_name; + if ((cmd_args.GetArgumentCount() == 0) + || (alias_name_str.compare (cmd_args.GetArgumentAtIndex(0)) != 0)) + cmd_args.Unshift (alias_name); + + result_str.Printf ("%s", alias_cmd_obj->GetCommandName ()); + OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name); + if (option_arg_vector_sp.get()) + { + OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); + + for (int i = 0; i < option_arg_vector->size(); ++i) + { + OptionArgPair option_pair = (*option_arg_vector)[i]; + OptionArgValue value_pair = option_pair.second; + int value_type = value_pair.first; + std::string option = option_pair.first; + std::string value = value_pair.second; + if (option.compare ("<argument>") == 0) + result_str.Printf (" %s", value.c_str()); + else + { + result_str.Printf (" %s", option.c_str()); + if (value_type != optional_argument) + result_str.Printf (" "); + if (value.compare ("<no_argument>") != 0) + { + int index = GetOptionArgumentPosition (value.c_str()); + if (index == 0) + result_str.Printf ("%s", value.c_str()); + else if (index >= cmd_args.GetArgumentCount()) + { + + result.AppendErrorWithFormat + ("Not enough arguments provided; you need at least %d arguments to use this alias.\n", + index); + result.SetStatus (eReturnStatusFailed); + return; + } + else + { + size_t strpos = raw_input_string.find (cmd_args.GetArgumentAtIndex (index)); + if (strpos != std::string::npos) + raw_input_string = raw_input_string.erase (strpos, + strlen (cmd_args.GetArgumentAtIndex (index))); + result_str.Printf ("%s", cmd_args.GetArgumentAtIndex (index)); + } + } + } + } + } + + alias_result = result_str.GetData(); + } +} + +bool +CommandInterpreter::HandleCommand (const char *command_line, + bool add_to_history, + CommandReturnObject &result, + ExecutionContext *override_context) +{ + bool done = false; + CommandObject *cmd_obj = NULL; + std::string next_word; + bool wants_raw_input = false; + std::string command_string (command_line); + + LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMANDS)); Host::SetCrashDescriptionWithFormat ("HandleCommand(command = \"%s\")", command_line); // Make a scoped cleanup object that will clear the crash description string // on exit of this function. lldb_utility::CleanUp <const char *, void> crash_description_cleanup(NULL, Host::SetCrashDescription); - // TODO: this should be a logging channel in lldb. -// if (DebugSelf()) -// { -// result.AppendMessageWithFormat ("Processing command: %s\n", command_line); -// } + if (log) + log->Printf ("Processing command: %s", command_line); Timer scoped_timer (__PRETTY_FUNCTION__, "Handling command: %s.", command_line); @@ -534,6 +688,7 @@ CommandInterpreter::HandleCommand else { command_line = m_repeat_command.c_str(); + command_string = command_line; if (m_repeat_command.empty()) { result.AppendErrorWithFormat("No auto repeat.\n"); @@ -544,158 +699,171 @@ CommandInterpreter::HandleCommand add_to_history = false; } - if (log) - log->Printf ("CommandInterpreter::HandleCommand, command_line = '%s'", command_line); - - Args command_args(command_line); - - if (command_args.GetArgumentCount() > 0) + // Phase 1. + + // Before we do ANY kind of argument processing, etc. we need to figure out what the real/final command object + // is for the specified command, and whether or not it wants raw input. This gets complicated by the fact that + // the user could have specified an alias, and in translating the alias there may also be command options and/or + // even data (including raw text strings) that need to be found and inserted into the command line as part of + // the translation. So this first step is plain look-up & replacement, resulting in three things: 1). the command + // object whose Execute method will actually be called; 2). a revised command string, with all substituitions & + // replacements taken care of; 3). whether or not the Execute function wants raw input or not. + + StreamString revised_command_line; + while (!done) { - std::string raw_command_string (command_line); // For commands that take raw input but may be aliased or - // have command options. - - const char *command_cstr = command_args.GetArgumentAtIndex(0); - if (command_cstr) + StripFirstWord (command_string, next_word); + if (!cmd_obj && AliasExists (next_word.c_str())) { - - // We're looking up the command object here. So first find an exact match to the - // command in the commands. - CommandObject *command_obj = GetCommandObject(command_cstr); - - if (command_obj != NULL) + std::string alias_result; + BuildAliasResult (next_word.c_str(), command_string, alias_result, cmd_obj, result); + revised_command_line.Printf ("%s", alias_result.c_str()); + if (cmd_obj) + wants_raw_input = cmd_obj->WantsRawCommandString (); + } + else if (!cmd_obj) + { + cmd_obj = GetCommandObject (next_word.c_str()); + if (cmd_obj) { - // Strip command name from the raw_command_string. - if (raw_command_string.find (command_cstr) == 0) - { - // The command name is at the front of the string (where it should be) so strip it off. - raw_command_string = raw_command_string.substr (strlen (command_cstr)); - } - + revised_command_line.Printf ("%s", next_word.c_str()); + wants_raw_input = cmd_obj->WantsRawCommandString (); + } + else + { + revised_command_line.Printf ("%s", next_word.c_str()); + } + } + else if (cmd_obj->IsMultiwordObject ()) + { + CommandObject *sub_cmd_obj = ((CommandObjectMultiword *) cmd_obj)->GetSubcommandObject (next_word.c_str()); + if (sub_cmd_obj) + { + revised_command_line.Printf (" %s", next_word.c_str()); + cmd_obj = sub_cmd_obj; + wants_raw_input = cmd_obj->WantsRawCommandString (); + } + else + { + revised_command_line.Printf (" %s", next_word.c_str()); + done = true; + } + } + else + { + revised_command_line.Printf (" %s", next_word.c_str()); + done = true; + } + + if (cmd_obj == NULL) + { + result.AppendErrorWithFormat ("'%s' is not a valid command.\n", next_word.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + next_word.erase (); + if (command_string.length() == 0) + done = true; - std::string aliased_cmd_str; - if (command_obj->IsAlias()) - { - if (log) - log->Printf ("Command '%s' is an alias. Building alias command args.", command_cstr); - BuildAliasCommandArgs (command_obj, command_cstr, command_args, raw_command_string, result); - if (!result.Succeeded()) - { - if (log) - log->Printf ("Building alias command args failed."); - return false; - } - else - { - // We need to transfer the newly constructed args back into the command_line, in case - // this happens to be an alias for a command that takes raw input. - if (command_args.GetCommandString (aliased_cmd_str)) - { - if (log) - log->Printf ("Result string from BuildAliasCommandArgs is '%s'", aliased_cmd_str.c_str()); - if (command_obj->WantsRawCommandString()) - { - if (log) - { - log->Printf ("This command takes raw input."); - } - aliased_cmd_str.append (" "); - aliased_cmd_str.append (raw_command_string); - } - else - { - if (log) - log->Printf ("This command does NOT take raw input."); - } - command_line = aliased_cmd_str.c_str(); - command_cstr = command_args.GetArgumentAtIndex (0); - if (log) - { - log->Printf ("Final command line, after resolving aliases is '%s'", command_line); - } - } - } - } + } - if (add_to_history) - { - const char *repeat_command = command_obj->GetRepeatCommand(command_args, 0); - if (repeat_command != NULL) - m_repeat_command.assign(repeat_command); - else - m_repeat_command.assign(command_line); - - m_command_history.push_back (command_line); - } + if (command_string.size() > 0) + revised_command_line.Printf (" %s", command_string.c_str()); + // End of Phase 1. + // At this point cmd_obj should contain the CommandObject whose Execute method will be called, if the command + // specified was valid; revised_command_line contains the complete command line (including command name(s)), + // fully translated with all substitutions & translations taken care of (still in raw text format); and + // wants_raw_input specifies whether the Execute method expects raw input or not. - if (command_obj->WantsRawCommandString()) - { - const char *stripped_command = ::strstr (command_line, command_cstr); - if (stripped_command) - { - stripped_command += strlen(command_cstr); - while (isspace(*stripped_command)) - ++stripped_command; - if (log) - log->Printf ("Input string being passed to ExecuteRawCommandString for '%s' command is '%s'", - command_obj->GetCommandName(), stripped_command); - command_obj->ExecuteRawCommandString (stripped_command, result); - } - } - else - { - // Remove the command from the args. - command_args.Shift(); - if (log) - { - size_t count = command_args.GetArgumentCount(); - log->Printf ("ExecuteWithOptions for '%s' command is being called with %d args:", - command_obj->GetCommandName(), count); - for (size_t k = 0; k < count; ++k) - log->Printf (" arg[%d]='%s'", k, command_args.GetArgumentAtIndex (k)); - } - command_obj->ExecuteWithOptions (command_args, result); - } - } - else - { - // We didn't find the first command object, so complete the first argument. - StringList matches; - int num_matches; - int cursor_index = 0; - int cursor_char_position = strlen (command_args.GetArgumentAtIndex(0)); - bool word_complete; - num_matches = HandleCompletionMatches (command_args, - cursor_index, - cursor_char_position, - 0, - -1, - word_complete, - matches); - - if (num_matches > 0) - { - std::string error_msg; - error_msg.assign ("ambiguous command '"); - error_msg.append(command_cstr); - error_msg.append ("'."); + + if (log) + { + log->Printf ("HandleCommand, cmd_obj : '%s'", cmd_obj ? cmd_obj->GetCommandName() : "<not found>"); + log->Printf ("HandleCommand, revised_command_line: '%s'", revised_command_line.GetData()); + log->Printf ("HandleCommand, wants_raw_input:'%s'", wants_raw_input ? "True" : "False"); + } - error_msg.append (" Possible completions:"); - for (int i = 0; i < num_matches; i++) - { - error_msg.append ("\n\t"); - error_msg.append (matches.GetStringAtIndex (i)); - } - error_msg.append ("\n"); - result.AppendRawError (error_msg.c_str(), error_msg.size()); - } - else - result.AppendErrorWithFormat ("Unrecognized command '%s'.\n", command_cstr); + // Phase 2. + // Take care of things like setting up the history command & calling the appropriate Execute method on the + // CommandObject, with the appropriate arguments. + + if (cmd_obj != NULL) + { + if (add_to_history) + { + Args command_args (revised_command_line.GetData()); + const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0); + if (repeat_command != NULL) + m_repeat_command.assign(repeat_command); + else + m_repeat_command.assign(command_line); + + m_command_history.push_back (command_line); + } + + command_string = revised_command_line.GetData(); + std::string command_name (cmd_obj->GetCommandName()); + std::string remainder (command_string.substr (command_name.size())); + + // Remove any initial spaces + std::string white_space (" \t\v"); + size_t pos = remainder.find_first_not_of (white_space); + if (pos != 0 && pos != std::string::npos) + remainder = remainder.substr (pos); + + if (log) + log->Printf ("HandleCommand, command line after removing command name(s): '%s'\n", remainder.c_str()); + - result.SetStatus (eReturnStatusFailed); + if (wants_raw_input) + cmd_obj->ExecuteRawCommandString (remainder.c_str(), result); + else + { + Args cmd_args (remainder.c_str()); + cmd_obj->ExecuteWithOptions (cmd_args, result); + } + } + else + { + // We didn't find the first command object, so complete the first argument. + Args command_args (revised_command_line.GetData()); + StringList matches; + int num_matches; + int cursor_index = 0; + int cursor_char_position = strlen (command_args.GetArgumentAtIndex(0)); + bool word_complete; + num_matches = HandleCompletionMatches (command_args, + cursor_index, + cursor_char_position, + 0, + -1, + word_complete, + matches); + + if (num_matches > 0) + { + std::string error_msg; + error_msg.assign ("ambiguous command '"); + error_msg.append(command_args.GetArgumentAtIndex(0)); + error_msg.append ("'."); + + error_msg.append (" Possible completions:"); + for (int i = 0; i < num_matches; i++) + { + error_msg.append ("\n\t"); + error_msg.append (matches.GetStringAtIndex (i)); } + error_msg.append ("\n"); + result.AppendRawError (error_msg.c_str(), error_msg.size()); } + else + result.AppendErrorWithFormat ("Unrecognized command '%s'.\n", command_args.GetArgumentAtIndex (0)); + + result.SetStatus (eReturnStatusFailed); } + return result.Succeeded(); } |

