Added the ability for users to create new regex commands.
To do this currently, it must be done in multi-line mode:

(lldb) commands regex --help "Help text for command" --syntax "syntax for command" <cmd-name>

Any example that would use "f" for "finish" when there are no arguments,
and "f <num>" to do a "frame select <num>" would be:
(lldb) commands regex f
Enter multiple regular expressions in the form s/find/replace/ then terminate with an empty line:
s/^$/finish/
s/([0-9]+)/frame select %1/

(lldb) f 11
frame select 12
...
(lldb) f
finish
...

Also added the string version of the OptionValue as OptionValueString.



git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@129855 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Commands/CommandObjectCommands.cpp b/source/Commands/CommandObjectCommands.cpp
index e0871e0..bc04b6b 100644
--- a/source/Commands/CommandObjectCommands.cpp
+++ b/source/Commands/CommandObjectCommands.cpp
@@ -13,9 +13,11 @@
 // C++ Includes
 // Other libraries and framework includes
 // Project includes
-#include "lldb/Interpreter/Args.h"
 #include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Interpreter/Args.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObjectRegexCommand.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Interpreter/Options.h"
 
@@ -92,10 +94,6 @@
         bool m_stop_on_continue;
     };
     
-    // Options table: Required for subclasses of Options.
-
-    static OptionDefinition g_option_table[];
-
     CommandOptions m_options;
     
     virtual Options *
@@ -640,6 +638,275 @@
     }
 };
 
+#pragma mark CommandObjectCommandsAddRegex
+//-------------------------------------------------------------------------
+// CommandObjectCommandsAddRegex
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsAddRegex : public CommandObject
+{
+public:
+    CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) :
+        CommandObject (interpreter,
+                       "commands regex",
+                       "Allow the user to create a regular expression command.",
+                       NULL),
+        m_options (interpreter)
+    {
+    }
+    
+    ~CommandObjectCommandsAddRegex()
+    {
+    }
+    
+    
+    bool
+    Execute (Args& args, CommandReturnObject &result)
+    {
+        if (args.GetArgumentCount() == 1)
+        {
+            const char *name = args.GetArgumentAtIndex(0);
+            InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+            m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter, 
+                                                                 name, 
+                                                                 m_options.GetHelp (),
+                                                                 m_options.GetSyntax (),
+                                                                 10));
+            if (reader_sp)
+            {
+                Error err (reader_sp->Initialize (CommandObjectCommandsAddRegex::InputReaderCallback,
+                                                  this,                         // baton
+                                                  eInputReaderGranularityLine,  // token size, to pass to callback function
+                                                  "DONE",                       // end token
+                                                  "> ",                         // prompt
+                                                  true));                       // echo input
+                if (err.Success())
+                {
+                    m_interpreter.GetDebugger().PushInputReader (reader_sp);
+                    result.SetStatus (eReturnStatusSuccessFinishNoResult);
+                }
+                else
+                {
+                    result.AppendError (err.AsCString());
+                    result.SetStatus (eReturnStatusFailed);
+                }
+            }
+        }
+        else
+        {
+            result.AppendError ("invalid arguments.\n");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
+    }
+    
+    bool
+    AppendRegexAndSubstitution (const char *regex, const char *subst)
+    {
+        if (m_regex_cmd_ap.get())
+        {
+            m_regex_cmd_ap->AddRegexCommand (regex, subst);
+            return true;
+        }
+        return false;
+    }
+    
+    void
+    InputReaderIsDone()
+    {
+        if (m_regex_cmd_ap.get())
+        {
+            if (m_regex_cmd_ap->HasRegexEntries())
+            {
+                CommandObjectSP cmd_sp (m_regex_cmd_ap.release());
+                m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
+            }
+        }
+    }
+
+    static size_t
+    InputReaderCallback (void *baton, 
+                         InputReader &reader, 
+                         lldb::InputReaderAction notification,
+                         const char *bytes, 
+                         size_t bytes_len);
+private:
+    std::auto_ptr<CommandObjectRegexCommand> m_regex_cmd_ap;    
+
+     class CommandOptions : public Options
+     {
+     public:
+         
+         CommandOptions (CommandInterpreter &interpreter) :
+            Options (interpreter)
+         {
+         }
+         
+         virtual
+         ~CommandOptions (){}
+         
+         virtual Error
+         SetOptionValue (uint32_t option_idx, const char *option_arg)
+         {
+             Error error;
+             char short_option = (char) m_getopt_table[option_idx].val;
+             
+             switch (short_option)
+             {
+                 case 'h':
+                     m_help.assign (option_arg);
+                     break;
+                 case 's':
+                     m_syntax.assign (option_arg);
+                     break;
+
+                 default:
+                     error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
+                     break;
+             }
+             
+             return error;
+         }
+         
+         void
+         OptionParsingStarting ()
+         {
+             m_help.clear();
+             m_syntax.clear();
+         }
+         
+         const OptionDefinition*
+         GetDefinitions ()
+         {
+             return g_option_table;
+         }
+         
+         // Options table: Required for subclasses of Options.
+         
+         static OptionDefinition g_option_table[];
+         
+         const char *
+         GetHelp ()
+         {
+             if (m_help.empty())
+                 return NULL;
+             return m_help.c_str();
+         }
+         const char *
+         GetSyntax ()
+         {
+             if (m_syntax.empty())
+                 return NULL;
+             return m_syntax.c_str();
+         }
+         // Instance variables to hold the values for command options.
+     protected:
+         std::string m_help;
+         std::string m_syntax;
+     };
+     
+     CommandOptions m_options;
+     
+     virtual Options *
+     GetOptions ()
+     {
+         return &m_options;
+     }
+
+};
+
+size_t
+CommandObjectCommandsAddRegex::InputReaderCallback (void *baton, 
+                                                    InputReader &reader, 
+                                                    lldb::InputReaderAction notification,
+                                                    const char *bytes, 
+                                                    size_t bytes_len)
+{
+    CommandObjectCommandsAddRegex *add_regex_cmd = (CommandObjectCommandsAddRegex *) baton;
+    
+    switch (notification)
+    {
+        case eInputReaderActivate:
+            reader.GetDebugger().GetOutputStream().Printf("%s\n", "Enter multiple regular expressions in the form s/find/replace/ then terminate with an empty line:");
+            break;
+        case eInputReaderReactivate:
+            break;
+            
+        case eInputReaderDeactivate:
+            break;
+            
+        case eInputReaderGotToken:
+            if (bytes_len == 0)
+                reader.SetIsDone(true);
+            else if (bytes)
+            {
+                std::string regex_sed (bytes, bytes_len);
+                bool success = regex_sed.size() > 3 && regex_sed[0] == 's';
+                if (success)
+                {
+                    const size_t first_separator_char_pos = 1;
+                    const char separator_char = regex_sed[first_separator_char_pos];
+                    const size_t third_separator_char_pos = regex_sed.rfind (separator_char);
+
+                    if (third_separator_char_pos != regex_sed.size() - 1)
+                        success = false;    // Didn't end with regex separator char
+                    else
+                    {
+                        const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1);
+                        if (second_separator_char_pos == std::string::npos)
+                            success = false;    // Didn't find second regex separator char
+                        else 
+                        {
+                            if (second_separator_char_pos <= 3)
+                                success = false;    // Empty regex is invalid ("s///")
+                            else
+                            {
+                                std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1));
+                                std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1));
+                                if (regex.empty() || subst.empty())
+                                    success= false;
+                                else
+                                {
+                                    add_regex_cmd->AppendRegexAndSubstitution(regex.c_str(), subst.c_str());
+                                }
+                            }
+                        }
+                    }
+                }
+                if (!success)
+                {
+                    reader.GetDebugger().GetOutputStream().PutCString("Regular expressions should be in the form s/<regex>/<subst>/.\n");
+                }
+            }
+            break;
+            
+        case eInputReaderInterrupt:
+            reader.SetIsDone (true);
+            reader.GetDebugger().GetOutputStream().PutCString("Regular expression command creations was cancelled.\n");
+            break;
+            
+        case eInputReaderEndOfFile:
+            reader.SetIsDone (true);
+            break;
+            
+        case eInputReaderDone:
+            add_regex_cmd->InputReaderIsDone();
+            break;
+    }
+    
+    return bytes_len;
+}
+
+                                                                 
+OptionDefinition
+CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "help", 'h', required_argument, NULL, 0, eArgTypeNone,    "The help text to display for this command."},
+{ LLDB_OPT_SET_1, false, "syntax", 's', required_argument, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
 #pragma mark CommandObjectMultiwordCommands
 
 //-------------------------------------------------------------------------
@@ -655,6 +922,7 @@
     LoadSubCommand ("source",  CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
     LoadSubCommand ("alias",   CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
     LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
+    LoadSubCommand ("regex",   CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter)));
 }
 
 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()