diff options
Diffstat (limited to 'source/Interpreter/CommandInterpreter.cpp')
-rw-r--r-- | source/Interpreter/CommandInterpreter.cpp | 475 |
1 files changed, 256 insertions, 219 deletions
diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp index 6318b80a..1da541b 100644 --- a/source/Interpreter/CommandInterpreter.cpp +++ b/source/Interpreter/CommandInterpreter.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include <string> #include <vector> #include <stdlib.h> @@ -19,6 +17,7 @@ #include "../Commands/CommandObjectApropos.h" #include "../Commands/CommandObjectArgs.h" #include "../Commands/CommandObjectBreakpoint.h" +#include "../Commands/CommandObjectBugreport.h" #include "../Commands/CommandObjectDisassemble.h" #include "../Commands/CommandObjectExpression.h" #include "../Commands/CommandObjectFrame.h" @@ -40,6 +39,7 @@ #include "../Commands/CommandObjectType.h" #include "../Commands/CommandObjectVersion.h" #include "../Commands/CommandObjectWatchpoint.h" +#include "../Commands/CommandObjectLanguage.h" #include "lldb/Core/Debugger.h" @@ -60,6 +60,8 @@ #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Interpreter/Property.h" #include "lldb/Interpreter/ScriptInterpreterNone.h" #include "lldb/Interpreter/ScriptInterpreterPython.h" @@ -77,6 +79,7 @@ using namespace lldb; using namespace lldb_private; +static const char *k_white_space = " \t\v"; static PropertyDefinition g_properties[] = @@ -107,7 +110,7 @@ CommandInterpreter::CommandInterpreter ScriptLanguage script_language, bool synchronous_execution ) : - Broadcaster (&debugger, "lldb.command-interpreter"), + Broadcaster (&debugger, CommandInterpreter::GetStaticBroadcasterClass().AsCString()), Properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))), IOHandlerDelegate (IOHandlerDelegate::Completion::LLDBCommand), m_debugger (debugger), @@ -147,6 +150,24 @@ CommandInterpreter::GetPromptOnQuit () const return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0); } +void +CommandInterpreter::SetPromptOnQuit (bool b) +{ + const uint32_t idx = ePropertyPromptOnQuit; + m_collection_sp->SetPropertyAtIndexAsBoolean (nullptr, idx, b); +} + +void +CommandInterpreter::ResolveCommand(const char *command_line, CommandReturnObject &result) +{ + std::string command = command_line; + if (ResolveCommandImpl(command, result) != nullptr) { + result.AppendMessageWithFormat("%s", command.c_str()); + result.SetStatus(eReturnStatusSuccessFinishResult); + } +} + + bool CommandInterpreter::GetStopCmdSourceOnError () const { @@ -401,6 +422,7 @@ CommandInterpreter::LoadCommandDictionary () m_command_dict["apropos"] = CommandObjectSP (new CommandObjectApropos (*this)); m_command_dict["breakpoint"]= CommandObjectSP (new CommandObjectMultiwordBreakpoint (*this)); + m_command_dict["bugreport"] = CommandObjectSP (new CommandObjectMultiwordBugreport (*this)); m_command_dict["command"] = CommandObjectSP (new CommandObjectMultiwordCommands (*this)); m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble (*this)); m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression (*this)); @@ -422,6 +444,7 @@ CommandInterpreter::LoadCommandDictionary () m_command_dict["type"] = CommandObjectSP (new CommandObjectType (*this)); m_command_dict["version"] = CommandObjectSP (new CommandObjectVersion (*this)); m_command_dict["watchpoint"]= CommandObjectSP (new CommandObjectMultiwordWatchpoint (*this)); + m_command_dict["language"] = CommandObjectSP (new CommandObjectLanguage(*this)); const char *break_regexes[][2] = {{"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "breakpoint set --file '%1' --line %2"}, {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"}, @@ -438,8 +461,14 @@ CommandInterpreter::LoadCommandDictionary () std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_ap(new CommandObjectRegexCommand (*this, "_regexp-break", - "Set a breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.", - "_regexp-break [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\n_regexp-break <...>", + "Set a breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.\n", + "\n_regexp-break <filename>:<linenum> # _regexp-break main.c:12 // Break on line 12 of main.c\n" + "_regexp-break <linenum> # _regexp-break 12 // Break on line 12 of current file\n" + "_regexp-break <address> # _regexp-break 0x1234000 // Break on address 0x1234000\n" + "_regexp-break <name> # _regexp-break main // Break in 'main' after the prologue\n" + "_regexp-break &<name> # _regexp-break &main // Break on the first instruction in 'main'\n" + "_regexp-break <module>`<name> # _regexp-break libc.so`malloc // Break in 'malloc' only in the 'libc.so' shared library\n" + "_regexp-break /<source-regex>/ # _regexp-break /break here/ // Break on all lines that match the regular expression 'break here' in the current file.\n", 2, CommandCompletions::eSymbolCompletion | CommandCompletions::eSourceFileCompletion, @@ -1243,8 +1272,7 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string) // eventually be invoked by the given command line. CommandObject *cmd_obj = nullptr; - std::string white_space (" \t\v"); - size_t start = command_string.find_first_not_of (white_space); + size_t start = command_string.find_first_not_of (k_white_space); size_t end = 0; bool done = false; while (!done) @@ -1252,7 +1280,7 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string) if (start != std::string::npos) { // Get the next word from command_string. - end = command_string.find_first_of (white_space, start); + end = command_string.find_first_of (k_white_space, start); if (end == std::string::npos) end = command_string.size(); std::string cmd_word = command_string.substr (start, end - start); @@ -1267,7 +1295,7 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string) CommandObject *sub_cmd_obj = 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 + else // cmd_word was not a valid sub-command word, so we are done done = true; } else @@ -1281,7 +1309,7 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string) if (!cmd_obj || !cmd_obj->IsMultiwordObject() || end >= command_string.size()) done = true; else - start = command_string.find_first_not_of (white_space, end); + start = command_string.find_first_not_of (k_white_space, end); } else // Unable to find any more words. @@ -1296,7 +1324,6 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string) return cmd_obj; } -static const char *k_white_space = " \t\v"; static const char *k_valid_command_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; static void StripLeadingSpaces (std::string &s) @@ -1412,7 +1439,7 @@ CommandInterpreter::BuildAliasResult (const char *alias_name, CommandReturnObject &result) { CommandObject *alias_cmd_obj = nullptr; - Args cmd_args (raw_input_string.c_str()); + Args cmd_args (raw_input_string); alias_cmd_obj = GetCommandObject (alias_name); StreamString result_str; @@ -1442,10 +1469,10 @@ CommandInterpreter::BuildAliasResult (const char *alias_name, else { result_str.Printf (" %s", option.c_str()); - if (value_type != OptionParser::eOptionalArgument) - result_str.Printf (" "); - if (value.compare ("<OptionParser::eNoArgument>") != 0) + if (value_type != OptionParser::eNoArgument) { + if (value_type != OptionParser::eOptionalArgument) + result_str.Printf (" "); int index = GetOptionArgumentPosition (value.c_str()); if (index == 0) result_str.Printf ("%s", value.c_str()); @@ -1456,7 +1483,7 @@ CommandInterpreter::BuildAliasResult (const char *alias_name, ("Not enough arguments provided; you need at least %d arguments to use this alias.\n", index); result.SetStatus (eReturnStatusFailed); - return alias_cmd_obj; + return nullptr; } else { @@ -1481,7 +1508,7 @@ CommandInterpreter::PreprocessCommand (std::string &command) { // The command preprocessor needs to do things to the command // line before any parsing of arguments or anything else is done. - // The only current stuff that gets proprocessed is anyting enclosed + // The only current stuff that gets preprocessed is anything enclosed // in backtick ('`') characters is evaluated as an expression and // the result of the expression must be a scalar that can be substituted // into the command. An example would be: @@ -1493,7 +1520,7 @@ CommandInterpreter::PreprocessCommand (std::string &command) { if (start_backtick > 0 && command[start_backtick-1] == '\\') { - // The backtick was preceeded by a '\' character, remove the slash + // The backtick was preceded by a '\' character, remove the slash // and don't treat the backtick as the start of an expression command.erase(start_backtick-1, 1); // No need to add one to start_backtick since we just deleted a char @@ -1622,9 +1649,6 @@ CommandInterpreter::HandleCommand (const char *command_line, { - bool done = false; - CommandObject *cmd_obj = nullptr; - bool wants_raw_input = false; std::string command_string (command_line); std::string original_command_string (command_line); @@ -1724,192 +1748,34 @@ CommandInterpreter::HandleCommand (const char *command_line, result.SetStatus(eReturnStatusFailed); return false; } - // 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 substitutions & - // replacements taken care of; 3). whether or not the Execute function wants raw input or not. - - StreamString revised_command_line; - size_t actual_cmd_name_len = 0; - std::string next_word; - StringList matches; - while (!done) - { - char quote_char = '\0'; - std::string suffix; - ExtractCommand (command_string, next_word, suffix, quote_char); - if (cmd_obj == nullptr) - { - std::string full_name; - if (GetAliasFullName(next_word.c_str(), full_name)) - { - std::string alias_result; - cmd_obj = BuildAliasResult (full_name.c_str(), command_string, alias_result, result); - revised_command_line.Printf ("%s", alias_result.c_str()); - if (cmd_obj) - { - wants_raw_input = cmd_obj->WantsRawCommandString (); - actual_cmd_name_len = strlen (cmd_obj->GetCommandName()); - } - } - else - { - cmd_obj = GetCommandObject (next_word.c_str(), &matches); - if (cmd_obj) - { - actual_cmd_name_len += next_word.length(); - 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 = cmd_obj->GetSubcommandObject (next_word.c_str()); - if (sub_cmd_obj) - { - actual_cmd_name_len += next_word.length() + 1; - revised_command_line.Printf (" %s", next_word.c_str()); - cmd_obj = sub_cmd_obj; - wants_raw_input = cmd_obj->WantsRawCommandString (); - } - else - { - if (quote_char) - revised_command_line.Printf (" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char); - else - revised_command_line.Printf (" %s%s", next_word.c_str(), suffix.c_str()); - done = true; - } - } - else - { - if (quote_char) - revised_command_line.Printf (" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char); - else - revised_command_line.Printf (" %s%s", next_word.c_str(), suffix.c_str()); - done = true; - } - } - - if (cmd_obj == nullptr) - { - const size_t num_matches = matches.GetSize(); - if (matches.GetSize() > 1) { - StreamString error_msg; - error_msg.Printf ("Ambiguous command '%s'. Possible matches:\n", next_word.c_str()); - - for (uint32_t i = 0; i < num_matches; ++i) { - error_msg.Printf ("\t%s\n", matches.GetStringAtIndex(i)); - } - result.AppendRawError (error_msg.GetString().c_str()); - } else { - // We didn't have only one match, otherwise we wouldn't get here. - assert(num_matches == 0); - result.AppendErrorWithFormat ("'%s' is not a valid command.\n", next_word.c_str()); - } - result.SetStatus (eReturnStatusFailed); - return false; - } - if (cmd_obj->IsMultiwordObject ()) - { - if (!suffix.empty()) - { - - result.AppendErrorWithFormat ("command '%s' did not recognize '%s%s%s' as valid (subcommand might be invalid).\n", - cmd_obj->GetCommandName(), - next_word.empty() ? "" : next_word.c_str(), - next_word.empty() ? " -- " : " ", - suffix.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; - } - } - else - { - // If we found a normal command, we are done - done = true; - if (!suffix.empty()) - { - switch (suffix[0]) - { - case '/': - // GDB format suffixes - { - Options *command_options = cmd_obj->GetOptions(); - if (command_options && command_options->SupportsLongOption("gdb-format")) - { - std::string gdb_format_option ("--gdb-format="); - gdb_format_option += (suffix.c_str() + 1); + // Phase 1. - bool inserted = false; - std::string &cmd = revised_command_line.GetString(); - size_t arg_terminator_idx = FindArgumentTerminator (cmd); - if (arg_terminator_idx != std::string::npos) - { - // Insert the gdb format option before the "--" that terminates options - gdb_format_option.append(1,' '); - cmd.insert(arg_terminator_idx, gdb_format_option); - inserted = true; - } + // Before we do ANY kind of argument processing, we need to figure out what + // the real/final command object is for the specified command. 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 and replacement, resulting in: + // 1. the command object whose Execute method will actually be called + // 2. a revised command string, with all substitutions and replacements + // taken care of + // From 1 above, we can determine whether the Execute function wants raw + // input or not. + + CommandObject *cmd_obj = ResolveCommandImpl(command_string, result); + + // Although the user may have abbreviated the command, the command_string now + // has the command expanded to the full name. For example, if the input + // was "br s -n main", command_string is now "breakpoint set -n main". - if (!inserted) - revised_command_line.Printf (" %s", gdb_format_option.c_str()); - - if (wants_raw_input && FindArgumentTerminator(cmd) == std::string::npos) - revised_command_line.PutCString (" --"); - } - else - { - result.AppendErrorWithFormat ("the '%s' command doesn't support the --gdb-format option\n", - cmd_obj->GetCommandName()); - result.SetStatus (eReturnStatusFailed); - return false; - } - } - break; - - default: - result.AppendErrorWithFormat ("unknown command shorthand suffix: '%s'\n", - suffix.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; - - } - } - } - if (command_string.length() == 0) - done = true; - - } - - if (!command_string.empty()) - 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 (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"); + log->Printf("HandleCommand, cmd_obj : '%s'", cmd_obj ? cmd_obj->GetCommandName() : "<not found>"); + log->Printf("HandleCommand, (revised) command_string: '%s'", command_string.c_str()); + const bool wants_raw_input = (cmd_obj != NULL) ? cmd_obj->WantsRawCommandString() : false; + log->Printf("HandleCommand, wants_raw_input:'%s'", wants_raw_input ? "True" : "False"); } // Phase 2. @@ -1920,7 +1786,7 @@ CommandInterpreter::HandleCommand (const char *command_line, { if (add_to_history) { - Args command_args (revised_command_line.GetData()); + Args command_args (command_string); const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0); if (repeat_command != nullptr) m_repeat_command.assign(repeat_command); @@ -1930,18 +1796,13 @@ CommandInterpreter::HandleCommand (const char *command_line, m_command_history.AppendString (original_command_string); } - command_string = revised_command_line.GetData(); - std::string command_name (cmd_obj->GetCommandName()); std::string remainder; + const std::size_t actual_cmd_name_len = strlen (cmd_obj->GetCommandName()); if (actual_cmd_name_len < command_string.length()) - remainder = command_string.substr (actual_cmd_name_len); // Note: 'actual_cmd_name_len' may be considerably shorter - // than cmd_obj->GetCommandName(), because name completion - // allows users to enter short versions of the names, - // e.g. 'br s' for 'breakpoint set'. + remainder = command_string.substr (actual_cmd_name_len); // Remove any initial spaces - std::string white_space (" \t\v"); - size_t pos = remainder.find_first_not_of (white_space); + size_t pos = remainder.find_first_not_of (k_white_space); if (pos != 0 && pos != std::string::npos) remainder.erase(0, pos); @@ -1953,7 +1814,7 @@ CommandInterpreter::HandleCommand (const char *command_line, else { // We didn't find the first command object, so complete the first argument. - Args command_args (revised_command_line.GetData()); + Args command_args (command_string); StringList matches; int num_matches; int cursor_index = 0; @@ -2082,8 +1943,8 @@ CommandInterpreter::HandleCompletion (const char *current_line, // We parse the argument up to the cursor, so the last argument in parsed_line is // the one containing the cursor, and the cursor is after the last character. - Args parsed_line(current_line, last_char - current_line); - Args partial_parsed_line(current_line, cursor - current_line); + Args parsed_line(llvm::StringRef(current_line, last_char - current_line)); + Args partial_parsed_line(llvm::StringRef(current_line, cursor - current_line)); // Don't complete comments, and if the line we are completing is just the history repeat character, // substitute the appropriate history line. @@ -2386,7 +2247,7 @@ CommandInterpreter::BuildAliasCommandArgs (CommandObject *alias_cmd_obj, } cmd_args.Clear(); - cmd_args.SetArguments (new_args.GetArgumentCount(), (const char **) new_args.GetArgumentVector()); + cmd_args.SetArguments (new_args.GetArgumentCount(), new_args.GetConstArgumentVector()); } else { @@ -2397,7 +2258,7 @@ CommandInterpreter::BuildAliasCommandArgs (CommandObject *alias_cmd_obj, if (wants_raw_input) { cmd_args.Clear(); - cmd_args.SetArguments (new_args.GetArgumentCount(), (const char **) new_args.GetArgumentVector()); + cmd_args.SetArguments (new_args.GetArgumentCount(), new_args.GetConstArgumentVector()); } return; } @@ -2413,7 +2274,7 @@ CommandInterpreter::GetOptionArgumentPosition (const char *in_string) int position = 0; // Any string that isn't an argument position, i.e. '%' followed by an integer, gets a position // of zero. - char *cptr = (char *) in_string; + const char *cptr = in_string; // Does it start with '%' if (cptr[0] == '%') @@ -3355,7 +3216,7 @@ CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, bool spawn_thread, CommandInterpreterRunOptions &options) { - // Always re-create the command intepreter when we run it in case + // Always re-create the command interpreter when we run it in case // any file handles have changed. bool force_create = true; m_debugger.PushIOHandler(GetIOHandler(force_create, &options)); @@ -3370,7 +3231,7 @@ CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, } else { - m_debugger.ExecuteIOHanders(); + m_debugger.ExecuteIOHandlers(); if (auto_handle_events) m_debugger.StopEventHandlerThread(); @@ -3378,3 +3239,179 @@ CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, } +CommandObject * +CommandInterpreter::ResolveCommandImpl(std::string &command_line, CommandReturnObject &result) +{ + std::string scratch_command(command_line); // working copy so we don't modify command_line unless we succeed + CommandObject *cmd_obj = nullptr; + StreamString revised_command_line; + bool wants_raw_input = false; + size_t actual_cmd_name_len = 0; + std::string next_word; + StringList matches; + bool done = false; + while (!done) + { + char quote_char = '\0'; + std::string suffix; + ExtractCommand(scratch_command, next_word, suffix, quote_char); + if (cmd_obj == nullptr) + { + std::string full_name; + if (GetAliasFullName(next_word.c_str(), full_name)) + { + std::string alias_result; + cmd_obj = BuildAliasResult(full_name.c_str(), scratch_command, alias_result, result); + revised_command_line.Printf("%s", alias_result.c_str()); + if (cmd_obj) + { + wants_raw_input = cmd_obj->WantsRawCommandString(); + actual_cmd_name_len = strlen(cmd_obj->GetCommandName()); + } + } + else + { + cmd_obj = GetCommandObject(next_word.c_str(), &matches); + if (cmd_obj) + { + actual_cmd_name_len += strlen(cmd_obj->GetCommandName()); + revised_command_line.Printf("%s", cmd_obj->GetCommandName()); + 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 = cmd_obj->GetSubcommandObject(next_word.c_str()); + if (sub_cmd_obj) + { + // The subcommand's name includes the parent command's name, + // so restart rather than append to the revised_command_line. + actual_cmd_name_len = strlen(sub_cmd_obj->GetCommandName()) + 1; + revised_command_line.Clear(); + revised_command_line.Printf("%s", sub_cmd_obj->GetCommandName()); + cmd_obj = sub_cmd_obj; + wants_raw_input = cmd_obj->WantsRawCommandString(); + } + else + { + if (quote_char) + revised_command_line.Printf(" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char); + else + revised_command_line.Printf(" %s%s", next_word.c_str(), suffix.c_str()); + done = true; + } + } + else + { + if (quote_char) + revised_command_line.Printf(" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char); + else + revised_command_line.Printf(" %s%s", next_word.c_str(), suffix.c_str()); + done = true; + } + } + + if (cmd_obj == nullptr) + { + const size_t num_matches = matches.GetSize(); + if (matches.GetSize() > 1) { + StreamString error_msg; + error_msg.Printf("Ambiguous command '%s'. Possible matches:\n", next_word.c_str()); + + for (uint32_t i = 0; i < num_matches; ++i) { + error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i)); + } + result.AppendRawError(error_msg.GetString().c_str()); + } else { + // We didn't have only one match, otherwise we wouldn't get here. + assert(num_matches == 0); + result.AppendErrorWithFormat("'%s' is not a valid command.\n", next_word.c_str()); + } + result.SetStatus(eReturnStatusFailed); + return nullptr; + } + + if (cmd_obj->IsMultiwordObject()) + { + if (!suffix.empty()) + { + result.AppendErrorWithFormat("command '%s' did not recognize '%s%s%s' as valid (subcommand might be invalid).\n", + cmd_obj->GetCommandName(), + next_word.empty() ? "" : next_word.c_str(), + next_word.empty() ? " -- " : " ", + suffix.c_str()); + result.SetStatus(eReturnStatusFailed); + return nullptr; + } + } + else + { + // If we found a normal command, we are done + done = true; + if (!suffix.empty()) + { + switch (suffix[0]) + { + case '/': + // GDB format suffixes + { + Options *command_options = cmd_obj->GetOptions(); + if (command_options && command_options->SupportsLongOption("gdb-format")) + { + std::string gdb_format_option("--gdb-format="); + gdb_format_option += (suffix.c_str() + 1); + + bool inserted = false; + std::string &cmd = revised_command_line.GetString(); + size_t arg_terminator_idx = FindArgumentTerminator(cmd); + if (arg_terminator_idx != std::string::npos) + { + // Insert the gdb format option before the "--" that terminates options + gdb_format_option.append(1,' '); + cmd.insert(arg_terminator_idx, gdb_format_option); + inserted = true; + } + + if (!inserted) + revised_command_line.Printf(" %s", gdb_format_option.c_str()); + + if (wants_raw_input && FindArgumentTerminator(cmd) == std::string::npos) + revised_command_line.PutCString(" --"); + } + else + { + result.AppendErrorWithFormat("the '%s' command doesn't support the --gdb-format option\n", + cmd_obj->GetCommandName()); + result.SetStatus(eReturnStatusFailed); + return nullptr; + } + } + break; + + default: + result.AppendErrorWithFormat("unknown command shorthand suffix: '%s'\n", + suffix.c_str()); + result.SetStatus(eReturnStatusFailed); + return nullptr; + } + } + } + if (scratch_command.empty()) + done = true; + } + + if (!scratch_command.empty()) + revised_command_line.Printf(" %s", scratch_command.c_str()); + + if (cmd_obj != NULL) + command_line = revised_command_line.GetData(); + + return cmd_obj; +} |