|  | //===-- CommandObjectMultiword.cpp ------------------------------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | // C Includes | 
|  | // C++ Includes | 
|  | // Other libraries and framework includes | 
|  | // Project includes | 
|  | #include "lldb/Interpreter/CommandObjectMultiword.h" | 
|  | #include "lldb/Core/Debugger.h" | 
|  | #include "lldb/Interpreter/CommandInterpreter.h" | 
|  | #include "lldb/Interpreter/CommandReturnObject.h" | 
|  | #include "lldb/Interpreter/Options.h" | 
|  |  | 
|  | using namespace lldb; | 
|  | using namespace lldb_private; | 
|  |  | 
|  | //------------------------------------------------------------------------- | 
|  | // CommandObjectMultiword | 
|  | //------------------------------------------------------------------------- | 
|  |  | 
|  | CommandObjectMultiword::CommandObjectMultiword(CommandInterpreter &interpreter, | 
|  | const char *name, | 
|  | const char *help, | 
|  | const char *syntax, | 
|  | uint32_t flags) | 
|  | : CommandObject(interpreter, name, help, syntax, flags), | 
|  | m_can_be_removed(false) {} | 
|  |  | 
|  | CommandObjectMultiword::~CommandObjectMultiword() = default; | 
|  |  | 
|  | CommandObjectSP CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd, | 
|  | StringList *matches) { | 
|  | CommandObjectSP return_cmd_sp; | 
|  | CommandObject::CommandMap::iterator pos; | 
|  |  | 
|  | if (!m_subcommand_dict.empty()) { | 
|  | pos = m_subcommand_dict.find(sub_cmd); | 
|  | if (pos != m_subcommand_dict.end()) { | 
|  | // An exact match; append the sub_cmd to the 'matches' string list. | 
|  | if (matches) | 
|  | matches->AppendString(sub_cmd); | 
|  | return_cmd_sp = pos->second; | 
|  | } else { | 
|  | StringList local_matches; | 
|  | if (matches == nullptr) | 
|  | matches = &local_matches; | 
|  | int num_matches = | 
|  | AddNamesMatchingPartialString(m_subcommand_dict, sub_cmd, *matches); | 
|  |  | 
|  | if (num_matches == 1) { | 
|  | // Cleaner, but slightly less efficient would be to call back into this | 
|  | // function, since I now know I have an exact match... | 
|  |  | 
|  | sub_cmd = matches->GetStringAtIndex(0); | 
|  | pos = m_subcommand_dict.find(sub_cmd); | 
|  | if (pos != m_subcommand_dict.end()) | 
|  | return_cmd_sp = pos->second; | 
|  | } | 
|  | } | 
|  | } | 
|  | return return_cmd_sp; | 
|  | } | 
|  |  | 
|  | CommandObject * | 
|  | CommandObjectMultiword::GetSubcommandObject(llvm::StringRef sub_cmd, | 
|  | StringList *matches) { | 
|  | return GetSubcommandSP(sub_cmd, matches).get(); | 
|  | } | 
|  |  | 
|  | bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name, | 
|  | const CommandObjectSP &cmd_obj) { | 
|  | if (cmd_obj) | 
|  | assert((&GetCommandInterpreter() == &cmd_obj->GetCommandInterpreter()) && | 
|  | "tried to add a CommandObject from a different interpreter"); | 
|  |  | 
|  | CommandMap::iterator pos; | 
|  | bool success = true; | 
|  |  | 
|  | pos = m_subcommand_dict.find(name); | 
|  | if (pos == m_subcommand_dict.end()) { | 
|  | m_subcommand_dict[name] = cmd_obj; | 
|  | } else | 
|  | success = false; | 
|  |  | 
|  | return success; | 
|  | } | 
|  |  | 
|  | bool CommandObjectMultiword::Execute(const char *args_string, | 
|  | CommandReturnObject &result) { | 
|  | Args args(args_string); | 
|  | const size_t argc = args.GetArgumentCount(); | 
|  | if (argc == 0) { | 
|  | this->CommandObject::GenerateHelpText(result); | 
|  | return result.Succeeded(); | 
|  | } | 
|  |  | 
|  | auto sub_command = args[0].ref; | 
|  | if (sub_command.empty()) | 
|  | return result.Succeeded(); | 
|  |  | 
|  | if (sub_command.equals_lower("help")) { | 
|  | this->CommandObject::GenerateHelpText(result); | 
|  | return result.Succeeded(); | 
|  | } | 
|  |  | 
|  | if (m_subcommand_dict.empty()) { | 
|  | result.AppendErrorWithFormat("'%s' does not have any subcommands.\n", | 
|  | GetCommandName().str().c_str()); | 
|  | result.SetStatus(eReturnStatusFailed); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | StringList matches; | 
|  | CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches); | 
|  | if (sub_cmd_obj != nullptr) { | 
|  | // Now call CommandObject::Execute to process options in `rest_of_line`. | 
|  | // From there the command-specific version of Execute will be called, with | 
|  | // the processed arguments. | 
|  |  | 
|  | args.Shift(); | 
|  | sub_cmd_obj->Execute(args_string, result); | 
|  | return result.Succeeded(); | 
|  | } | 
|  |  | 
|  | std::string error_msg; | 
|  | const size_t num_subcmd_matches = matches.GetSize(); | 
|  | if (num_subcmd_matches > 0) | 
|  | error_msg.assign("ambiguous command "); | 
|  | else | 
|  | error_msg.assign("invalid command "); | 
|  |  | 
|  | error_msg.append("'"); | 
|  | error_msg.append(GetCommandName()); | 
|  | error_msg.append(" "); | 
|  | error_msg.append(sub_command); | 
|  | error_msg.append("'."); | 
|  |  | 
|  | if (num_subcmd_matches > 0) { | 
|  | error_msg.append(" Possible completions:"); | 
|  | for (size_t i = 0; i < matches.GetSize(); i++) { | 
|  | error_msg.append("\n\t"); | 
|  | error_msg.append(matches.GetStringAtIndex(i)); | 
|  | } | 
|  | } | 
|  | error_msg.append("\n"); | 
|  | result.AppendRawError(error_msg.c_str()); | 
|  | result.SetStatus(eReturnStatusFailed); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void CommandObjectMultiword::GenerateHelpText(Stream &output_stream) { | 
|  | // First time through here, generate the help text for the object and push it | 
|  | // to the return result object as well | 
|  |  | 
|  | CommandObject::GenerateHelpText(output_stream); | 
|  | output_stream.PutCString("\nThe following subcommands are supported:\n\n"); | 
|  |  | 
|  | CommandMap::iterator pos; | 
|  | uint32_t max_len = FindLongestCommandWord(m_subcommand_dict); | 
|  |  | 
|  | if (max_len) | 
|  | max_len += 4; // Indent the output by 4 spaces. | 
|  |  | 
|  | for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) { | 
|  | std::string indented_command("    "); | 
|  | indented_command.append(pos->first); | 
|  | if (pos->second->WantsRawCommandString()) { | 
|  | std::string help_text(pos->second->GetHelp()); | 
|  | help_text.append("  Expects 'raw' input (see 'help raw-input'.)"); | 
|  | m_interpreter.OutputFormattedHelpText(output_stream, | 
|  | indented_command.c_str(), "--", | 
|  | help_text.c_str(), max_len); | 
|  | } else | 
|  | m_interpreter.OutputFormattedHelpText(output_stream, | 
|  | indented_command.c_str(), "--", | 
|  | pos->second->GetHelp(), max_len); | 
|  | } | 
|  |  | 
|  | output_stream.PutCString("\nFor more help on any particular subcommand, type " | 
|  | "'help <command> <subcommand>'.\n"); | 
|  | } | 
|  |  | 
|  | int CommandObjectMultiword::HandleCompletion(CompletionRequest &request) { | 
|  | // Any of the command matches will provide a complete word, otherwise the | 
|  | // individual completers will override this. | 
|  | request.SetWordComplete(true); | 
|  |  | 
|  | auto arg0 = request.GetParsedLine()[0].ref; | 
|  | if (request.GetCursorIndex() == 0) { | 
|  | StringList new_matches; | 
|  | AddNamesMatchingPartialString(m_subcommand_dict, arg0, new_matches); | 
|  | request.AddCompletions(new_matches); | 
|  |  | 
|  | if (new_matches.GetSize() == 1 && | 
|  | new_matches.GetStringAtIndex(0) != nullptr && | 
|  | (arg0 == new_matches.GetStringAtIndex(0))) { | 
|  | StringList temp_matches; | 
|  | CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches); | 
|  | if (cmd_obj != nullptr) { | 
|  | if (request.GetParsedLine().GetArgumentCount() == 1) { | 
|  | request.SetWordComplete(true); | 
|  | } else { | 
|  | request.GetParsedLine().Shift(); | 
|  | request.SetCursorCharPosition(0); | 
|  | request.GetParsedLine().AppendArgument(llvm::StringRef()); | 
|  | return cmd_obj->HandleCompletion(request); | 
|  | } | 
|  | } | 
|  | } | 
|  | return new_matches.GetSize(); | 
|  | } else { | 
|  | StringList new_matches; | 
|  | CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches); | 
|  | if (sub_command_object == nullptr) { | 
|  | request.AddCompletions(new_matches); | 
|  | return request.GetNumberOfMatches(); | 
|  | } else { | 
|  | // Remove the one match that we got from calling GetSubcommandObject. | 
|  | new_matches.DeleteStringAtIndex(0); | 
|  | request.AddCompletions(new_matches); | 
|  | request.GetParsedLine().Shift(); | 
|  | request.SetCursorIndex(request.GetCursorIndex() - 1); | 
|  | return sub_command_object->HandleCompletion(request); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | const char *CommandObjectMultiword::GetRepeatCommand(Args ¤t_command_args, | 
|  | uint32_t index) { | 
|  | index++; | 
|  | if (current_command_args.GetArgumentCount() <= index) | 
|  | return nullptr; | 
|  | CommandObject *sub_command_object = | 
|  | GetSubcommandObject(current_command_args[index].ref); | 
|  | if (sub_command_object == nullptr) | 
|  | return nullptr; | 
|  | return sub_command_object->GetRepeatCommand(current_command_args, index); | 
|  | } | 
|  |  | 
|  | void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix, | 
|  | llvm::StringRef search_word, | 
|  | StringList &commands_found, | 
|  | StringList &commands_help) { | 
|  | CommandObject::CommandMap::const_iterator pos; | 
|  |  | 
|  | for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) { | 
|  | const char *command_name = pos->first.c_str(); | 
|  | CommandObject *sub_cmd_obj = pos->second.get(); | 
|  | StreamString complete_command_name; | 
|  |  | 
|  | complete_command_name << prefix << " " << command_name; | 
|  |  | 
|  | if (sub_cmd_obj->HelpTextContainsWord(search_word)) { | 
|  | commands_found.AppendString(complete_command_name.GetString()); | 
|  | commands_help.AppendString(sub_cmd_obj->GetHelp()); | 
|  | } | 
|  |  | 
|  | if (sub_cmd_obj->IsMultiwordObject()) | 
|  | sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(), | 
|  | search_word, commands_found, | 
|  | commands_help); | 
|  | } | 
|  | } | 
|  |  | 
|  | CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter, | 
|  | const char *name, const char *help, | 
|  | const char *syntax, uint32_t flags) | 
|  | : CommandObject(interpreter, name, help, syntax, flags) {} | 
|  |  | 
|  | CommandObjectProxy::~CommandObjectProxy() = default; | 
|  |  | 
|  | llvm::StringRef CommandObjectProxy::GetHelpLong() { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->GetHelpLong(); | 
|  | return llvm::StringRef(); | 
|  | } | 
|  |  | 
|  | bool CommandObjectProxy::IsRemovable() const { | 
|  | const CommandObject *proxy_command = | 
|  | const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->IsRemovable(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool CommandObjectProxy::IsMultiwordObject() { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->IsMultiwordObject(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->GetAsMultiwordCommand(); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | void CommandObjectProxy::GenerateHelpText(Stream &result) { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->GenerateHelpText(result); | 
|  | } | 
|  |  | 
|  | lldb::CommandObjectSP | 
|  | CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd, | 
|  | StringList *matches) { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->GetSubcommandSP(sub_cmd, matches); | 
|  | return lldb::CommandObjectSP(); | 
|  | } | 
|  |  | 
|  | CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd, | 
|  | StringList *matches) { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->GetSubcommandObject(sub_cmd, matches); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix, | 
|  | llvm::StringRef search_word, | 
|  | StringList &commands_found, | 
|  | StringList &commands_help) { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->AproposAllSubCommands(prefix, search_word, | 
|  | commands_found, commands_help); | 
|  | } | 
|  |  | 
|  | bool CommandObjectProxy::LoadSubCommand( | 
|  | llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->LoadSubCommand(cmd_name, command_sp); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool CommandObjectProxy::WantsRawCommandString() { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->WantsRawCommandString(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool CommandObjectProxy::WantsCompletion() { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->WantsCompletion(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Options *CommandObjectProxy::GetOptions() { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->GetOptions(); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | int CommandObjectProxy::HandleCompletion(CompletionRequest &request) { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->HandleCompletion(request); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int CommandObjectProxy::HandleArgumentCompletion( | 
|  | CompletionRequest &request, OptionElementVector &opt_element_vector) { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->HandleArgumentCompletion(request, opt_element_vector); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | const char *CommandObjectProxy::GetRepeatCommand(Args ¤t_command_args, | 
|  | uint32_t index) { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->GetRepeatCommand(current_command_args, index); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | bool CommandObjectProxy::Execute(const char *args_string, | 
|  | CommandReturnObject &result) { | 
|  | CommandObject *proxy_command = GetProxyCommandObject(); | 
|  | if (proxy_command) | 
|  | return proxy_command->Execute(args_string, result); | 
|  | result.AppendError("command is not implemented"); | 
|  | result.SetStatus(eReturnStatusFailed); | 
|  | return false; | 
|  | } |