Introduce the notion of an escape helper. Different languages have different notion of what to print in a string and how to escape non-printable things. The escape helper is where this notion is provided to LLDB

This is NFC, other than a code re-org

llvm-svn: 247200
diff --git a/lldb/source/DataFormatters/StringPrinter.cpp b/lldb/source/DataFormatters/StringPrinter.cpp
index a5ed7e4..3225168 100644
--- a/lldb/source/DataFormatters/StringPrinter.cpp
+++ b/lldb/source/DataFormatters/StringPrinter.cpp
@@ -13,6 +13,7 @@
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Error.h"
 #include "lldb/Core/ValueObject.h"
+#include "lldb/Target/Language.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
 
@@ -27,7 +28,7 @@
 
 // we define this for all values of type but only implement it for those we care about
 // that's good because we get linker errors for any unsupported type
-template <StringElementType type>
+template <lldb_private::formatters::StringPrinter::StringElementType type>
 static StringPrinter::StringPrinterBufferPointer<>
 GetPrintableImpl(uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next);
 
@@ -60,7 +61,7 @@
 
 template <>
 StringPrinter::StringPrinterBufferPointer<>
-GetPrintableImpl<StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
+GetPrintableImpl<StringPrinter::StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
 {
     StringPrinter::StringPrinterBufferPointer<> retval = {nullptr};
     
@@ -130,7 +131,7 @@
 
 template <>
 StringPrinter::StringPrinterBufferPointer<>
-GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
+GetPrintableImpl<StringPrinter::StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
 {
     StringPrinter::StringPrinterBufferPointer<> retval {nullptr};
     
@@ -149,7 +150,7 @@
     {
         case 1:
             // this is just an ASCII byte - ask ASCII
-            return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next);
+            return GetPrintableImpl<StringPrinter::StringElementType::ASCII>(buffer, buffer_end, next);
         case 2:
             codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1));
             break;
@@ -227,22 +228,38 @@
 // a sequence of bytes to actually print out + a length
 // the following unscanned position of the buffer is in next
 static StringPrinter::StringPrinterBufferPointer<>
-GetPrintable(StringElementType type, uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
+GetPrintable(StringPrinter::StringElementType type, uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
 {
     if (!buffer)
         return {nullptr};
     
     switch (type)
     {
-        case StringElementType::ASCII:
-            return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next);
-        case StringElementType::UTF8:
-            return GetPrintableImpl<StringElementType::UTF8>(buffer, buffer_end, next);
+        case StringPrinter::StringElementType::ASCII:
+            return GetPrintableImpl<StringPrinter::StringElementType::ASCII>(buffer, buffer_end, next);
+        case StringPrinter::StringElementType::UTF8:
+            return GetPrintableImpl<StringPrinter::StringElementType::UTF8>(buffer, buffer_end, next);
         default:
             return {nullptr};
     }
 }
 
+StringPrinter::EscapingHelper
+StringPrinter::GetDefaultEscapingHelper (GetPrintableElementType elem_type)
+{
+    switch (elem_type)
+    {
+        case GetPrintableElementType::UTF8:
+            return [] (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) -> StringPrinter::StringPrinterBufferPointer<> {
+                return GetPrintable(StringPrinter::StringElementType::UTF8, buffer, buffer_end, next);
+            };
+        case GetPrintableElementType::ASCII:
+            return [] (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) -> StringPrinter::StringPrinterBufferPointer<> {
+                return GetPrintable(StringPrinter::StringElementType::ASCII, buffer, buffer_end, next);
+            };
+    }
+}
+
 // use this call if you already have an LLDB-side buffer for the data
 template<typename SourceDataType>
 static bool
@@ -251,7 +268,7 @@
                                                             UTF8**,
                                                             UTF8*,
                                                             ConversionFlags),
-                       const ReadBufferAndDumpToStreamOptions& dump_options)
+                       const StringPrinter::ReadBufferAndDumpToStreamOptions& dump_options)
 {
     Stream &stream(*dump_options.GetStream());
     if (dump_options.GetPrefixToken() != 0)
@@ -312,6 +329,14 @@
         }
         
         const bool escape_non_printables = dump_options.GetEscapeNonPrintables();
+        lldb_private::formatters::StringPrinter::EscapingHelper escaping_callback;
+        if (escape_non_printables)
+        {
+            if (Language *language = Language::FindPlugin(dump_options.GetLanguage()))
+                escaping_callback = language->GetStringPrinterEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::UTF8);
+            else
+                escaping_callback = lldb_private::formatters::StringPrinter::GetDefaultEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::UTF8);
+        }
         
         // since we tend to accept partial data (and even partially malformed data)
         // we might end up with no NULL terminator before the end_ptr
@@ -324,7 +349,7 @@
             if (escape_non_printables)
             {
                 uint8_t* next_data = nullptr;
-                auto printable = GetPrintable(StringElementType::UTF8, utf8_data_ptr, utf8_data_end_ptr, next_data);
+                auto printable = escaping_callback(utf8_data_ptr, utf8_data_end_ptr, next_data);
                 auto printable_bytes = printable.GetBytes();
                 auto printable_size = printable.GetSize();
                 if (!printable_bytes || !next_data)
@@ -350,19 +375,19 @@
     return true;
 }
 
-lldb_private::formatters::ReadStringAndDumpToStreamOptions::ReadStringAndDumpToStreamOptions (ValueObject& valobj) :
+lldb_private::formatters::StringPrinter::ReadStringAndDumpToStreamOptions::ReadStringAndDumpToStreamOptions (ValueObject& valobj) :
     ReadStringAndDumpToStreamOptions()
 {
     SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
 }
 
-lldb_private::formatters::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (ValueObject& valobj) :
+lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (ValueObject& valobj) :
     ReadBufferAndDumpToStreamOptions()
 {
     SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
 }
 
-lldb_private::formatters::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (const lldb_private::formatters::ReadStringAndDumpToStreamOptions& options) :
+lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (const ReadStringAndDumpToStreamOptions& options) :
     ReadBufferAndDumpToStreamOptions()
 {
     SetStream(options.GetStream());
@@ -370,6 +395,7 @@
     SetQuote(options.GetQuote());
     SetEscapeNonPrintables(options.GetEscapeNonPrintables());
     SetBinaryZeroIsTerminator(options.GetBinaryZeroIsTerminator());
+    SetLanguage(options.GetLanguage());
 }
 
 
@@ -381,7 +407,7 @@
 
 template <>
 bool
-StringPrinter::ReadStringAndDumpToStream<StringElementType::ASCII> (const ReadStringAndDumpToStreamOptions& options)
+StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::ASCII> (const ReadStringAndDumpToStreamOptions& options)
 {
     assert(options.GetStream() && "need a Stream to print the string to");
     Error my_error;
@@ -417,15 +443,25 @@
 
     uint8_t* data_end = buffer_sp->GetBytes()+buffer_sp->GetByteSize();
 
+    const bool escape_non_printables = options.GetEscapeNonPrintables();
+    lldb_private::formatters::StringPrinter::EscapingHelper escaping_callback;
+    if (escape_non_printables)
+    {
+        if (Language *language = Language::FindPlugin(options.GetLanguage()))
+            escaping_callback = language->GetStringPrinterEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::ASCII);
+        else
+            escaping_callback = lldb_private::formatters::StringPrinter::GetDefaultEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::ASCII);
+    }
+    
     // since we tend to accept partial data (and even partially malformed data)
     // we might end up with no NULL terminator before the end_ptr
     // hence we need to take a slower route and ensure we stay within boundaries
     for (uint8_t* data = buffer_sp->GetBytes(); *data && (data < data_end);)
     {
-        if (options.GetEscapeNonPrintables())
+        if (escape_non_printables)
         {
             uint8_t* next_data = nullptr;
-            auto printable = GetPrintable(StringElementType::ASCII, data, data_end, next_data);
+            auto printable = escaping_callback(data, data_end, next_data);
             auto printable_bytes = printable.GetBytes();
             auto printable_size = printable.GetSize();
             if (!printable_bytes || !next_data)
@@ -454,7 +490,7 @@
 
 template<typename SourceDataType>
 static bool
-ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options,
+ReadUTFBufferAndDumpToStream (const StringPrinter::ReadStringAndDumpToStreamOptions& options,
                               ConversionResult (*ConvertFunction) (const SourceDataType**,
                                                                    const SourceDataType*,
                                                                    UTF8**,
@@ -516,7 +552,7 @@
 
     DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
     
-    ReadBufferAndDumpToStreamOptions dump_options(options);
+    StringPrinter::ReadBufferAndDumpToStreamOptions dump_options(options);
     dump_options.SetData(data);
     dump_options.SetSourceSize(sourceSize);
 
@@ -525,7 +561,7 @@
 
 template <>
 bool
-StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8> (const ReadStringAndDumpToStreamOptions& options)
+StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8> (const ReadStringAndDumpToStreamOptions& options)
 {
     return ReadUTFBufferAndDumpToStream<UTF8>(options,
                                               nullptr);
@@ -533,7 +569,7 @@
 
 template <>
 bool
-StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16> (const ReadStringAndDumpToStreamOptions& options)
+StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16> (const ReadStringAndDumpToStreamOptions& options)
 {
     return ReadUTFBufferAndDumpToStream<UTF16>(options,
                                                ConvertUTF16toUTF8);
@@ -541,7 +577,7 @@
 
 template <>
 bool
-StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF32> (const ReadStringAndDumpToStreamOptions& options)
+StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF32> (const ReadStringAndDumpToStreamOptions& options)
 {
     return ReadUTFBufferAndDumpToStream<UTF32>(options,
                                                ConvertUTF32toUTF8);
@@ -549,7 +585,7 @@
 
 template <>
 bool
-StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF8> (const ReadBufferAndDumpToStreamOptions& options)
+StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF8> (const ReadBufferAndDumpToStreamOptions& options)
 {
     assert(options.GetStream() && "need a Stream to print the string to");
 
@@ -558,7 +594,7 @@
 
 template <>
 bool
-StringPrinter::ReadBufferAndDumpToStream<StringElementType::ASCII> (const ReadBufferAndDumpToStreamOptions& options)
+StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::ASCII> (const ReadBufferAndDumpToStreamOptions& options)
 {
     // treat ASCII the same as UTF8
     // FIXME: can we optimize ASCII some more?
@@ -567,7 +603,7 @@
 
 template <>
 bool
-StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF16> (const ReadBufferAndDumpToStreamOptions& options)
+StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF16> (const ReadBufferAndDumpToStreamOptions& options)
 {
     assert(options.GetStream() && "need a Stream to print the string to");
 
@@ -576,7 +612,7 @@
 
 template <>
 bool
-StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF32> (const ReadBufferAndDumpToStreamOptions& options)
+StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF32> (const ReadBufferAndDumpToStreamOptions& options)
 {
     assert(options.GetStream() && "need a Stream to print the string to");