<rdar://problem/12491387>

I added the ability for a process plug-in to implement custom commands. All the lldb_private::Process plug-in has to do is override:

virtual CommandObject *
GetPluginCommandObject();

This object returned should be a multi-word command that vends LLDB commands. There is a sample implementation in ProcessGDBRemote that is hollowed out. It is intended to be used for sending a custom packet, though the body of the command execute function has yet to be implemented! 



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@165861 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Commands/CommandObjectCommands.cpp b/source/Commands/CommandObjectCommands.cpp
index 364c6f5..4c41d31 100644
--- a/source/Commands/CommandObjectCommands.cpp
+++ b/source/Commands/CommandObjectCommands.cpp
@@ -599,8 +599,7 @@
                      {
                          const std::string sub_command = args.GetArgumentAtIndex(0);
                          assert (sub_command.length() != 0);
-                         subcommand_obj_sp =
-                                           (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str()));
+                         subcommand_obj_sp = cmd_obj->GetSubcommandSP (sub_command.c_str());
                          if (subcommand_obj_sp.get())
                          {
                              sub_cmd_obj = subcommand_obj_sp.get();
diff --git a/source/Commands/CommandObjectHelp.cpp b/source/Commands/CommandObjectHelp.cpp
index 5dfb105..3879005 100644
--- a/source/Commands/CommandObjectHelp.cpp
+++ b/source/Commands/CommandObjectHelp.cpp
@@ -103,8 +103,7 @@
                 else
                 {
                     CommandObject *found_cmd;
-                    found_cmd = ((CommandObjectMultiword *) sub_cmd_obj)->GetSubcommandObject(sub_command.c_str(), 
-                                                                                              &matches);
+                    found_cmd = sub_cmd_obj->GetSubcommandObject(sub_command.c_str(), &matches);
                     if (found_cmd == NULL)
                         all_okay = false;
                     else if (matches.GetSize() > 1)
@@ -189,7 +188,7 @@
                     }
                     else
                         m_interpreter.OutputFormattedHelpText (output_strm, "", "", sub_cmd_obj->GetHelp(), 1);
-                    ((CommandObjectMultiword *) sub_cmd_obj)->GenerateHelpText (result);
+                    sub_cmd_obj->GenerateHelpText (result);
                 }
                 else
                 {
diff --git a/source/Commands/CommandObjectMultiword.cpp b/source/Commands/CommandObjectMultiword.cpp
index e11d37b..9fcd40f 100644
--- a/source/Commands/CommandObjectMultiword.cpp
+++ b/source/Commands/CommandObjectMultiword.cpp
@@ -307,3 +307,232 @@
     return sub_command_object->GetRepeatCommand(current_command_args, index);
 }
 
+
+void
+CommandObjectMultiword::AproposAllSubCommands (const char *prefix,
+                                               const char *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.Printf ("%s %s", prefix, command_name);
+        
+        if (sub_cmd_obj->HelpTextContainsWord (search_word))
+        {
+            commands_found.AppendString (complete_command_name.GetData());
+            commands_help.AppendString (sub_cmd_obj->GetHelp());
+        }
+        
+        if (sub_cmd_obj->IsMultiwordObject())
+            sub_cmd_obj->AproposAllSubCommands (complete_command_name.GetData(),
+                                                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 ()
+{
+}
+
+const char *
+CommandObjectProxy::GetHelpLong ()
+{
+    CommandObject *proxy_command = GetProxyCommandObject();
+    if (proxy_command)
+        return proxy_command->GetHelpLong();
+    return NULL;
+}
+
+void
+CommandObjectProxy::AddObject (const char *obj_name)
+{
+    CommandObject *proxy_command = GetProxyCommandObject();
+    if (proxy_command)
+        return proxy_command->AddObject (obj_name);
+}
+
+bool
+CommandObjectProxy::IsCrossRefObject ()
+{
+    CommandObject *proxy_command = GetProxyCommandObject();
+    if (proxy_command)
+        return proxy_command->IsCrossRefObject();
+    return false;
+}
+
+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;
+}
+
+lldb::CommandObjectSP
+CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches)
+{
+    CommandObject *proxy_command = GetProxyCommandObject();
+    if (proxy_command)
+        return proxy_command->GetSubcommandSP(sub_cmd, matches);
+    return lldb::CommandObjectSP();
+}
+
+CommandObject *
+CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches)
+{
+    CommandObject *proxy_command = GetProxyCommandObject();
+    if (proxy_command)
+        return proxy_command->GetSubcommandObject(sub_cmd, matches);
+    return NULL;
+}
+
+void
+CommandObjectProxy::AproposAllSubCommands (const char *prefix,
+                                           const char *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 (const char *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 NULL;
+}
+
+
+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 &current_command_args,
+                                      uint32_t index)
+{
+    CommandObject *proxy_command = GetProxyCommandObject();
+    if (proxy_command)
+        return proxy_command->GetRepeatCommand (current_command_args, index);
+    return NULL;
+}
+
+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;
+}
+
+
diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp
index 5653e7a..41e216e 100644
--- a/source/Commands/CommandObjectProcess.cpp
+++ b/source/Commands/CommandObjectProcess.cpp
@@ -1071,7 +1071,6 @@
     CommandOptions m_options;
 };
 
-
 OptionDefinition
 CommandObjectProcessConnect::CommandOptions::g_option_table[] =
 {
@@ -1080,6 +1079,39 @@
 };
 
 //-------------------------------------------------------------------------
+// CommandObjectProcessPlugin
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessPlugin
+
+class CommandObjectProcessPlugin : public CommandObjectProxy
+{
+public:
+    
+    CommandObjectProcessPlugin (CommandInterpreter &interpreter) :
+        CommandObjectProxy (interpreter,
+                            "process plugin",
+                            "Send a custom command to the current process plug-in.",
+                            "process plugin <args>",
+                            0)
+    {
+    }
+    
+    ~CommandObjectProcessPlugin ()
+    {
+    }
+
+    virtual CommandObject *
+    GetProxyCommandObject()
+    {
+        Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
+        if (process)
+            return process->GetPluginCommandObject();
+        return NULL;
+    }
+};
+
+
+//-------------------------------------------------------------------------
 // CommandObjectProcessLoad
 //-------------------------------------------------------------------------
 #pragma mark CommandObjectProcessLoad
@@ -1794,6 +1826,7 @@
     LoadSubCommand ("status",      CommandObjectSP (new CommandObjectProcessStatus    (interpreter)));
     LoadSubCommand ("interrupt",   CommandObjectSP (new CommandObjectProcessInterrupt (interpreter)));
     LoadSubCommand ("kill",        CommandObjectSP (new CommandObjectProcessKill      (interpreter)));
+    LoadSubCommand ("plugin",      CommandObjectSP (new CommandObjectProcessPlugin    (interpreter)));
 }
 
 CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess ()
diff --git a/source/Commands/CommandObjectSyntax.cpp b/source/Commands/CommandObjectSyntax.cpp
index d96542e..64308aa 100644
--- a/source/Commands/CommandObjectSyntax.cpp
+++ b/source/Commands/CommandObjectSyntax.cpp
@@ -66,14 +66,12 @@
         for (int i = 1; i < argc; ++i)
         {
             std::string sub_command = command.GetArgumentAtIndex (i);
-            if (! cmd_obj->IsMultiwordObject())
+            if (!cmd_obj->IsMultiwordObject())
                 all_okay = false;
             else
             {
-                pos = ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict.find (sub_command);
-                if (pos != ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict.end())
-                    cmd_obj = pos->second.get();
-                else
+                cmd_obj = cmd_obj->GetSubcommandObject(sub_command.c_str());
+                if (!cmd_obj)
                     all_okay = false;
             }
         }