[Lldb-commits] [lldb] r184140 - <rdar://problem/14134716>

Enrico Granata egranata at apple.com
Mon Jun 17 15:51:50 PDT 2013


Author: enrico
Date: Mon Jun 17 17:51:50 2013
New Revision: 184140

URL: http://llvm.org/viewvc/llvm-project?rev=184140&view=rev
Log:
<rdar://problem/14134716>

This is a rewrite of the command history facility of LLDB

It takes the history management out of the CommandInterpreter into its own CommandHistory class
It reimplements the command history command to allow more combinations of options to work correctly (e.g. com hist -c 1 -s 5)
It adds a new --wipe (-w) option to command history to allow clearing the history on demand
It extends the lldbtest runCmd: and expect: methods to allow adding commands to history if need be
It adds a test case for the reimplemented facility


Added:
    lldb/trunk/include/lldb/Interpreter/CommandHistory.h
    lldb/trunk/include/lldb/Utility/Range.h
    lldb/trunk/source/Interpreter/CommandHistory.cpp
    lldb/trunk/source/Utility/Range.cpp
    lldb/trunk/test/functionalities/command_history/
    lldb/trunk/test/functionalities/command_history/TestCommandHistory.py
Modified:
    lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/source/Commands/CommandObjectCommands.cpp
    lldb/trunk/source/Interpreter/CommandInterpreter.cpp
    lldb/trunk/test/lldbtest.py

Added: lldb/trunk/include/lldb/Interpreter/CommandHistory.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/CommandHistory.h?rev=184140&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/CommandHistory.h (added)
+++ lldb/trunk/include/lldb/Interpreter/CommandHistory.h Mon Jun 17 17:51:50 2013
@@ -0,0 +1,76 @@
+//===-- CommandHistory.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandHistory_h_
+#define liblldb_CommandHistory_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+    
+class CommandHistory
+{
+public:
+    CommandHistory ();
+    
+    ~CommandHistory ();
+    
+    size_t
+    GetSize () const;
+    
+    bool
+    IsEmpty () const;
+    
+    const char*
+    FindString (const char* input_str) const;
+    
+    const char*
+    GetStringAtIndex (size_t idx) const;
+    
+    const char*
+    operator [] (size_t idx) const;
+    
+    const char*
+    GetRecentmostString () const;
+    
+    void
+    AppendString (const std::string& str,
+                  bool reject_if_dupe = true);
+    
+    void
+    Clear ();
+
+    void
+    Dump (Stream& stream,
+          size_t start_idx = 0,
+          size_t stop_idx = UINT64_MAX) const;
+    
+    static const char g_repeat_char = '!';
+    
+private:
+    DISALLOW_COPY_AND_ASSIGN(CommandHistory);
+    
+    typedef std::vector<std::string> History;
+    mutable Mutex m_mutex;
+    History m_history;
+};
+
+} // namespace lldb_private
+
+#endif  // liblldb_CommandHistory_h_

Modified: lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h?rev=184140&r1=184139&r2=184140&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h (original)
+++ lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h Mon Jun 17 17:51:50 2013
@@ -18,6 +18,7 @@
 #include "lldb/Core/Broadcaster.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Log.h"
+#include "lldb/Interpreter/CommandHistory.h"
 #include "lldb/Interpreter/CommandObject.h"
 #include "lldb/Interpreter/ScriptInterpreter.h"
 #include "lldb/Core/Event.h"
@@ -381,15 +382,6 @@ public:
     bool
     GetSynchronous ();
     
-    void
-    DumpHistory (Stream &stream, uint32_t count) const;
-
-    void
-    DumpHistory (Stream &stream, uint32_t start, uint32_t end) const;
-    
-    const char *
-    FindHistoryString (const char *input_str) const;
-
     size_t
     FindLongestCommandWord (CommandObject::CommandMap &dict);
 
@@ -407,30 +399,42 @@ public:
     SetBatchCommandMode (bool value) { m_batch_command_mode = value; }
     
     void
-    ChildrenTruncated()
+    ChildrenTruncated ()
     {
         if (m_truncation_warning == eNoTruncation)
             m_truncation_warning = eUnwarnedTruncation;
     }
     
     bool
-    TruncationWarningNecessary()
+    TruncationWarningNecessary ()
     {
         return (m_truncation_warning == eUnwarnedTruncation);
     }
     
     void
-    TruncationWarningGiven()
+    TruncationWarningGiven ()
     {
         m_truncation_warning = eWarnedTruncation;
     }
     
     const char *
-    TruncationWarningText()
+    TruncationWarningText ()
     {
         return "*** Some of your variables have more members than the debugger will show by default. To show all of them, you can either use the --show-all-children option to %s or raise the limit by changing the target.max-children-count setting.\n";
     }
     
+    const CommandHistory&
+    GetCommandHistory () const
+    {
+        return m_command_history;
+    }
+    
+    CommandHistory&
+    GetCommandHistory ()
+    {
+        return m_command_history;
+    }
+    
     //------------------------------------------------------------------
     // Properties
     //------------------------------------------------------------------
@@ -466,11 +470,10 @@ private:
     CommandObject::CommandMap m_alias_dict;     // Stores user aliases/abbreviations for commands
     CommandObject::CommandMap m_user_dict;      // Stores user-defined commands
     OptionArgMap m_alias_options;               // Stores any options (with or without arguments) that go with any alias.
-    std::vector<std::string> m_command_history;
+    CommandHistory m_command_history;
     std::string m_repeat_command;               // Stores the command that will be executed for an empty command string.
     std::unique_ptr<ScriptInterpreter> m_script_interpreter_ap;
     char m_comment_char;
-    char m_repeat_char;
     bool m_batch_command_mode;
     ChildrenTruncatedWarningStatus m_truncation_warning;    // Whether we truncated children and whether the user has been told
     uint32_t m_command_source_depth;

Added: lldb/trunk/include/lldb/Utility/Range.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Utility/Range.h?rev=184140&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Utility/Range.h (added)
+++ lldb/trunk/include/lldb/Utility/Range.h Mon Jun 17 17:51:50 2013
@@ -0,0 +1,89 @@
+//===--------------------- Range.h ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef utility_Range_h_
+#define utility_Range_h_
+
+#include <stdint.h>
+#include <algorithm>
+
+namespace lldb_utility {
+    
+class Range
+{
+public:
+    
+    typedef uint64_t ValueType;
+    
+    static const ValueType OPEN_END = UINT64_MAX;
+    
+    Range (const Range& rng);
+    
+    Range (ValueType low = 0,
+           ValueType high = OPEN_END);
+
+    Range&
+    operator = (const Range& rhs);
+    
+    ValueType
+    GetLow ()
+    {
+        return m_low;
+    }
+    
+    ValueType
+    GetHigh ()
+    {
+        return m_high;
+    }
+    
+    void
+    SetLow (ValueType low)
+    {
+        m_low = low;
+    }
+    
+    void
+    SetHigh (ValueType high)
+    {
+        m_high = high;
+    }
+    
+    void
+    Flip ();
+    
+    void
+    Intersection (const Range& other);
+    
+    void
+    Union (const Range& other);
+    
+    typedef bool (*RangeCallback)(ValueType index);
+    
+    void
+    Iterate (RangeCallback callback);
+    
+    ValueType
+    GetSize ();
+    
+    bool
+    IsEmpty ();
+    
+private:
+    
+    void
+    InitRange ();
+    
+    ValueType m_low;
+    ValueType m_high;
+};
+    
+} // namespace lldb_private
+
+#endif // #ifndef utility_Range_h_

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=184140&r1=184139&r2=184140&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Mon Jun 17 17:51:50 2013
@@ -545,6 +545,8 @@
 		947A1D651616476B0017C8D1 /* CommandObjectPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 947A1D631616476A0017C8D1 /* CommandObjectPlugin.h */; };
 		949ADF031406F648004833E1 /* ValueObjectConstResultImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 949ADF021406F648004833E1 /* ValueObjectConstResultImpl.cpp */; };
 		94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */; };
+		94BA8B6D176F8C9B005A91B5 /* Range.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94BA8B6C176F8C9B005A91B5 /* Range.cpp */; };
+		94BA8B70176F97CE005A91B5 /* CommandHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94BA8B6F176F97CE005A91B5 /* CommandHistory.cpp */; };
 		94CB255B16B069770059775D /* CXXFormatterFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CB255716B069770059775D /* CXXFormatterFunctions.cpp */; };
 		94CB255C16B069770059775D /* DataVisualization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CB255816B069770059775D /* DataVisualization.cpp */; };
 		94CB255D16B069770059775D /* FormatClasses.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CB255916B069770059775D /* FormatClasses.cpp */; };
@@ -1601,6 +1603,10 @@
 		949ADF021406F648004833E1 /* ValueObjectConstResultImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectConstResultImpl.cpp; path = source/Core/ValueObjectConstResultImpl.cpp; sourceTree = "<group>"; };
 		94B6E76013D8833C005F417F /* ValueObjectSyntheticFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ValueObjectSyntheticFilter.h; path = include/lldb/Core/ValueObjectSyntheticFilter.h; sourceTree = "<group>"; };
 		94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectSyntheticFilter.cpp; path = source/Core/ValueObjectSyntheticFilter.cpp; sourceTree = "<group>"; };
+		94BA8B6C176F8C9B005A91B5 /* Range.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Range.cpp; path = source/Utility/Range.cpp; sourceTree = "<group>"; };
+		94BA8B6E176F8CA0005A91B5 /* Range.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Range.h; path = include/lldb/Utility/Range.h; sourceTree = "<group>"; };
+		94BA8B6F176F97CE005A91B5 /* CommandHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandHistory.cpp; path = source/Interpreter/CommandHistory.cpp; sourceTree = "<group>"; };
+		94BA8B71176F97D4005A91B5 /* CommandHistory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommandHistory.h; path = include/lldb/Interpreter/CommandHistory.h; sourceTree = "<group>"; };
 		94CB255716B069770059775D /* CXXFormatterFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXXFormatterFunctions.cpp; path = source/DataFormatters/CXXFormatterFunctions.cpp; sourceTree = "<group>"; };
 		94CB255816B069770059775D /* DataVisualization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DataVisualization.cpp; path = source/DataFormatters/DataVisualization.cpp; sourceTree = "<group>"; };
 		94CB255916B069770059775D /* FormatClasses.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FormatClasses.cpp; path = source/DataFormatters/FormatClasses.cpp; sourceTree = "<group>"; };
@@ -2403,6 +2409,8 @@
 				26D1804616CEE12C00EDFB5B /* TimeSpecTimeout.h */,
 				26D1804016CEDF0700EDFB5B /* TimeSpecTimeout.cpp */,
 				94EBAC8313D9EE26009BA64E /* PythonPointer.h */,
+				94BA8B6E176F8CA0005A91B5 /* Range.h */,
+				94BA8B6C176F8C9B005A91B5 /* Range.cpp */,
 				B2462249141AE62200F3D409 /* Utils.h */,
 			);
 			name = Utility;
@@ -2946,6 +2954,8 @@
 				26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */,
 				4C09CB73116BD98B00C7A725 /* CommandCompletions.h */,
 				4C09CB74116BD98B00C7A725 /* CommandCompletions.cpp */,
+				94BA8B71176F97D4005A91B5 /* CommandHistory.h */,
+				94BA8B6F176F97CE005A91B5 /* CommandHistory.cpp */,
 				26BC7DE210F1B7F900F91463 /* CommandInterpreter.h */,
 				26BC7F0810F1B8DD00F91463 /* CommandInterpreter.cpp */,
 				26BC7DE310F1B7F900F91463 /* CommandObject.h */,
@@ -4091,6 +4101,7 @@
 				2689007413353E1A00698AC0 /* Terminal.cpp in Sources */,
 				2689007513353E1A00698AC0 /* TimeValue.cpp in Sources */,
 				2689007613353E1A00698AC0 /* CFCBundle.cpp in Sources */,
+				94BA8B70176F97CE005A91B5 /* CommandHistory.cpp in Sources */,
 				2689007713353E1A00698AC0 /* CFCData.cpp in Sources */,
 				2689007813353E1A00698AC0 /* CFCMutableArray.cpp in Sources */,
 				2689007913353E1A00698AC0 /* CFCMutableDictionary.cpp in Sources */,
@@ -4324,6 +4335,7 @@
 				260CC65215D0440D002BF2E0 /* OptionValueString.cpp in Sources */,
 				260CC65315D0440D002BF2E0 /* OptionValueUInt64.cpp in Sources */,
 				260CC65415D0440D002BF2E0 /* OptionValueUUID.cpp in Sources */,
+				94BA8B6D176F8C9B005A91B5 /* Range.cpp in Sources */,
 				26DAED6315D327C200E15819 /* OptionValuePathMappings.cpp in Sources */,
 				B2B7CCEB15D1BD6700EEFB57 /* CommandObjectWatchpointCommand.cpp in Sources */,
 				B2B7CCF015D1C20F00EEFB57 /* WatchpointOptions.cpp in Sources */,

Modified: lldb/trunk/source/Commands/CommandObjectCommands.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectCommands.cpp?rev=184140&r1=184139&r2=184140&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectCommands.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectCommands.cpp Mon Jun 17 17:51:50 2013
@@ -22,10 +22,12 @@
 #include "lldb/Core/InputReaderEZ.h"
 #include "lldb/Core/StringList.h"
 #include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandHistory.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandObjectRegexCommand.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Interpreter/OptionValueBoolean.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
 #include "lldb/Interpreter/Options.h"
 #include "lldb/Interpreter/ScriptInterpreter.h"
 #include "lldb/Interpreter/ScriptInterpreterPython.h"
@@ -64,7 +66,11 @@ protected:
     public:
 
         CommandOptions (CommandInterpreter &interpreter) :
-            Options (interpreter)
+            Options (interpreter),
+            m_start_idx(0),
+            m_stop_idx(0),
+            m_count(0),
+            m_wipe(false)
         {
         }
 
@@ -76,27 +82,27 @@ protected:
         {
             Error error;
             const int short_option = m_getopt_table[option_idx].val;
-            bool success;
             
             switch (short_option)
             {
                 case 'c':
-                    m_end_idx = Args::StringToUInt32(option_arg, UINT_MAX, 0, &success);
-                    if (!success)
-                        error.SetErrorStringWithFormat("invalid value for count: %s", option_arg);
-                    if (m_end_idx != 0)
-                        m_end_idx--;
-                    m_start_idx = 0;
+                    error = m_count.SetValueFromCString(option_arg,eVarSetOperationAssign);
+                    break;
+                case 's':
+                    if (option_arg && strcmp("end", option_arg) == 0)
+                    {
+                        m_start_idx.SetCurrentValue(UINT64_MAX);
+                        m_start_idx.SetOptionWasSet();
+                    }
+                    else
+                        error = m_start_idx.SetValueFromCString(option_arg,eVarSetOperationAssign);
                     break;
                 case 'e':
-                    m_end_idx = Args::StringToUInt32(option_arg, 0, 0, &success);
-                    if (!success)
-                        error.SetErrorStringWithFormat("invalid value for end index: %s", option_arg);
+                    error = m_stop_idx.SetValueFromCString(option_arg,eVarSetOperationAssign);
                     break;
-                case 's':
-                    m_start_idx = Args::StringToUInt32(option_arg, 0, 0, &success);
-                    if (!success)
-                        error.SetErrorStringWithFormat("invalid value for start index: %s", option_arg);
+                case 'w':
+                    m_wipe.SetCurrentValue(true);
+                    m_wipe.SetOptionWasSet();
                     break;
                 default:
                     error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
@@ -109,8 +115,10 @@ protected:
         void
         OptionParsingStarting ()
         {
-            m_start_idx = 0;
-            m_end_idx = UINT_MAX;
+            m_start_idx.Clear();
+            m_stop_idx.Clear();
+            m_count.Clear();
+            m_wipe.Clear();
         }
 
         const OptionDefinition*
@@ -125,17 +133,90 @@ protected:
 
         // Instance variables to hold the values for command options.
 
-        uint32_t m_start_idx;
-        uint32_t m_end_idx;
+        OptionValueUInt64 m_start_idx;
+        OptionValueUInt64 m_stop_idx;
+        OptionValueUInt64 m_count;
+        OptionValueBoolean m_wipe;
     };
     
     bool
     DoExecute (Args& command, CommandReturnObject &result)
     {
-        
-        m_interpreter.DumpHistory (result.GetOutputStream(),
-                                   m_options.m_start_idx, 
-                                   m_options.m_end_idx);
+        if (m_options.m_wipe.GetCurrentValue() && m_options.m_wipe.OptionWasSet())
+        {
+            m_interpreter.GetCommandHistory().Clear();
+            result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
+        }
+        else
+        {
+            if (m_options.m_start_idx.OptionWasSet() && m_options.m_stop_idx.OptionWasSet() && m_options.m_count.OptionWasSet())
+            {
+                result.AppendError("--count, --start-index and --end-index cannot be all specified in the same invocation");
+                result.SetStatus(lldb::eReturnStatusFailed);
+            }
+            else
+            {
+                std::pair<bool,uint64_t> start_idx = {m_options.m_start_idx.OptionWasSet(),m_options.m_start_idx.GetCurrentValue()};
+                std::pair<bool,uint64_t> stop_idx = {m_options.m_stop_idx.OptionWasSet(),m_options.m_stop_idx.GetCurrentValue()};
+                std::pair<bool,uint64_t> count = {m_options.m_count.OptionWasSet(),m_options.m_count.GetCurrentValue()};
+                
+                const CommandHistory& history(m_interpreter.GetCommandHistory());
+                                              
+                if (start_idx.first && start_idx.second == UINT64_MAX)
+                {
+                    if (count.first)
+                    {
+                        start_idx.second = history.GetSize() - count.second;
+                        stop_idx.second = history.GetSize() - 1;
+                    }
+                    else if (stop_idx.first)
+                    {
+                        start_idx.second = stop_idx.second;
+                        stop_idx.second = history.GetSize() - 1;
+                    }
+                    else
+                    {
+                        start_idx.second = 0;
+                        stop_idx.second = history.GetSize() - 1;
+                    }
+                }
+                else
+                {
+                    if (!start_idx.first && !stop_idx.first && !count.first)
+                    {
+                        start_idx.second = 0;
+                        stop_idx.second = history.GetSize() - 1;
+                    }
+                    else if (start_idx.first)
+                    {
+                        if (count.first)
+                        {
+                            stop_idx.second = start_idx.second + count.second - 1;
+                        }
+                        else if (!stop_idx.first)
+                        {
+                            stop_idx.second = history.GetSize() - 1;
+                        }
+                    }
+                    else if (stop_idx.first)
+                    {
+                        if (count.first)
+                        {
+                            if (stop_idx.second >= count.second)
+                                start_idx.second = stop_idx.second - count.second + 1;
+                            else
+                                start_idx.second = 0;
+                        }
+                    }
+                    else /* if (count.first) */
+                    {
+                        start_idx.second = 0;
+                        stop_idx.second = count.second - 1;
+                    }
+                }
+                history.Dump(result.GetOutputStream(), start_idx.second, stop_idx.second);
+            }
+        }
         return result.Succeeded();
 
     }
@@ -147,8 +228,9 @@ OptionDefinition
 CommandObjectCommandsHistory::CommandOptions::g_option_table[] =
 {
 { LLDB_OPT_SET_1, false, "count", 'c', required_argument, NULL, 0, eArgTypeUnsignedInteger,        "How many history commands to print."},
-{ LLDB_OPT_SET_1, false, "start-index", 's', required_argument, NULL, 0, eArgTypeUnsignedInteger,  "Index at which to start printing history commands."},
+{ LLDB_OPT_SET_1, false, "start-index", 's', required_argument, NULL, 0, eArgTypeUnsignedInteger,  "Index at which to start printing history commands (or end to mean tail mode)."},
 { LLDB_OPT_SET_1, false, "end-index", 'e', required_argument, NULL, 0, eArgTypeUnsignedInteger,    "Index at which to stop printing history commands."},
+{ LLDB_OPT_SET_2, false, "wipe", 'w', no_argument, NULL, 0, eArgTypeBoolean,    "Clears the current command history."},
 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
 };
 

Added: lldb/trunk/source/Interpreter/CommandHistory.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandHistory.cpp?rev=184140&view=auto
==============================================================================
--- lldb/trunk/source/Interpreter/CommandHistory.cpp (added)
+++ lldb/trunk/source/Interpreter/CommandHistory.cpp Mon Jun 17 17:51:50 2013
@@ -0,0 +1,143 @@
+//===-- CommandHistory.cpp --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Interpreter/CommandHistory.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+CommandHistory::CommandHistory () :
+    m_mutex(Mutex::eMutexTypeRecursive),
+    m_history()
+{}
+
+CommandHistory::~CommandHistory ()
+{}
+
+size_t
+CommandHistory::GetSize () const
+{
+    Mutex::Locker locker(m_mutex);
+    return m_history.size();
+}
+
+bool
+CommandHistory::IsEmpty () const
+{
+    Mutex::Locker locker(m_mutex);
+    return m_history.empty();
+}
+
+const char*
+CommandHistory::FindString (const char* input_str) const
+{
+    Mutex::Locker locker(m_mutex);
+    if (!input_str)
+        return NULL;
+    if (input_str[0] != g_repeat_char)
+        return NULL;
+    if (input_str[1] == '-')
+    {
+        bool success;
+        size_t idx = Args::StringToUInt32 (input_str+2, 0, 0, &success);
+        if (!success)
+            return NULL;
+        if (idx > m_history.size())
+            return NULL;
+        idx = m_history.size() - idx;
+        return m_history[idx].c_str();
+        
+    }
+    else if (input_str[1] == g_repeat_char)
+    {
+        if (m_history.empty())
+            return NULL;
+        else
+            return m_history.back().c_str();
+    }
+    else
+    {
+        bool success;
+        uint32_t idx = Args::StringToUInt32 (input_str+1, 0, 0, &success);
+        if (!success)
+            return NULL;
+        if (idx >= m_history.size())
+            return NULL;
+        return m_history[idx].c_str();
+    }
+}
+
+const char*
+CommandHistory::GetStringAtIndex (size_t idx) const
+{
+    Mutex::Locker locker(m_mutex);
+    if (idx < m_history.size())
+        return m_history[idx].c_str();
+    return NULL;
+}
+
+const char*
+CommandHistory::operator [] (size_t idx) const
+{
+    return GetStringAtIndex(idx);
+}
+
+const char*
+CommandHistory::GetRecentmostString () const
+{
+    Mutex::Locker locker(m_mutex);
+    if (m_history.empty())
+        return NULL;
+    return m_history.back().c_str();
+}
+
+void
+CommandHistory::AppendString (const std::string& str,
+                              bool reject_if_dupe)
+{
+    Mutex::Locker locker(m_mutex);
+    if (reject_if_dupe)
+    {
+        if (!m_history.empty())
+        {
+            if (str == m_history.back())
+                return;
+        }
+    }
+    m_history.push_back(std::string(str));
+}
+
+void
+CommandHistory::Clear ()
+{
+    Mutex::Locker locker(m_mutex);
+    m_history.clear();
+}
+
+void
+CommandHistory::Dump (Stream& stream,
+                      size_t start_idx,
+                      size_t stop_idx) const
+{
+    Mutex::Locker locker(m_mutex);
+    stop_idx = std::min(stop_idx, m_history.size() - 1);
+    for (size_t counter = start_idx;
+         counter <= stop_idx;
+         counter++)
+    {
+        const std::string hist_item = m_history[counter];
+        if (!hist_item.empty())
+        {
+            stream.Indent();
+            stream.Printf ("%4zu: %s\n", counter, hist_item.c_str());
+        }
+    }
+}

Modified: lldb/trunk/source/Interpreter/CommandInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandInterpreter.cpp?rev=184140&r1=184139&r2=184140&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/CommandInterpreter.cpp (original)
+++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp Mon Jun 17 17:51:50 2013
@@ -107,7 +107,6 @@ CommandInterpreter::CommandInterpreter
     m_skip_app_init_files (false),
     m_script_interpreter_ap (),
     m_comment_char ('#'),
-    m_repeat_char ('!'),
     m_batch_command_mode (false),
     m_truncation_warning(eNoTruncation),
     m_command_source_depth (0)
@@ -1534,9 +1533,9 @@ CommandInterpreter::HandleCommand (const
             empty_command = true;
         else if (command_string[non_space] == m_comment_char)
              comment_command = true;
-        else if (command_string[non_space] == m_repeat_char)
+        else if (command_string[non_space] == CommandHistory::g_repeat_char)
         {
-            const char *history_string = FindHistoryString (command_string.c_str() + non_space);
+            const char *history_string = m_command_history.FindString(command_string.c_str() + non_space);
             if (history_string == NULL)
             {
                 result.AppendErrorWithFormat ("Could not find entry: %s in history", command_string.c_str());
@@ -1553,7 +1552,7 @@ CommandInterpreter::HandleCommand (const
     {
         if (repeat_on_empty_command)
         {
-            if (m_command_history.empty())
+            if (m_command_history.IsEmpty())
             {
                 result.AppendError ("empty command");
                 result.SetStatus(eReturnStatusFailed);
@@ -1797,9 +1796,7 @@ CommandInterpreter::HandleCommand (const
             else
                 m_repeat_command.assign(original_command_string.c_str());
             
-            // Don't keep pushing the same command onto the history...
-            if (m_command_history.empty() || m_command_history.back() != original_command_string) 
-                m_command_history.push_back (original_command_string);
+            m_command_history.AppendString (original_command_string);
         }
         
         command_string = revised_command_line.GetData();
@@ -1957,9 +1954,9 @@ CommandInterpreter::HandleCompletion (co
     {
         if (first_arg[0] == m_comment_char)
             return 0;
-        else if (first_arg[0] == m_repeat_char)
+        else if (first_arg[0] == CommandHistory::g_repeat_char)
         {
-            const char *history_string = FindHistoryString (first_arg);
+            const char *history_string = m_command_history.FindString (first_arg);
             if (history_string != NULL)
             {
                 matches.Clear();
@@ -2878,59 +2875,3 @@ CommandInterpreter::UpdateExecutionConte
         m_exe_ctx_ref.SetTargetPtr (m_debugger.GetSelectedTarget().get(), adopt_selected);
     }
 }
-
-void
-CommandInterpreter::DumpHistory (Stream &stream, uint32_t count) const
-{
-    DumpHistory (stream, 0, count - 1);
-}
-
-void
-CommandInterpreter::DumpHistory (Stream &stream, uint32_t start, uint32_t end) const
-{
-    const size_t last_idx = std::min<size_t>(m_command_history.size(), end==UINT32_MAX ? UINT32_MAX : end + 1);
-    for (size_t i = start; i < last_idx; i++)
-    {
-        if (!m_command_history[i].empty())
-        {
-            stream.Indent();
-            stream.Printf ("%4zu: %s\n", i, m_command_history[i].c_str());
-        }
-    }
-}
-
-const char *
-CommandInterpreter::FindHistoryString (const char *input_str) const
-{
-    if (input_str[0] != m_repeat_char)
-        return NULL;
-    if (input_str[1] == '-')
-    {
-        bool success;
-        size_t idx = Args::StringToUInt32 (input_str+2, 0, 0, &success);
-        if (!success)
-            return NULL;
-        if (idx > m_command_history.size())
-            return NULL;
-        idx = m_command_history.size() - idx;
-        return m_command_history[idx].c_str();
-            
-    }
-    else if (input_str[1] == m_repeat_char)
-    {
-        if (m_command_history.empty())
-            return NULL;
-        else
-            return m_command_history.back().c_str();
-    }
-    else
-    {
-        bool success;
-        uint32_t idx = Args::StringToUInt32 (input_str+1, 0, 0, &success);
-        if (!success)
-            return NULL;
-        if (idx >= m_command_history.size())
-            return NULL;
-        return m_command_history[idx].c_str();
-    }
-}

Added: lldb/trunk/source/Utility/Range.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/Range.cpp?rev=184140&view=auto
==============================================================================
--- lldb/trunk/source/Utility/Range.cpp (added)
+++ lldb/trunk/source/Utility/Range.cpp Mon Jun 17 17:51:50 2013
@@ -0,0 +1,103 @@
+//===--------------------- Range.cpp -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Range.h"
+
+using namespace lldb_utility;
+
+Range::Range (const Range& rng) :
+m_low(rng.m_low),
+m_high(rng.m_high)
+{
+    InitRange();
+}
+
+Range::Range (Range::ValueType low,
+              Range::ValueType high) :
+m_low(low),
+m_high(high)
+{
+    InitRange();
+}
+
+void
+Range::InitRange ()
+{
+    if (m_low == OPEN_END)
+    {
+        if (m_high == OPEN_END)
+            m_low = 0;
+        else
+        {
+            // make an empty range
+            m_low = 1;
+            m_high = 0;
+        }
+    }
+}
+
+Range&
+Range::operator = (const Range& rhs)
+{
+    if (&rhs != this)
+    {
+        this->m_low = rhs.m_low;
+        this->m_high = rhs.m_high;
+    }
+    return *this;
+}
+
+void
+Range::Flip ()
+{
+    std::swap(m_high, m_low);
+}
+
+void
+Range::Intersection (const Range& other)
+{
+    m_low = std::max(m_low,other.m_low);
+    m_high = std::min(m_high,other.m_high);
+}
+
+void
+Range::Union (const Range& other)
+{
+    m_low = std::min(m_low,other.m_low);
+    m_high = std::max(m_high,other.m_high);
+}
+
+void
+Range::Iterate (RangeCallback callback)
+{
+    ValueType counter = m_low;
+    while (counter <= m_high)
+    {
+        bool should_continue = callback(counter);
+        if (!should_continue)
+            return;
+        counter++;
+    }
+}
+
+bool
+Range::IsEmpty ()
+{
+    return (m_low > m_high);
+}
+
+Range::ValueType
+Range::GetSize ()
+{
+    if (m_high == OPEN_END)
+        return OPEN_END;
+    if (m_high >= m_low)
+        return m_high - m_low + 1;
+    return 0;
+}

Added: lldb/trunk/test/functionalities/command_history/TestCommandHistory.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/command_history/TestCommandHistory.py?rev=184140&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/command_history/TestCommandHistory.py (added)
+++ lldb/trunk/test/functionalities/command_history/TestCommandHistory.py Mon Jun 17 17:51:50 2013
@@ -0,0 +1,72 @@
+"""
+Test the command history mechanism
+"""
+
+import os
+import unittest2
+import lldb
+import pexpect
+from lldbtest import *
+
+class CommandHistoryTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "command_history")
+
+    def test_history(self):
+        self.runCmd('command history --wipe', inHistory=False)
+        self.runCmd('breakpoint list', check=False, inHistory=True) #0
+        self.runCmd('register read', check=False, inHistory=True) #1
+        self.runCmd('apropos hello', check=False, inHistory=True) #2
+        self.runCmd('memory write', check=False, inHistory=True) #3
+        self.runCmd('script foo', check=False, inHistory=True) #4
+        self.runCmd('disassemble', check=False, inHistory=True) #5
+        self.runCmd('expression 1', check=False, inHistory=True) #6
+        self.runCmd('type summary list -w default', check=False, inHistory=True) #7
+        self.runCmd('version', check=False, inHistory=True) #8
+        self.runCmd('frame select 1', check=False, inHistory=True) #9
+
+        self.expect ("command history -s 3 -c 3", inHistory=True,
+                     substrs = ['3: memory write','4: script foo','5: disassemble'])
+        
+        self.expect ("command history -s 3 -e 3", inHistory=True,
+                     substrs = ['3: memory write'])
+
+        self.expect ("command history -s 6 -e 7", inHistory=True,
+                     substrs = ['6: expression 1','7: type summary list -w default'])
+
+        self.expect ("command history -c 2", inHistory=True,
+                     substrs = ['0: breakpoint list','1: register read'])
+
+        self.expect ("command history -e 3 -c 1", inHistory=True,
+                     substrs = ['3: memory write'])
+
+        self.expect ("command history -e 2", inHistory=True,
+                     substrs = ['0: breakpoint list','1: register read','2: apropos hello'])
+
+        self.expect ("command history -s 12", inHistory=True,
+                     substrs = ['12: command history -s 6 -e 7','13: command history -c 2','14: command history -e 3 -c 1','15: command history -e 2','16: command history -s 12'])
+
+        self.expect ("command history -s end -c 3", inHistory=True,
+                     substrs = ['15: command history -e 2','16: command history -s 12','17: command history -s end -c 3'])
+
+        self.expect ("command history -s end -e 15", inHistory=True,
+                     substrs = ['15: command history -e 2','16: command history -s 12','17: command history -s end -c 3','command history -s end -e 15'])
+
+        self.expect ("command history -s 5 -c 1", inHistory=True,
+                     substrs = ['5: disassemble'])
+
+        self.expect ("command history -c 1 -s 5", inHistory=True,
+                     substrs = ['5: disassemble'])
+
+        self.expect ("command history -c 1 -e 3", inHistory=True,
+                     substrs = ['3: memory write'])
+
+        self.expect ("command history -c 1 -e 3 -s 5",error=True, inHistory=True,
+                     substrs = ['error: --count, --start-index and --end-index cannot be all specified in the same invocation'])
+
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Modified: lldb/trunk/test/lldbtest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lldbtest.py?rev=184140&r1=184139&r2=184140&view=diff
==============================================================================
--- lldb/trunk/test/lldbtest.py (original)
+++ lldb/trunk/test/lldbtest.py Mon Jun 17 17:51:50 2013
@@ -1543,7 +1543,7 @@ class TestBase(Base):
             if matched:
                 self.runCmd('thread select %s' % matched.group(1))
 
-    def runCmd(self, cmd, msg=None, check=True, trace=False):
+    def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False):
         """
         Ask the command interpreter to handle the command and then check its
         return status.
@@ -1557,7 +1557,7 @@ class TestBase(Base):
         running = (cmd.startswith("run") or cmd.startswith("process launch"))
 
         for i in range(self.maxLaunchCount if running else 1):
-            self.ci.HandleCommand(cmd, self.res)
+            self.ci.HandleCommand(cmd, self.res, inHistory)
 
             with recording(self, trace) as sbuf:
                 print >> sbuf, "runCmd:", cmd
@@ -1624,7 +1624,7 @@ class TestBase(Base):
 
         return match_object        
 
-    def expect(self, str, msg=None, patterns=None, startstr=None, endstr=None, substrs=None, trace=False, error=False, matching=True, exe=True):
+    def expect(self, str, msg=None, patterns=None, startstr=None, endstr=None, substrs=None, trace=False, error=False, matching=True, exe=True, inHistory=False):
         """
         Similar to runCmd; with additional expect style output matching ability.
 
@@ -1653,7 +1653,7 @@ class TestBase(Base):
         if exe:
             # First run the command.  If we are expecting error, set check=False.
             # Pass the assert message along since it provides more semantic info.
-            self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error)
+            self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error, inHistory=inHistory)
 
             # Then compare the output against expected strings.
             output = self.res.GetError() if error else self.res.GetOutput()





More information about the lldb-commits mailing list