Made it so changes to the prompt via "settings set prompt" get noticed by the command line.

Added the ability for OptionValueString objects to take flags. The only flag is currently for parsing escape sequences. Not the prompt string can have escape characters translate which will allow colors in the prompt.

Added functions to Args that will parse the escape sequences in a string, and also re-encode the escape sequences for display. This was looted from other parts of LLDB (the Debugger::FormatString() function).

llvm-svn: 163043
This commit is contained in:
Greg Clayton 2012-09-01 00:38:36 +00:00
parent c373ca5c74
commit 4c05410f8f
11 changed files with 270 additions and 20 deletions

View File

@ -262,6 +262,12 @@ public:
eStopDisassemblyTypeAlways
};
virtual Error
SetPropertyValue (const ExecutionContext *exe_ctx,
VarSetOperationType op,
const char *property_path,
const char *value);
bool
GetAutoConfirm () const;

View File

@ -411,6 +411,25 @@ public:
static const char *
GetShellSafeArgument (const char *unsafe_arg, std::string &safe_arg);
// EncodeEscapeSequences will change the textual representation of common
// escape sequences like "\n" (two characters) into a single '\n'. It does
// this for all of the supported escaped sequences and for the \0ooo (octal)
// and \xXX (hex). The resulting "dst" string will contain the character
// versions of all supported escape sequences. The common supported escape
// sequences are: "\a", "\b", "\f", "\n", "\r", "\t", "\v", "\'", "\"", "\\".
static void
EncodeEscapeSequences (const char *src, std::string &dst);
// ExpandEscapeSequences will change a string of possibly non-printable
// characters and expand them into text. So '\n' will turn into two chracters
// like "\n" which is suitable for human reading. When a character is not
// printable and isn't one of the common in escape sequences listed in the
// help for EncodeEscapeSequences, then it will be encoded as octal. Printable
// characters are left alone.
static void
ExpandEscapedCharacters (const char *src, std::string &dst);
// This one isn't really relevant to Arguments per se, but we're using the Args as a
// general strings container, so...
void

View File

@ -210,7 +210,10 @@ public:
bool
SetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *new_value);
OptionValueString *
GetPropertyAtIndexAsOptionValueString (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const;
OptionValueFileSpec *
GetPropertyAtIndexAsOptionValueFileSpec (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const;

View File

@ -16,6 +16,7 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Flags.h"
#include "lldb/Interpreter/OptionValue.h"
namespace lldb_private {
@ -23,17 +24,24 @@ namespace lldb_private {
class OptionValueString : public OptionValue
{
public:
enum Options
{
eOptionEncodeCharacterEscapeSequences = (1u << 0)
};
OptionValueString () :
OptionValue(),
m_current_value (),
m_default_value ()
m_default_value (),
m_options()
{
}
OptionValueString (const char *value) :
OptionValue(),
m_current_value (),
m_default_value ()
m_default_value (),
m_options()
{
if (value && value[0])
{
@ -46,7 +54,8 @@ public:
const char *default_value) :
OptionValue(),
m_current_value (),
m_default_value ()
m_default_value (),
m_options()
{
if (current_value && current_value[0])
m_current_value.assign (current_value);
@ -90,6 +99,18 @@ public:
//---------------------------------------------------------------------
// Subclass specific functions
//---------------------------------------------------------------------
Flags &
GetOptions ()
{
return m_options;
}
const Flags &
GetOptions () const
{
return m_options;
}
const char *
operator = (const char *value)
@ -154,6 +175,7 @@ public:
protected:
std::string m_current_value;
std::string m_default_value;
Flags m_options;
};
} // namespace lldb_private

View File

@ -112,7 +112,7 @@ g_properties[] =
{ "auto-confirm", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." },
{ "frame-format", OptionValue::eTypeString , true, 0 , DEFAULT_FRAME_FORMAT, NULL, "The default frame format string to use when displaying stack frame information for threads." },
{ "notify-void", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Notify the user explicitly if an expression returns void (default: false)." },
{ "prompt", OptionValue::eTypeString , true, 0 , "(lldb) ", NULL, "The debugger command line prompt displayed for the user." },
{ "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", NULL, "The debugger command line prompt displayed for the user." },
{ "script-lang", OptionValue::eTypeEnum , true, eScriptLanguagePython, NULL, g_language_enumerators, "The script language to be used for evaluating user-written scripts." },
{ "stop-disassembly-count", OptionValue::eTypeSInt64 , true, 4 , NULL, NULL, "The number of disassembly lines to show when displaying a stopped context." },
{ "stop-disassembly-display", OptionValue::eTypeEnum , true, Debugger::eStopDisassemblyTypeNoSource, NULL, g_show_disassembly_enum_values, "Control when to display disassembly when displaying a stopped context." },
@ -152,6 +152,27 @@ enum
// return m_properties_sp->GetThreadFormat();
//}
//
Error
Debugger::SetPropertyValue (const ExecutionContext *exe_ctx,
VarSetOperationType op,
const char *property_path,
const char *value)
{
Error error (Properties::SetPropertyValue (exe_ctx, op, property_path, value));
if (error.Success())
{
if (strcmp(property_path, g_properties[ePropertyPrompt].name) == 0)
{
const char *new_prompt = GetPrompt();
EventSP prompt_change_event_sp (new Event(CommandInterpreter::eBroadcastBitResetPrompt, new EventDataBytes (new_prompt)));
GetCommandInterpreter().BroadcastEvent (prompt_change_event_sp);
}
}
return error;
}
bool
Debugger::GetAutoConfirm () const
{

View File

@ -1528,3 +1528,137 @@ Args::ParseArgsForCompletion
}
}
void
Args::EncodeEscapeSequences (const char *src, std::string &dst)
{
dst.clear();
if (src)
{
for (const char *p = src; *p != '\0'; ++p)
{
size_t non_special_chars = ::strcspn (p, "\\");
if (non_special_chars > 0)
{
dst.append(p, non_special_chars);
p += non_special_chars;
if (*p == '\0')
break;
}
if (*p == '\\')
{
++p; // skip the slash
switch (*p)
{
case 'a' : dst.append(1, '\a'); break;
case 'b' : dst.append(1, '\b'); break;
case 'f' : dst.append(1, '\f'); break;
case 'n' : dst.append(1, '\n'); break;
case 'r' : dst.append(1, '\r'); break;
case 't' : dst.append(1, '\t'); break;
case 'v' : dst.append(1, '\v'); break;
case '\\': dst.append(1, '\\'); break;
case '\'': dst.append(1, '\''); break;
case '"' : dst.append(1, '"'); break;
case '0' :
// 1 to 3 octal chars
{
// Make a string that can hold onto the initial zero char,
// up to 3 octal digits, and a terminating NULL.
char oct_str[5] = { '\0', '\0', '\0', '\0', '\0' };
int i;
for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i)
oct_str[i] = p[i];
// We don't want to consume the last octal character since
// the main for loop will do this for us, so we advance p by
// one less than i (even if i is zero)
p += i - 1;
unsigned long octal_value = ::strtoul (oct_str, NULL, 8);
if (octal_value <= UINT8_MAX)
{
const char octal_char = octal_value;
dst.append(1, octal_char);
}
}
break;
case 'x':
// hex number in the format
if (isxdigit(p[1]))
{
++p; // Skip the 'x'
// Make a string that can hold onto two hex chars plus a
// NULL terminator
char hex_str[3] = { *p, '\0', '\0' };
if (isxdigit(p[1]))
{
++p; // Skip the first of the two hex chars
hex_str[1] = *p;
}
unsigned long hex_value = strtoul (hex_str, NULL, 16);
if (hex_value <= UINT8_MAX)
dst.append (1, (char)hex_value);
}
else
{
dst.append(1, 'x');
}
break;
default:
// Just desensitize any other character by just printing what
// came after the '\'
dst.append(1, *p);
break;
}
}
}
}
}
void
Args::ExpandEscapedCharacters (const char *src, std::string &dst)
{
dst.clear();
if (src)
{
for (const char *p = src; *p != '\0'; ++p)
{
if (isprint(*p))
dst.append(1, *p);
else
{
switch (*p)
{
case '\a': dst.append("\\a"); break;
case '\b': dst.append("\\b"); break;
case '\f': dst.append("\\f"); break;
case '\n': dst.append("\\n"); break;
case '\r': dst.append("\\r"); break;
case '\t': dst.append("\\t"); break;
case '\v': dst.append("\\v"); break;
case '\'': dst.append("\\'"); break;
case '"': dst.append("\\\""); break;
case '\\': dst.append("\\\\"); break;
default:
{
// Just encode as octal
dst.append("\\0");
char octal_str[32];
snprintf(octal_str, sizeof(octal_str), "%o", *p);
dst.append(octal_str);
}
break;
}
}
}
}
}

View File

@ -106,11 +106,12 @@ CommandReturnObject::AppendWarningWithFormat (const char *format, ...)
void
CommandReturnObject::AppendMessage (const char *in_string, int len)
{
if (!in_string)
if (!in_string || len == 0)
return;
if (len < 0)
len = ::strlen (in_string);
GetOutputStream().Printf("%*.*s\n", len, len, in_string);
GetOutputStream().Printf("%s\n", in_string);
else
GetOutputStream().Printf("%*.*s\n", len, len, in_string);
}
void

View File

@ -526,6 +526,16 @@ OptionValueProperties::SetPropertyAtIndexAsString (const ExecutionContext *exe_c
return false;
}
OptionValueString *
OptionValueProperties::GetPropertyAtIndexAsOptionValueString (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
{
OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
if (value_sp)
return value_sp->GetAsString();
return NULL;
}
uint64_t
OptionValueProperties::GetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t fail_value) const
{

View File

@ -14,6 +14,7 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Stream.h"
#include "lldb/Interpreter/Args.h"
using namespace lldb;
using namespace lldb_private;
@ -29,10 +30,22 @@ OptionValueString::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uin
strm.PutCString (" = ");
if (!m_current_value.empty() || m_value_was_set)
{
if (dump_mask & eDumpOptionRaw)
strm.Printf ("%s", m_current_value.c_str());
if (m_options.Test (eOptionEncodeCharacterEscapeSequences))
{
std::string expanded_escape_value;
Args::ExpandEscapedCharacters(m_current_value.c_str(), expanded_escape_value);
if (dump_mask & eDumpOptionRaw)
strm.Printf ("%s", expanded_escape_value.c_str());
else
strm.Printf ("\"%s\"", expanded_escape_value.c_str());
}
else
strm.Printf ("\"%s\"", m_current_value.c_str());
{
if (dump_mask & eDumpOptionRaw)
strm.Printf ("%s", m_current_value.c_str());
else
strm.Printf ("\"%s\"", m_current_value.c_str());
}
}
}
}
@ -53,7 +66,16 @@ OptionValueString::SetValueFromCString (const char *value_cstr,
case eVarSetOperationAppend:
if (value_cstr && value_cstr[0])
m_current_value += value_cstr;
{
if (m_options.Test (eOptionEncodeCharacterEscapeSequences))
{
std::string str;
Args::EncodeEscapeSequences (value_cstr, str);
m_current_value += str;
}
else
m_current_value += value_cstr;
}
break;
case eVarSetOperationClear:
@ -63,7 +85,14 @@ OptionValueString::SetValueFromCString (const char *value_cstr,
case eVarSetOperationReplace:
case eVarSetOperationAssign:
m_value_was_set = true;
SetCurrentValue (value_cstr);
if (m_options.Test (eOptionEncodeCharacterEscapeSequences))
{
Args::EncodeEscapeSequences (value_cstr, m_current_value);
}
else
{
SetCurrentValue (value_cstr);
}
break;
}
return error;

View File

@ -154,9 +154,14 @@ Property::Property (const PropertyDefinition &definition) :
break;
case OptionValue::eTypeString:
// "definition.default_uint_value" is not used for a OptionValueFileSpecList
// "definition.default_uint_value" can contain the string option flags OR'ed together
// "definition.default_cstr_value" can contain a default string value
m_value_sp.reset (new OptionValueString(definition.default_cstr_value));
{
OptionValueString *string_value = new OptionValueString(definition.default_cstr_value);
if (definition.default_uint_value != 0)
string_value->GetOptions().Reset(definition.default_uint_value);
m_value_sp.reset (string_value);
}
break;
}
}

View File

@ -376,11 +376,11 @@ ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback
break;
case eInputReaderReactivate:
{
ScriptInterpreterPython::Locker locker(script_interpreter,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock);
}
// {
// ScriptInterpreterPython::Locker locker(script_interpreter,
// ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
// ScriptInterpreterPython::Locker::FreeAcquiredLock);
// }
break;
case eInputReaderAsynchronousOutputWritten: