419 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			419 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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 < num_subcmd_matches; 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(Args &input, int &cursor_index,
 | |
|                                              int &cursor_char_position,
 | |
|                                              int match_start_point,
 | |
|                                              int max_return_elements,
 | |
|                                              bool &word_complete,
 | |
|                                              StringList &matches) {
 | |
|   // Any of the command matches will provide a complete word, otherwise the
 | |
|   // individual completers will override this.
 | |
|   word_complete = true;
 | |
| 
 | |
|   auto arg0 = input[0].ref;
 | |
|   if (cursor_index == 0) {
 | |
|     AddNamesMatchingPartialString(m_subcommand_dict, arg0, matches);
 | |
| 
 | |
|     if (matches.GetSize() == 1 && matches.GetStringAtIndex(0) != nullptr &&
 | |
|         (arg0 == matches.GetStringAtIndex(0))) {
 | |
|       StringList temp_matches;
 | |
|       CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
 | |
|       if (cmd_obj != nullptr) {
 | |
|         if (input.GetArgumentCount() == 1) {
 | |
|           word_complete = true;
 | |
|         } else {
 | |
|           matches.DeleteStringAtIndex(0);
 | |
|           input.Shift();
 | |
|           cursor_char_position = 0;
 | |
|           input.AppendArgument(llvm::StringRef());
 | |
|           return cmd_obj->HandleCompletion(
 | |
|               input, cursor_index, cursor_char_position, match_start_point,
 | |
|               max_return_elements, word_complete, matches);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return matches.GetSize();
 | |
|   } else {
 | |
|     CommandObject *sub_command_object = GetSubcommandObject(arg0, &matches);
 | |
|     if (sub_command_object == nullptr) {
 | |
|       return matches.GetSize();
 | |
|     } else {
 | |
|       // Remove the one match that we got from calling GetSubcommandObject.
 | |
|       matches.DeleteStringAtIndex(0);
 | |
|       input.Shift();
 | |
|       cursor_index--;
 | |
|       return sub_command_object->HandleCompletion(
 | |
|           input, cursor_index, cursor_char_position, match_start_point,
 | |
|           max_return_elements, word_complete, matches);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 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(Args &input, int &cursor_index,
 | |
|                                          int &cursor_char_position,
 | |
|                                          int match_start_point,
 | |
|                                          int max_return_elements,
 | |
|                                          bool &word_complete,
 | |
|                                          StringList &matches) {
 | |
|   CommandObject *proxy_command = GetProxyCommandObject();
 | |
|   if (proxy_command)
 | |
|     return proxy_command->HandleCompletion(
 | |
|         input, cursor_index, cursor_char_position, match_start_point,
 | |
|         max_return_elements, word_complete, matches);
 | |
|   matches.Clear();
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int CommandObjectProxy::HandleArgumentCompletion(
 | |
|     Args &input, int &cursor_index, int &cursor_char_position,
 | |
|     OptionElementVector &opt_element_vector, int match_start_point,
 | |
|     int max_return_elements, bool &word_complete, StringList &matches) {
 | |
|   CommandObject *proxy_command = GetProxyCommandObject();
 | |
|   if (proxy_command)
 | |
|     return proxy_command->HandleArgumentCompletion(
 | |
|         input, cursor_index, cursor_char_position, opt_element_vector,
 | |
|         match_start_point, max_return_elements, word_complete, matches);
 | |
|   matches.Clear();
 | |
|   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;
 | |
| }
 |