several improvements to "type summary":
 - type names can now be regular expressions (exact matching is done first, and is faster)
 - integral (and floating) types can be printed as bitfields, i.e. ${var[low-high]} will extract bits low thru high of the value and print them
 - array subscripts are supported, both for arrays and for pointers. the syntax is ${*var[low-high]}, or ${*var[]} to print the whole array (the latter only works for statically sized arrays)
 - summary is now printed by default when a summary string references a variable. if that variable's type has no summary, value is printed instead. to force value, you can use %V as a format specifier
 - basic support for ObjectiveC:
  - ObjectiveC inheritance chains are now walked through
  - %@ can be specified as a summary format, to print the ObjectiveC runtime description for an object
 - some bug fixes

git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@134293 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp
index 7d3b83b..492b015 100644
--- a/source/Commands/CommandObjectType.cpp
+++ b/source/Commands/CommandObjectType.cpp
@@ -15,6 +15,7 @@
 #include "lldb/Core/ConstString.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/FormatManager.h"
+#include "lldb/Core/RegularExpression.h"
 #include "lldb/Core/State.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandObject.h"
@@ -54,11 +55,14 @@
             
             switch (short_option)
             {
-                case 'c':
+                case 'C':
                     m_cascade = Args::StringToBoolean(option_arg, true, &success);
                     if (!success)
                         error.SetErrorStringWithFormat("Invalid value for cascade: %s.\n", option_arg);
                     break;
+                case 'f':
+                    error = Args::StringToFormat(option_arg, m_format, NULL);
+                    break;
                 default:
                     error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
                     break;
@@ -71,6 +75,7 @@
         OptionParsingStarting ()
         {
             m_cascade = true;
+            m_format = eFormatInvalid;
         }
         
         const OptionDefinition*
@@ -86,6 +91,7 @@
         // Instance variables to hold the values for command options.
         
         bool m_cascade;
+        lldb::Format m_format;
     };
     
     CommandOptions m_options;
@@ -103,21 +109,14 @@
                    "Add a new formatting style for a type.",
                    NULL), m_options (interpreter)
     {
-        CommandArgumentEntry format_arg;
-        CommandArgumentData format_style_arg;
         CommandArgumentEntry type_arg;
         CommandArgumentData type_style_arg;
         
-        format_style_arg.arg_type = eArgTypeFormat;
-        format_style_arg.arg_repetition = eArgRepeatPlain;
-                
         type_style_arg.arg_type = eArgTypeName;
         type_style_arg.arg_repetition = eArgRepeatPlus;
         
-        format_arg.push_back (format_style_arg);
         type_arg.push_back (type_style_arg);
-        
-        m_arguments.push_back (format_arg);
+
         m_arguments.push_back (type_arg);
     }
     
@@ -130,40 +129,27 @@
     {
         const size_t argc = command.GetArgumentCount();
         
-        if (argc < 2)
+        if (argc < 1)
         {
-            result.AppendErrorWithFormat ("%s takes two or more args.\n", m_cmd_name.c_str());
+            result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
             result.SetStatus(eReturnStatusFailed);
             return false;
         }
         
-        const char* format_cstr = command.GetArgumentAtIndex(0);
-        
-        if (!format_cstr || !format_cstr[0])
+        if(m_options.m_format == eFormatInvalid)
         {
-            result.AppendError("empty format strings not allowed");
+            result.AppendErrorWithFormat ("%s needs a valid format.\n", m_cmd_name.c_str());
             result.SetStatus(eReturnStatusFailed);
             return false;
         }
         
-        lldb::Format format;
-        Error error;
+        ValueFormatSP entry;
         
-        error = Args::StringToFormat(format_cstr, format, NULL);
-        ValueFormat::SharedPointer entry;
-        
-        entry.reset(new ValueFormat(format,m_options.m_cascade));
+        entry.reset(new ValueFormat(m_options.m_format,m_options.m_cascade));
 
-        if (error.Fail()) 
-        {
-            result.AppendError(error.AsCString());
-            result.SetStatus(eReturnStatusFailed);
-            return false;
-        }
-        
         // now I have a valid format, let's add it to every type
         
-        for(int i = 1; i < argc; i++) {
+        for(int i = 0; i < argc; i++) {
             const char* typeA = command.GetArgumentAtIndex(i);
             ConstString typeCS(typeA);
             if (typeCS)
@@ -179,13 +165,13 @@
         result.SetStatus(eReturnStatusSuccessFinishNoResult);
         return result.Succeeded();
     }
-        
 };
 
 OptionDefinition
 CommandObjectTypeFormatAdd::CommandOptions::g_option_table[] =
 {
-    { LLDB_OPT_SET_ALL, false, "cascade", 'c', required_argument, NULL, 0, eArgTypeBoolean,    "If true, cascade to derived typedefs."},
+    { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean,    "If true, cascade to derived typedefs."},
+    { LLDB_OPT_SET_ALL, false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat,    "The format to use to display this type."},
     { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
 };
 
@@ -411,25 +397,31 @@
             
             switch (short_option)
             {
-                case 'c':
+                case 'C':
                     m_cascade = Args::StringToBoolean(option_arg, true, &success);
                     if (!success)
                         error.SetErrorStringWithFormat("Invalid value for cascade: %s.\n", option_arg);
                     break;
-                case 'h':
-                    m_no_children = !Args::StringToBoolean(option_arg, true, &success);
-                    if (!success)
-                        error.SetErrorStringWithFormat("Invalid value for nochildren: %s.\n", option_arg);
+                case 'e':
+                    m_no_children = false;
                     break;
                 case 'v':
-                    m_no_value = !Args::StringToBoolean(option_arg, true, &success);
-                    if (!success)
-                        error.SetErrorStringWithFormat("Invalid value for novalue: %s.\n", option_arg);
+                    m_no_value = true;
                     break;
-                case 'o':
-                    m_one_liner = Args::StringToBoolean(option_arg, true, &success);
-                    if (!success)
-                        error.SetErrorStringWithFormat("Invalid value for oneliner: %s.\n", option_arg);
+                case 'c':
+                    m_one_liner = true;
+                    break;
+                case 'f':
+                    m_format_string = std::string(option_arg);
+                    break;
+                case 'p':
+                    m_skip_pointers = true;
+                    break;
+                case 'r':
+                    m_skip_references = true;
+                    break;
+                case 'x':
+                    m_regex = true;
                     break;
                 default:
                     error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
@@ -446,6 +438,9 @@
             m_no_children = true;
             m_no_value = false;
             m_one_liner = false;
+            m_skip_references = false;
+            m_skip_pointers = false;
+            m_regex = false;
         }
         
         const OptionDefinition*
@@ -464,6 +459,10 @@
         bool m_no_children;
         bool m_no_value;
         bool m_one_liner;
+        bool m_skip_references;
+        bool m_skip_pointers;
+        bool m_regex;
+        std::string m_format_string;
     };
     
     CommandOptions m_options;
@@ -481,21 +480,14 @@
                    "Add a new summary style for a type.",
                    NULL), m_options (interpreter)
     {
-        CommandArgumentEntry format_arg;
-        CommandArgumentData format_style_arg;
         CommandArgumentEntry type_arg;
         CommandArgumentData type_style_arg;
         
-        format_style_arg.arg_type = eArgTypeFormat;
-        format_style_arg.arg_repetition = eArgRepeatPlain;
-        
         type_style_arg.arg_type = eArgTypeName;
         type_style_arg.arg_repetition = eArgRepeatPlus;
         
-        format_arg.push_back (format_style_arg);
         type_arg.push_back (type_style_arg);
         
-        m_arguments.push_back (format_arg);
         m_arguments.push_back (type_arg);
     }
     
@@ -508,34 +500,29 @@
     {
         const size_t argc = command.GetArgumentCount();
         
-        // we support just one custom syntax: type summary add -o yes typeName
-        // anything else, must take the usual route
-        // e.g. type summary add -o yes "" type1 type2 ... typeN
-        
-        bool isValidShortcut = m_options.m_one_liner && (argc == 1);
-        bool isValid = (argc >= 2);
-        
-        if (!isValidShortcut && !isValid)
+        if (argc < 1)
         {
-            result.AppendErrorWithFormat ("%s takes two or more args.\n", m_cmd_name.c_str());
+            result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
             result.SetStatus(eReturnStatusFailed);
             return false;
         }
         
-        const char* format_cstr = (isValidShortcut ? "" : command.GetArgumentAtIndex(0));
-        
-        if ( (!format_cstr || !format_cstr[0]) && !m_options.m_one_liner )
+        if(!m_options.m_one_liner && m_options.m_format_string.empty())
         {
             result.AppendError("empty summary strings not allowed");
             result.SetStatus(eReturnStatusFailed);
             return false;
         }
         
+        const char* format_cstr = (m_options.m_one_liner ? "" : m_options.m_format_string.c_str());
+        
         Error error;
         
         SummaryFormat::SharedPointer entry(new SummaryFormat(format_cstr,m_options.m_cascade,
                                              m_options.m_no_children,m_options.m_no_value,
-                                             m_options.m_one_liner));
+                                             m_options.m_one_liner,
+                                             m_options.m_skip_pointers,
+                                             m_options.m_skip_references));
         
         if (error.Fail()) 
         {
@@ -546,17 +533,31 @@
         
         // now I have a valid format, let's add it to every type
         
-        for(int i = (isValidShortcut ? 0 : 1); i < argc; i++) {
+        for(int i = 0; i < argc; i++) {
             const char* typeA = command.GetArgumentAtIndex(i);
-            ConstString typeCS(typeA);
-            if (typeCS)
-                Debugger::SummaryFormats::Add(typeCS, entry);
-            else
+            if(!typeA || typeA[0] == '\0')
             {
                 result.AppendError("empty typenames not allowed");
                 result.SetStatus(eReturnStatusFailed);
                 return false;
             }
+            ConstString typeCS(typeA);
+            if(!m_options.m_regex)
+            {
+                Debugger::SummaryFormats::Add(typeCS, entry);
+            }
+            else
+            {
+                RegularExpressionSP typeRX(new RegularExpression());
+                if(!typeRX->Compile(typeA))
+                {
+                    result.AppendError("regex format error (maybe this is not really a regex?)");
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                Debugger::RegexSummaryFormats::Delete(typeCS);
+                Debugger::RegexSummaryFormats::Add(typeRX, entry);
+            }
         }
         result.SetStatus(eReturnStatusSuccessFinishNoResult);
         return result.Succeeded();
@@ -567,10 +568,14 @@
 OptionDefinition
 CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] =
 {
-    { LLDB_OPT_SET_ALL, false, "cascade", 'c', required_argument, NULL, 0, eArgTypeBoolean,    "If true, cascade to derived typedefs."},
-    { LLDB_OPT_SET_ALL, false, "show-children", 'h', required_argument, NULL, 0, eArgTypeBoolean,    "If true, print children."},
-    { LLDB_OPT_SET_ALL, false, "show-value", 'v', required_argument, NULL, 0, eArgTypeBoolean,    "If true, print value."},
-    { LLDB_OPT_SET_ALL, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeBoolean,    "If true, just print a one-line preformatted summary."},
+    { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean,    "If true, cascade to derived typedefs."},
+    { LLDB_OPT_SET_ALL, false, "no-value", 'v', no_argument, NULL, 0, eArgTypeBoolean,         "Don't show the value, just show the summary, for this type."},
+    { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeBoolean,         "Don't use this format for pointers-to-type objects."},
+    { LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeBoolean,         "Don't use this format for references-to-type objects."},
+    { LLDB_OPT_SET_ALL, false,  "regex", 'x', no_argument, NULL, 0, eArgTypeBoolean,    "Type names are actually regular expressions."},
+    { LLDB_OPT_SET_1  , true, "inline-children", 'c', no_argument, NULL, 0, eArgTypeBoolean,    "If true, inline all child values into summary string."},
+    { LLDB_OPT_SET_2  , true, "format-string", 'f', required_argument, NULL, 0, eArgTypeFormatString,    "Format string used to display text and object contents."},
+    { LLDB_OPT_SET_2, false, "expand", 'e', no_argument, NULL, 0, eArgTypeBoolean,    "Expand aggregate data types to show children on separate lines."},
     { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
 };
 
@@ -626,8 +631,9 @@
             return false;
         }
         
-        
-        if (Debugger::SummaryFormats::Delete(typeCS))
+        bool delete_summary = Debugger::SummaryFormats::Delete(typeCS);
+        bool delete_regex = Debugger::RegexSummaryFormats::Delete(typeCS);
+        if (delete_summary || delete_regex)
         {
             result.SetStatus(eReturnStatusSuccessFinishNoResult);
             return result.Succeeded();
@@ -666,6 +672,7 @@
     Execute (Args& command, CommandReturnObject &result)
     {
         Debugger::SummaryFormats::Clear();
+        Debugger::RegexSummaryFormats::Clear();
         result.SetStatus(eReturnStatusSuccessFinishResult);
         return result.Succeeded();
     }
@@ -677,6 +684,7 @@
 //-------------------------------------------------------------------------
 
 bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const SummaryFormat::SharedPointer& entry);
+bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SummaryFormat::SharedPointer& entry);
 
 class CommandObjectTypeSummaryList;
 
@@ -688,6 +696,14 @@
                                                   RegularExpression* X = NULL) : self(S), result(R), regex(X) {}
 };
 
+struct CommandObjectTypeRXSummaryList_LoopCallbackParam {
+    CommandObjectTypeSummaryList* self;
+    CommandReturnObject* result;
+    RegularExpression* regex;
+    CommandObjectTypeRXSummaryList_LoopCallbackParam(CommandObjectTypeSummaryList* S, CommandReturnObject* R,
+                                                   RegularExpression* X = NULL) : self(S), result(R), regex(X) {}
+};
+
 class CommandObjectTypeSummaryList : public CommandObject
 {
 public:
@@ -718,6 +734,7 @@
         const size_t argc = command.GetArgumentCount();
         
         CommandObjectTypeSummaryList_LoopCallbackParam *param;
+        CommandObjectTypeRXSummaryList_LoopCallbackParam *rxparam;
         
         if (argc == 1) {
             RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
@@ -728,6 +745,24 @@
             param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result);
         Debugger::SummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param);
         delete param;
+        
+        if(Debugger::RegexSummaryFormats::GetCount() == 0)
+        {
+            result.SetStatus(eReturnStatusSuccessFinishResult);
+            return result.Succeeded();
+        }
+        
+        result.GetOutputStream().Printf("Regex-based summaries (slower):\n");
+        if (argc == 1) {
+            RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+            regex->Compile(command.GetArgumentAtIndex(0));
+            rxparam = new CommandObjectTypeRXSummaryList_LoopCallbackParam(this,&result,regex);
+        }
+        else
+            rxparam = new CommandObjectTypeRXSummaryList_LoopCallbackParam(this,&result);
+        Debugger::RegexSummaryFormats::LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, rxparam);
+        delete rxparam;
+        
         result.SetStatus(eReturnStatusSuccessFinishResult);
         return result.Succeeded();
     }
@@ -742,18 +777,21 @@
     {
         if (regex == NULL || regex->Execute(type)) 
         {
-                result->GetOutputStream().Printf ("%s: `%s`%s%s%s%s\n", type, 
+                result->GetOutputStream().Printf ("%s: `%s`%s%s%s%s%s%s\n", type, 
                                                   entry->m_format.c_str(),
                                                   entry->m_cascades ? "" : " (not cascading)",
                                                   entry->m_dont_show_children ? "" : " (show children)",
-                                                  entry->m_dont_show_value ? "" : " (show value)",
-                                                  entry->m_show_members_oneliner ? " (one-line printout)" : "");
+                                                  entry->m_dont_show_value ? " (hide value)" : "",
+                                                  entry->m_show_members_oneliner ? " (one-line printout)" : "",
+                                                  entry->m_skip_pointers ? " (skip pointers)" : "",
+                                                  entry->m_skip_references ? " (skip references)" : "");
         }
         return true;
     }
     
     friend bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const SummaryFormat::SharedPointer& entry);
-    
+    friend bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SummaryFormat::SharedPointer& entry);
+
 };
 
 bool
@@ -766,6 +804,15 @@
     return param->self->LoopCallback(type, entry, param->regex, param->result);
 }
 
+bool
+CommandObjectTypeRXSummaryList_LoopCallback (
+                                           void* pt2self,
+                                           lldb::RegularExpressionSP regex,
+                                           const SummaryFormat::SharedPointer& entry)
+{
+    CommandObjectTypeRXSummaryList_LoopCallbackParam* param = (CommandObjectTypeRXSummaryList_LoopCallbackParam*)pt2self;
+    return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result);
+}
 
 
 
@@ -796,7 +843,7 @@
 public:
     CommandObjectTypeSummary (CommandInterpreter &interpreter) :
     CommandObjectMultiword (interpreter,
-                            "type format",
+                            "type summary",
                             "A set of commands for editing variable summary display options",
                             "type summary [<sub-command-options>] ")
     {
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index fadeafd..39ac87a 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -791,15 +791,201 @@
                         case '*':
                             {
                                 if (!vobj) break;
-                                var_name_begin++;
                                 lldb::clang_type_t pointer_clang_type = vobj->GetClangType();
                                 clang_type_t elem_or_pointee_clang_type;
                                 const Flags type_flags (ClangASTContext::GetTypeInfo (pointer_clang_type, 
                                                                                       vobj->GetClangAST(), 
                                                                                       &elem_or_pointee_clang_type));
-                                if (type_flags.Test (ClangASTContext::eTypeIsPointer))
+                                bool is_pointer = type_flags.Test (ClangASTContext::eTypeIsPointer),
+                                is_array = type_flags.Test (ClangASTContext::eTypeIsArray);
+                                if ( is_array || 
+                                    ( is_pointer && ::strchr(var_name_begin,'[') && ::strchr(var_name_begin,'[') < var_name_end )
+                                   )
                                 {
-                                    if (ClangASTContext::IsCharType (elem_or_pointee_clang_type))
+                                    const char* var_name_final;
+                                    char* close_bracket_position = NULL;
+                                    const char* percent_position = NULL;
+                                    const char* targetvalue;
+                                    lldb::Format custom_format = eFormatInvalid;
+                                    int index_lower = -1;
+                                    int index_higher = -1;
+                                    ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eDisplaySummary;
+                                    {
+                                        percent_position = ::strchr(var_name_begin,'%');
+                                        if(!percent_position || percent_position > var_name_end)
+                                            var_name_final = var_name_end;
+                                        else
+                                        {
+                                            var_name_final = percent_position;
+                                            char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
+                                            memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
+                                            if ( !FormatManager::GetFormatFromCString(format_name,
+                                                                                      true,
+                                                                                      custom_format) )
+                                            {
+                                                // if this is an @ sign, print ObjC description
+                                                if(*format_name == '@')
+                                                    val_obj_display = ValueObject::eDisplayLanguageSpecific;
+                                                // if this is a V, print the value using the default format
+                                                if(*format_name == 'V')
+                                                    val_obj_display = ValueObject::eDisplayValue;
+                                            }
+                                            // a good custom format tells us to print the value using it
+                                            else
+                                                val_obj_display = ValueObject::eDisplayValue;
+                                        }
+                                    }
+                                    
+                                    {
+                                        const char* open_bracket_position = ::strchr(var_name_begin,'[');
+                                        if(open_bracket_position && open_bracket_position < var_name_final)
+                                        {
+                                            // TODO: pick a way to say "all entries". this will make more sense once
+                                            // regex typenames are in place. now, you need to be size-aware anyways
+                                            char* separator_position = ::strchr(open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield
+                                            close_bracket_position = ::strchr(open_bracket_position,']');
+                                            // as usual, we assume that [] will come before %
+                                            //printf("trying to expand a []\n");
+                                            var_name_final = open_bracket_position;
+                                            if(close_bracket_position - open_bracket_position == 1)
+                                            {
+                                                if(is_array)
+                                                {
+                                                    index_lower = 0;
+                                                    index_higher = vobj->GetNumChildren() - 1;
+                                                }
+                                                else
+                                                    break; // cannot auto-determine size for pointers
+                                            }
+                                            else if (separator_position == NULL || separator_position > var_name_end)
+                                            {
+                                                char *end = NULL;
+                                                index_lower = ::strtoul (open_bracket_position+1, &end, 0);
+                                                index_higher = index_lower;
+                                                //printf("got to read low=%d high same\n",bitfield_lower);
+                                            }
+                                            else if(close_bracket_position && close_bracket_position < var_name_end)
+                                            {
+                                                char *end = NULL;
+                                                index_lower = ::strtoul (open_bracket_position+1, &end, 0);
+                                                index_higher = ::strtoul (separator_position+1, &end, 0);
+                                                //printf("got to read low=%d high=%d\n",bitfield_lower,bitfield_higher);
+                                            }
+                                            else
+                                                break;
+                                            if (index_lower > index_higher)
+                                            {
+                                                int temp = index_lower;
+                                                index_lower = index_higher;
+                                                index_higher = temp;
+                                            }
+                                            //*((char*)open_bracket_position) = '\0';
+                                            //printf("variable name is %s\n",var_name_begin);
+                                            //*((char*)open_bracket_position) = '[';
+                                        }
+                                    }
+                                    
+                                    // if you just type a range, lldb will do the "right thing" in picking
+                                    // a reasonable display for the array entries. you can override this by
+                                    // giving other input (e.g. ${*var[1-3].member1%uint8_t[]}) and they
+                                    // will be honored
+                                    char* special_directions = NULL;
+                                    if (close_bracket_position && (var_name_end-close_bracket_position > 1))
+                                    {
+                                        int base_len = var_name_end-close_bracket_position;
+                                        special_directions = new char[8+base_len];
+                                        special_directions[0] = '$';
+                                        special_directions[1] = '{';                                        
+                                        special_directions[2] = 'v';
+                                        special_directions[3] = 'a';
+                                        special_directions[4] = 'r';
+                                        memcpy(special_directions+5, close_bracket_position+1, base_len);
+                                        special_directions[base_len+7] = '\0';
+                                        printf("%s\n",special_directions);
+                                    }
+                                    
+                                    // let us display items index_lower thru index_higher of this array
+                                    s.PutChar('[');
+                                    var_success = true;
+                                    const char* expr_path = NULL;
+                                    const char* ptr_deref_format = "%s[%d]";
+                                    char* ptr_deref_buffer = new char[1024];
+                                    StreamString expr_path_string;
+                                    
+                                    if(is_pointer)
+                                    {
+                                        vobj->GetExpressionPath(expr_path_string, true, ValueObject::eHonorPointers);
+                                        expr_path = expr_path_string.GetData();
+                                    }
+                                    
+                                    for(;index_lower<=index_higher;index_lower++)
+                                    {
+                                        ValueObject* item;
+                                        
+                                        if(is_array)
+                                            item = vobj->GetChildAtIndex(index_lower, true).get();
+                                        else
+                                        {
+#ifdef VERBOSE_FORMATPROMPT_OUTPUT
+                                            printf("name to deref in phase 0: %s\n",expr_path);
+#endif //VERBOSE_FORMATPROMPT_OUTPUT
+                                            ::sprintf(ptr_deref_buffer, ptr_deref_format, expr_path, index_lower);
+#ifdef VERBOSE_FORMATPROMPT_OUTPUT
+                                            printf("name to deref in phase 1: %s\n",ptr_deref_buffer);
+#endif //VERBOSE_FORMATPROMPT_OUTPUT
+                                            lldb::VariableSP var_sp;
+                                            Error error;
+                                            item = exe_ctx->frame->GetValueForVariableExpressionPath (ptr_deref_buffer,
+                                                                                                      eNoDynamicValues, 
+                                                                                                      0,
+                                                                                                      var_sp,
+                                                                                                      error).get();
+                                            if (error.Fail())
+                                            {
+#ifdef VERBOSE_FORMATPROMPT_OUTPUT
+                                                printf("ERROR: %s\n",error.AsCString("unknown"));
+#endif //VERBOSE_FORMATPROMPT_OUTPUT
+                                                break;
+                                            }
+                                        }
+                                        
+                                        if (!special_directions)
+                                        {
+                                            targetvalue = item->GetPrintableRepresentation(val_obj_display, custom_format);
+                                            if(targetvalue)
+                                                s.PutCString(targetvalue);
+                                            var_success &= (targetvalue != NULL);
+                                            if(custom_format != eFormatInvalid)
+                                                item->SetFormat(eFormatDefault);
+                                        }
+                                        else
+                                        {
+                                            var_success &= FormatPrompt(special_directions, sc, exe_ctx, addr, s, NULL, item);
+                                        }
+                                        
+                                        if(index_lower < index_higher)
+                                            s.PutChar(',');
+                                    }
+                                    s.PutChar(']');
+                                    break;
+
+                                }
+                                else if (is_pointer)
+                                {
+                                    var_name_begin++;
+                                    uint32_t offset = 0;
+                                    DataExtractor read_for_null = vobj->GetDataExtractor();
+                                    if (read_for_null.GetPointer(&offset) == 0)
+                                        break;
+                                    if (ClangASTContext::IsAggregateType (elem_or_pointee_clang_type) )
+                                    {
+                                        Error error;
+                                        realvobj = vobj;
+                                        vobj = vobj->Dereference(error).get();
+                                        if(!vobj || error.Fail())
+                                            break;
+                                    }
+                                    else if (ClangASTContext::IsCharType (elem_or_pointee_clang_type))
                                     {
                                         StreamString sstr;
                                         ExecutionContextScope *exe_scope = vobj->GetExecutionContextScope();
@@ -849,7 +1035,7 @@
                                             break;
                                         }
                                     }
-                                    else /*if (ClangASTContext::IsAggregateType (elem_or_pointee_clang_type)) or this is some other pointer type*/
+                                    else /*some other pointer type*/
                                     {
                                         Error error;
                                         realvobj = vobj;
@@ -864,7 +1050,7 @@
                         case 'v':
                             {
                             const char* targetvalue;
-                            bool use_summary = false;
+                            ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eDisplaySummary;
                             ValueObject* target;
                             lldb::Format custom_format = eFormatInvalid;
                             int bitfield_lower = -1;
@@ -872,12 +1058,16 @@
                             if (!vobj) break;
                             // simplest case ${var}, just print vobj's value
                             if (::strncmp (var_name_begin, "var}", strlen("var}")) == 0)
+                            {
                                 target = vobj;
+                                val_obj_display = ValueObject::eDisplayValue;
+                            }
                             else if (::strncmp(var_name_begin,"var%",strlen("var%")) == 0)
                             {
                                 // this is a variable with some custom format applied to it
                                 const char* var_name_final;
                                 target = vobj;
+                                val_obj_display = ValueObject::eDisplayValue;
                                 {
                                     const char* percent_position = ::strchr(var_name_begin,'%'); // TODO: make this a constant
                                     //if(!percent_position || percent_position > var_name_end)
@@ -887,9 +1077,14 @@
                                     var_name_final = percent_position;
                                     char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
                                     memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
-                                    FormatManager::GetFormatFromCString(format_name,
+                                    if ( !FormatManager::GetFormatFromCString(format_name,
                                                                         true,
-                                                                        custom_format); // if this fails, custom_format is reset to invalid
+                                                                        custom_format) )
+                                    {
+                                        // if this is an @ sign, print ObjC description
+                                        if(*format_name == '@')
+                                            val_obj_display = ValueObject::eDisplayLanguageSpecific;
+                                    }
                                     delete format_name;
                                     //}
                                 }
@@ -899,7 +1094,7 @@
                                 // this is a bitfield variable
                                 const char *var_name_final;
                                 target = vobj;
-                                
+                                val_obj_display = ValueObject::eDisplayValue;
                                 {
                                     const char* percent_position = ::strchr(var_name_begin,'%');
                                     if(!percent_position || percent_position > var_name_end)
@@ -909,10 +1104,15 @@
                                         var_name_final = percent_position;
                                         char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
                                         memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
-                                        FormatManager::GetFormatFromCString(format_name,
-                                                                            true,
-                                                                            custom_format); // if this fails, custom_format is reset to invalid
-                                        delete format_name;
+                                        if ( !FormatManager::GetFormatFromCString(format_name,
+                                                                                  true,
+                                                                                  custom_format) )
+                                        {
+                                            delete format_name;
+                                            break;
+                                        }
+                                        else
+                                            delete format_name;
                                     }
                                 }
                                 
@@ -943,7 +1143,11 @@
                                         else
                                             break;
                                         if(bitfield_lower > bitfield_higher)
-                                            break;
+                                        {
+                                            int temp = bitfield_lower;
+                                            bitfield_lower = bitfield_higher;
+                                            bitfield_higher = temp;
+                                        }
                                     }
                                 }
                             }
@@ -966,10 +1170,20 @@
                                         var_name_final = percent_position;
                                         char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
                                         memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
-                                        FormatManager::GetFormatFromCString(format_name,
-                                                                            true,
-                                                                            custom_format); // if this fails, custom_format is reset to invalid
-                                        delete format_name;
+                                        if ( !FormatManager::GetFormatFromCString(format_name,
+                                                                                  true,
+                                                                                  custom_format) )
+                                        {
+                                            // if this is an @ sign, print ObjC description
+                                            if(*format_name == '@')
+                                                val_obj_display = ValueObject::eDisplayLanguageSpecific;
+                                            // if this is a V, print the value using the default format
+                                            if(*format_name == 'V')
+                                                val_obj_display = ValueObject::eDisplayValue;
+                                        }
+                                        // a good custom format tells us to print the value using it
+                                        else
+                                            val_obj_display = ValueObject::eDisplayValue;
                                     }
                                 }
                                 
@@ -999,7 +1213,11 @@
                                         else
                                             break;
                                         if(bitfield_lower > bitfield_higher)
-                                            break;
+                                        {
+                                            int temp = bitfield_lower;
+                                            bitfield_lower = bitfield_higher;
+                                            bitfield_higher = temp;
+                                        }
                                         //*((char*)open_bracket_position) = '\0';
                                         //printf("variable name is %s\n",var_name_begin);
                                         //*((char*)open_bracket_position) = '[';
@@ -1010,9 +1228,13 @@
                                 lldb::VariableSP var_sp;
                                 StreamString sstring;
                                 vobj->GetExpressionPath(sstring, true, ValueObject::eHonorPointers);
-                                //printf("name to expand in phase 0: %s\n",sstring.GetData());
+#ifdef VERBOSE_FORMATPROMPT_OUTPUT                                
+                                printf("name to expand in phase 0: %s\n",sstring.GetData());
+#endif //VERBOSE_FORMATPROMPT_OUTPUT
                                 sstring.PutRawBytes(var_name_begin+3, var_name_final-var_name_begin-3);
-                                //printf("name to expand in phase 1: %s\n",sstring.GetData());
+#ifdef VERBOSE_FORMATPROMPT_OUTPUT
+                                printf("name to expand in phase 1: %s\n",sstring.GetData());
+#endif //VERBOSE_FORMATPROMPT_OUTPUT
                                 std::string name = std::string(sstring.GetData());
                                 target = exe_ctx->frame->GetValueForVariableExpressionPath (name.c_str(),
                                                                                             eNoDynamicValues, 
@@ -1021,17 +1243,14 @@
                                                                                             error).get();
                                 if (error.Fail())
                                 {
-                                    //printf("ERROR: %s\n",error.AsCString("unknown"));
+#ifdef VERBOSE_FORMATPROMPT_OUTPUT                                
+                                    printf("ERROR: %s\n",error.AsCString("unknown"));
+#endif //VERBOSE_FORMATPROMPT_OUTPUT
                                     break;
                                 }
                             }
                             else
                                 break;
-                            if(*(var_name_end+1)=='s')
-                            {
-                                use_summary = true;
-                                var_name_end++;
-                            }
                             if (bitfield_lower >= 0)
                             {
                                 //printf("trying to print a []\n");
@@ -1046,16 +1265,8 @@
                             }
                             else
                             {
-                                //printf("here I come 1\n");
                                 // format this as usual
-                                if(custom_format != eFormatInvalid)
-                                    target->SetFormat(custom_format);
-                                //printf("here I come 2\n");
-                                if(!use_summary)
-                                    targetvalue = target->GetValueAsCString();
-                                else
-                                    targetvalue = target->GetSummaryAsCString();
-                                //printf("here I come 3\n");
+                                targetvalue = target->GetPrintableRepresentation(val_obj_display, custom_format);
                                 if(targetvalue)
                                     s.PutCString(targetvalue);
                                 var_success = targetvalue;
@@ -1634,7 +1845,7 @@
 }
 
 void
-Debugger::ValueFormats::LoopThrough(FormatManager::ValueCallback callback, void* callback_baton)
+Debugger::ValueFormats::LoopThrough(ValueFormat::ValueCallback callback, void* callback_baton)
 {
     GetFormatManager().Value().LoopThrough(callback, callback_baton);
 }
@@ -1645,6 +1856,11 @@
     return GetFormatManager().GetCurrentRevision();
 }
 
+uint32_t
+Debugger::ValueFormats::GetCount()
+{
+    return GetFormatManager().Value().GetCount();
+}
 
 bool
 Debugger::SummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry)
@@ -1671,7 +1887,7 @@
 }
 
 void
-Debugger::SummaryFormats::LoopThrough(FormatManager::SummaryCallback callback, void* callback_baton)
+Debugger::SummaryFormats::LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton)
 {
     GetFormatManager().Summary().LoopThrough(callback, callback_baton);
 }
@@ -1682,6 +1898,54 @@
     return GetFormatManager().GetCurrentRevision();
 }
 
+uint32_t
+Debugger::SummaryFormats::GetCount()
+{
+    return GetFormatManager().Summary().GetCount();
+}
+
+bool
+Debugger::RegexSummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry)
+{
+    return GetFormatManager().RegexSummary().Get(vobj,entry);
+}
+
+void
+Debugger::RegexSummaryFormats::Add(const lldb::RegularExpressionSP &type, const SummaryFormat::SharedPointer &entry)
+{
+    GetFormatManager().RegexSummary().Add(type,entry);
+}
+
+bool
+Debugger::RegexSummaryFormats::Delete(const ConstString &type)
+{
+    return GetFormatManager().RegexSummary().Delete(type.AsCString());
+}
+
+void
+Debugger::RegexSummaryFormats::Clear()
+{
+    GetFormatManager().RegexSummary().Clear();
+}
+
+void
+Debugger::RegexSummaryFormats::LoopThrough(SummaryFormat::RegexSummaryCallback callback, void* callback_baton)
+{
+    GetFormatManager().RegexSummary().LoopThrough(callback, callback_baton);
+}
+
+uint32_t
+Debugger::RegexSummaryFormats::GetCurrentRevision()
+{
+    return GetFormatManager().GetCurrentRevision();
+}
+
+uint32_t
+Debugger::RegexSummaryFormats::GetCount()
+{
+    return GetFormatManager().RegexSummary().GetCount();
+}
+
 #pragma mark Debugger::SettingsController
 
 //--------------------------------------------------
diff --git a/source/Core/FormatManager.cpp b/source/Core/FormatManager.cpp
index 8f8a60d..75d025f 100644
--- a/source/Core/FormatManager.cpp
+++ b/source/Core/FormatManager.cpp
@@ -151,3 +151,40 @@
         return g_format_infos[format].format_name;
     return NULL;
 }
+
+template<>
+bool
+FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Get(const char* key,
+                                                                                                                     SummaryFormat::SharedPointer& value)
+{
+    Mutex::Locker(m_map_mutex);
+    MapIterator pos, end = m_map.end();
+    for (pos = m_map.begin(); pos != end; pos++)
+    {
+        lldb::RegularExpressionSP regex = pos->first;
+        if (regex->Execute(key))
+        {
+            value = pos->second;
+            return true;
+        }
+    }
+    return false;
+}
+
+template<>
+bool
+FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Delete(const char* type)
+{
+    Mutex::Locker(m_map_mutex);
+    MapIterator pos, end = m_map.end();
+    for (pos = m_map.begin(); pos != end; pos++)
+    {
+        lldb::RegularExpressionSP regex = pos->first;
+        if ( ::strcmp(type,regex->GetText()) == 0)
+        {
+            m_map.erase(pos);
+            return true;
+        }
+    }
+    return false;
+}
diff --git a/source/Core/RegularExpression.cpp b/source/Core/RegularExpression.cpp
index 7848931..6fb94d9 100644
--- a/source/Core/RegularExpression.cpp
+++ b/source/Core/RegularExpression.cpp
@@ -176,4 +176,9 @@
     return ::regerror (m_comp_err, &m_preg, err_str, err_str_max_len);
 }
 
+bool
+RegularExpression::operator < (const RegularExpression& rhs) const
+{
+    return (m_re < rhs.m_re);
+}
 
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index 5177600..a8696be 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -73,6 +73,7 @@
     m_old_value_valid (false),
     m_pointers_point_to_load_addrs (false),
     m_is_deref_of_parent (false),
+    m_is_array_item_for_pointer(false),
     m_last_format_mgr_revision(0),
     m_last_summary_format(),
     m_last_value_format()
@@ -108,6 +109,7 @@
     m_old_value_valid (false),
     m_pointers_point_to_load_addrs (false),
     m_is_deref_of_parent (false),
+    m_is_array_item_for_pointer(false),
     m_last_format_mgr_revision(0),
     m_last_summary_format(),
     m_last_value_format()
@@ -124,10 +126,11 @@
 }
 
 bool
-ValueObject::UpdateValueIfNeeded ()
+ValueObject::UpdateValueIfNeeded (bool update_format)
 {
     
-    UpdateFormatsIfNeeded();
+    if (update_format)
+        UpdateFormatsIfNeeded();
     
     // If this is a constant value, then our success is predicated on whether
     // we have an error or not
@@ -191,7 +194,8 @@
         if (m_last_value_format.get())
             m_last_value_format.reset((ValueFormat*)NULL);
         Debugger::ValueFormats::Get(*this, m_last_value_format);
-        Debugger::SummaryFormats::Get(*this, m_last_summary_format);
+        if (!Debugger::SummaryFormats::Get(*this, m_last_summary_format))
+            Debugger::RegexSummaryFormats::Get(*this, m_last_summary_format);
         m_last_format_mgr_revision = Debugger::ValueFormats::GetCurrentRevision();
         m_value_str.clear();
         m_summary_str.clear();
@@ -493,12 +497,47 @@
                 ExecutionContext exe_ctx;
                 this->GetExecutionContextScope()->CalculateExecutionContext(exe_ctx);
                 SymbolContext sc = exe_ctx.frame->GetSymbolContext(eSymbolContextEverything);
-                if (Debugger::FormatPrompt(m_last_summary_format->m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, this))
+                
+                if (m_last_summary_format->m_show_members_oneliner)
                 {
-                    m_summary_str.swap(s.GetString());
-                    return m_summary_str.c_str();
+                    const uint32_t num_children = GetNumChildren();
+                    if (num_children)
+                    {
+                        
+                        s.PutChar('(');
+                        
+                        for (uint32_t idx=0; idx<num_children; ++idx)
+                        {
+                            ValueObjectSP child_sp(GetChildAtIndex(idx, true));
+                            if (child_sp.get())
+                            {
+                                if (idx)
+                                    s.PutCString(", ");
+                                s.PutCString(child_sp.get()->GetName().AsCString());
+                                s.PutChar('=');
+                                s.PutCString(child_sp.get()->GetValueAsCString());
+                            }
+                        }
+                        
+                        s.PutChar(')');
+                        
+                        m_summary_str.swap(s.GetString());
+                        return m_summary_str.c_str();
+                    }
+                    else
+                        return "()";
+
                 }
-                return NULL;
+                else
+                {
+                    if (Debugger::FormatPrompt(m_last_summary_format->m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, this))
+                    {
+                        m_summary_str.swap(s.GetString());
+                        return m_summary_str.c_str();
+                    }
+                    else
+                        return NULL;
+                }
             }
             
             clang_type_t clang_type = GetClangType();
@@ -655,12 +694,13 @@
 const char *
 ValueObject::GetObjectDescription ()
 {
-    if (!m_object_desc_str.empty())
-        return m_object_desc_str.c_str();
-        
+    
     if (!UpdateValueIfNeeded ())
         return NULL;
-        
+
+    if (!m_object_desc_str.empty())
+        return m_object_desc_str.c_str();
+
     ExecutionContextScope *exe_scope = GetExecutionContextScope();
     if (exe_scope == NULL)
         return NULL;
@@ -782,6 +822,37 @@
     return m_value_str.c_str();
 }
 
+const char *
+ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_display,
+                                        lldb::Format custom_format)
+{
+    if(custom_format != lldb::eFormatInvalid)
+        SetFormat(custom_format);
+    
+    const char * return_value;
+    
+    switch(val_obj_display)
+    {
+        case eDisplayValue:
+            return_value = GetValueAsCString();
+            break;
+        case eDisplaySummary:
+            return_value = GetSummaryAsCString();
+            break;
+        case eDisplayLanguageSpecific:
+            return_value = GetObjectDescription();
+            break;
+    }
+    
+    
+    // try to use the value if the user's choice failed
+    if(!return_value && val_obj_display != eDisplayValue)
+        return_value = GetValueAsCString();
+    
+    return return_value;
+
+}
+
 addr_t
 ValueObject::GetAddressOf (AddressType &address_type, bool scalar_is_load_address)
 {
@@ -1049,6 +1120,8 @@
             {
                 AddSyntheticChild(index_const_str, synthetic_child);
                 synthetic_child_sp = synthetic_child->GetSP();
+                synthetic_child_sp->SetName(index_str);
+                synthetic_child_sp->m_is_array_item_for_pointer = true;
             }
         }
     }
@@ -1165,6 +1238,12 @@
     
     if (parent)
         parent->GetExpressionPath (s, qualify_cxx_base_classes, epformat);
+    
+    // if we are a deref_of_parent just because we are synthetic array
+    // members made up to allow ptr[%d] syntax to work in variable
+    // printing, then add our name ([%d]) to the expression path
+    if(m_is_array_item_for_pointer && epformat == eHonorPointers)
+        s.PutCString(m_name.AsCString());
             
     if (!IsBaseClass())
     {
@@ -1312,8 +1391,17 @@
                 if (val_cstr && (!entry || entry->DoesPrintValue() || !sum_cstr))
                     s.Printf(" %s", valobj->GetValueAsCString());
 
-                if (sum_cstr)
-                    s.Printf(" %s", sum_cstr);
+                if(sum_cstr)
+                {
+                    // for some reason, using %@ (ObjC description) in a summary string, makes
+                    // us believe we need to reset ourselves, thus invalidating the content of
+                    // sum_cstr. Thus, IF we had a valid sum_cstr before, but it is now empty
+                    // let us recalculate it!
+                    if (sum_cstr[0] == '\0')
+                        s.Printf(" %s", valobj->GetSummaryAsCString());
+                    else
+                        s.Printf(" %s", sum_cstr);
+                }
                 
                 if (use_objc)
                 {
@@ -1323,7 +1411,7 @@
                     else
                         s.Printf (" [no Objective-C description available]\n");
                     return;
-                }                
+                }
             }
 
             if (curr_depth < max_depth)
@@ -1360,32 +1448,7 @@
                         print_children = false;
                 }
                 
-                if (entry && entry->IsOneliner())
-                {
-                    const uint32_t num_children = valobj->GetNumChildren();
-                    if (num_children)
-                    {
-                        
-                        s.PutChar('(');
-                        
-                        for (uint32_t idx=0; idx<num_children; ++idx)
-                        {
-                            ValueObjectSP child_sp(valobj->GetChildAtIndex(idx, true));
-                            if (child_sp.get())
-                            {
-                                if (idx)
-                                    s.PutCString(", ");
-                                s.PutCString(child_sp.get()->GetName().AsCString());
-                                s.PutChar('=');
-                                s.PutCString(child_sp.get()->GetValueAsCString());
-                            }
-                        }
-                        
-                        s.PutChar(')');
-                        s.EOL();
-                    }
-                }
-                else if (print_children && (!entry || entry->DoesPrintChildren() || !sum_cstr))
+                if (print_children && (!entry || entry->DoesPrintChildren() || !sum_cstr))
                 {
                     const uint32_t num_children = valobj->GetNumChildren();
                     if (num_children)
diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp
index 0a90b85..e0d94f7 100644
--- a/source/Core/ValueObjectDynamicValue.cpp
+++ b/source/Core/ValueObjectDynamicValue.cpp
@@ -80,7 +80,7 @@
 clang::ASTContext *
 ValueObjectDynamicValue::GetClangAST ()
 {
-    const bool success = UpdateValueIfNeeded();
+    const bool success = UpdateValueIfNeeded(false);
     if (success && m_type_sp)
         return m_type_sp->GetClangAST();
     else
diff --git a/source/Interpreter/CommandObject.cpp b/source/Interpreter/CommandObject.cpp
index 76cee5a..241adca 100644
--- a/source/Interpreter/CommandObject.cpp
+++ b/source/Interpreter/CommandObject.cpp
@@ -627,6 +627,37 @@
     return "A 'breakpoint id list' is a manner of specifying multiple breakpoints. This can be done  through several mechanisms.  The easiest way is to just enter a space-separated list of breakpoint ids.  To specify all the breakpoint locations under a major breakpoint, you can use the major breakpoint number followed by '.*', eg. '5.*' means all the locations under breakpoint 5.  You can also indicate a range of breakpoints by using <start-bp-id> - <end-bp-id>.  The start-bp-id and end-bp-id for a range can be any valid breakpoint ids.  It is not legal, however, to specify a range using specific locations that cross major breakpoint numbers.  I.e. 3.2 - 3.7 is legal; 2 - 5 is legal; but 3.2 - 4.4 is not legal.";
 }
 
+static const char *
+FormatHelpTextCallback ()
+{
+    StreamString sstr;
+    sstr << "One of the format names (or one-character names) that can be used to show a variable's value:\n";
+    for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1))
+    {
+        char format_char = FormatManager::GetFormatAsFormatChar(f);
+        if (format_char)
+            sstr.Printf("'%c' or ", format_char);
+        
+        sstr.Printf ("\"%s\" ; ", FormatManager::GetFormatAsCString(f));
+    }
+    
+    sstr.Flush();
+    
+    std::string data = sstr.GetString();
+    
+    char* help = new char[data.length()+1];
+    
+    data.copy(help, data.length());
+    
+    return help;
+}
+
+static const char *
+FormatStringHelpTextCallback()
+{
+    return "Ask me tomorrow";
+}
+
 const char * 
 CommandObject::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type)
 {
@@ -662,7 +693,8 @@
     { eArgTypeExpression, "expr", CommandCompletions::eNoCompletion, NULL, "Help text goes here." },
     { eArgTypeExprFormat, "expression-format", CommandCompletions::eNoCompletion, NULL, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]" },
     { eArgTypeFilename, "filename", CommandCompletions::eDiskFileCompletion, NULL, "The name of a file (can include path)." },
-    { eArgTypeFormat, "format", CommandCompletions::eNoCompletion, NULL, "Help text goes here." },
+    { eArgTypeFormat, "format", CommandCompletions::eNoCompletion, FormatHelpTextCallback, NULL },
+    { eArgTypeFormatString, "format-string", CommandCompletions::eNoCompletion, FormatStringHelpTextCallback, NULL },
     { eArgTypeFrameIndex, "frame-index", CommandCompletions::eNoCompletion, NULL, "Index into a thread's list of frames." },
     { eArgTypeFullName, "fullname", CommandCompletions::eNoCompletion, NULL, "Help text goes here." },
     { eArgTypeFunctionName, "function-name", CommandCompletions::eNoCompletion, NULL, "The name of a function." },
diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp
index 9da3c70..dd29719 100644
--- a/source/Symbol/ClangASTContext.cpp
+++ b/source/Symbol/ClangASTContext.cpp
@@ -117,21 +117,26 @@
                 clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
                 // We currently can't complete objective C types through the newly added ASTContext
                 // because it only supports TagDecl objects right now...
-                bool is_forward_decl = class_interface_decl->isForwardDecl();
-                if (is_forward_decl && class_interface_decl->hasExternalLexicalStorage())
+                if(class_interface_decl)
                 {
-                    if (ast)
+                    bool is_forward_decl = class_interface_decl->isForwardDecl();
+                    if (is_forward_decl && class_interface_decl->hasExternalLexicalStorage())
                     {
-                        ExternalASTSource *external_ast_source = ast->getExternalSource();
-                        if (external_ast_source)
+                        if (ast)
                         {
-                            external_ast_source->CompleteType (class_interface_decl);
-                            is_forward_decl = class_interface_decl->isForwardDecl();
+                            ExternalASTSource *external_ast_source = ast->getExternalSource();
+                            if (external_ast_source)
+                            {
+                                external_ast_source->CompleteType (class_interface_decl);
+                                is_forward_decl = class_interface_decl->isForwardDecl();
+                            }
                         }
+                        return is_forward_decl == false;
                     }
-                    return is_forward_decl == false;
+                    return true;
                 }
-                return true;
+                else
+                    return false;
             }
         }
         break;