Index: include/lldb/Core/UserSettingsController.h =================================================================== --- include/lldb/Core/UserSettingsController.h +++ include/lldb/Core/UserSettingsController.h @@ -46,6 +46,9 @@ ~Properties() { } + + virtual void + Initialize(const PropertyDefinition *definitions); virtual lldb::OptionValuePropertiesSP GetValueProperties () const Index: include/lldb/Interpreter/CommandInterpreter.h =================================================================== --- include/lldb/Interpreter/CommandInterpreter.h +++ include/lldb/Interpreter/CommandInterpreter.h @@ -195,7 +195,6 @@ class CommandInterpreter : public Broadcaster, - public Properties, public IOHandlerDelegate { public: @@ -449,6 +448,18 @@ const char *help_text, uint32_t max_word_len); + Properties & + GetProperties () + { + return m_properties; + } + + static Properties & + GetGlobalProperties() + { + return m_global_properties; + } + Debugger & GetDebugger () { @@ -619,6 +630,9 @@ bool GetStopCmdSourceOnError () const; + static char + GetEscapeCharacter(); + uint32_t GetNumErrors() const { @@ -676,6 +690,8 @@ Error PreprocessCommand (std::string &command); + Properties m_properties; // The non-global CommandInterpreter properties. + static Properties m_global_properties; // The global CommandInterpreter properties. Debugger &m_debugger; // The debugger session that this interpreter is associated with ExecutionContextRef m_exe_ctx_ref; // The current execution context to use when handling commands bool m_synchronous_execution; Index: include/lldb/Interpreter/OptionValueProperties.h =================================================================== --- include/lldb/Interpreter/OptionValueProperties.h +++ include/lldb/Interpreter/OptionValueProperties.h @@ -181,7 +181,13 @@ bool SetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool new_value); - + + char + GetPropertyAtIndexAsChar (const ExecutionContext *exe_ctx, uint32_t idx, char fail_value) const; + + bool + SetPropertyAtIndexAsChar (const ExecutionContext *exe_ctx, uint32_t idx, char new_value); + OptionValueDictionary * GetPropertyAtIndexAsOptionValueDictionary (const ExecutionContext *exe_ctx, uint32_t idx) const; Index: source/Core/Debugger.cpp =================================================================== --- source/Core/Debugger.cpp +++ source/Core/Debugger.cpp @@ -167,7 +167,7 @@ ePropertyUseExternalEditor, ePropertyUseColor, ePropertyAutoOneLineSummaries, - ePropertyEscapeNonPrintables + ePropertyEscapeNonPrintables, }; Debugger::LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL; @@ -382,6 +382,7 @@ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true); } + #pragma mark Debugger //const DebuggerPropertiesSP & @@ -679,16 +680,21 @@ m_collection_sp->Initialize (g_properties); m_collection_sp->AppendProperty (ConstString("target"), - ConstString("Settings specify to debugging targets."), + ConstString("Settings specific to debugging targets."), true, Target::GetGlobalProperties()->GetValueProperties()); if (m_command_interpreter_ap.get()) { m_collection_sp->AppendProperty (ConstString("interpreter"), - ConstString("Settings specify to the debugger's command interpreter."), + ConstString("Settings specific to the debugger's command interpreter."), true, - m_command_interpreter_ap->GetValueProperties()); + m_command_interpreter_ap->GetProperties().GetValueProperties()); } + m_collection_sp->AppendProperty (ConstString("interpreter-global"), + ConstString("Settings for all command interpreters."), + true, + CommandInterpreter::GetGlobalProperties().GetValueProperties()); + OptionValueSInt64 *term_width = m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64 (NULL, ePropertyTerminalWidth); term_width->SetMinimumValue(10); term_width->SetMaximumValue(1024); Index: source/Core/UserSettingsController.cpp =================================================================== --- source/Core/UserSettingsController.cpp +++ source/Core/UserSettingsController.cpp @@ -23,6 +23,11 @@ using namespace lldb; using namespace lldb_private; +void +Properties::Initialize(const PropertyDefinition *definitions) +{ + m_collection_sp->Initialize(definitions); +} lldb::OptionValueSP Properties::GetPropertyValue (const ExecutionContext *exe_ctx, Index: source/Interpreter/Args.cpp =================================================================== --- source/Interpreter/Args.cpp +++ source/Interpreter/Args.cpp @@ -166,7 +166,8 @@ if (command && command[0]) { static const char *k_space_separators = " \t"; - static const char *k_space_separators_with_slash_and_quotes = " \t \\'\""; + std::string space_separators_with_escape_and_quotes(" \t'\""); + space_separators_with_escape_and_quotes.push_back(CommandInterpreter::GetEscapeCharacter()); const char *arg_end = nullptr; const char *arg_pos; for (arg_pos = command; @@ -202,12 +203,38 @@ do { - arg_end = ::strcspn (arg_pos, k_space_separators_with_slash_and_quotes) + arg_pos; + arg_end = ::strcspn (arg_pos, space_separators_with_escape_and_quotes.c_str()) + arg_pos; switch (arg_end[0]) { default: - assert (!"Unhandled case statement, we must handle this..."); + if (arg_end[0] == CommandInterpreter::GetEscapeCharacter()) + { + switch (arg_end[1]) + { + case '\0': + arg.append (arg_piece_start); + ++arg_end; + arg_complete = true; + break; + + default: + if (quote_char == '\0') + { + arg.append (arg_piece_start, arg_end - arg_piece_start); + if (arg_end[1] != '\0') + { + arg.append (arg_end + 1, 1); + arg_pos = arg_end + 2; + arg_piece_start = arg_pos; + } + } + else + arg_pos = arg_end + 2; + break; + } + } + break; case '\0': @@ -217,33 +244,6 @@ arg_complete = true; break; - case '\\': - // Backslash character - switch (arg_end[1]) - { - case '\0': - arg.append (arg_piece_start); - ++arg_end; - arg_complete = true; - break; - - default: - if (quote_char == '\0') - { - arg.append (arg_piece_start, arg_end - arg_piece_start); - if (arg_end[1] != '\0') - { - arg.append (arg_end + 1, 1); - arg_pos = arg_end + 2; - arg_piece_start = arg_pos; - } - } - else - arg_pos = arg_end + 2; - break; - } - break; - case '"': case '\'': case '`': Index: source/Interpreter/CommandInterpreter.cpp =================================================================== --- source/Interpreter/CommandInterpreter.cpp +++ source/Interpreter/CommandInterpreter.cpp @@ -77,13 +77,26 @@ using namespace lldb; using namespace lldb_private; +#if defined(_WIN32) +#define DEFAULT_ESCAPE_CHARACTER '#' +#else +#define DEFAULT_ESCAPE_CHARACTER '\\' +#endif + static PropertyDefinition g_properties[] = { - { "expand-regex-aliases", OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, regular expression alias commands will show the expanded command that will be executed. This can be used to debug new regular expression alias commands." }, - { "prompt-on-quit", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case." }, - { "stop-command-source-on-error", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, LLDB will stop running a 'command source' script upon encountering an error." }, + { "expand-regex-aliases", OptionValue::eTypeBoolean, false, false, nullptr, nullptr, "If true, regular expression alias commands will show the expanded command that will be executed. This can be used to debug new regular expression alias commands." }, + { "prompt-on-quit", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, "If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case." }, + { "stop-command-source-on-error", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, "If true, LLDB will stop running a 'command source' script upon encountering an error." }, + { nullptr , OptionValue::eTypeInvalid, true, 0 , nullptr, nullptr, nullptr } +}; + +static PropertyDefinition +g_global_properties[] = +{ + { "escape-character", OptionValue::eTypeChar, true, DEFAULT_ESCAPE_CHARACTER, nullptr, nullptr, "The character LLDB will recognize as an escape character while parsing command arguments" }, { nullptr , OptionValue::eTypeInvalid, true, 0 , nullptr, nullptr, nullptr } }; @@ -91,9 +104,17 @@ { ePropertyExpandRegexAliases = 0, ePropertyPromptOnQuit = 1, - ePropertyStopCmdSourceOnError = 2 + ePropertyStopCmdSourceOnError = 2, +}; + +enum +{ + eGlobalPropertyEscapeCharacter = 0, }; +Properties CommandInterpreter::m_global_properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter-global")))); + + ConstString & CommandInterpreter::GetStaticBroadcasterClass () { @@ -108,7 +129,6 @@ bool synchronous_execution ) : Broadcaster (&debugger, "lldb.command-interpreter"), - Properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))), IOHandlerDelegate (IOHandlerDelegate::Completion::LLDBCommand), m_debugger (debugger), m_synchronous_execution (synchronous_execution), @@ -122,36 +142,45 @@ m_command_source_depth (0), m_num_errors(0), m_quit_requested(false), - m_stopped_for_crash(false) - + m_stopped_for_crash(false), + m_properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))) { debugger.SetScriptLanguage (script_language); SetEventName (eBroadcastBitThreadShouldExit, "thread-should-exit"); SetEventName (eBroadcastBitResetPrompt, "reset-prompt"); SetEventName (eBroadcastBitQuitCommandReceived, "quit"); CheckInWithManager (); - m_collection_sp->Initialize (g_properties); + m_properties.Initialize(g_properties); + m_global_properties.Initialize(g_global_properties); } bool CommandInterpreter::GetExpandRegexAliases () const { const uint32_t idx = ePropertyExpandRegexAliases; - return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0); + return m_properties.GetValueProperties()->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0); } bool CommandInterpreter::GetPromptOnQuit () const { const uint32_t idx = ePropertyPromptOnQuit; - return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0); + return m_properties.GetValueProperties()->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0); } bool CommandInterpreter::GetStopCmdSourceOnError () const { const uint32_t idx = ePropertyStopCmdSourceOnError; - return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0); + return m_properties.GetValueProperties()->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0); +} + +char +CommandInterpreter::GetEscapeCharacter() +{ + const uint32_t idx = eGlobalPropertyEscapeCharacter; + lldb::OptionValuePropertiesSP value_props = m_global_properties.GetValueProperties(); + return value_props->GetPropertyAtIndexAsChar(NULL, idx, static_cast(g_global_properties[idx].default_uint_value)); } void Index: source/Interpreter/OptionValueProperties.cpp =================================================================== --- source/Interpreter/OptionValueProperties.cpp +++ source/Interpreter/OptionValueProperties.cpp @@ -376,6 +376,35 @@ return false; } +char +OptionValueProperties::GetPropertyAtIndexAsChar (const ExecutionContext *exe_ctx, uint32_t idx, char fail_value) const +{ + const Property *property = GetPropertyAtIndex (exe_ctx, false, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetCharValue(fail_value); + } + return fail_value; +} + +bool +OptionValueProperties::SetPropertyAtIndexAsChar(const ExecutionContext *exe_ctx, uint32_t idx, char new_value) +{ + const Property *property = GetPropertyAtIndex (exe_ctx, true, idx); + if (property) + { + OptionValue *value = property->GetValue().get(); + if (value) + { + value->SetCharValue(new_value); + return true; + } + } + return false; +} + OptionValueDictionary * OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary (const ExecutionContext *exe_ctx, uint32_t idx) const { Index: source/Interpreter/Property.cpp =================================================================== --- source/Interpreter/Property.cpp +++ source/Interpreter/Property.cpp @@ -62,7 +62,7 @@ break; case OptionValue::eTypeChar: - m_value_sp.reset(new OptionValueChar(Args::StringToChar(definition.default_cstr_value, '\0', nullptr))); + m_value_sp.reset(new OptionValueChar(static_cast(definition.default_uint_value))); break; case OptionValue::eTypeDictionary: