diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp | 3631 |
1 files changed, 1646 insertions, 1985 deletions
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp index dd2fd9a..aa07c10 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp @@ -1,4 +1,4 @@ -//===-- CommandObjectSource.cpp ---------------------------------*- C++ -*-===// +//===-- CommandObjectCommands.cpp -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -36,386 +36,305 @@ using namespace lldb_private; // CommandObjectCommandsSource //------------------------------------------------------------------------- -class CommandObjectCommandsHistory : public CommandObjectParsed -{ +static OptionDefinition g_history_options[] = { + // clang-format off + { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "How many history commands to print." }, + { LLDB_OPT_SET_1, false, "start-index", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)." }, + { LLDB_OPT_SET_1, false, "end-index", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands." }, + { LLDB_OPT_SET_2, false, "clear", 'C', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Clears the current command history." }, + // clang-format on +}; + +class CommandObjectCommandsHistory : public CommandObjectParsed { public: - CommandObjectCommandsHistory(CommandInterpreter &interpreter) : - CommandObjectParsed(interpreter, - "command history", + CommandObjectCommandsHistory(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "command history", "Dump the history of commands in this session.", nullptr), - m_options (interpreter) - { - } + m_options() {} - ~CommandObjectCommandsHistory() override = default; + ~CommandObjectCommandsHistory() override = default; - Options * - GetOptions () override - { - return &m_options; - } + Options *GetOptions() override { return &m_options; } protected: - class CommandOptions : public Options - { - public: - CommandOptions (CommandInterpreter &interpreter) : - Options (interpreter), - m_start_idx(0), - m_stop_idx(0), - m_count(0), - m_clear(false) - { - } + class CommandOptions : public Options { + public: + CommandOptions() + : Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) { + } - ~CommandOptions() override = default; - - Error - SetOptionValue (uint32_t option_idx, const char *option_arg) override - { - Error error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) - { - case 'c': - error = m_count.SetValueFromString(option_arg,eVarSetOperationAssign); - break; - case 's': - if (option_arg && strcmp("end", option_arg) == 0) - { - m_start_idx.SetCurrentValue(UINT64_MAX); - m_start_idx.SetOptionWasSet(); - } - else - error = m_start_idx.SetValueFromString(option_arg,eVarSetOperationAssign); - break; - case 'e': - error = m_stop_idx.SetValueFromString(option_arg,eVarSetOperationAssign); - break; - case 'C': - m_clear.SetCurrentValue(true); - m_clear.SetOptionWasSet(); - break; - default: - error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); - break; - } - - return error; - } + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'c': + error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign); + break; + case 's': + if (option_arg == "end") { + m_start_idx.SetCurrentValue(UINT64_MAX); + m_start_idx.SetOptionWasSet(); + } else + error = m_start_idx.SetValueFromString(option_arg, + eVarSetOperationAssign); + break; + case 'e': + error = + m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign); + break; + case 'C': + m_clear.SetCurrentValue(true); + m_clear.SetOptionWasSet(); + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + + return error; + } - void - OptionParsingStarting () override - { - m_start_idx.Clear(); - m_stop_idx.Clear(); - m_count.Clear(); - m_clear.Clear(); - } + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_start_idx.Clear(); + m_stop_idx.Clear(); + m_count.Clear(); + m_clear.Clear(); + } - const OptionDefinition* - GetDefinitions () override - { - return g_option_table; - } + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_history_options); + } - // Options table: Required for subclasses of Options. - - static OptionDefinition g_option_table[]; - - // Instance variables to hold the values for command options. - - OptionValueUInt64 m_start_idx; - OptionValueUInt64 m_stop_idx; - OptionValueUInt64 m_count; - OptionValueBoolean m_clear; - }; - - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - if (m_options.m_clear.GetCurrentValue() && m_options.m_clear.OptionWasSet()) - { - m_interpreter.GetCommandHistory().Clear(); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - } - else - { - if (m_options.m_start_idx.OptionWasSet() && m_options.m_stop_idx.OptionWasSet() && m_options.m_count.OptionWasSet()) - { - result.AppendError("--count, --start-index and --end-index cannot be all specified in the same invocation"); - result.SetStatus(lldb::eReturnStatusFailed); + // Instance variables to hold the values for command options. + + OptionValueUInt64 m_start_idx; + OptionValueUInt64 m_stop_idx; + OptionValueUInt64 m_count; + OptionValueBoolean m_clear; + }; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (m_options.m_clear.GetCurrentValue() && + m_options.m_clear.OptionWasSet()) { + m_interpreter.GetCommandHistory().Clear(); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + } else { + if (m_options.m_start_idx.OptionWasSet() && + m_options.m_stop_idx.OptionWasSet() && + m_options.m_count.OptionWasSet()) { + result.AppendError("--count, --start-index and --end-index cannot be " + "all specified in the same invocation"); + result.SetStatus(lldb::eReturnStatusFailed); + } else { + std::pair<bool, uint64_t> start_idx( + m_options.m_start_idx.OptionWasSet(), + m_options.m_start_idx.GetCurrentValue()); + std::pair<bool, uint64_t> stop_idx( + m_options.m_stop_idx.OptionWasSet(), + m_options.m_stop_idx.GetCurrentValue()); + std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(), + m_options.m_count.GetCurrentValue()); + + const CommandHistory &history(m_interpreter.GetCommandHistory()); + + if (start_idx.first && start_idx.second == UINT64_MAX) { + if (count.first) { + start_idx.second = history.GetSize() - count.second; + stop_idx.second = history.GetSize() - 1; + } else if (stop_idx.first) { + start_idx.second = stop_idx.second; + stop_idx.second = history.GetSize() - 1; + } else { + start_idx.second = 0; + stop_idx.second = history.GetSize() - 1; + } + } else { + if (!start_idx.first && !stop_idx.first && !count.first) { + start_idx.second = 0; + stop_idx.second = history.GetSize() - 1; + } else if (start_idx.first) { + if (count.first) { + stop_idx.second = start_idx.second + count.second - 1; + } else if (!stop_idx.first) { + stop_idx.second = history.GetSize() - 1; } - else - { - std::pair<bool,uint64_t> start_idx(m_options.m_start_idx.OptionWasSet(),m_options.m_start_idx.GetCurrentValue()); - std::pair<bool,uint64_t> stop_idx(m_options.m_stop_idx.OptionWasSet(),m_options.m_stop_idx.GetCurrentValue()); - std::pair<bool,uint64_t> count(m_options.m_count.OptionWasSet(),m_options.m_count.GetCurrentValue()); - - const CommandHistory& history(m_interpreter.GetCommandHistory()); - - if (start_idx.first && start_idx.second == UINT64_MAX) - { - if (count.first) - { - start_idx.second = history.GetSize() - count.second; - stop_idx.second = history.GetSize() - 1; - } - else if (stop_idx.first) - { - start_idx.second = stop_idx.second; - stop_idx.second = history.GetSize() - 1; - } - else - { - start_idx.second = 0; - stop_idx.second = history.GetSize() - 1; - } - } - else - { - if (!start_idx.first && !stop_idx.first && !count.first) - { - start_idx.second = 0; - stop_idx.second = history.GetSize() - 1; - } - else if (start_idx.first) - { - if (count.first) - { - stop_idx.second = start_idx.second + count.second - 1; - } - else if (!stop_idx.first) - { - stop_idx.second = history.GetSize() - 1; - } - } - else if (stop_idx.first) - { - if (count.first) - { - if (stop_idx.second >= count.second) - start_idx.second = stop_idx.second - count.second + 1; - else - start_idx.second = 0; - } - } - else /* if (count.first) */ - { - start_idx.second = 0; - stop_idx.second = count.second - 1; - } - } - history.Dump(result.GetOutputStream(), start_idx.second, stop_idx.second); + } else if (stop_idx.first) { + if (count.first) { + if (stop_idx.second >= count.second) + start_idx.second = stop_idx.second - count.second + 1; + else + start_idx.second = 0; } - } - return result.Succeeded(); - + } else /* if (count.first) */ + { + start_idx.second = 0; + stop_idx.second = count.second - 1; + } + } + history.Dump(result.GetOutputStream(), start_idx.second, + stop_idx.second); + } } + return result.Succeeded(); + } - CommandOptions m_options; -}; - -OptionDefinition -CommandObjectCommandsHistory::CommandOptions::g_option_table[] = -{ -{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "How many history commands to print."}, -{ LLDB_OPT_SET_1, false, "start-index", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)."}, -{ LLDB_OPT_SET_1, false, "end-index", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands."}, -{ LLDB_OPT_SET_2, false, "clear", 'C', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Clears the current command history."}, -{ 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } + CommandOptions m_options; }; //------------------------------------------------------------------------- // CommandObjectCommandsSource //------------------------------------------------------------------------- -class CommandObjectCommandsSource : public CommandObjectParsed -{ +static OptionDefinition g_source_options[] = { + // clang-format off + { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on error." }, + { LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on continue." }, + { LLDB_OPT_SET_ALL, false, "silent-run", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true don't echo commands while executing." }, + // clang-format on +}; + +class CommandObjectCommandsSource : public CommandObjectParsed { public: - CommandObjectCommandsSource(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "command source", "Read and execute LLDB commands from the file <filename>.", - nullptr), - m_options(interpreter) - { - CommandArgumentEntry arg; - CommandArgumentData file_arg; - - // Define the first (and only) variant of this arg. - file_arg.arg_type = eArgTypeFilename; - file_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (file_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); - } - - ~CommandObjectCommandsSource() override = default; - - const char* - GetRepeatCommand (Args ¤t_command_args, uint32_t index) override - { - return ""; - } - - int - HandleArgumentCompletion (Args &input, - int &cursor_index, - int &cursor_char_position, - OptionElementVector &opt_element_vector, - int match_start_point, - int max_return_elements, - bool &word_complete, - StringList &matches) override - { - std::string completion_str (input.GetArgumentAtIndex(cursor_index)); - completion_str.erase (cursor_char_position); - - CommandCompletions::InvokeCommonCompletionCallbacks(m_interpreter, - CommandCompletions::eDiskFileCompletion, - completion_str.c_str(), - match_start_point, - max_return_elements, - nullptr, - word_complete, - matches); - return matches.GetSize(); - } - - Options * - GetOptions () override - { - return &m_options; - } + CommandObjectCommandsSource(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "command source", + "Read and execute LLDB commands from the file <filename>.", + nullptr), + m_options() { + CommandArgumentEntry arg; + CommandArgumentData file_arg; + + // Define the first (and only) variant of this arg. + file_arg.arg_type = eArgTypeFilename; + file_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg.push_back(file_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg); + } + + ~CommandObjectCommandsSource() override = default; + + const char *GetRepeatCommand(Args ¤t_command_args, + uint32_t index) override { + return ""; + } + + int HandleArgumentCompletion(Args &input, int &cursor_index, + int &cursor_char_position, + OptionElementVector &opt_element_vector, + int match_start_point, int max_return_elements, + bool &word_complete, + StringList &matches) override { + auto completion_str = input[cursor_index].ref; + completion_str = completion_str.take_front(cursor_char_position); + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + completion_str, match_start_point, max_return_elements, nullptr, + word_complete, matches); + return matches.GetSize(); + } + + Options *GetOptions() override { return &m_options; } protected: - class CommandOptions : public Options - { - public: - CommandOptions (CommandInterpreter &interpreter) : - Options (interpreter), - m_stop_on_error (true), - m_silent_run (false), - m_stop_on_continue (true) - { - } + class CommandOptions : public Options { + public: + CommandOptions() + : Options(), m_stop_on_error(true), m_silent_run(false), + m_stop_on_continue(true) {} + + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'e': + error = m_stop_on_error.SetValueFromString(option_arg); + break; + + case 'c': + error = m_stop_on_continue.SetValueFromString(option_arg); + break; + + case 's': + error = m_silent_run.SetValueFromString(option_arg); + break; + + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + + return error; + } - ~CommandOptions() override = default; - - Error - SetOptionValue (uint32_t option_idx, const char *option_arg) override - { - Error error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) - { - case 'e': - error = m_stop_on_error.SetValueFromString(option_arg); - break; - - case 'c': - error = m_stop_on_continue.SetValueFromString(option_arg); - break; - - case 's': - error = m_silent_run.SetValueFromString(option_arg); - break; - - default: - error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); - break; - } - - return error; - } + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_stop_on_error.Clear(); + m_silent_run.Clear(); + m_stop_on_continue.Clear(); + } - void - OptionParsingStarting () override - { - m_stop_on_error.Clear(); - m_silent_run.Clear(); - m_stop_on_continue.Clear(); - } + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_source_options); + } - const OptionDefinition* - GetDefinitions () override - { - return g_option_table; - } + // Instance variables to hold the values for command options. - // Options table: Required for subclasses of Options. - - static OptionDefinition g_option_table[]; - - // Instance variables to hold the values for command options. - - OptionValueBoolean m_stop_on_error; - OptionValueBoolean m_silent_run; - OptionValueBoolean m_stop_on_continue; - }; - - bool - DoExecute(Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc == 1) - { - const char *filename = command.GetArgumentAtIndex(0); - - FileSpec cmd_file (filename, true); - ExecutionContext *exe_ctx = nullptr; // Just use the default context. - - // If any options were set, then use them - if (m_options.m_stop_on_error.OptionWasSet() || - m_options.m_silent_run.OptionWasSet() || - m_options.m_stop_on_continue.OptionWasSet()) - { - // Use user set settings - CommandInterpreterRunOptions options; - options.SetStopOnContinue(m_options.m_stop_on_continue.GetCurrentValue()); - options.SetStopOnError (m_options.m_stop_on_error.GetCurrentValue()); - options.SetEchoCommands (!m_options.m_silent_run.GetCurrentValue()); - options.SetPrintResults (!m_options.m_silent_run.GetCurrentValue()); - - m_interpreter.HandleCommandsFromFile (cmd_file, - exe_ctx, - options, - result); - } - else - { - // No options were set, inherit any settings from nested "command source" commands, - // or set to sane default settings... - CommandInterpreterRunOptions options; - m_interpreter.HandleCommandsFromFile (cmd_file, - exe_ctx, - options, - result); - } - } - else - { - result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName()); - result.SetStatus (eReturnStatusFailed); - } - return result.Succeeded(); + OptionValueBoolean m_stop_on_error; + OptionValueBoolean m_silent_run; + OptionValueBoolean m_stop_on_continue; + }; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (command.GetArgumentCount() != 1) { + result.AppendErrorWithFormat( + "'%s' takes exactly one executable filename argument.\n", + GetCommandName().str().c_str()); + result.SetStatus(eReturnStatusFailed); + return false; } - CommandOptions m_options; -}; + FileSpec cmd_file(command[0].ref, true); + ExecutionContext *exe_ctx = nullptr; // Just use the default context. + + // If any options were set, then use them + if (m_options.m_stop_on_error.OptionWasSet() || + m_options.m_silent_run.OptionWasSet() || + m_options.m_stop_on_continue.OptionWasSet()) { + // Use user set settings + CommandInterpreterRunOptions options; + options.SetStopOnContinue(m_options.m_stop_on_continue.GetCurrentValue()); + options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue()); + options.SetEchoCommands(!m_options.m_silent_run.GetCurrentValue()); + options.SetPrintResults(!m_options.m_silent_run.GetCurrentValue()); + + m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result); + } else { + // No options were set, inherit any settings from nested "command + // source" commands, + // or set to sane default settings... + CommandInterpreterRunOptions options; + m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result); + } + return result.Succeeded(); + } -OptionDefinition -CommandObjectCommandsSource::CommandOptions::g_option_table[] = -{ -{ LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on error."}, -{ LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on continue."}, -{ LLDB_OPT_SET_ALL, false, "silent-run", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true don't echo commands while executing."}, -{ 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } + CommandOptions m_options; }; #pragma mark CommandObjectCommandsAlias @@ -423,102 +342,85 @@ CommandObjectCommandsSource::CommandOptions::g_option_table[] = // CommandObjectCommandsAlias //------------------------------------------------------------------------- -static const char *g_python_command_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" - "You must define a Python function with this signature:\n" - "def my_command_impl(debugger, args, result, internal_dict):\n"; +static OptionDefinition g_alias_options[] = { + // clang-format off + { LLDB_OPT_SET_ALL, false, "help", 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Help text for this command" }, + { LLDB_OPT_SET_ALL, false, "long-help", 'H', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Long help text for this command" }, + // clang-format on +}; + +static const char *g_python_command_instructions = + "Enter your Python command(s). Type 'DONE' to end.\n" + "You must define a Python function with this signature:\n" + "def my_command_impl(debugger, args, result, internal_dict):\n"; -class CommandObjectCommandsAlias : public CommandObjectRaw -{ +class CommandObjectCommandsAlias : public CommandObjectRaw { protected: - class CommandOptions : public OptionGroup - { - public: - CommandOptions () : - OptionGroup(), - m_help(), - m_long_help() - {} - - ~CommandOptions() override = default; - - uint32_t - GetNumDefinitions () override - { - return 3; - } - - const OptionDefinition* - GetDefinitions () override - { - return g_option_table; - } - - Error - SetOptionValue (CommandInterpreter &interpreter, - uint32_t option_idx, - const char *option_value) override - { - Error error; - - const int short_option = g_option_table[option_idx].short_option; - - switch (short_option) - { - case 'h': - m_help.SetCurrentValue(option_value); - m_help.SetOptionWasSet(); - break; - - case 'H': - m_long_help.SetCurrentValue(option_value); - m_long_help.SetOptionWasSet(); - break; - - default: - error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); - break; - } - - return error; - } - - void - OptionParsingStarting (CommandInterpreter &interpreter) override - { - m_help.Clear(); - m_long_help.Clear(); - } - - // Options table: Required for subclasses of Options. - - static OptionDefinition g_option_table[]; - OptionValueString m_help; - OptionValueString m_long_help; - }; - - OptionGroupOptions m_option_group; - CommandOptions m_command_options; - + class CommandOptions : public OptionGroup { + public: + CommandOptions() : OptionGroup(), m_help(), m_long_help() {} + + ~CommandOptions() override = default; + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_alias_options); + } + + Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override { + Error error; + + const int short_option = GetDefinitions()[option_idx].short_option; + std::string option_str(option_value); + + switch (short_option) { + case 'h': + m_help.SetCurrentValue(option_str); + m_help.SetOptionWasSet(); + break; + + case 'H': + m_long_help.SetCurrentValue(option_str); + m_long_help.SetOptionWasSet(); + break; + + default: + error.SetErrorStringWithFormat("invalid short option character '%c'", + short_option); + break; + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_help.Clear(); + m_long_help.Clear(); + } + + OptionValueString m_help; + OptionValueString m_long_help; + }; + + OptionGroupOptions m_option_group; + CommandOptions m_command_options; + public: - Options * - GetOptions () override - { - return &m_option_group; - } - - CommandObjectCommandsAlias(CommandInterpreter &interpreter) - : CommandObjectRaw(interpreter, "command alias", "Define a custom command in terms of an existing command.", - nullptr), - m_option_group(interpreter), - m_command_options() - { - m_option_group.Append(&m_command_options); - m_option_group.Finalize(); - - SetHelpLong( -"'alias' allows the user to create a short-cut or abbreviation for long \ + Options *GetOptions() override { return &m_option_group; } + + CommandObjectCommandsAlias(CommandInterpreter &interpreter) + : CommandObjectRaw( + interpreter, "command alias", + "Define a custom command in terms of an existing command."), + m_option_group(), m_command_options() { + m_option_group.Append(&m_command_options); + m_option_group.Finalize(); + + SetHelpLong( + "'alias' allows the user to create a short-cut or abbreviation for long \ commands, multi-word commands, and commands that take particular options. \ -Below are some simple examples of how one might use the 'alias' command:" R"( +Below are some simple examples of how one might use the 'alias' command:" + R"( (lldb) command alias sc script @@ -526,22 +428,27 @@ Below are some simple examples of how one might use the 'alias' command:" R"( (lldb) command alias bp breakpoint -)" " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \ +)" + " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \ breakpoint commands are two-word commands, the user would still need to \ -enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." R"( +enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." + R"( (lldb) command alias bpl breakpoint list Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'. -)" "An alias can include some options for the command, with the values either \ +)" + "An alias can include some options for the command, with the values either \ filled in at the time the alias is created, or specified as positional \ arguments, to be filled in when the alias is invoked. The following example \ -shows how to create aliases with options:" R"( +shows how to create aliases with options:" + R"( (lldb) command alias bfl breakpoint set -f %1 -l %2 -)" " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \ +)" + " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \ options already part of the alias. So if the user wants to set a breakpoint \ by file and line without explicitly having to use the -f and -l options, the \ user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \ @@ -551,18 +458,23 @@ occupies when the alias is used. All the occurrences of '%1' in the alias \ will be replaced with the first argument, all the occurrences of '%2' in the \ alias will be replaced with the second argument, and so on. This also allows \ actual arguments to be used multiple times within an alias (see 'process \ -launch' example below)." R"( +launch' example below)." + R"( -)" "Note: the positional arguments must substitute as whole words in the resultant \ +)" + "Note: the positional arguments must substitute as whole words in the resultant \ command, so you can't at present do something like this to append the file extension \ -\".cpp\":" R"( +\".cpp\":" + R"( (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2 -)" "For more complex aliasing, use the \"command regex\" command instead. In the \ +)" + "For more complex aliasing, use the \"command regex\" command instead. In the \ 'bfl' case above, the actual file value will be filled in with the first argument \ following 'bfl' and the actual line number value will be filled in with the second \ -argument. The user would use this alias as follows:" R"( +argument. The user would use this alias as follows:" + R"( (lldb) command alias bfl breakpoint set -f %1 -l %2 (lldb) bfl my-file.c 137 @@ -576,340 +488,310 @@ Another example: Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0' -)" "If the user always wanted to pass the same value to a particular option, the \ +)" + "If the user always wanted to pass the same value to a particular option, the \ alias could be defined with that value directly in the alias as a constant, \ -rather than using a positional placeholder:" R"( +rather than using a positional placeholder:" + R"( (lldb) command alias bl3 breakpoint set -f %1 -l 3 - Always sets a breakpoint on line 3 of whatever file is indicated.)" - ); - - CommandArgumentEntry arg1; - CommandArgumentEntry arg2; - CommandArgumentEntry arg3; - CommandArgumentData alias_arg; - CommandArgumentData cmd_arg; - CommandArgumentData options_arg; - - // Define the first (and only) variant of this arg. - alias_arg.arg_type = eArgTypeAliasName; - alias_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg1.push_back (alias_arg); - - // Define the first (and only) variant of this arg. - cmd_arg.arg_type = eArgTypeCommandName; - cmd_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg2.push_back (cmd_arg); - - // Define the first (and only) variant of this arg. - options_arg.arg_type = eArgTypeAliasOptions; - options_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the argument entry. - arg3.push_back (options_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg1); - m_arguments.push_back (arg2); - m_arguments.push_back (arg3); - } - - ~CommandObjectCommandsAlias() override = default; + Always sets a breakpoint on line 3 of whatever file is indicated.)"); + + CommandArgumentEntry arg1; + CommandArgumentEntry arg2; + CommandArgumentEntry arg3; + CommandArgumentData alias_arg; + CommandArgumentData cmd_arg; + CommandArgumentData options_arg; + + // Define the first (and only) variant of this arg. + alias_arg.arg_type = eArgTypeAliasName; + alias_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg1.push_back(alias_arg); + + // Define the first (and only) variant of this arg. + cmd_arg.arg_type = eArgTypeCommandName; + cmd_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg2.push_back(cmd_arg); + + // Define the first (and only) variant of this arg. + options_arg.arg_type = eArgTypeAliasOptions; + options_arg.arg_repetition = eArgRepeatOptional; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg3.push_back(options_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg1); + m_arguments.push_back(arg2); + m_arguments.push_back(arg3); + } + + ~CommandObjectCommandsAlias() override = default; protected: - bool - DoExecute (const char *raw_command_line, CommandReturnObject &result) override - { - if (!raw_command_line || !raw_command_line[0]) - { - result.AppendError ("'command alias' requires at least two arguments"); - return false; - } - - m_option_group.NotifyOptionParsingStarting(); - - const char * remainder = nullptr; - - if (raw_command_line[0] == '-') - { - // We have some options and these options MUST end with --. - const char *end_options = nullptr; - const char *s = raw_command_line; - while (s && s[0]) - { - end_options = ::strstr (s, "--"); - if (end_options) - { - end_options += 2; // Get past the "--" - if (::isspace (end_options[0])) - { - remainder = end_options; - while (::isspace (*remainder)) - ++remainder; - break; - } - } - s = end_options; - } - - if (end_options) - { - Args args (llvm::StringRef(raw_command_line, end_options - raw_command_line)); - if (!ParseOptions (args, result)) - return false; - - Error error (m_option_group.NotifyOptionParsingFinished()); - if (error.Fail()) - { - result.AppendError (error.AsCString()); - result.SetStatus (eReturnStatusFailed); - return false; - } - } - } - if (nullptr == remainder) - remainder = raw_command_line; - - std::string raw_command_string (remainder); - Args args (raw_command_string.c_str()); - - size_t argc = args.GetArgumentCount(); - - if (argc < 2) - { - result.AppendError ("'command alias' requires at least two arguments"); - result.SetStatus (eReturnStatusFailed); - return false; - } - - // Get the alias command. - - const std::string alias_command = args.GetArgumentAtIndex (0); - if (alias_command.size() > 1 && - alias_command[0] == '-') - { - result.AppendError("aliases starting with a dash are not supported"); - if (alias_command == "--help" || alias_command == "--long-help") - { - result.AppendWarning("if trying to pass options to 'command alias' add a -- at the end of the options"); - } - result.SetStatus (eReturnStatusFailed); - return false; - } - - // Strip the new alias name off 'raw_command_string' (leave it on args, which gets passed to 'Execute', which - // does the stripping itself. - size_t pos = raw_command_string.find (alias_command); - if (pos == 0) - { - raw_command_string = raw_command_string.substr (alias_command.size()); - pos = raw_command_string.find_first_not_of (' '); - if ((pos != std::string::npos) && (pos > 0)) - raw_command_string = raw_command_string.substr (pos); - } - else - { - result.AppendError ("Error parsing command string. No alias created."); - result.SetStatus (eReturnStatusFailed); - return false; - } - - - // Verify that the command is alias-able. - if (m_interpreter.CommandExists (alias_command.c_str())) - { - result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", - alias_command.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; - } - - // Get CommandObject that is being aliased. The command name is read from the front of raw_command_string. - // raw_command_string is returned with the name of the command object stripped off the front. - std::string original_raw_command_string(raw_command_string); - CommandObject *cmd_obj = m_interpreter.GetCommandObjectForCommand (raw_command_string); - - if (!cmd_obj) - { - result.AppendErrorWithFormat ("invalid command given to 'command alias'. '%s' does not begin with a valid command." - " No alias created.", original_raw_command_string.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; - } - else if (!cmd_obj->WantsRawCommandString ()) - { - // Note that args was initialized with the original command, and has not been updated to this point. - // Therefore can we pass it to the version of Execute that does not need/expect raw input in the alias. - return HandleAliasingNormalCommand (args, result); - } - else - { - return HandleAliasingRawCommand (alias_command, raw_command_string, *cmd_obj, result); - } - return result.Succeeded(); - } - - bool - HandleAliasingRawCommand (const std::string &alias_command, std::string &raw_command_string, CommandObject &cmd_obj, CommandReturnObject &result) - { - // Verify & handle any options/arguments passed to the alias command - - OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); - - if (CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj.GetCommandName(), false)) - { - if (m_interpreter.AliasExists (alias_command.c_str()) - || m_interpreter.UserCommandExists (alias_command.c_str())) - { - result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", - alias_command.c_str()); - } - if (CommandAlias *alias = m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp, raw_command_string.c_str())) - { - if (m_command_options.m_help.OptionWasSet()) - alias->SetHelp(m_command_options.m_help.GetCurrentValue()); - if (m_command_options.m_long_help.OptionWasSet()) - alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError ("Unable to create requested alias.\n"); - result.SetStatus (eReturnStatusFailed); - } + bool DoExecute(const char *raw_command_line, + CommandReturnObject &result) override { + if (!raw_command_line || !raw_command_line[0]) { + result.AppendError("'command alias' requires at least two arguments"); + return false; + } - } - else - { - result.AppendError ("Unable to create requested alias.\n"); - result.SetStatus (eReturnStatusFailed); - } + ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext(); + m_option_group.NotifyOptionParsingStarting(&exe_ctx); + + const char *remainder = nullptr; + + if (raw_command_line[0] == '-') { + // We have some options and these options MUST end with --. + const char *end_options = nullptr; + const char *s = raw_command_line; + while (s && s[0]) { + end_options = ::strstr(s, "--"); + if (end_options) { + end_options += 2; // Get past the "--" + if (::isspace(end_options[0])) { + remainder = end_options; + while (::isspace(*remainder)) + ++remainder; + break; + } + } + s = end_options; + } + + if (end_options) { + Args args( + llvm::StringRef(raw_command_line, end_options - raw_command_line)); + if (!ParseOptions(args, result)) + return false; + + Error error(m_option_group.NotifyOptionParsingFinished(&exe_ctx)); + if (error.Fail()) { + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + } + if (nullptr == remainder) + remainder = raw_command_line; - return result.Succeeded (); + llvm::StringRef raw_command_string(remainder); + Args args(raw_command_string); + + if (args.GetArgumentCount() < 2) { + result.AppendError("'command alias' requires at least two arguments"); + result.SetStatus(eReturnStatusFailed); + return false; } - - bool - HandleAliasingNormalCommand (Args& args, CommandReturnObject &result) - { - size_t argc = args.GetArgumentCount(); - if (argc < 2) - { - result.AppendError ("'command alias' requires at least two arguments"); - result.SetStatus (eReturnStatusFailed); - return false; - } + // Get the alias command. + + auto alias_command = args[0].ref; + if (alias_command.startswith("-")) { + result.AppendError("aliases starting with a dash are not supported"); + if (alias_command == "--help" || alias_command == "--long-help") { + result.AppendWarning("if trying to pass options to 'command alias' add " + "a -- at the end of the options"); + } + result.SetStatus(eReturnStatusFailed); + return false; + } - const std::string alias_command = args.GetArgumentAtIndex(0); - const std::string actual_command = args.GetArgumentAtIndex(1); + // Strip the new alias name off 'raw_command_string' (leave it on args, + // which gets passed to 'Execute', which + // does the stripping itself. + size_t pos = raw_command_string.find(alias_command); + if (pos == 0) { + raw_command_string = raw_command_string.substr(alias_command.size()); + pos = raw_command_string.find_first_not_of(' '); + if ((pos != std::string::npos) && (pos > 0)) + raw_command_string = raw_command_string.substr(pos); + } else { + result.AppendError("Error parsing command string. No alias created."); + result.SetStatus(eReturnStatusFailed); + return false; + } - args.Shift(); // Shift the alias command word off the argument vector. - args.Shift(); // Shift the old command word off the argument vector. + // Verify that the command is alias-able. + if (m_interpreter.CommandExists(alias_command)) { + result.AppendErrorWithFormat( + "'%s' is a permanent debugger command and cannot be redefined.\n", + args[0].c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + // Get CommandObject that is being aliased. The command name is read from + // the front of raw_command_string. raw_command_string is returned with the + // name of the command object stripped off the front. + llvm::StringRef original_raw_command_string = raw_command_string; + CommandObject *cmd_obj = + m_interpreter.GetCommandObjectForCommand(raw_command_string); + + if (!cmd_obj) { + result.AppendErrorWithFormat("invalid command given to 'command alias'. " + "'%s' does not begin with a valid command." + " No alias created.", + original_raw_command_string.str().c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } else if (!cmd_obj->WantsRawCommandString()) { + // Note that args was initialized with the original command, and has not + // been updated to this point. + // Therefore can we pass it to the version of Execute that does not + // need/expect raw input in the alias. + return HandleAliasingNormalCommand(args, result); + } else { + return HandleAliasingRawCommand(alias_command, raw_command_string, + *cmd_obj, result); + } + return result.Succeeded(); + } + + bool HandleAliasingRawCommand(llvm::StringRef alias_command, + llvm::StringRef raw_command_string, + CommandObject &cmd_obj, + CommandReturnObject &result) { + // Verify & handle any options/arguments passed to the alias command + + OptionArgVectorSP option_arg_vector_sp = + OptionArgVectorSP(new OptionArgVector); + + if (CommandObjectSP cmd_obj_sp = + m_interpreter.GetCommandSPExact(cmd_obj.GetCommandName(), false)) { + if (m_interpreter.AliasExists(alias_command) || + m_interpreter.UserCommandExists(alias_command)) { + result.AppendWarningWithFormat( + "Overwriting existing definition for '%s'.\n", + alias_command.str().c_str()); + } + if (CommandAlias *alias = m_interpreter.AddAlias( + alias_command, cmd_obj_sp, raw_command_string)) { + if (m_command_options.m_help.OptionWasSet()) + alias->SetHelp(m_command_options.m_help.GetCurrentValue()); + if (m_command_options.m_long_help.OptionWasSet()) + alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } else { + result.AppendError("Unable to create requested alias.\n"); + result.SetStatus(eReturnStatusFailed); + } + + } else { + result.AppendError("Unable to create requested alias.\n"); + result.SetStatus(eReturnStatusFailed); + } - // Verify that the command is alias'able, and get the appropriate command object. + return result.Succeeded(); + } - if (m_interpreter.CommandExists (alias_command.c_str())) - { - result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", - alias_command.c_str()); - result.SetStatus (eReturnStatusFailed); - } - else - { - CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true)); - CommandObjectSP subcommand_obj_sp; - bool use_subcommand = false; - if (command_obj_sp) - { - CommandObject *cmd_obj = command_obj_sp.get(); - CommandObject *sub_cmd_obj = nullptr; - OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); - - while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0) - { - if (argc >= 3) - { - const std::string sub_command = args.GetArgumentAtIndex(0); - assert (sub_command.length() != 0); - subcommand_obj_sp = cmd_obj->GetSubcommandSP (sub_command.c_str()); - if (subcommand_obj_sp) - { - sub_cmd_obj = subcommand_obj_sp.get(); - use_subcommand = true; - args.Shift(); // Shift the sub_command word off the argument vector. - cmd_obj = sub_cmd_obj; - } - else - { - result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'. " - "Unable to create alias.\n", - sub_command.c_str(), actual_command.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; - } - } - } - - // Verify & handle any options/arguments passed to the alias command - - std::string args_string; - - if (args.GetArgumentCount () > 0) - { - CommandObjectSP tmp_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false); - if (use_subcommand) - tmp_sp = m_interpreter.GetCommandSPExact (sub_cmd_obj->GetCommandName(), false); - - args.GetCommandString (args_string); - } - - if (m_interpreter.AliasExists (alias_command.c_str()) - || m_interpreter.UserCommandExists (alias_command.c_str())) - { - result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", - alias_command.c_str()); - } - - if (CommandAlias *alias = m_interpreter.AddAlias(alias_command.c_str(), - use_subcommand ? subcommand_obj_sp : command_obj_sp, - args_string.c_str())) - { - if (m_command_options.m_help.OptionWasSet()) - alias->SetHelp(m_command_options.m_help.GetCurrentValue()); - if (m_command_options.m_long_help.OptionWasSet()) - alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError ("Unable to create requested alias.\n"); - result.SetStatus (eReturnStatusFailed); - return false; - } - } - else - { - result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; - } - } + bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) { + size_t argc = args.GetArgumentCount(); - return result.Succeeded(); + if (argc < 2) { + result.AppendError("'command alias' requires at least two arguments"); + result.SetStatus(eReturnStatusFailed); + return false; } -}; -OptionDefinition -CommandObjectCommandsAlias::CommandOptions::g_option_table[] = -{ - { LLDB_OPT_SET_ALL, false, "help", 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Help text for this command"}, - { LLDB_OPT_SET_ALL, false, "long-help", 'H', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Long help text for this command"}, - { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } + // Save these in std::strings since we're going to shift them off. + const std::string alias_command(args[0].ref); + const std::string actual_command(args[1].ref); + + args.Shift(); // Shift the alias command word off the argument vector. + args.Shift(); // Shift the old command word off the argument vector. + + // Verify that the command is alias'able, and get the appropriate command + // object. + + if (m_interpreter.CommandExists(alias_command)) { + result.AppendErrorWithFormat( + "'%s' is a permanent debugger command and cannot be redefined.\n", + alias_command.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + CommandObjectSP command_obj_sp( + m_interpreter.GetCommandSPExact(actual_command, true)); + CommandObjectSP subcommand_obj_sp; + bool use_subcommand = false; + if (!command_obj_sp) { + result.AppendErrorWithFormat("'%s' is not an existing command.\n", + actual_command.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + CommandObject *cmd_obj = command_obj_sp.get(); + CommandObject *sub_cmd_obj = nullptr; + OptionArgVectorSP option_arg_vector_sp = + OptionArgVectorSP(new OptionArgVector); + + while (cmd_obj->IsMultiwordObject() && !args.empty()) { + auto sub_command = args[0].ref; + assert(!sub_command.empty()); + subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command); + if (!subcommand_obj_sp) { + result.AppendErrorWithFormat( + "'%s' is not a valid sub-command of '%s'. " + "Unable to create alias.\n", + args[0].c_str(), actual_command.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + sub_cmd_obj = subcommand_obj_sp.get(); + use_subcommand = true; + args.Shift(); // Shift the sub_command word off the argument vector. + cmd_obj = sub_cmd_obj; + } + + // Verify & handle any options/arguments passed to the alias command + + std::string args_string; + + if (!args.empty()) { + CommandObjectSP tmp_sp = + m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName(), false); + if (use_subcommand) + tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName(), + false); + + args.GetCommandString(args_string); + } + + if (m_interpreter.AliasExists(alias_command) || + m_interpreter.UserCommandExists(alias_command)) { + result.AppendWarningWithFormat( + "Overwriting existing definition for '%s'.\n", alias_command.c_str()); + } + + if (CommandAlias *alias = m_interpreter.AddAlias( + alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp, + args_string)) { + if (m_command_options.m_help.OptionWasSet()) + alias->SetHelp(m_command_options.m_help.GetCurrentValue()); + if (m_command_options.m_long_help.OptionWasSet()) + alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } else { + result.AppendError("Unable to create requested alias.\n"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + return result.Succeeded(); + } }; #pragma mark CommandObjectCommandsUnalias @@ -917,87 +799,82 @@ CommandObjectCommandsAlias::CommandOptions::g_option_table[] = // CommandObjectCommandsUnalias //------------------------------------------------------------------------- -class CommandObjectCommandsUnalias : public CommandObjectParsed -{ +class CommandObjectCommandsUnalias : public CommandObjectParsed { public: - CommandObjectCommandsUnalias(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "command unalias", - "Delete one or more custom commands defined by 'command alias'.", nullptr) - { - CommandArgumentEntry arg; - CommandArgumentData alias_arg; - - // Define the first (and only) variant of this arg. - alias_arg.arg_type = eArgTypeAliasName; - alias_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (alias_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); - } - - ~CommandObjectCommandsUnalias() override = default; + CommandObjectCommandsUnalias(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "command unalias", + "Delete one or more custom commands defined by 'command alias'.", + nullptr) { + CommandArgumentEntry arg; + CommandArgumentData alias_arg; + + // Define the first (and only) variant of this arg. + alias_arg.arg_type = eArgTypeAliasName; + alias_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg.push_back(alias_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg); + } + + ~CommandObjectCommandsUnalias() override = default; protected: - bool - DoExecute (Args& args, CommandReturnObject &result) override - { - CommandObject::CommandMap::iterator pos; - CommandObject *cmd_obj; - - if (args.GetArgumentCount() != 0) - { - const char *command_name = args.GetArgumentAtIndex(0); - cmd_obj = m_interpreter.GetCommandObject(command_name); - if (cmd_obj) - { - if (m_interpreter.CommandExists (command_name)) - { - if (cmd_obj->IsRemovable()) - { - result.AppendErrorWithFormat ("'%s' is not an alias, it is a debugger command which can be removed using the 'command delete' command.\n", - command_name); - } - else - { - result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", - command_name); - } - result.SetStatus (eReturnStatusFailed); - } - else - { - if (!m_interpreter.RemoveAlias(command_name)) - { - if (m_interpreter.AliasExists (command_name)) - result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n", - command_name); - else - result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name); - result.SetStatus (eReturnStatusFailed); - } - else - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - } - else - { - result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a " - "current list of commands.\n", - command_name); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendError ("must call 'unalias' with a valid alias"); - result.SetStatus (eReturnStatusFailed); - } + bool DoExecute(Args &args, CommandReturnObject &result) override { + CommandObject::CommandMap::iterator pos; + CommandObject *cmd_obj; + + if (args.empty()) { + result.AppendError("must call 'unalias' with a valid alias"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + auto command_name = args[0].ref; + cmd_obj = m_interpreter.GetCommandObject(command_name); + if (!cmd_obj) { + result.AppendErrorWithFormat( + "'%s' is not a known command.\nTry 'help' to see a " + "current list of commands.\n", + args[0].c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (m_interpreter.CommandExists(command_name)) { + if (cmd_obj->IsRemovable()) { + result.AppendErrorWithFormat( + "'%s' is not an alias, it is a debugger command which can be " + "removed using the 'command delete' command.\n", + args[0].c_str()); + } else { + result.AppendErrorWithFormat( + "'%s' is a permanent debugger command and cannot be removed.\n", + args[0].c_str()); + } + result.SetStatus(eReturnStatusFailed); + return false; + } - return result.Succeeded(); + if (!m_interpreter.RemoveAlias(command_name)) { + if (m_interpreter.AliasExists(command_name)) + result.AppendErrorWithFormat( + "Error occurred while attempting to unalias '%s'.\n", + args[0].c_str()); + else + result.AppendErrorWithFormat("'%s' is not an existing alias.\n", + args[0].c_str()); + result.SetStatus(eReturnStatusFailed); + return false; } + + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return result.Succeeded(); + } }; #pragma mark CommandObjectCommandsDelete @@ -1005,1249 +882,1016 @@ protected: // CommandObjectCommandsDelete //------------------------------------------------------------------------- -class CommandObjectCommandsDelete : public CommandObjectParsed -{ +class CommandObjectCommandsDelete : public CommandObjectParsed { public: - CommandObjectCommandsDelete(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "command delete", - "Delete one or more custom commands defined by 'command regex'.", nullptr) - { - CommandArgumentEntry arg; - CommandArgumentData alias_arg; + CommandObjectCommandsDelete(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "command delete", + "Delete one or more custom commands defined by 'command regex'.", + nullptr) { + CommandArgumentEntry arg; + CommandArgumentData alias_arg; - // Define the first (and only) variant of this arg. - alias_arg.arg_type = eArgTypeCommandName; - alias_arg.arg_repetition = eArgRepeatPlain; + // Define the first (and only) variant of this arg. + alias_arg.arg_type = eArgTypeCommandName; + alias_arg.arg_repetition = eArgRepeatPlain; - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (alias_arg); + // There is only one variant this argument could be; put it into the + // argument entry. + arg.push_back(alias_arg); - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); - } + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg); + } - ~CommandObjectCommandsDelete() override = default; + ~CommandObjectCommandsDelete() override = default; protected: - bool - DoExecute (Args& args, CommandReturnObject &result) override - { - CommandObject::CommandMap::iterator pos; - - if (args.GetArgumentCount() != 0) - { - const char *command_name = args.GetArgumentAtIndex(0); - if (m_interpreter.CommandExists (command_name)) - { - if (m_interpreter.RemoveCommand (command_name)) - { - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", - command_name); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - StreamString error_msg_stream; - const bool generate_apropos = true; - const bool generate_type_lookup = false; - CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(&error_msg_stream, - command_name, - nullptr, - nullptr, - generate_apropos, - generate_type_lookup); - result.AppendErrorWithFormat ("%s", error_msg_stream.GetData()); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendErrorWithFormat( - "must call '%s' with one or more valid user defined regular expression command names", - GetCommandName()); - result.SetStatus (eReturnStatusFailed); - } + bool DoExecute(Args &args, CommandReturnObject &result) override { + CommandObject::CommandMap::iterator pos; + + if (args.empty()) { + result.AppendErrorWithFormat("must call '%s' with one or more valid user " + "defined regular expression command names", + GetCommandName().str().c_str()); + result.SetStatus(eReturnStatusFailed); + } - return result.Succeeded(); + auto command_name = args[0].ref; + if (!m_interpreter.CommandExists(command_name)) { + StreamString error_msg_stream; + const bool generate_apropos = true; + const bool generate_type_lookup = false; + CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage( + &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(), + generate_apropos, generate_type_lookup); + result.AppendError(error_msg_stream.GetString()); + result.SetStatus(eReturnStatusFailed); + return false; } + + if (!m_interpreter.RemoveCommand(command_name)) { + result.AppendErrorWithFormat( + "'%s' is a permanent debugger command and cannot be removed.\n", + args[0].c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return true; + } }; //------------------------------------------------------------------------- // CommandObjectCommandsAddRegex //------------------------------------------------------------------------- + +static OptionDefinition g_regex_options[] = { + // clang-format off + { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "The help text to display for this command." }, + { LLDB_OPT_SET_1, false, "syntax", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "A syntax string showing the typical usage syntax." }, + // clang-format on +}; + #pragma mark CommandObjectCommandsAddRegex -class CommandObjectCommandsAddRegex : - public CommandObjectParsed, - public IOHandlerDelegateMultiline -{ +class CommandObjectCommandsAddRegex : public CommandObjectParsed, + public IOHandlerDelegateMultiline { public: - CommandObjectCommandsAddRegex(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "command regex", - "Define a custom command in terms of existing commands by matching regular expressions.", - "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), - IOHandlerDelegateMultiline("", IOHandlerDelegate::Completion::LLDBCommand), - m_options(interpreter) - { - SetHelpLong(R"( -)" "This command allows the user to create powerful regular expression commands \ + CommandObjectCommandsAddRegex(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "command regex", "Define a custom command in terms of " + "existing commands by matching " + "regular expressions.", + "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), + IOHandlerDelegateMultiline("", + IOHandlerDelegate::Completion::LLDBCommand), + m_options() { + SetHelpLong( + R"( +)" + "This command allows the user to create powerful regular expression commands \ with substitutions. The regular expressions and substitutions are specified \ -using the regular expression substitution format of:" R"( +using the regular expression substitution format of:" + R"( s/<regex>/<subst>/ -)" "<regex> is a regular expression that can use parenthesis to capture regular \ +)" + "<regex> is a regular expression that can use parenthesis to capture regular \ expression input and substitute the captured matches in the output using %1 \ -for the first match, %2 for the second, and so on." R"( +for the first match, %2 for the second, and so on." + R"( -)" "The regular expressions can all be specified on the command line if more than \ +)" + "The regular expressions can all be specified on the command line if more than \ one argument is provided. If just the command name is provided on the command \ line, then the regular expressions and substitutions can be entered on separate \ -lines, followed by an empty line to terminate the command definition." R"( +lines, followed by an empty line to terminate the command definition." + R"( EXAMPLES -)" "The following example will define a regular expression command named 'f' that \ +)" + "The following example will define a regular expression command named 'f' that \ will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ -a number follows 'f':" R"( +a number follows 'f':" + R"( - (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')" - ); - } + (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"); + } - ~CommandObjectCommandsAddRegex() override = default; + ~CommandObjectCommandsAddRegex() override = default; protected: - void - IOHandlerActivated (IOHandler &io_handler) override - { - StreamFileSP output_sp(io_handler.GetOutputStreamFile()); - if (output_sp) - { - output_sp->PutCString("Enter one of more sed substitution commands in the form: 's/<regex>/<subst>/'.\nTerminate the substitution list with an empty line.\n"); - output_sp->Flush(); - } + void IOHandlerActivated(IOHandler &io_handler) override { + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) { + output_sp->PutCString("Enter one of more sed substitution commands in " + "the form: 's/<regex>/<subst>/'.\nTerminate the " + "substitution list with an empty line.\n"); + output_sp->Flush(); } - - void - IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override - { - io_handler.SetIsDone(true); - if (m_regex_cmd_ap) - { - StringList lines; - if (lines.SplitIntoLines (data)) - { - const size_t num_lines = lines.GetSize(); - bool check_only = false; - for (size_t i=0; i<num_lines; ++i) - { - llvm::StringRef bytes_strref (lines[i]); - Error error = AppendRegexSubstitution (bytes_strref, check_only); - if (error.Fail()) - { - if (!m_interpreter.GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) - { - StreamSP out_stream = m_interpreter.GetDebugger().GetAsyncOutputStream(); - out_stream->Printf("error: %s\n", error.AsCString()); - } - } - } - } - if (m_regex_cmd_ap->HasRegexEntries()) - { - CommandObjectSP cmd_sp (m_regex_cmd_ap.release()); - m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); + } + + void IOHandlerInputComplete(IOHandler &io_handler, + std::string &data) override { + io_handler.SetIsDone(true); + if (m_regex_cmd_ap) { + StringList lines; + if (lines.SplitIntoLines(data)) { + const size_t num_lines = lines.GetSize(); + bool check_only = false; + for (size_t i = 0; i < num_lines; ++i) { + llvm::StringRef bytes_strref(lines[i]); + Error error = AppendRegexSubstitution(bytes_strref, check_only); + if (error.Fail()) { + if (!m_interpreter.GetDebugger() + .GetCommandInterpreter() + .GetBatchCommandMode()) { + StreamSP out_stream = + m_interpreter.GetDebugger().GetAsyncOutputStream(); + out_stream->Printf("error: %s\n", error.AsCString()); } + } } + } + if (m_regex_cmd_ap->HasRegexEntries()) { + CommandObjectSP cmd_sp(m_regex_cmd_ap.release()); + m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); + } + } + } + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + result.AppendError("usage: 'command regex <command-name> " + "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); + result.SetStatus(eReturnStatusFailed); + return false; } - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) - { - result.AppendError ("usage: 'command regex <command-name> [s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); - result.SetStatus (eReturnStatusFailed); - } - else - { - Error error; - const char *name = command.GetArgumentAtIndex(0); - m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter, - name, - m_options.GetHelp (), - m_options.GetSyntax (), - 10, - 0, - true)); - - if (argc == 1) - { - Debugger &debugger = m_interpreter.GetDebugger(); - bool color_prompt = debugger.GetUseColor(); - const bool multiple_lines = true; // Get multiple lines - IOHandlerSP io_handler_sp(new IOHandlerEditline(debugger, - IOHandler::Type::Other, - "lldb-regex", // Name of input reader for history - "> ", // Prompt - nullptr, // Continuation prompt - multiple_lines, - color_prompt, - 0, // Don't show line numbers - *this)); - - if (io_handler_sp) - { - debugger.PushIOHandler(io_handler_sp); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - } - else - { - for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx) - { - llvm::StringRef arg_strref (command.GetArgumentAtIndex(arg_idx)); - bool check_only = false; - error = AppendRegexSubstitution (arg_strref, check_only); - if (error.Fail()) - break; - } - - if (error.Success()) - { - AddRegexCommandToInterpreter(); - } - } - if (error.Fail()) - { - result.AppendError (error.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } + Error error; + auto name = command[0].ref; + m_regex_cmd_ap = llvm::make_unique<CommandObjectRegexCommand>( + m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0, + true); + + if (argc == 1) { + Debugger &debugger = m_interpreter.GetDebugger(); + bool color_prompt = debugger.GetUseColor(); + const bool multiple_lines = true; // Get multiple lines + IOHandlerSP io_handler_sp(new IOHandlerEditline( + debugger, IOHandler::Type::Other, + "lldb-regex", // Name of input reader for history + llvm::StringRef("> "), // Prompt + llvm::StringRef(), // Continuation prompt + multiple_lines, color_prompt, + 0, // Don't show line numbers + *this)); + + if (io_handler_sp) { + debugger.PushIOHandler(io_handler_sp); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + } else { + for (auto &entry : command.entries().drop_front()) { + bool check_only = false; + error = AppendRegexSubstitution(entry.ref, check_only); + if (error.Fail()) + break; + } + + if (error.Success()) { + AddRegexCommandToInterpreter(); + } + } + if (error.Fail()) { + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + } - return result.Succeeded(); - } - - Error - AppendRegexSubstitution (const llvm::StringRef ®ex_sed, bool check_only) - { - Error error; - - if (!m_regex_cmd_ap) - { - error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'", - (int)regex_sed.size(), - regex_sed.data()); - return error; - } - - size_t regex_sed_size = regex_sed.size(); - - if (regex_sed_size <= 1) - { - error.SetErrorStringWithFormat("regular expression substitution string is too short: '%.*s'", - (int)regex_sed.size(), - regex_sed.data()); - return error; - } + return result.Succeeded(); + } - if (regex_sed[0] != 's') - { - error.SetErrorStringWithFormat("regular expression substitution string doesn't start with 's': '%.*s'", - (int)regex_sed.size(), - regex_sed.data()); - return error; - } - const size_t first_separator_char_pos = 1; - // use the char that follows 's' as the regex separator character - // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" - const char separator_char = regex_sed[first_separator_char_pos]; - const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1); - - if (second_separator_char_pos == std::string::npos) - { - error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s' in '%.*s'", - separator_char, - (int)(regex_sed.size() - first_separator_char_pos - 1), - regex_sed.data() + (first_separator_char_pos + 1), - (int)regex_sed.size(), - regex_sed.data()); - return error; - } + Error AppendRegexSubstitution(const llvm::StringRef ®ex_sed, + bool check_only) { + Error error; - const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1); - - if (third_separator_char_pos == std::string::npos) - { - error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s' in '%.*s'", - separator_char, - (int)(regex_sed.size() - second_separator_char_pos - 1), - regex_sed.data() + (second_separator_char_pos + 1), - (int)regex_sed.size(), - regex_sed.data()); - return error; - } + if (!m_regex_cmd_ap) { + error.SetErrorStringWithFormat( + "invalid regular expression command object for: '%.*s'", + (int)regex_sed.size(), regex_sed.data()); + return error; + } - if (third_separator_char_pos != regex_sed_size - 1) - { - // Make sure that everything that follows the last regex - // separator char - if (regex_sed.find_first_not_of("\t\n\v\f\r ", third_separator_char_pos + 1) != std::string::npos) - { - error.SetErrorStringWithFormat("extra data found after the '%.*s' regular expression substitution string: '%.*s'", - (int)third_separator_char_pos + 1, - regex_sed.data(), - (int)(regex_sed.size() - third_separator_char_pos - 1), - regex_sed.data() + (third_separator_char_pos + 1)); - return error; - } - } - else if (first_separator_char_pos + 1 == second_separator_char_pos) - { - error.SetErrorStringWithFormat("<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", - separator_char, - separator_char, - separator_char, - (int)regex_sed.size(), - regex_sed.data()); - return error; - } - else if (second_separator_char_pos + 1 == third_separator_char_pos) - { - error.SetErrorStringWithFormat("<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", - separator_char, - separator_char, - separator_char, - (int)regex_sed.size(), - regex_sed.data()); - return error; - } + size_t regex_sed_size = regex_sed.size(); - if (!check_only) - { - std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1)); - std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1)); - m_regex_cmd_ap->AddRegexCommand (regex.c_str(), - subst.c_str()); - } - return error; + if (regex_sed_size <= 1) { + error.SetErrorStringWithFormat( + "regular expression substitution string is too short: '%.*s'", + (int)regex_sed.size(), regex_sed.data()); + return error; } - - void - AddRegexCommandToInterpreter() - { - if (m_regex_cmd_ap) - { - if (m_regex_cmd_ap->HasRegexEntries()) - { - CommandObjectSP cmd_sp (m_regex_cmd_ap.release()); - m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); - } - } + + if (regex_sed[0] != 's') { + error.SetErrorStringWithFormat("regular expression substitution string " + "doesn't start with 's': '%.*s'", + (int)regex_sed.size(), regex_sed.data()); + return error; + } + const size_t first_separator_char_pos = 1; + // use the char that follows 's' as the regex separator character + // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" + const char separator_char = regex_sed[first_separator_char_pos]; + const size_t second_separator_char_pos = + regex_sed.find(separator_char, first_separator_char_pos + 1); + + if (second_separator_char_pos == std::string::npos) { + error.SetErrorStringWithFormat( + "missing second '%c' separator char after '%.*s' in '%.*s'", + separator_char, + (int)(regex_sed.size() - first_separator_char_pos - 1), + regex_sed.data() + (first_separator_char_pos + 1), + (int)regex_sed.size(), regex_sed.data()); + return error; } -private: - std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_ap; - - class CommandOptions : public Options - { - public: - CommandOptions (CommandInterpreter &interpreter) : - Options (interpreter) - { - } - - ~CommandOptions() override = default; - - Error - SetOptionValue (uint32_t option_idx, const char *option_arg) override - { - Error error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) - { - case 'h': - m_help.assign (option_arg); - break; - case 's': - m_syntax.assign (option_arg); - break; - default: - error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); - break; - } - - return error; - } - - void - OptionParsingStarting () override - { - m_help.clear(); - m_syntax.clear(); - } - - const OptionDefinition* - GetDefinitions () override - { - return g_option_table; - } - - // Options table: Required for subclasses of Options. - - static OptionDefinition g_option_table[]; - - const char * - GetHelp() - { - return (m_help.empty() ? nullptr : m_help.c_str()); - } - - const char * - GetSyntax () - { - return (m_syntax.empty() ? nullptr : m_syntax.c_str()); - } - - protected: - // Instance variables to hold the values for command options. - - std::string m_help; - std::string m_syntax; - }; - - Options * - GetOptions () override - { - return &m_options; - } - - CommandOptions m_options; -}; + const size_t third_separator_char_pos = + regex_sed.find(separator_char, second_separator_char_pos + 1); + + if (third_separator_char_pos == std::string::npos) { + error.SetErrorStringWithFormat( + "missing third '%c' separator char after '%.*s' in '%.*s'", + separator_char, + (int)(regex_sed.size() - second_separator_char_pos - 1), + regex_sed.data() + (second_separator_char_pos + 1), + (int)regex_sed.size(), regex_sed.data()); + return error; + } -OptionDefinition -CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] = -{ -{ LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "The help text to display for this command."}, -{ LLDB_OPT_SET_1, false, "syntax", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."}, -{ 0 , false, nullptr , 0 , 0 , nullptr, nullptr, 0, eArgTypeNone, nullptr } -}; + if (third_separator_char_pos != regex_sed_size - 1) { + // Make sure that everything that follows the last regex + // separator char + if (regex_sed.find_first_not_of("\t\n\v\f\r ", + third_separator_char_pos + 1) != + std::string::npos) { + error.SetErrorStringWithFormat( + "extra data found after the '%.*s' regular expression substitution " + "string: '%.*s'", + (int)third_separator_char_pos + 1, regex_sed.data(), + (int)(regex_sed.size() - third_separator_char_pos - 1), + regex_sed.data() + (third_separator_char_pos + 1)); + return error; + } + } else if (first_separator_char_pos + 1 == second_separator_char_pos) { + error.SetErrorStringWithFormat( + "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", + separator_char, separator_char, separator_char, (int)regex_sed.size(), + regex_sed.data()); + return error; + } else if (second_separator_char_pos + 1 == third_separator_char_pos) { + error.SetErrorStringWithFormat( + "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", + separator_char, separator_char, separator_char, (int)regex_sed.size(), + regex_sed.data()); + return error; + } -class CommandObjectPythonFunction : public CommandObjectRaw -{ -public: - CommandObjectPythonFunction (CommandInterpreter &interpreter, - std::string name, - std::string funct, - std::string help, - ScriptedCommandSynchronicity synch) : - CommandObjectRaw(interpreter, - name.c_str(), - nullptr, - nullptr), - m_function_name(funct), - m_synchro(synch), - m_fetched_help_long(false) - { - if (!help.empty()) - SetHelp(help.c_str()); - else - { - StreamString stream; - stream.Printf("For more information run 'help %s'",name.c_str()); - SetHelp(stream.GetData()); - } + if (!check_only) { + std::string regex(regex_sed.substr(first_separator_char_pos + 1, + second_separator_char_pos - + first_separator_char_pos - 1)); + std::string subst(regex_sed.substr(second_separator_char_pos + 1, + third_separator_char_pos - + second_separator_char_pos - 1)); + m_regex_cmd_ap->AddRegexCommand(regex.c_str(), subst.c_str()); + } + return error; + } + + void AddRegexCommandToInterpreter() { + if (m_regex_cmd_ap) { + if (m_regex_cmd_ap->HasRegexEntries()) { + CommandObjectSP cmd_sp(m_regex_cmd_ap.release()); + m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); + } } + } - ~CommandObjectPythonFunction() override = default; +private: + std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_ap; + + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'h': + m_help.assign(option_arg); + break; + case 's': + m_syntax.assign(option_arg); + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + + return error; + } - bool - IsRemovable () const override - { - return true; + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_help.clear(); + m_syntax.clear(); } - const std::string& - GetFunctionName () - { - return m_function_name; + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_regex_options); } - ScriptedCommandSynchronicity - GetSynchronicity () - { - return m_synchro; + // TODO: Convert these functions to return StringRefs. + const char *GetHelp() { + return (m_help.empty() ? nullptr : m_help.c_str()); } - - const char * - GetHelpLong () override - { - if (!m_fetched_help_long) - { - ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); - if (scripter) - { - std::string docstring; - m_fetched_help_long = scripter->GetDocumentationForItem(m_function_name.c_str(),docstring); - if (!docstring.empty()) - SetHelpLong(docstring.c_str()); - } - } - return CommandObjectRaw::GetHelpLong(); + + const char *GetSyntax() { + return (m_syntax.empty() ? nullptr : m_syntax.c_str()); } - + + protected: + // Instance variables to hold the values for command options. + + std::string m_help; + std::string m_syntax; + }; + + Options *GetOptions() override { return &m_options; } + + CommandOptions m_options; +}; + +class CommandObjectPythonFunction : public CommandObjectRaw { +public: + CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, + std::string funct, std::string help, + ScriptedCommandSynchronicity synch) + : CommandObjectRaw(interpreter, name), + m_function_name(funct), m_synchro(synch), m_fetched_help_long(false) { + if (!help.empty()) + SetHelp(help); + else { + StreamString stream; + stream.Printf("For more information run 'help %s'", name.c_str()); + SetHelp(stream.GetString()); + } + } + + ~CommandObjectPythonFunction() override = default; + + bool IsRemovable() const override { return true; } + + const std::string &GetFunctionName() { return m_function_name; } + + ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } + + llvm::StringRef GetHelpLong() override { + if (m_fetched_help_long) + return CommandObjectRaw::GetHelpLong(); + + ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); + if (!scripter) + return CommandObjectRaw::GetHelpLong(); + + std::string docstring; + m_fetched_help_long = + scripter->GetDocumentationForItem(m_function_name.c_str(), docstring); + if (!docstring.empty()) + SetHelpLong(docstring); + return CommandObjectRaw::GetHelpLong(); + } + protected: - bool - DoExecute (const char *raw_command_line, CommandReturnObject &result) override - { - ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); - - Error error; - - result.SetStatus(eReturnStatusInvalid); - - if (!scripter || !scripter->RunScriptBasedCommand(m_function_name.c_str(), - raw_command_line, - m_synchro, - result, - error, - m_exe_ctx)) - { - result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); - } + bool DoExecute(const char *raw_command_line, + CommandReturnObject &result) override { + ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); + + Error error; + + result.SetStatus(eReturnStatusInvalid); + + if (!scripter || + !scripter->RunScriptBasedCommand(m_function_name.c_str(), + raw_command_line, m_synchro, result, + error, m_exe_ctx)) { + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + } else { + // Don't change the status if the command already set it... + if (result.GetStatus() == eReturnStatusInvalid) { + if (result.GetOutputData().empty()) + result.SetStatus(eReturnStatusSuccessFinishNoResult); else - { - // Don't change the status if the command already set it... - if (result.GetStatus() == eReturnStatusInvalid) - { - if (result.GetOutputData() == nullptr || result.GetOutputData()[0] == '\0') - result.SetStatus(eReturnStatusSuccessFinishNoResult); - else - result.SetStatus(eReturnStatusSuccessFinishResult); - } - } - - return result.Succeeded(); + result.SetStatus(eReturnStatusSuccessFinishResult); + } } + return result.Succeeded(); + } + private: - std::string m_function_name; - ScriptedCommandSynchronicity m_synchro; - bool m_fetched_help_long; + std::string m_function_name; + ScriptedCommandSynchronicity m_synchro; + bool m_fetched_help_long; }; -class CommandObjectScriptingObject : public CommandObjectRaw -{ +class CommandObjectScriptingObject : public CommandObjectRaw { public: - CommandObjectScriptingObject (CommandInterpreter &interpreter, - std::string name, - StructuredData::GenericSP cmd_obj_sp, - ScriptedCommandSynchronicity synch) : - CommandObjectRaw(interpreter, - name.c_str(), - nullptr, - nullptr), - m_cmd_obj_sp(cmd_obj_sp), - m_synchro(synch), - m_fetched_help_short(false), - m_fetched_help_long(false) - { - StreamString stream; - stream.Printf("For more information run 'help %s'",name.c_str()); - SetHelp(stream.GetData()); - if (ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter()) - GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); - } - - ~CommandObjectScriptingObject() override = default; - - bool - IsRemovable () const override - { - return true; - } - - StructuredData::GenericSP - GetImplementingObject () - { - return m_cmd_obj_sp; - } - - ScriptedCommandSynchronicity - GetSynchronicity () - { - return m_synchro; - } - - const char * - GetHelp () override - { - if (!m_fetched_help_short) - { - ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); - if (scripter) - { - std::string docstring; - m_fetched_help_short = scripter->GetShortHelpForCommandObject(m_cmd_obj_sp,docstring); - if (!docstring.empty()) - SetHelp(docstring.c_str()); - } - } - return CommandObjectRaw::GetHelp(); - } - - const char * - GetHelpLong () override - { - if (!m_fetched_help_long) - { - ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); - if (scripter) - { - std::string docstring; - m_fetched_help_long = scripter->GetLongHelpForCommandObject(m_cmd_obj_sp,docstring); - if (!docstring.empty()) - SetHelpLong(docstring.c_str()); - } - } - return CommandObjectRaw::GetHelpLong(); - } - + CommandObjectScriptingObject(CommandInterpreter &interpreter, + std::string name, + StructuredData::GenericSP cmd_obj_sp, + ScriptedCommandSynchronicity synch) + : CommandObjectRaw(interpreter, name), + m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), m_fetched_help_short(false), + m_fetched_help_long(false) { + StreamString stream; + stream.Printf("For more information run 'help %s'", name.c_str()); + SetHelp(stream.GetString()); + if (ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter()) + GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); + } + + ~CommandObjectScriptingObject() override = default; + + bool IsRemovable() const override { return true; } + + StructuredData::GenericSP GetImplementingObject() { return m_cmd_obj_sp; } + + ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } + + llvm::StringRef GetHelp() override { + if (m_fetched_help_short) + return CommandObjectRaw::GetHelp(); + ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); + if (!scripter) + return CommandObjectRaw::GetHelp(); + std::string docstring; + m_fetched_help_short = + scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); + if (!docstring.empty()) + SetHelp(docstring); + + return CommandObjectRaw::GetHelp(); + } + + llvm::StringRef GetHelpLong() override { + if (m_fetched_help_long) + return CommandObjectRaw::GetHelpLong(); + + ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); + if (!scripter) + return CommandObjectRaw::GetHelpLong(); + + std::string docstring; + m_fetched_help_long = + scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); + if (!docstring.empty()) + SetHelpLong(docstring); + return CommandObjectRaw::GetHelpLong(); + } + protected: - bool - DoExecute (const char *raw_command_line, CommandReturnObject &result) override - { - ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); - - Error error; - - result.SetStatus(eReturnStatusInvalid); - - if (!scripter || !scripter->RunScriptBasedCommand(m_cmd_obj_sp, - raw_command_line, - m_synchro, - result, - error, - m_exe_ctx)) - { - result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); - } + bool DoExecute(const char *raw_command_line, + CommandReturnObject &result) override { + ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter(); + + Error error; + + result.SetStatus(eReturnStatusInvalid); + + if (!scripter || + !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, + m_synchro, result, error, m_exe_ctx)) { + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + } else { + // Don't change the status if the command already set it... + if (result.GetStatus() == eReturnStatusInvalid) { + if (result.GetOutputData().empty()) + result.SetStatus(eReturnStatusSuccessFinishNoResult); else - { - // Don't change the status if the command already set it... - if (result.GetStatus() == eReturnStatusInvalid) - { - if (result.GetOutputData() == nullptr || result.GetOutputData()[0] == '\0') - result.SetStatus(eReturnStatusSuccessFinishNoResult); - else - result.SetStatus(eReturnStatusSuccessFinishResult); - } - } - - return result.Succeeded(); + result.SetStatus(eReturnStatusSuccessFinishResult); + } } + return result.Succeeded(); + } + private: - StructuredData::GenericSP m_cmd_obj_sp; - ScriptedCommandSynchronicity m_synchro; - bool m_fetched_help_short: 1; - bool m_fetched_help_long: 1; + StructuredData::GenericSP m_cmd_obj_sp; + ScriptedCommandSynchronicity m_synchro; + bool m_fetched_help_short : 1; + bool m_fetched_help_long : 1; }; //------------------------------------------------------------------------- // CommandObjectCommandsScriptImport //------------------------------------------------------------------------- -class CommandObjectCommandsScriptImport : public CommandObjectParsed -{ +OptionDefinition g_script_import_options[] = { + // clang-format off + { LLDB_OPT_SET_1, false, "allow-reload", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not." }, + // clang-format on +}; + +class CommandObjectCommandsScriptImport : public CommandObjectParsed { public: - CommandObjectCommandsScriptImport (CommandInterpreter &interpreter) : - CommandObjectParsed(interpreter, - "command script import", - "Import a scripting module in LLDB.", - nullptr), - m_options(interpreter) - { - CommandArgumentEntry arg1; - CommandArgumentData cmd_arg; - - // Define the first (and only) variant of this arg. - cmd_arg.arg_type = eArgTypeFilename; - cmd_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the argument entry. - arg1.push_back (cmd_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg1); - } - - ~CommandObjectCommandsScriptImport() override = default; - - int - HandleArgumentCompletion (Args &input, - int &cursor_index, - int &cursor_char_position, - OptionElementVector &opt_element_vector, - int match_start_point, - int max_return_elements, - bool &word_complete, - StringList &matches) override - { - std::string completion_str (input.GetArgumentAtIndex(cursor_index)); - completion_str.erase (cursor_char_position); - - CommandCompletions::InvokeCommonCompletionCallbacks(m_interpreter, - CommandCompletions::eDiskFileCompletion, - completion_str.c_str(), - match_start_point, - max_return_elements, - nullptr, - word_complete, - matches); - return matches.GetSize(); - } - - Options * - GetOptions () override - { - return &m_options; - } + CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "command script import", + "Import a scripting module in LLDB.", nullptr), + m_options() { + CommandArgumentEntry arg1; + CommandArgumentData cmd_arg; + + // Define the first (and only) variant of this arg. + cmd_arg.arg_type = eArgTypeFilename; + cmd_arg.arg_repetition = eArgRepeatPlus; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg1.push_back(cmd_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg1); + } + + ~CommandObjectCommandsScriptImport() override = default; + + int HandleArgumentCompletion(Args &input, int &cursor_index, + int &cursor_char_position, + OptionElementVector &opt_element_vector, + int match_start_point, int max_return_elements, + bool &word_complete, + StringList &matches) override { + llvm::StringRef completion_str = input[cursor_index].ref; + completion_str = completion_str.take_front(cursor_char_position); + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + completion_str, match_start_point, max_return_elements, nullptr, + word_complete, matches); + return matches.GetSize(); + } + + Options *GetOptions() override { return &m_options; } protected: - class CommandOptions : public Options - { - public: - CommandOptions (CommandInterpreter &interpreter) : - Options (interpreter) - { - } + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'r': + m_allow_reload = true; + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + + return error; + } - ~CommandOptions() override = default; - - Error - SetOptionValue (uint32_t option_idx, const char *option_arg) override - { - Error error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) - { - case 'r': - m_allow_reload = true; - break; - default: - error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); - break; - } - - return error; - } - - void - OptionParsingStarting () override - { - m_allow_reload = true; - } - - const OptionDefinition* - GetDefinitions () override - { - return g_option_table; - } - - // Options table: Required for subclasses of Options. - - static OptionDefinition g_option_table[]; - - // Instance variables to hold the values for command options. - - bool m_allow_reload; - }; - - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) - { - result.AppendError ("only scripting language supported for module importing is currently Python"); - result.SetStatus (eReturnStatusFailed); - return false; - } - - size_t argc = command.GetArgumentCount(); - if (0 == argc) - { - result.AppendError("command script import needs one or more arguments"); - result.SetStatus (eReturnStatusFailed); - return false; - } - - for (size_t i = 0; - i < argc; - i++) - { - std::string path = command.GetArgumentAtIndex(i); - Error error; - - const bool init_session = true; - // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that - // commands won't ever be recursively invoked, but it's actually possible to craft - // a Python script that does other "command script imports" in __lldb_init_module - // the real fix is to have recursive commands possible with a CommandInvocation object - // separate from the CommandObject itself, so that recursive command invocations - // won't stomp on each other (wrt to execution contents, options, and more) - m_exe_ctx.Clear(); - if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(), - m_options.m_allow_reload, - init_session, - error)) - { - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendErrorWithFormat("module importing failed: %s", error.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } - - return result.Succeeded(); + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_allow_reload = true; } - - CommandOptions m_options; -}; -OptionDefinition -CommandObjectCommandsScriptImport::CommandOptions::g_option_table[] = -{ - { LLDB_OPT_SET_1, false, "allow-reload", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not."}, - { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_script_import_options); + } + + // Instance variables to hold the values for command options. + + bool m_allow_reload; + }; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (m_interpreter.GetDebugger().GetScriptLanguage() != + lldb::eScriptLanguagePython) { + result.AppendError("only scripting language supported for module " + "importing is currently Python"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (command.empty()) { + result.AppendError("command script import needs one or more arguments"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + for (auto &entry : command.entries()) { + Error error; + + const bool init_session = true; + // FIXME: this is necessary because CommandObject::CheckRequirements() + // assumes that commands won't ever be recursively invoked, but it's + // actually possible to craft a Python script that does other "command + // script imports" in __lldb_init_module the real fix is to have recursive + // commands possible with a CommandInvocation object separate from the + // CommandObject itself, so that recursive command invocations won't stomp + // on each other (wrt to execution contents, options, and more) + m_exe_ctx.Clear(); + if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule( + entry.c_str(), m_options.m_allow_reload, init_session, error)) { + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } else { + result.AppendErrorWithFormat("module importing failed: %s", + error.AsCString()); + result.SetStatus(eReturnStatusFailed); + } + } + + return result.Succeeded(); + } + + CommandOptions m_options; }; //------------------------------------------------------------------------- // CommandObjectCommandsScriptAdd //------------------------------------------------------------------------- -class CommandObjectCommandsScriptAdd : - public CommandObjectParsed, - public IOHandlerDelegateMultiline -{ +static OptionEnumValueElement g_script_synchro_type[] = { + {eScriptedCommandSynchronicitySynchronous, "synchronous", + "Run synchronous"}, + {eScriptedCommandSynchronicityAsynchronous, "asynchronous", + "Run asynchronous"}, + {eScriptedCommandSynchronicityCurrentValue, "current", + "Do not alter current setting"}, + {0, nullptr, nullptr}}; + +static OptionDefinition g_script_add_options[] = { + // clang-format off + { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name." }, + { LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name." }, + { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "The help text to display for this command." }, + { LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, nullptr, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system." }, + // clang-format on +}; + +class CommandObjectCommandsScriptAdd : public CommandObjectParsed, + public IOHandlerDelegateMultiline { public: - CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) : - CommandObjectParsed(interpreter, - "command script add", + CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "command script add", "Add a scripted function as an LLDB command.", nullptr), - IOHandlerDelegateMultiline ("DONE"), - m_options (interpreter) - { - CommandArgumentEntry arg1; - CommandArgumentData cmd_arg; - - // Define the first (and only) variant of this arg. - cmd_arg.arg_type = eArgTypeCommandName; - cmd_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg1.push_back (cmd_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg1); - } - - ~CommandObjectCommandsScriptAdd() override = default; - - Options * - GetOptions () override - { - return &m_options; - } - + IOHandlerDelegateMultiline("DONE"), m_options() { + CommandArgumentEntry arg1; + CommandArgumentData cmd_arg; + + // Define the first (and only) variant of this arg. + cmd_arg.arg_type = eArgTypeCommandName; + cmd_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg1.push_back(cmd_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg1); + } + + ~CommandObjectCommandsScriptAdd() override = default; + + Options *GetOptions() override { return &m_options; } + protected: - class CommandOptions : public Options - { - public: - CommandOptions (CommandInterpreter &interpreter) : - Options (interpreter), - m_class_name(), - m_funct_name(), - m_short_help(), - m_synchronicity(eScriptedCommandSynchronicitySynchronous) - { - } + class CommandOptions : public Options { + public: + CommandOptions() + : Options(), m_class_name(), m_funct_name(), m_short_help(), + m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} + + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'f': + if (!option_arg.empty()) + m_funct_name = option_arg; + break; + case 'c': + if (!option_arg.empty()) + m_class_name = option_arg; + break; + case 'h': + if (!option_arg.empty()) + m_short_help = option_arg; + break; + case 's': + m_synchronicity = + (ScriptedCommandSynchronicity)Args::StringToOptionEnum( + option_arg, GetDefinitions()[option_idx].enum_values, 0, error); + if (!error.Success()) + error.SetErrorStringWithFormat( + "unrecognized value for synchronicity '%s'", + option_arg.str().c_str()); + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + + return error; + } - ~CommandOptions() override = default; - - Error - SetOptionValue (uint32_t option_idx, const char *option_arg) override - { - Error error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) - { - case 'f': - if (option_arg) - m_funct_name.assign(option_arg); - break; - case 'c': - if (option_arg) - m_class_name.assign(option_arg); - break; - case 'h': - if (option_arg) - m_short_help.assign(option_arg); - break; - case 's': - m_synchronicity = (ScriptedCommandSynchronicity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); - if (!error.Success()) - error.SetErrorStringWithFormat ("unrecognized value for synchronicity '%s'", option_arg); - break; - default: - error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); - break; - } - - return error; - } - - void - OptionParsingStarting () override - { - m_class_name.clear(); - m_funct_name.clear(); - m_short_help.clear(); - m_synchronicity = eScriptedCommandSynchronicitySynchronous; - } - - const OptionDefinition* - GetDefinitions () override - { - return g_option_table; - } - - // Options table: Required for subclasses of Options. - - static OptionDefinition g_option_table[]; - - // Instance variables to hold the values for command options. - - std::string m_class_name; - std::string m_funct_name; - std::string m_short_help; - ScriptedCommandSynchronicity m_synchronicity; - }; - - void - IOHandlerActivated (IOHandler &io_handler) override - { - StreamFileSP output_sp(io_handler.GetOutputStreamFile()); - if (output_sp) - { - output_sp->PutCString(g_python_command_instructions); - output_sp->Flush(); - } + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_class_name.clear(); + m_funct_name.clear(); + m_short_help.clear(); + m_synchronicity = eScriptedCommandSynchronicitySynchronous; } - - - void - IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override - { - StreamFileSP error_sp = io_handler.GetErrorStreamFile(); - - ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); - if (interpreter) - { - - StringList lines; - lines.SplitIntoLines(data); - if (lines.GetSize() > 0) - { - std::string funct_name_str; - if (interpreter->GenerateScriptAliasFunction (lines, funct_name_str)) - { - if (funct_name_str.empty()) - { - error_sp->Printf ("error: unable to obtain a function name, didn't add python command.\n"); - error_sp->Flush(); - } - else - { - // everything should be fine now, let's add this alias - - CommandObjectSP command_obj_sp(new CommandObjectPythonFunction (m_interpreter, - m_cmd_name, - funct_name_str.c_str(), - m_short_help, - m_synchronicity)); - - if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, true)) - { - error_sp->Printf ("error: unable to add selected command, didn't add python command.\n"); - error_sp->Flush(); - } - } - } - else - { - error_sp->Printf ("error: unable to create function, didn't add python command.\n"); - error_sp->Flush(); - } - } - else - { - error_sp->Printf ("error: empty function, didn't add python command.\n"); - error_sp->Flush(); - } - } - else - { - error_sp->Printf ("error: script interpreter missing, didn't add python command.\n"); - error_sp->Flush(); - } - io_handler.SetIsDone(true); + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_script_add_options); } -protected: - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) - { - result.AppendError ("only scripting language supported for scripted commands is currently Python"); - result.SetStatus (eReturnStatusFailed); - return false; - } - - size_t argc = command.GetArgumentCount(); - - if (argc != 1) - { - result.AppendError ("'command script add' requires one argument"); - result.SetStatus (eReturnStatusFailed); - return false; - } - - // Store the options in case we get multi-line input - m_cmd_name = command.GetArgumentAtIndex(0); - m_short_help.assign(m_options.m_short_help); - m_synchronicity = m_options.m_synchronicity; - - if (m_options.m_class_name.empty()) - { - if (m_options.m_funct_name.empty()) - { - m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt - *this, // IOHandlerDelegate - true, // Run IOHandler in async mode - nullptr); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions - } - else - { - CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter, - m_cmd_name, - m_options.m_funct_name, - m_options.m_short_help, - m_synchronicity)); - if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) - { - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError("cannot add command"); - result.SetStatus (eReturnStatusFailed); - } - } - } - else - { - ScriptInterpreter *interpreter = GetCommandInterpreter().GetScriptInterpreter(); - if (!interpreter) - { - result.AppendError("cannot find ScriptInterpreter"); - result.SetStatus(eReturnStatusFailed); - return false; - } - - auto cmd_obj_sp = interpreter->CreateScriptCommandObject(m_options.m_class_name.c_str()); - if (!cmd_obj_sp) - { - result.AppendError("cannot create helper object"); - result.SetStatus(eReturnStatusFailed); - return false; - } - - CommandObjectSP new_cmd(new CommandObjectScriptingObject(m_interpreter, - m_cmd_name, - cmd_obj_sp, - m_synchronicity)); - if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) - { - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError("cannot add command"); - result.SetStatus (eReturnStatusFailed); - } - } + // Instance variables to hold the values for command options. - return result.Succeeded(); - } - - CommandOptions m_options; - std::string m_cmd_name; + std::string m_class_name; + std::string m_funct_name; std::string m_short_help; ScriptedCommandSynchronicity m_synchronicity; -}; + }; -static OptionEnumValueElement g_script_synchro_type[] = -{ - { eScriptedCommandSynchronicitySynchronous, "synchronous", "Run synchronous"}, - { eScriptedCommandSynchronicityAsynchronous, "asynchronous", "Run asynchronous"}, - { eScriptedCommandSynchronicityCurrentValue, "current", "Do not alter current setting"}, - { 0, nullptr, nullptr } -}; + void IOHandlerActivated(IOHandler &io_handler) override { + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) { + output_sp->PutCString(g_python_command_instructions); + output_sp->Flush(); + } + } + + void IOHandlerInputComplete(IOHandler &io_handler, + std::string &data) override { + StreamFileSP error_sp = io_handler.GetErrorStreamFile(); + + ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); + if (interpreter) { + + StringList lines; + lines.SplitIntoLines(data); + if (lines.GetSize() > 0) { + std::string funct_name_str; + if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { + if (funct_name_str.empty()) { + error_sp->Printf("error: unable to obtain a function name, didn't " + "add python command.\n"); + error_sp->Flush(); + } else { + // everything should be fine now, let's add this alias + + CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( + m_interpreter, m_cmd_name, funct_name_str, m_short_help, + m_synchronicity)); + + if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, + true)) { + error_sp->Printf("error: unable to add selected command, didn't " + "add python command.\n"); + error_sp->Flush(); + } + } + } else { + error_sp->Printf( + "error: unable to create function, didn't add python command.\n"); + error_sp->Flush(); + } + } else { + error_sp->Printf("error: empty function, didn't add python command.\n"); + error_sp->Flush(); + } + } else { + error_sp->Printf( + "error: script interpreter missing, didn't add python command.\n"); + error_sp->Flush(); + } + + io_handler.SetIsDone(true); + } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (m_interpreter.GetDebugger().GetScriptLanguage() != + lldb::eScriptLanguagePython) { + result.AppendError("only scripting language supported for scripted " + "commands is currently Python"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (command.GetArgumentCount() != 1) { + result.AppendError("'command script add' requires one argument"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + // Store the options in case we get multi-line input + m_cmd_name = command[0].ref; + m_short_help.assign(m_options.m_short_help); + m_synchronicity = m_options.m_synchronicity; + + if (m_options.m_class_name.empty()) { + if (m_options.m_funct_name.empty()) { + m_interpreter.GetPythonCommandsFromIOHandler( + " ", // Prompt + *this, // IOHandlerDelegate + true, // Run IOHandler in async mode + nullptr); // Baton for the "io_handler" that will be passed back + // into our IOHandlerDelegate functions + } else { + CommandObjectSP new_cmd(new CommandObjectPythonFunction( + m_interpreter, m_cmd_name, m_options.m_funct_name, + m_options.m_short_help, m_synchronicity)); + if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } else { + result.AppendError("cannot add command"); + result.SetStatus(eReturnStatusFailed); + } + } + } else { + ScriptInterpreter *interpreter = + GetCommandInterpreter().GetScriptInterpreter(); + if (!interpreter) { + result.AppendError("cannot find ScriptInterpreter"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + auto cmd_obj_sp = interpreter->CreateScriptCommandObject( + m_options.m_class_name.c_str()); + if (!cmd_obj_sp) { + result.AppendError("cannot create helper object"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + CommandObjectSP new_cmd(new CommandObjectScriptingObject( + m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); + if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } else { + result.AppendError("cannot add command"); + result.SetStatus(eReturnStatusFailed); + } + } + + return result.Succeeded(); + } -OptionDefinition -CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] = -{ - { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name."}, - { LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name."}, - { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "The help text to display for this command."}, - { LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, nullptr, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."}, - { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } + CommandOptions m_options; + std::string m_cmd_name; + std::string m_short_help; + ScriptedCommandSynchronicity m_synchronicity; }; //------------------------------------------------------------------------- // CommandObjectCommandsScriptList //------------------------------------------------------------------------- -class CommandObjectCommandsScriptList : public CommandObjectParsed -{ +class CommandObjectCommandsScriptList : public CommandObjectParsed { public: - CommandObjectCommandsScriptList(CommandInterpreter &interpreter) : - CommandObjectParsed(interpreter, - "command script list", - "List defined scripted commands.", - nullptr) - { - } - - ~CommandObjectCommandsScriptList() override = default; - - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - m_interpreter.GetHelp(result, - CommandInterpreter::eCommandTypesUserDef); - - result.SetStatus (eReturnStatusSuccessFinishResult); - - return true; - } + CommandObjectCommandsScriptList(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "command script list", + "List defined scripted commands.", nullptr) {} + + ~CommandObjectCommandsScriptList() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); + + result.SetStatus(eReturnStatusSuccessFinishResult); + + return true; + } }; //------------------------------------------------------------------------- // CommandObjectCommandsScriptClear //------------------------------------------------------------------------- -class CommandObjectCommandsScriptClear : public CommandObjectParsed -{ +class CommandObjectCommandsScriptClear : public CommandObjectParsed { public: - CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) : - CommandObjectParsed(interpreter, - "command script clear", - "Delete all scripted commands.", - nullptr) - { - } + CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "command script clear", + "Delete all scripted commands.", nullptr) {} - ~CommandObjectCommandsScriptClear() override = default; + ~CommandObjectCommandsScriptClear() override = default; protected: - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - m_interpreter.RemoveAllUser(); - - result.SetStatus (eReturnStatusSuccessFinishResult); - - return true; - } + bool DoExecute(Args &command, CommandReturnObject &result) override { + m_interpreter.RemoveAllUser(); + + result.SetStatus(eReturnStatusSuccessFinishResult); + + return true; + } }; //------------------------------------------------------------------------- // CommandObjectCommandsScriptDelete //------------------------------------------------------------------------- -class CommandObjectCommandsScriptDelete : public CommandObjectParsed -{ +class CommandObjectCommandsScriptDelete : public CommandObjectParsed { public: - CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) : - CommandObjectParsed(interpreter, - "command script delete", - "Delete a scripted command.", - nullptr) - { - CommandArgumentEntry arg1; - CommandArgumentData cmd_arg; - - // Define the first (and only) variant of this arg. - cmd_arg.arg_type = eArgTypeCommandName; - cmd_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg1.push_back (cmd_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg1); - } - - ~CommandObjectCommandsScriptDelete() override = default; + CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "command script delete", + "Delete a scripted command.", nullptr) { + CommandArgumentEntry arg1; + CommandArgumentData cmd_arg; + + // Define the first (and only) variant of this arg. + cmd_arg.arg_type = eArgTypeCommandName; + cmd_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg1.push_back(cmd_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg1); + } + + ~CommandObjectCommandsScriptDelete() override = default; protected: - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - - size_t argc = command.GetArgumentCount(); - - if (argc != 1) - { - result.AppendError ("'command script delete' requires one argument"); - result.SetStatus (eReturnStatusFailed); - return false; - } - - const char* cmd_name = command.GetArgumentAtIndex(0); - - if (cmd_name && *cmd_name && m_interpreter.HasUserCommands() && m_interpreter.UserCommandExists(cmd_name)) - { - m_interpreter.RemoveUser(cmd_name); - result.SetStatus (eReturnStatusSuccessFinishResult); - } - else - { - result.AppendErrorWithFormat ("command %s not found", cmd_name); - result.SetStatus (eReturnStatusFailed); - } - - return result.Succeeded(); + bool DoExecute(Args &command, CommandReturnObject &result) override { + + if (command.GetArgumentCount() != 1) { + result.AppendError("'command script delete' requires one argument"); + result.SetStatus(eReturnStatusFailed); + return false; } + + auto cmd_name = command[0].ref; + + if (cmd_name.empty() || !m_interpreter.HasUserCommands() || + !m_interpreter.UserCommandExists(cmd_name)) { + result.AppendErrorWithFormat("command %s not found", command[0].c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + m_interpreter.RemoveUser(cmd_name); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } }; #pragma mark CommandObjectMultiwordCommandsScript @@ -2256,22 +1900,30 @@ protected: // CommandObjectMultiwordCommandsScript //------------------------------------------------------------------------- -class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword -{ +class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { public: - CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "command script", - "Commands for managing custom commands implemented by interpreter scripts.", - "command script <subcommand> [<subcommand-options>]") - { - LoadSubCommand ("add", CommandObjectSP (new CommandObjectCommandsScriptAdd (interpreter))); - LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsScriptDelete (interpreter))); - LoadSubCommand ("clear", CommandObjectSP (new CommandObjectCommandsScriptClear (interpreter))); - LoadSubCommand ("list", CommandObjectSP (new CommandObjectCommandsScriptList (interpreter))); - LoadSubCommand ("import", CommandObjectSP (new CommandObjectCommandsScriptImport (interpreter))); - } - - ~CommandObjectMultiwordCommandsScript() override = default; + CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "command script", "Commands for managing custom " + "commands implemented by " + "interpreter scripts.", + "command script <subcommand> [<subcommand-options>]") { + LoadSubCommand("add", CommandObjectSP( + new CommandObjectCommandsScriptAdd(interpreter))); + LoadSubCommand( + "delete", + CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); + LoadSubCommand( + "clear", + CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); + LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( + interpreter))); + LoadSubCommand( + "import", + CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); + } + + ~CommandObjectMultiwordCommandsScript() override = default; }; #pragma mark CommandObjectMultiwordCommands @@ -2280,17 +1932,26 @@ public: // CommandObjectMultiwordCommands //------------------------------------------------------------------------- -CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "command", "Commands for managing custom LLDB commands.", - "command <subcommand> [<subcommand-options>]") -{ - LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter))); - LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter))); - LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter))); - LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsDelete (interpreter))); - LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter))); - LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter))); - LoadSubCommand ("script", CommandObjectSP (new CommandObjectMultiwordCommandsScript (interpreter))); +CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( + CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "command", + "Commands for managing custom LLDB commands.", + "command <subcommand> [<subcommand-options>]") { + LoadSubCommand("source", + CommandObjectSP(new CommandObjectCommandsSource(interpreter))); + LoadSubCommand("alias", + CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); + LoadSubCommand("unalias", CommandObjectSP( + new CommandObjectCommandsUnalias(interpreter))); + LoadSubCommand("delete", + CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); + LoadSubCommand( + "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); + LoadSubCommand("history", CommandObjectSP( + new CommandObjectCommandsHistory(interpreter))); + LoadSubCommand( + "script", + CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); } CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; |