15ffd83dbSDimitry Andric //===-- CommandObjectCommands.cpp -----------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "CommandObjectCommands.h"
100b57cec5SDimitry Andric #include "CommandObjectHelp.h"
11af732203SDimitry Andric #include "CommandObjectRegexCommand.h"
120b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
130b57cec5SDimitry Andric #include "lldb/Core/IOHandler.h"
140b57cec5SDimitry Andric #include "lldb/Interpreter/CommandHistory.h"
150b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
160b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
170b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
180b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueBoolean.h"
190b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueString.h"
200b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueUInt64.h"
210b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
220b57cec5SDimitry Andric #include "lldb/Interpreter/ScriptInterpreter.h"
230b57cec5SDimitry Andric #include "lldb/Utility/Args.h"
240b57cec5SDimitry Andric #include "lldb/Utility/StringList.h"
25af732203SDimitry Andric #include "llvm/ADT/StringRef.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace lldb;
280b57cec5SDimitry Andric using namespace lldb_private;
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric // CommandObjectCommandsSource
310b57cec5SDimitry Andric 
329dba64beSDimitry Andric #define LLDB_OPTIONS_source
339dba64beSDimitry Andric #include "CommandOptions.inc"
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric class CommandObjectCommandsSource : public CommandObjectParsed {
360b57cec5SDimitry Andric public:
CommandObjectCommandsSource(CommandInterpreter & interpreter)370b57cec5SDimitry Andric   CommandObjectCommandsSource(CommandInterpreter &interpreter)
380b57cec5SDimitry Andric       : CommandObjectParsed(
390b57cec5SDimitry Andric             interpreter, "command source",
400b57cec5SDimitry Andric             "Read and execute LLDB commands from the file <filename>.",
410b57cec5SDimitry Andric             nullptr),
420b57cec5SDimitry Andric         m_options() {
430b57cec5SDimitry Andric     CommandArgumentEntry arg;
440b57cec5SDimitry Andric     CommandArgumentData file_arg;
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
470b57cec5SDimitry Andric     file_arg.arg_type = eArgTypeFilename;
480b57cec5SDimitry Andric     file_arg.arg_repetition = eArgRepeatPlain;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
510b57cec5SDimitry Andric     // argument entry.
520b57cec5SDimitry Andric     arg.push_back(file_arg);
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
550b57cec5SDimitry Andric     m_arguments.push_back(arg);
560b57cec5SDimitry Andric   }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   ~CommandObjectCommandsSource() override = default;
590b57cec5SDimitry Andric 
GetRepeatCommand(Args & current_command_args,uint32_t index)600b57cec5SDimitry Andric   const char *GetRepeatCommand(Args &current_command_args,
610b57cec5SDimitry Andric                                uint32_t index) override {
620b57cec5SDimitry Andric     return "";
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric 
659dba64beSDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)669dba64beSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
670b57cec5SDimitry Andric                            OptionElementVector &opt_element_vector) override {
680b57cec5SDimitry Andric     CommandCompletions::InvokeCommonCompletionCallbacks(
690b57cec5SDimitry Andric         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
700b57cec5SDimitry Andric         request, nullptr);
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric 
GetOptions()730b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric protected:
760b57cec5SDimitry Andric   class CommandOptions : public Options {
770b57cec5SDimitry Andric   public:
CommandOptions()780b57cec5SDimitry Andric     CommandOptions()
790b57cec5SDimitry Andric         : Options(), m_stop_on_error(true), m_silent_run(false),
800b57cec5SDimitry Andric           m_stop_on_continue(true) {}
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric     ~CommandOptions() override = default;
830b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)840b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
850b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
860b57cec5SDimitry Andric       Status error;
870b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric       switch (short_option) {
900b57cec5SDimitry Andric       case 'e':
910b57cec5SDimitry Andric         error = m_stop_on_error.SetValueFromString(option_arg);
920b57cec5SDimitry Andric         break;
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric       case 'c':
950b57cec5SDimitry Andric         error = m_stop_on_continue.SetValueFromString(option_arg);
960b57cec5SDimitry Andric         break;
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric       case 's':
990b57cec5SDimitry Andric         error = m_silent_run.SetValueFromString(option_arg);
1000b57cec5SDimitry Andric         break;
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric       default:
1039dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
1040b57cec5SDimitry Andric       }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric       return error;
1070b57cec5SDimitry Andric     }
1080b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)1090b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
1100b57cec5SDimitry Andric       m_stop_on_error.Clear();
1110b57cec5SDimitry Andric       m_silent_run.Clear();
1120b57cec5SDimitry Andric       m_stop_on_continue.Clear();
1130b57cec5SDimitry Andric     }
1140b57cec5SDimitry Andric 
GetDefinitions()1150b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1160b57cec5SDimitry Andric       return llvm::makeArrayRef(g_source_options);
1170b57cec5SDimitry Andric     }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric     OptionValueBoolean m_stop_on_error;
1220b57cec5SDimitry Andric     OptionValueBoolean m_silent_run;
1230b57cec5SDimitry Andric     OptionValueBoolean m_stop_on_continue;
1240b57cec5SDimitry Andric   };
1250b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)1260b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
1270b57cec5SDimitry Andric     if (command.GetArgumentCount() != 1) {
1280b57cec5SDimitry Andric       result.AppendErrorWithFormat(
1290b57cec5SDimitry Andric           "'%s' takes exactly one executable filename argument.\n",
1300b57cec5SDimitry Andric           GetCommandName().str().c_str());
1310b57cec5SDimitry Andric       return false;
1320b57cec5SDimitry Andric     }
1330b57cec5SDimitry Andric 
1349dba64beSDimitry Andric     FileSpec cmd_file(command[0].ref());
1350b57cec5SDimitry Andric     FileSystem::Instance().Resolve(cmd_file);
1360b57cec5SDimitry Andric 
137*5f7ddb14SDimitry Andric     CommandInterpreterRunOptions options;
1380b57cec5SDimitry Andric     // If any options were set, then use them
1390b57cec5SDimitry Andric     if (m_options.m_stop_on_error.OptionWasSet() ||
1400b57cec5SDimitry Andric         m_options.m_silent_run.OptionWasSet() ||
1410b57cec5SDimitry Andric         m_options.m_stop_on_continue.OptionWasSet()) {
1420b57cec5SDimitry Andric       if (m_options.m_stop_on_continue.OptionWasSet())
1430b57cec5SDimitry Andric         options.SetStopOnContinue(
1440b57cec5SDimitry Andric             m_options.m_stop_on_continue.GetCurrentValue());
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric       if (m_options.m_stop_on_error.OptionWasSet())
1470b57cec5SDimitry Andric         options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric       // Individual silent setting is override for global command echo settings.
1500b57cec5SDimitry Andric       if (m_options.m_silent_run.GetCurrentValue()) {
1510b57cec5SDimitry Andric         options.SetSilent(true);
1520b57cec5SDimitry Andric       } else {
1530b57cec5SDimitry Andric         options.SetPrintResults(true);
1540b57cec5SDimitry Andric         options.SetPrintErrors(true);
1550b57cec5SDimitry Andric         options.SetEchoCommands(m_interpreter.GetEchoCommands());
1560b57cec5SDimitry Andric         options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
1570b57cec5SDimitry Andric       }
1580b57cec5SDimitry Andric     }
159*5f7ddb14SDimitry Andric 
160*5f7ddb14SDimitry Andric     m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
1610b57cec5SDimitry Andric     return result.Succeeded();
1620b57cec5SDimitry Andric   }
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   CommandOptions m_options;
1650b57cec5SDimitry Andric };
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric #pragma mark CommandObjectCommandsAlias
1680b57cec5SDimitry Andric // CommandObjectCommandsAlias
1690b57cec5SDimitry Andric 
1709dba64beSDimitry Andric #define LLDB_OPTIONS_alias
1719dba64beSDimitry Andric #include "CommandOptions.inc"
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric static const char *g_python_command_instructions =
1740b57cec5SDimitry Andric     "Enter your Python command(s). Type 'DONE' to end.\n"
1750b57cec5SDimitry Andric     "You must define a Python function with this signature:\n"
1760b57cec5SDimitry Andric     "def my_command_impl(debugger, args, result, internal_dict):\n";
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric class CommandObjectCommandsAlias : public CommandObjectRaw {
1790b57cec5SDimitry Andric protected:
1800b57cec5SDimitry Andric   class CommandOptions : public OptionGroup {
1810b57cec5SDimitry Andric   public:
CommandOptions()1820b57cec5SDimitry Andric     CommandOptions() : OptionGroup(), m_help(), m_long_help() {}
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric     ~CommandOptions() override = default;
1850b57cec5SDimitry Andric 
GetDefinitions()1860b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1870b57cec5SDimitry Andric       return llvm::makeArrayRef(g_alias_options);
1880b57cec5SDimitry Andric     }
1890b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)1900b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
1910b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
1920b57cec5SDimitry Andric       Status error;
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric       const int short_option = GetDefinitions()[option_idx].short_option;
1950b57cec5SDimitry Andric       std::string option_str(option_value);
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric       switch (short_option) {
1980b57cec5SDimitry Andric       case 'h':
1990b57cec5SDimitry Andric         m_help.SetCurrentValue(option_str);
2000b57cec5SDimitry Andric         m_help.SetOptionWasSet();
2010b57cec5SDimitry Andric         break;
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric       case 'H':
2040b57cec5SDimitry Andric         m_long_help.SetCurrentValue(option_str);
2050b57cec5SDimitry Andric         m_long_help.SetOptionWasSet();
2060b57cec5SDimitry Andric         break;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric       default:
2099dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
2100b57cec5SDimitry Andric       }
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric       return error;
2130b57cec5SDimitry Andric     }
2140b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)2150b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
2160b57cec5SDimitry Andric       m_help.Clear();
2170b57cec5SDimitry Andric       m_long_help.Clear();
2180b57cec5SDimitry Andric     }
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric     OptionValueString m_help;
2210b57cec5SDimitry Andric     OptionValueString m_long_help;
2220b57cec5SDimitry Andric   };
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   OptionGroupOptions m_option_group;
2250b57cec5SDimitry Andric   CommandOptions m_command_options;
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric public:
GetOptions()2280b57cec5SDimitry Andric   Options *GetOptions() override { return &m_option_group; }
2290b57cec5SDimitry Andric 
CommandObjectCommandsAlias(CommandInterpreter & interpreter)2300b57cec5SDimitry Andric   CommandObjectCommandsAlias(CommandInterpreter &interpreter)
2310b57cec5SDimitry Andric       : CommandObjectRaw(
2320b57cec5SDimitry Andric             interpreter, "command alias",
2330b57cec5SDimitry Andric             "Define a custom command in terms of an existing command."),
2340b57cec5SDimitry Andric         m_option_group(), m_command_options() {
2350b57cec5SDimitry Andric     m_option_group.Append(&m_command_options);
2360b57cec5SDimitry Andric     m_option_group.Finalize();
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric     SetHelpLong(
2390b57cec5SDimitry Andric         "'alias' allows the user to create a short-cut or abbreviation for long \
2400b57cec5SDimitry Andric commands, multi-word commands, and commands that take particular options.  \
2410b57cec5SDimitry Andric Below are some simple examples of how one might use the 'alias' command:"
2420b57cec5SDimitry Andric         R"(
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric (lldb) command alias sc script
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric     Creates the abbreviation 'sc' for the 'script' command.
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric (lldb) command alias bp breakpoint
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric )"
2510b57cec5SDimitry Andric         "    Creates the abbreviation 'bp' for the 'breakpoint' command.  Since \
2520b57cec5SDimitry Andric breakpoint commands are two-word commands, the user would still need to \
2530b57cec5SDimitry Andric enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
2540b57cec5SDimitry Andric         R"(
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric (lldb) command alias bpl breakpoint list
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric     Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric )"
2610b57cec5SDimitry Andric         "An alias can include some options for the command, with the values either \
2620b57cec5SDimitry Andric filled in at the time the alias is created, or specified as positional \
2630b57cec5SDimitry Andric arguments, to be filled in when the alias is invoked.  The following example \
2640b57cec5SDimitry Andric shows how to create aliases with options:"
2650b57cec5SDimitry Andric         R"(
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric (lldb) command alias bfl breakpoint set -f %1 -l %2
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric )"
2700b57cec5SDimitry Andric         "    Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
2710b57cec5SDimitry Andric options already part of the alias.  So if the user wants to set a breakpoint \
2720b57cec5SDimitry Andric by file and line without explicitly having to use the -f and -l options, the \
2730b57cec5SDimitry Andric user can now use 'bfl' instead.  The '%1' and '%2' are positional placeholders \
2740b57cec5SDimitry Andric for the actual arguments that will be passed when the alias command is used.  \
2750b57cec5SDimitry Andric The number in the placeholder refers to the position/order the actual value \
2760b57cec5SDimitry Andric occupies when the alias is used.  All the occurrences of '%1' in the alias \
2770b57cec5SDimitry Andric will be replaced with the first argument, all the occurrences of '%2' in the \
2780b57cec5SDimitry Andric alias will be replaced with the second argument, and so on.  This also allows \
2790b57cec5SDimitry Andric actual arguments to be used multiple times within an alias (see 'process \
2800b57cec5SDimitry Andric launch' example below)."
2810b57cec5SDimitry Andric         R"(
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric )"
2840b57cec5SDimitry Andric         "Note: the positional arguments must substitute as whole words in the resultant \
2850b57cec5SDimitry Andric command, so you can't at present do something like this to append the file extension \
2860b57cec5SDimitry Andric \".cpp\":"
2870b57cec5SDimitry Andric         R"(
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric )"
2920b57cec5SDimitry Andric         "For more complex aliasing, use the \"command regex\" command instead.  In the \
2930b57cec5SDimitry Andric 'bfl' case above, the actual file value will be filled in with the first argument \
2940b57cec5SDimitry Andric following 'bfl' and the actual line number value will be filled in with the second \
2950b57cec5SDimitry Andric argument.  The user would use this alias as follows:"
2960b57cec5SDimitry Andric         R"(
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric (lldb) command alias bfl breakpoint set -f %1 -l %2
2990b57cec5SDimitry Andric (lldb) bfl my-file.c 137
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric Another example:
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric (lldb) command alias pltty process launch -s -o %1 -e %1
3060b57cec5SDimitry Andric (lldb) pltty /dev/tty0
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric     Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric )"
3110b57cec5SDimitry Andric         "If the user always wanted to pass the same value to a particular option, the \
3120b57cec5SDimitry Andric alias could be defined with that value directly in the alias as a constant, \
3130b57cec5SDimitry Andric rather than using a positional placeholder:"
3140b57cec5SDimitry Andric         R"(
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric (lldb) command alias bl3 breakpoint set -f %1 -l 3
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric     Always sets a breakpoint on line 3 of whatever file is indicated.)");
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric     CommandArgumentEntry arg1;
3210b57cec5SDimitry Andric     CommandArgumentEntry arg2;
3220b57cec5SDimitry Andric     CommandArgumentEntry arg3;
3230b57cec5SDimitry Andric     CommandArgumentData alias_arg;
3240b57cec5SDimitry Andric     CommandArgumentData cmd_arg;
3250b57cec5SDimitry Andric     CommandArgumentData options_arg;
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
3280b57cec5SDimitry Andric     alias_arg.arg_type = eArgTypeAliasName;
3290b57cec5SDimitry Andric     alias_arg.arg_repetition = eArgRepeatPlain;
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
3320b57cec5SDimitry Andric     // argument entry.
3330b57cec5SDimitry Andric     arg1.push_back(alias_arg);
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
3360b57cec5SDimitry Andric     cmd_arg.arg_type = eArgTypeCommandName;
3370b57cec5SDimitry Andric     cmd_arg.arg_repetition = eArgRepeatPlain;
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
3400b57cec5SDimitry Andric     // argument entry.
3410b57cec5SDimitry Andric     arg2.push_back(cmd_arg);
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
3440b57cec5SDimitry Andric     options_arg.arg_type = eArgTypeAliasOptions;
3450b57cec5SDimitry Andric     options_arg.arg_repetition = eArgRepeatOptional;
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
3480b57cec5SDimitry Andric     // argument entry.
3490b57cec5SDimitry Andric     arg3.push_back(options_arg);
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
3520b57cec5SDimitry Andric     m_arguments.push_back(arg1);
3530b57cec5SDimitry Andric     m_arguments.push_back(arg2);
3540b57cec5SDimitry Andric     m_arguments.push_back(arg3);
3550b57cec5SDimitry Andric   }
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   ~CommandObjectCommandsAlias() override = default;
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)3600b57cec5SDimitry Andric   bool DoExecute(llvm::StringRef raw_command_line,
3610b57cec5SDimitry Andric                  CommandReturnObject &result) override {
3620b57cec5SDimitry Andric     if (raw_command_line.empty()) {
3630b57cec5SDimitry Andric       result.AppendError("'command alias' requires at least two arguments");
3640b57cec5SDimitry Andric       return false;
3650b57cec5SDimitry Andric     }
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric     ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
3680b57cec5SDimitry Andric     m_option_group.NotifyOptionParsingStarting(&exe_ctx);
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric     OptionsWithRaw args_with_suffix(raw_command_line);
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric     if (args_with_suffix.HasArgs())
3730b57cec5SDimitry Andric       if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
3740b57cec5SDimitry Andric                                  m_option_group, exe_ctx))
3750b57cec5SDimitry Andric         return false;
3760b57cec5SDimitry Andric 
3775ffd83dbSDimitry Andric     llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
3780b57cec5SDimitry Andric     Args args(raw_command_string);
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric     if (args.GetArgumentCount() < 2) {
3810b57cec5SDimitry Andric       result.AppendError("'command alias' requires at least two arguments");
3820b57cec5SDimitry Andric       return false;
3830b57cec5SDimitry Andric     }
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric     // Get the alias command.
3860b57cec5SDimitry Andric 
3879dba64beSDimitry Andric     auto alias_command = args[0].ref();
3880b57cec5SDimitry Andric     if (alias_command.startswith("-")) {
3890b57cec5SDimitry Andric       result.AppendError("aliases starting with a dash are not supported");
3900b57cec5SDimitry Andric       if (alias_command == "--help" || alias_command == "--long-help") {
3910b57cec5SDimitry Andric         result.AppendWarning("if trying to pass options to 'command alias' add "
3920b57cec5SDimitry Andric                              "a -- at the end of the options");
3930b57cec5SDimitry Andric       }
3940b57cec5SDimitry Andric       return false;
3950b57cec5SDimitry Andric     }
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric     // Strip the new alias name off 'raw_command_string'  (leave it on args,
3980b57cec5SDimitry Andric     // which gets passed to 'Execute', which does the stripping itself.
3990b57cec5SDimitry Andric     size_t pos = raw_command_string.find(alias_command);
4000b57cec5SDimitry Andric     if (pos == 0) {
4010b57cec5SDimitry Andric       raw_command_string = raw_command_string.substr(alias_command.size());
4020b57cec5SDimitry Andric       pos = raw_command_string.find_first_not_of(' ');
4030b57cec5SDimitry Andric       if ((pos != std::string::npos) && (pos > 0))
4040b57cec5SDimitry Andric         raw_command_string = raw_command_string.substr(pos);
4050b57cec5SDimitry Andric     } else {
4060b57cec5SDimitry Andric       result.AppendError("Error parsing command string.  No alias created.");
4070b57cec5SDimitry Andric       return false;
4080b57cec5SDimitry Andric     }
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric     // Verify that the command is alias-able.
4110b57cec5SDimitry Andric     if (m_interpreter.CommandExists(alias_command)) {
4120b57cec5SDimitry Andric       result.AppendErrorWithFormat(
4130b57cec5SDimitry Andric           "'%s' is a permanent debugger command and cannot be redefined.\n",
4140b57cec5SDimitry Andric           args[0].c_str());
4150b57cec5SDimitry Andric       return false;
4160b57cec5SDimitry Andric     }
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric     // Get CommandObject that is being aliased. The command name is read from
4190b57cec5SDimitry Andric     // the front of raw_command_string. raw_command_string is returned with the
4200b57cec5SDimitry Andric     // name of the command object stripped off the front.
4210b57cec5SDimitry Andric     llvm::StringRef original_raw_command_string = raw_command_string;
4220b57cec5SDimitry Andric     CommandObject *cmd_obj =
4230b57cec5SDimitry Andric         m_interpreter.GetCommandObjectForCommand(raw_command_string);
4240b57cec5SDimitry Andric 
4250b57cec5SDimitry Andric     if (!cmd_obj) {
4260b57cec5SDimitry Andric       result.AppendErrorWithFormat("invalid command given to 'command alias'. "
4270b57cec5SDimitry Andric                                    "'%s' does not begin with a valid command."
4280b57cec5SDimitry Andric                                    "  No alias created.",
4290b57cec5SDimitry Andric                                    original_raw_command_string.str().c_str());
4300b57cec5SDimitry Andric       return false;
4310b57cec5SDimitry Andric     } else if (!cmd_obj->WantsRawCommandString()) {
4320b57cec5SDimitry Andric       // Note that args was initialized with the original command, and has not
4330b57cec5SDimitry Andric       // been updated to this point. Therefore can we pass it to the version of
4340b57cec5SDimitry Andric       // Execute that does not need/expect raw input in the alias.
4350b57cec5SDimitry Andric       return HandleAliasingNormalCommand(args, result);
4360b57cec5SDimitry Andric     } else {
4370b57cec5SDimitry Andric       return HandleAliasingRawCommand(alias_command, raw_command_string,
4380b57cec5SDimitry Andric                                       *cmd_obj, result);
4390b57cec5SDimitry Andric     }
4400b57cec5SDimitry Andric     return result.Succeeded();
4410b57cec5SDimitry Andric   }
4420b57cec5SDimitry Andric 
HandleAliasingRawCommand(llvm::StringRef alias_command,llvm::StringRef raw_command_string,CommandObject & cmd_obj,CommandReturnObject & result)4430b57cec5SDimitry Andric   bool HandleAliasingRawCommand(llvm::StringRef alias_command,
4440b57cec5SDimitry Andric                                 llvm::StringRef raw_command_string,
4450b57cec5SDimitry Andric                                 CommandObject &cmd_obj,
4460b57cec5SDimitry Andric                                 CommandReturnObject &result) {
4470b57cec5SDimitry Andric     // Verify & handle any options/arguments passed to the alias command
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric     OptionArgVectorSP option_arg_vector_sp =
4500b57cec5SDimitry Andric         OptionArgVectorSP(new OptionArgVector);
4510b57cec5SDimitry Andric 
4520b57cec5SDimitry Andric     if (CommandObjectSP cmd_obj_sp =
453af732203SDimitry Andric             m_interpreter.GetCommandSPExact(cmd_obj.GetCommandName())) {
4540b57cec5SDimitry Andric       if (m_interpreter.AliasExists(alias_command) ||
4550b57cec5SDimitry Andric           m_interpreter.UserCommandExists(alias_command)) {
4560b57cec5SDimitry Andric         result.AppendWarningWithFormat(
4570b57cec5SDimitry Andric             "Overwriting existing definition for '%s'.\n",
4580b57cec5SDimitry Andric             alias_command.str().c_str());
4590b57cec5SDimitry Andric       }
4600b57cec5SDimitry Andric       if (CommandAlias *alias = m_interpreter.AddAlias(
4610b57cec5SDimitry Andric               alias_command, cmd_obj_sp, raw_command_string)) {
4620b57cec5SDimitry Andric         if (m_command_options.m_help.OptionWasSet())
4630b57cec5SDimitry Andric           alias->SetHelp(m_command_options.m_help.GetCurrentValue());
4640b57cec5SDimitry Andric         if (m_command_options.m_long_help.OptionWasSet())
4650b57cec5SDimitry Andric           alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
4660b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
4670b57cec5SDimitry Andric       } else {
4680b57cec5SDimitry Andric         result.AppendError("Unable to create requested alias.\n");
4690b57cec5SDimitry Andric       }
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric     } else {
4720b57cec5SDimitry Andric       result.AppendError("Unable to create requested alias.\n");
4730b57cec5SDimitry Andric     }
4740b57cec5SDimitry Andric 
4750b57cec5SDimitry Andric     return result.Succeeded();
4760b57cec5SDimitry Andric   }
4770b57cec5SDimitry Andric 
HandleAliasingNormalCommand(Args & args,CommandReturnObject & result)4780b57cec5SDimitry Andric   bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
4790b57cec5SDimitry Andric     size_t argc = args.GetArgumentCount();
4800b57cec5SDimitry Andric 
4810b57cec5SDimitry Andric     if (argc < 2) {
4820b57cec5SDimitry Andric       result.AppendError("'command alias' requires at least two arguments");
4830b57cec5SDimitry Andric       return false;
4840b57cec5SDimitry Andric     }
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric     // Save these in std::strings since we're going to shift them off.
4875ffd83dbSDimitry Andric     const std::string alias_command(std::string(args[0].ref()));
4885ffd83dbSDimitry Andric     const std::string actual_command(std::string(args[1].ref()));
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric     args.Shift(); // Shift the alias command word off the argument vector.
4910b57cec5SDimitry Andric     args.Shift(); // Shift the old command word off the argument vector.
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric     // Verify that the command is alias'able, and get the appropriate command
4940b57cec5SDimitry Andric     // object.
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric     if (m_interpreter.CommandExists(alias_command)) {
4970b57cec5SDimitry Andric       result.AppendErrorWithFormat(
4980b57cec5SDimitry Andric           "'%s' is a permanent debugger command and cannot be redefined.\n",
4990b57cec5SDimitry Andric           alias_command.c_str());
5000b57cec5SDimitry Andric       return false;
5010b57cec5SDimitry Andric     }
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric     CommandObjectSP command_obj_sp(
5040b57cec5SDimitry Andric         m_interpreter.GetCommandSPExact(actual_command, true));
5050b57cec5SDimitry Andric     CommandObjectSP subcommand_obj_sp;
5060b57cec5SDimitry Andric     bool use_subcommand = false;
5070b57cec5SDimitry Andric     if (!command_obj_sp) {
5080b57cec5SDimitry Andric       result.AppendErrorWithFormat("'%s' is not an existing command.\n",
5090b57cec5SDimitry Andric                                    actual_command.c_str());
5100b57cec5SDimitry Andric       return false;
5110b57cec5SDimitry Andric     }
5120b57cec5SDimitry Andric     CommandObject *cmd_obj = command_obj_sp.get();
5130b57cec5SDimitry Andric     CommandObject *sub_cmd_obj = nullptr;
5140b57cec5SDimitry Andric     OptionArgVectorSP option_arg_vector_sp =
5150b57cec5SDimitry Andric         OptionArgVectorSP(new OptionArgVector);
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric     while (cmd_obj->IsMultiwordObject() && !args.empty()) {
5189dba64beSDimitry Andric       auto sub_command = args[0].ref();
5190b57cec5SDimitry Andric       assert(!sub_command.empty());
5200b57cec5SDimitry Andric       subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
5210b57cec5SDimitry Andric       if (!subcommand_obj_sp) {
5220b57cec5SDimitry Andric         result.AppendErrorWithFormat(
5230b57cec5SDimitry Andric             "'%s' is not a valid sub-command of '%s'.  "
5240b57cec5SDimitry Andric             "Unable to create alias.\n",
5250b57cec5SDimitry Andric             args[0].c_str(), actual_command.c_str());
5260b57cec5SDimitry Andric         return false;
5270b57cec5SDimitry Andric       }
5280b57cec5SDimitry Andric 
5290b57cec5SDimitry Andric       sub_cmd_obj = subcommand_obj_sp.get();
5300b57cec5SDimitry Andric       use_subcommand = true;
5310b57cec5SDimitry Andric       args.Shift(); // Shift the sub_command word off the argument vector.
5320b57cec5SDimitry Andric       cmd_obj = sub_cmd_obj;
5330b57cec5SDimitry Andric     }
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric     // Verify & handle any options/arguments passed to the alias command
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric     std::string args_string;
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric     if (!args.empty()) {
5400b57cec5SDimitry Andric       CommandObjectSP tmp_sp =
541af732203SDimitry Andric           m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
5420b57cec5SDimitry Andric       if (use_subcommand)
543af732203SDimitry Andric         tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
5440b57cec5SDimitry Andric 
5450b57cec5SDimitry Andric       args.GetCommandString(args_string);
5460b57cec5SDimitry Andric     }
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric     if (m_interpreter.AliasExists(alias_command) ||
5490b57cec5SDimitry Andric         m_interpreter.UserCommandExists(alias_command)) {
5500b57cec5SDimitry Andric       result.AppendWarningWithFormat(
5510b57cec5SDimitry Andric           "Overwriting existing definition for '%s'.\n", alias_command.c_str());
5520b57cec5SDimitry Andric     }
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric     if (CommandAlias *alias = m_interpreter.AddAlias(
5550b57cec5SDimitry Andric             alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
5560b57cec5SDimitry Andric             args_string)) {
5570b57cec5SDimitry Andric       if (m_command_options.m_help.OptionWasSet())
5580b57cec5SDimitry Andric         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
5590b57cec5SDimitry Andric       if (m_command_options.m_long_help.OptionWasSet())
5600b57cec5SDimitry Andric         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
5610b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
5620b57cec5SDimitry Andric     } else {
5630b57cec5SDimitry Andric       result.AppendError("Unable to create requested alias.\n");
5640b57cec5SDimitry Andric       return false;
5650b57cec5SDimitry Andric     }
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric     return result.Succeeded();
5680b57cec5SDimitry Andric   }
5690b57cec5SDimitry Andric };
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric #pragma mark CommandObjectCommandsUnalias
5720b57cec5SDimitry Andric // CommandObjectCommandsUnalias
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric class CommandObjectCommandsUnalias : public CommandObjectParsed {
5750b57cec5SDimitry Andric public:
CommandObjectCommandsUnalias(CommandInterpreter & interpreter)5760b57cec5SDimitry Andric   CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
5770b57cec5SDimitry Andric       : CommandObjectParsed(
5780b57cec5SDimitry Andric             interpreter, "command unalias",
5790b57cec5SDimitry Andric             "Delete one or more custom commands defined by 'command alias'.",
5800b57cec5SDimitry Andric             nullptr) {
5810b57cec5SDimitry Andric     CommandArgumentEntry arg;
5820b57cec5SDimitry Andric     CommandArgumentData alias_arg;
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
5850b57cec5SDimitry Andric     alias_arg.arg_type = eArgTypeAliasName;
5860b57cec5SDimitry Andric     alias_arg.arg_repetition = eArgRepeatPlain;
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
5890b57cec5SDimitry Andric     // argument entry.
5900b57cec5SDimitry Andric     arg.push_back(alias_arg);
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
5930b57cec5SDimitry Andric     m_arguments.push_back(arg);
5940b57cec5SDimitry Andric   }
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric   ~CommandObjectCommandsUnalias() override = default;
5970b57cec5SDimitry Andric 
598af732203SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)599af732203SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
600af732203SDimitry Andric                            OptionElementVector &opt_element_vector) override {
601af732203SDimitry Andric     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
602af732203SDimitry Andric       return;
603af732203SDimitry Andric 
604af732203SDimitry Andric     for (const auto &ent : m_interpreter.GetAliases()) {
605af732203SDimitry Andric       request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
606af732203SDimitry Andric     }
607af732203SDimitry Andric   }
608af732203SDimitry Andric 
6090b57cec5SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)6100b57cec5SDimitry Andric   bool DoExecute(Args &args, CommandReturnObject &result) override {
6110b57cec5SDimitry Andric     CommandObject::CommandMap::iterator pos;
6120b57cec5SDimitry Andric     CommandObject *cmd_obj;
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric     if (args.empty()) {
6150b57cec5SDimitry Andric       result.AppendError("must call 'unalias' with a valid alias");
6160b57cec5SDimitry Andric       return false;
6170b57cec5SDimitry Andric     }
6180b57cec5SDimitry Andric 
6199dba64beSDimitry Andric     auto command_name = args[0].ref();
6200b57cec5SDimitry Andric     cmd_obj = m_interpreter.GetCommandObject(command_name);
6210b57cec5SDimitry Andric     if (!cmd_obj) {
6220b57cec5SDimitry Andric       result.AppendErrorWithFormat(
6230b57cec5SDimitry Andric           "'%s' is not a known command.\nTry 'help' to see a "
6240b57cec5SDimitry Andric           "current list of commands.\n",
6250b57cec5SDimitry Andric           args[0].c_str());
6260b57cec5SDimitry Andric       return false;
6270b57cec5SDimitry Andric     }
6280b57cec5SDimitry Andric 
6290b57cec5SDimitry Andric     if (m_interpreter.CommandExists(command_name)) {
6300b57cec5SDimitry Andric       if (cmd_obj->IsRemovable()) {
6310b57cec5SDimitry Andric         result.AppendErrorWithFormat(
6320b57cec5SDimitry Andric             "'%s' is not an alias, it is a debugger command which can be "
6330b57cec5SDimitry Andric             "removed using the 'command delete' command.\n",
6340b57cec5SDimitry Andric             args[0].c_str());
6350b57cec5SDimitry Andric       } else {
6360b57cec5SDimitry Andric         result.AppendErrorWithFormat(
6370b57cec5SDimitry Andric             "'%s' is a permanent debugger command and cannot be removed.\n",
6380b57cec5SDimitry Andric             args[0].c_str());
6390b57cec5SDimitry Andric       }
6400b57cec5SDimitry Andric       return false;
6410b57cec5SDimitry Andric     }
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric     if (!m_interpreter.RemoveAlias(command_name)) {
6440b57cec5SDimitry Andric       if (m_interpreter.AliasExists(command_name))
6450b57cec5SDimitry Andric         result.AppendErrorWithFormat(
6460b57cec5SDimitry Andric             "Error occurred while attempting to unalias '%s'.\n",
6470b57cec5SDimitry Andric             args[0].c_str());
6480b57cec5SDimitry Andric       else
6490b57cec5SDimitry Andric         result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
6500b57cec5SDimitry Andric                                      args[0].c_str());
6510b57cec5SDimitry Andric       return false;
6520b57cec5SDimitry Andric     }
6530b57cec5SDimitry Andric 
6540b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
6550b57cec5SDimitry Andric     return result.Succeeded();
6560b57cec5SDimitry Andric   }
6570b57cec5SDimitry Andric };
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric #pragma mark CommandObjectCommandsDelete
6600b57cec5SDimitry Andric // CommandObjectCommandsDelete
6610b57cec5SDimitry Andric 
6620b57cec5SDimitry Andric class CommandObjectCommandsDelete : public CommandObjectParsed {
6630b57cec5SDimitry Andric public:
CommandObjectCommandsDelete(CommandInterpreter & interpreter)6640b57cec5SDimitry Andric   CommandObjectCommandsDelete(CommandInterpreter &interpreter)
6650b57cec5SDimitry Andric       : CommandObjectParsed(
6660b57cec5SDimitry Andric             interpreter, "command delete",
6670b57cec5SDimitry Andric             "Delete one or more custom commands defined by 'command regex'.",
6680b57cec5SDimitry Andric             nullptr) {
6690b57cec5SDimitry Andric     CommandArgumentEntry arg;
6700b57cec5SDimitry Andric     CommandArgumentData alias_arg;
6710b57cec5SDimitry Andric 
6720b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
6730b57cec5SDimitry Andric     alias_arg.arg_type = eArgTypeCommandName;
6740b57cec5SDimitry Andric     alias_arg.arg_repetition = eArgRepeatPlain;
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
6770b57cec5SDimitry Andric     // argument entry.
6780b57cec5SDimitry Andric     arg.push_back(alias_arg);
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
6810b57cec5SDimitry Andric     m_arguments.push_back(arg);
6820b57cec5SDimitry Andric   }
6830b57cec5SDimitry Andric 
6840b57cec5SDimitry Andric   ~CommandObjectCommandsDelete() override = default;
6850b57cec5SDimitry Andric 
686af732203SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)687af732203SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
688af732203SDimitry Andric                            OptionElementVector &opt_element_vector) override {
689af732203SDimitry Andric     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
690af732203SDimitry Andric       return;
691af732203SDimitry Andric 
692af732203SDimitry Andric     for (const auto &ent : m_interpreter.GetCommands()) {
693af732203SDimitry Andric       if (ent.second->IsRemovable())
694af732203SDimitry Andric         request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
695af732203SDimitry Andric     }
696af732203SDimitry Andric   }
697af732203SDimitry Andric 
6980b57cec5SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)6990b57cec5SDimitry Andric   bool DoExecute(Args &args, CommandReturnObject &result) override {
7000b57cec5SDimitry Andric     CommandObject::CommandMap::iterator pos;
7010b57cec5SDimitry Andric 
7020b57cec5SDimitry Andric     if (args.empty()) {
7030b57cec5SDimitry Andric       result.AppendErrorWithFormat("must call '%s' with one or more valid user "
7040b57cec5SDimitry Andric                                    "defined regular expression command names",
7050b57cec5SDimitry Andric                                    GetCommandName().str().c_str());
7069dba64beSDimitry Andric       return false;
7070b57cec5SDimitry Andric     }
7080b57cec5SDimitry Andric 
7099dba64beSDimitry Andric     auto command_name = args[0].ref();
7100b57cec5SDimitry Andric     if (!m_interpreter.CommandExists(command_name)) {
7110b57cec5SDimitry Andric       StreamString error_msg_stream;
7120b57cec5SDimitry Andric       const bool generate_upropos = true;
7130b57cec5SDimitry Andric       const bool generate_type_lookup = false;
7140b57cec5SDimitry Andric       CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
7150b57cec5SDimitry Andric           &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
7160b57cec5SDimitry Andric           generate_upropos, generate_type_lookup);
7170b57cec5SDimitry Andric       result.AppendError(error_msg_stream.GetString());
7180b57cec5SDimitry Andric       return false;
7190b57cec5SDimitry Andric     }
7200b57cec5SDimitry Andric 
7210b57cec5SDimitry Andric     if (!m_interpreter.RemoveCommand(command_name)) {
7220b57cec5SDimitry Andric       result.AppendErrorWithFormat(
7230b57cec5SDimitry Andric           "'%s' is a permanent debugger command and cannot be removed.\n",
7240b57cec5SDimitry Andric           args[0].c_str());
7250b57cec5SDimitry Andric       return false;
7260b57cec5SDimitry Andric     }
7270b57cec5SDimitry Andric 
7280b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
7290b57cec5SDimitry Andric     return true;
7300b57cec5SDimitry Andric   }
7310b57cec5SDimitry Andric };
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric // CommandObjectCommandsAddRegex
7340b57cec5SDimitry Andric 
7359dba64beSDimitry Andric #define LLDB_OPTIONS_regex
7369dba64beSDimitry Andric #include "CommandOptions.inc"
7370b57cec5SDimitry Andric 
7380b57cec5SDimitry Andric #pragma mark CommandObjectCommandsAddRegex
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric class CommandObjectCommandsAddRegex : public CommandObjectParsed,
7410b57cec5SDimitry Andric                                       public IOHandlerDelegateMultiline {
7420b57cec5SDimitry Andric public:
CommandObjectCommandsAddRegex(CommandInterpreter & interpreter)7430b57cec5SDimitry Andric   CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
7440b57cec5SDimitry Andric       : CommandObjectParsed(
745480093f4SDimitry Andric             interpreter, "command regex",
746480093f4SDimitry Andric             "Define a custom command in terms of "
7470b57cec5SDimitry Andric             "existing commands by matching "
7480b57cec5SDimitry Andric             "regular expressions.",
7490b57cec5SDimitry Andric             "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
7500b57cec5SDimitry Andric         IOHandlerDelegateMultiline("",
7510b57cec5SDimitry Andric                                    IOHandlerDelegate::Completion::LLDBCommand),
7520b57cec5SDimitry Andric         m_options() {
7530b57cec5SDimitry Andric     SetHelpLong(
7540b57cec5SDimitry Andric         R"(
7550b57cec5SDimitry Andric )"
7560b57cec5SDimitry Andric         "This command allows the user to create powerful regular expression commands \
7570b57cec5SDimitry Andric with substitutions. The regular expressions and substitutions are specified \
7580b57cec5SDimitry Andric using the regular expression substitution format of:"
7590b57cec5SDimitry Andric         R"(
7600b57cec5SDimitry Andric 
7610b57cec5SDimitry Andric     s/<regex>/<subst>/
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric )"
7640b57cec5SDimitry Andric         "<regex> is a regular expression that can use parenthesis to capture regular \
7650b57cec5SDimitry Andric expression input and substitute the captured matches in the output using %1 \
7660b57cec5SDimitry Andric for the first match, %2 for the second, and so on."
7670b57cec5SDimitry Andric         R"(
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric )"
7700b57cec5SDimitry Andric         "The regular expressions can all be specified on the command line if more than \
7710b57cec5SDimitry Andric one argument is provided. If just the command name is provided on the command \
7720b57cec5SDimitry Andric line, then the regular expressions and substitutions can be entered on separate \
7730b57cec5SDimitry Andric lines, followed by an empty line to terminate the command definition."
7740b57cec5SDimitry Andric         R"(
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric EXAMPLES
7770b57cec5SDimitry Andric 
7780b57cec5SDimitry Andric )"
7790b57cec5SDimitry Andric         "The following example will define a regular expression command named 'f' that \
7800b57cec5SDimitry Andric will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
7810b57cec5SDimitry Andric a number follows 'f':"
7820b57cec5SDimitry Andric         R"(
7830b57cec5SDimitry Andric 
7840b57cec5SDimitry Andric     (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
7850b57cec5SDimitry Andric   }
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric   ~CommandObjectCommandsAddRegex() override = default;
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric protected:
IOHandlerActivated(IOHandler & io_handler,bool interactive)7900b57cec5SDimitry Andric   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
7919dba64beSDimitry Andric     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
7920b57cec5SDimitry Andric     if (output_sp && interactive) {
7930b57cec5SDimitry Andric       output_sp->PutCString("Enter one or more sed substitution commands in "
7940b57cec5SDimitry Andric                             "the form: 's/<regex>/<subst>/'.\nTerminate the "
7950b57cec5SDimitry Andric                             "substitution list with an empty line.\n");
7960b57cec5SDimitry Andric       output_sp->Flush();
7970b57cec5SDimitry Andric     }
7980b57cec5SDimitry Andric   }
7990b57cec5SDimitry Andric 
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)8000b57cec5SDimitry Andric   void IOHandlerInputComplete(IOHandler &io_handler,
8010b57cec5SDimitry Andric                               std::string &data) override {
8020b57cec5SDimitry Andric     io_handler.SetIsDone(true);
8030b57cec5SDimitry Andric     if (m_regex_cmd_up) {
8040b57cec5SDimitry Andric       StringList lines;
8050b57cec5SDimitry Andric       if (lines.SplitIntoLines(data)) {
8060b57cec5SDimitry Andric         bool check_only = false;
8079dba64beSDimitry Andric         for (const std::string &line : lines) {
8089dba64beSDimitry Andric           Status error = AppendRegexSubstitution(line, check_only);
8090b57cec5SDimitry Andric           if (error.Fail()) {
8100b57cec5SDimitry Andric             if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
8110b57cec5SDimitry Andric               StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
8120b57cec5SDimitry Andric               out_stream->Printf("error: %s\n", error.AsCString());
8130b57cec5SDimitry Andric             }
8140b57cec5SDimitry Andric           }
8150b57cec5SDimitry Andric         }
8160b57cec5SDimitry Andric       }
8170b57cec5SDimitry Andric       if (m_regex_cmd_up->HasRegexEntries()) {
8180b57cec5SDimitry Andric         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
8190b57cec5SDimitry Andric         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
8200b57cec5SDimitry Andric       }
8210b57cec5SDimitry Andric     }
8220b57cec5SDimitry Andric   }
8230b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)8240b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
8250b57cec5SDimitry Andric     const size_t argc = command.GetArgumentCount();
8260b57cec5SDimitry Andric     if (argc == 0) {
8270b57cec5SDimitry Andric       result.AppendError("usage: 'command regex <command-name> "
8280b57cec5SDimitry Andric                          "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
8290b57cec5SDimitry Andric       return false;
8300b57cec5SDimitry Andric     }
8310b57cec5SDimitry Andric 
8320b57cec5SDimitry Andric     Status error;
8339dba64beSDimitry Andric     auto name = command[0].ref();
8349dba64beSDimitry Andric     m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
8350b57cec5SDimitry Andric         m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0,
8360b57cec5SDimitry Andric         true);
8370b57cec5SDimitry Andric 
8380b57cec5SDimitry Andric     if (argc == 1) {
8390b57cec5SDimitry Andric       Debugger &debugger = GetDebugger();
8400b57cec5SDimitry Andric       bool color_prompt = debugger.GetUseColor();
8410b57cec5SDimitry Andric       const bool multiple_lines = true; // Get multiple lines
8420b57cec5SDimitry Andric       IOHandlerSP io_handler_sp(new IOHandlerEditline(
8430b57cec5SDimitry Andric           debugger, IOHandler::Type::Other,
8440b57cec5SDimitry Andric           "lldb-regex",          // Name of input reader for history
8450b57cec5SDimitry Andric           llvm::StringRef("> "), // Prompt
8460b57cec5SDimitry Andric           llvm::StringRef(),     // Continuation prompt
8470b57cec5SDimitry Andric           multiple_lines, color_prompt,
8480b57cec5SDimitry Andric           0, // Don't show line numbers
8490b57cec5SDimitry Andric           *this, nullptr));
8500b57cec5SDimitry Andric 
8510b57cec5SDimitry Andric       if (io_handler_sp) {
8525ffd83dbSDimitry Andric         debugger.RunIOHandlerAsync(io_handler_sp);
8530b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
8540b57cec5SDimitry Andric       }
8550b57cec5SDimitry Andric     } else {
8560b57cec5SDimitry Andric       for (auto &entry : command.entries().drop_front()) {
8570b57cec5SDimitry Andric         bool check_only = false;
8589dba64beSDimitry Andric         error = AppendRegexSubstitution(entry.ref(), check_only);
8590b57cec5SDimitry Andric         if (error.Fail())
8600b57cec5SDimitry Andric           break;
8610b57cec5SDimitry Andric       }
8620b57cec5SDimitry Andric 
8630b57cec5SDimitry Andric       if (error.Success()) {
8640b57cec5SDimitry Andric         AddRegexCommandToInterpreter();
8650b57cec5SDimitry Andric       }
8660b57cec5SDimitry Andric     }
8670b57cec5SDimitry Andric     if (error.Fail()) {
8680b57cec5SDimitry Andric       result.AppendError(error.AsCString());
8690b57cec5SDimitry Andric     }
8700b57cec5SDimitry Andric 
8710b57cec5SDimitry Andric     return result.Succeeded();
8720b57cec5SDimitry Andric   }
8730b57cec5SDimitry Andric 
AppendRegexSubstitution(const llvm::StringRef & regex_sed,bool check_only)8740b57cec5SDimitry Andric   Status AppendRegexSubstitution(const llvm::StringRef &regex_sed,
8750b57cec5SDimitry Andric                                  bool check_only) {
8760b57cec5SDimitry Andric     Status error;
8770b57cec5SDimitry Andric 
8780b57cec5SDimitry Andric     if (!m_regex_cmd_up) {
8790b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
8800b57cec5SDimitry Andric           "invalid regular expression command object for: '%.*s'",
8810b57cec5SDimitry Andric           (int)regex_sed.size(), regex_sed.data());
8820b57cec5SDimitry Andric       return error;
8830b57cec5SDimitry Andric     }
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric     size_t regex_sed_size = regex_sed.size();
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric     if (regex_sed_size <= 1) {
8880b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
8890b57cec5SDimitry Andric           "regular expression substitution string is too short: '%.*s'",
8900b57cec5SDimitry Andric           (int)regex_sed.size(), regex_sed.data());
8910b57cec5SDimitry Andric       return error;
8920b57cec5SDimitry Andric     }
8930b57cec5SDimitry Andric 
8940b57cec5SDimitry Andric     if (regex_sed[0] != 's') {
8950b57cec5SDimitry Andric       error.SetErrorStringWithFormat("regular expression substitution string "
8960b57cec5SDimitry Andric                                      "doesn't start with 's': '%.*s'",
8970b57cec5SDimitry Andric                                      (int)regex_sed.size(), regex_sed.data());
8980b57cec5SDimitry Andric       return error;
8990b57cec5SDimitry Andric     }
9000b57cec5SDimitry Andric     const size_t first_separator_char_pos = 1;
9010b57cec5SDimitry Andric     // use the char that follows 's' as the regex separator character so we can
9020b57cec5SDimitry Andric     // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
9030b57cec5SDimitry Andric     const char separator_char = regex_sed[first_separator_char_pos];
9040b57cec5SDimitry Andric     const size_t second_separator_char_pos =
9050b57cec5SDimitry Andric         regex_sed.find(separator_char, first_separator_char_pos + 1);
9060b57cec5SDimitry Andric 
9070b57cec5SDimitry Andric     if (second_separator_char_pos == std::string::npos) {
9080b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
9090b57cec5SDimitry Andric           "missing second '%c' separator char after '%.*s' in '%.*s'",
9100b57cec5SDimitry Andric           separator_char,
9110b57cec5SDimitry Andric           (int)(regex_sed.size() - first_separator_char_pos - 1),
9120b57cec5SDimitry Andric           regex_sed.data() + (first_separator_char_pos + 1),
9130b57cec5SDimitry Andric           (int)regex_sed.size(), regex_sed.data());
9140b57cec5SDimitry Andric       return error;
9150b57cec5SDimitry Andric     }
9160b57cec5SDimitry Andric 
9170b57cec5SDimitry Andric     const size_t third_separator_char_pos =
9180b57cec5SDimitry Andric         regex_sed.find(separator_char, second_separator_char_pos + 1);
9190b57cec5SDimitry Andric 
9200b57cec5SDimitry Andric     if (third_separator_char_pos == std::string::npos) {
9210b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
9220b57cec5SDimitry Andric           "missing third '%c' separator char after '%.*s' in '%.*s'",
9230b57cec5SDimitry Andric           separator_char,
9240b57cec5SDimitry Andric           (int)(regex_sed.size() - second_separator_char_pos - 1),
9250b57cec5SDimitry Andric           regex_sed.data() + (second_separator_char_pos + 1),
9260b57cec5SDimitry Andric           (int)regex_sed.size(), regex_sed.data());
9270b57cec5SDimitry Andric       return error;
9280b57cec5SDimitry Andric     }
9290b57cec5SDimitry Andric 
9300b57cec5SDimitry Andric     if (third_separator_char_pos != regex_sed_size - 1) {
9310b57cec5SDimitry Andric       // Make sure that everything that follows the last regex separator char
9320b57cec5SDimitry Andric       if (regex_sed.find_first_not_of("\t\n\v\f\r ",
9330b57cec5SDimitry Andric                                       third_separator_char_pos + 1) !=
9340b57cec5SDimitry Andric           std::string::npos) {
9350b57cec5SDimitry Andric         error.SetErrorStringWithFormat(
9360b57cec5SDimitry Andric             "extra data found after the '%.*s' regular expression substitution "
9370b57cec5SDimitry Andric             "string: '%.*s'",
9380b57cec5SDimitry Andric             (int)third_separator_char_pos + 1, regex_sed.data(),
9390b57cec5SDimitry Andric             (int)(regex_sed.size() - third_separator_char_pos - 1),
9400b57cec5SDimitry Andric             regex_sed.data() + (third_separator_char_pos + 1));
9410b57cec5SDimitry Andric         return error;
9420b57cec5SDimitry Andric       }
9430b57cec5SDimitry Andric     } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
9440b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
9450b57cec5SDimitry Andric           "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
9460b57cec5SDimitry Andric           separator_char, separator_char, separator_char, (int)regex_sed.size(),
9470b57cec5SDimitry Andric           regex_sed.data());
9480b57cec5SDimitry Andric       return error;
9490b57cec5SDimitry Andric     } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
9500b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
9510b57cec5SDimitry Andric           "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
9520b57cec5SDimitry Andric           separator_char, separator_char, separator_char, (int)regex_sed.size(),
9530b57cec5SDimitry Andric           regex_sed.data());
9540b57cec5SDimitry Andric       return error;
9550b57cec5SDimitry Andric     }
9560b57cec5SDimitry Andric 
9570b57cec5SDimitry Andric     if (!check_only) {
9585ffd83dbSDimitry Andric       std::string regex(std::string(regex_sed.substr(
9595ffd83dbSDimitry Andric           first_separator_char_pos + 1,
9605ffd83dbSDimitry Andric           second_separator_char_pos - first_separator_char_pos - 1)));
9615ffd83dbSDimitry Andric       std::string subst(std::string(regex_sed.substr(
9625ffd83dbSDimitry Andric           second_separator_char_pos + 1,
9635ffd83dbSDimitry Andric           third_separator_char_pos - second_separator_char_pos - 1)));
964af732203SDimitry Andric       m_regex_cmd_up->AddRegexCommand(regex, subst);
9650b57cec5SDimitry Andric     }
9660b57cec5SDimitry Andric     return error;
9670b57cec5SDimitry Andric   }
9680b57cec5SDimitry Andric 
AddRegexCommandToInterpreter()9690b57cec5SDimitry Andric   void AddRegexCommandToInterpreter() {
9700b57cec5SDimitry Andric     if (m_regex_cmd_up) {
9710b57cec5SDimitry Andric       if (m_regex_cmd_up->HasRegexEntries()) {
9720b57cec5SDimitry Andric         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
9730b57cec5SDimitry Andric         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
9740b57cec5SDimitry Andric       }
9750b57cec5SDimitry Andric     }
9760b57cec5SDimitry Andric   }
9770b57cec5SDimitry Andric 
9780b57cec5SDimitry Andric private:
9790b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
9800b57cec5SDimitry Andric 
9810b57cec5SDimitry Andric   class CommandOptions : public Options {
9820b57cec5SDimitry Andric   public:
CommandOptions()9830b57cec5SDimitry Andric     CommandOptions() : Options() {}
9840b57cec5SDimitry Andric 
9850b57cec5SDimitry Andric     ~CommandOptions() override = default;
9860b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)9870b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
9880b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
9890b57cec5SDimitry Andric       Status error;
9900b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
9910b57cec5SDimitry Andric 
9920b57cec5SDimitry Andric       switch (short_option) {
9930b57cec5SDimitry Andric       case 'h':
9945ffd83dbSDimitry Andric         m_help.assign(std::string(option_arg));
9950b57cec5SDimitry Andric         break;
9960b57cec5SDimitry Andric       case 's':
9975ffd83dbSDimitry Andric         m_syntax.assign(std::string(option_arg));
9980b57cec5SDimitry Andric         break;
9990b57cec5SDimitry Andric       default:
10009dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
10010b57cec5SDimitry Andric       }
10020b57cec5SDimitry Andric 
10030b57cec5SDimitry Andric       return error;
10040b57cec5SDimitry Andric     }
10050b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)10060b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
10070b57cec5SDimitry Andric       m_help.clear();
10080b57cec5SDimitry Andric       m_syntax.clear();
10090b57cec5SDimitry Andric     }
10100b57cec5SDimitry Andric 
GetDefinitions()10110b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
10120b57cec5SDimitry Andric       return llvm::makeArrayRef(g_regex_options);
10130b57cec5SDimitry Andric     }
10140b57cec5SDimitry Andric 
GetHelp()10155ffd83dbSDimitry Andric     llvm::StringRef GetHelp() { return m_help; }
10160b57cec5SDimitry Andric 
GetSyntax()10175ffd83dbSDimitry Andric     llvm::StringRef GetSyntax() { return m_syntax; }
10180b57cec5SDimitry Andric 
10190b57cec5SDimitry Andric   protected:
10200b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
10210b57cec5SDimitry Andric 
10220b57cec5SDimitry Andric     std::string m_help;
10230b57cec5SDimitry Andric     std::string m_syntax;
10240b57cec5SDimitry Andric   };
10250b57cec5SDimitry Andric 
GetOptions()10260b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
10270b57cec5SDimitry Andric 
10280b57cec5SDimitry Andric   CommandOptions m_options;
10290b57cec5SDimitry Andric };
10300b57cec5SDimitry Andric 
10310b57cec5SDimitry Andric class CommandObjectPythonFunction : public CommandObjectRaw {
10320b57cec5SDimitry Andric public:
CommandObjectPythonFunction(CommandInterpreter & interpreter,std::string name,std::string funct,std::string help,ScriptedCommandSynchronicity synch)10330b57cec5SDimitry Andric   CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
10340b57cec5SDimitry Andric                               std::string funct, std::string help,
10350b57cec5SDimitry Andric                               ScriptedCommandSynchronicity synch)
1036480093f4SDimitry Andric       : CommandObjectRaw(interpreter, name), m_function_name(funct),
1037480093f4SDimitry Andric         m_synchro(synch), m_fetched_help_long(false) {
10380b57cec5SDimitry Andric     if (!help.empty())
10390b57cec5SDimitry Andric       SetHelp(help);
10400b57cec5SDimitry Andric     else {
10410b57cec5SDimitry Andric       StreamString stream;
10420b57cec5SDimitry Andric       stream.Printf("For more information run 'help %s'", name.c_str());
10430b57cec5SDimitry Andric       SetHelp(stream.GetString());
10440b57cec5SDimitry Andric     }
10450b57cec5SDimitry Andric   }
10460b57cec5SDimitry Andric 
10470b57cec5SDimitry Andric   ~CommandObjectPythonFunction() override = default;
10480b57cec5SDimitry Andric 
IsRemovable() const10490b57cec5SDimitry Andric   bool IsRemovable() const override { return true; }
10500b57cec5SDimitry Andric 
GetFunctionName()10510b57cec5SDimitry Andric   const std::string &GetFunctionName() { return m_function_name; }
10520b57cec5SDimitry Andric 
GetSynchronicity()10530b57cec5SDimitry Andric   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
10540b57cec5SDimitry Andric 
GetHelpLong()10550b57cec5SDimitry Andric   llvm::StringRef GetHelpLong() override {
10560b57cec5SDimitry Andric     if (m_fetched_help_long)
10570b57cec5SDimitry Andric       return CommandObjectRaw::GetHelpLong();
10580b57cec5SDimitry Andric 
10590b57cec5SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
10600b57cec5SDimitry Andric     if (!scripter)
10610b57cec5SDimitry Andric       return CommandObjectRaw::GetHelpLong();
10620b57cec5SDimitry Andric 
10630b57cec5SDimitry Andric     std::string docstring;
10640b57cec5SDimitry Andric     m_fetched_help_long =
10650b57cec5SDimitry Andric         scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
10660b57cec5SDimitry Andric     if (!docstring.empty())
10670b57cec5SDimitry Andric       SetHelpLong(docstring);
10680b57cec5SDimitry Andric     return CommandObjectRaw::GetHelpLong();
10690b57cec5SDimitry Andric   }
10700b57cec5SDimitry Andric 
10710b57cec5SDimitry Andric protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)10720b57cec5SDimitry Andric   bool DoExecute(llvm::StringRef raw_command_line,
10730b57cec5SDimitry Andric                  CommandReturnObject &result) override {
10740b57cec5SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
10750b57cec5SDimitry Andric 
10760b57cec5SDimitry Andric     Status error;
10770b57cec5SDimitry Andric 
10780b57cec5SDimitry Andric     result.SetStatus(eReturnStatusInvalid);
10790b57cec5SDimitry Andric 
1080480093f4SDimitry Andric     if (!scripter || !scripter->RunScriptBasedCommand(
1081480093f4SDimitry Andric                          m_function_name.c_str(), raw_command_line, m_synchro,
1082480093f4SDimitry Andric                          result, error, m_exe_ctx)) {
10830b57cec5SDimitry Andric       result.AppendError(error.AsCString());
10840b57cec5SDimitry Andric     } else {
10850b57cec5SDimitry Andric       // Don't change the status if the command already set it...
10860b57cec5SDimitry Andric       if (result.GetStatus() == eReturnStatusInvalid) {
10870b57cec5SDimitry Andric         if (result.GetOutputData().empty())
10880b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishNoResult);
10890b57cec5SDimitry Andric         else
10900b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
10910b57cec5SDimitry Andric       }
10920b57cec5SDimitry Andric     }
10930b57cec5SDimitry Andric 
10940b57cec5SDimitry Andric     return result.Succeeded();
10950b57cec5SDimitry Andric   }
10960b57cec5SDimitry Andric 
10970b57cec5SDimitry Andric private:
10980b57cec5SDimitry Andric   std::string m_function_name;
10990b57cec5SDimitry Andric   ScriptedCommandSynchronicity m_synchro;
11000b57cec5SDimitry Andric   bool m_fetched_help_long;
11010b57cec5SDimitry Andric };
11020b57cec5SDimitry Andric 
11030b57cec5SDimitry Andric class CommandObjectScriptingObject : public CommandObjectRaw {
11040b57cec5SDimitry Andric public:
CommandObjectScriptingObject(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch)11050b57cec5SDimitry Andric   CommandObjectScriptingObject(CommandInterpreter &interpreter,
11060b57cec5SDimitry Andric                                std::string name,
11070b57cec5SDimitry Andric                                StructuredData::GenericSP cmd_obj_sp,
11080b57cec5SDimitry Andric                                ScriptedCommandSynchronicity synch)
1109480093f4SDimitry Andric       : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1110480093f4SDimitry Andric         m_synchro(synch), m_fetched_help_short(false),
11110b57cec5SDimitry Andric         m_fetched_help_long(false) {
11120b57cec5SDimitry Andric     StreamString stream;
11130b57cec5SDimitry Andric     stream.Printf("For more information run 'help %s'", name.c_str());
11140b57cec5SDimitry Andric     SetHelp(stream.GetString());
11150b57cec5SDimitry Andric     if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
11160b57cec5SDimitry Andric       GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
11170b57cec5SDimitry Andric   }
11180b57cec5SDimitry Andric 
11190b57cec5SDimitry Andric   ~CommandObjectScriptingObject() override = default;
11200b57cec5SDimitry Andric 
IsRemovable() const11210b57cec5SDimitry Andric   bool IsRemovable() const override { return true; }
11220b57cec5SDimitry Andric 
GetSynchronicity()11230b57cec5SDimitry Andric   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
11240b57cec5SDimitry Andric 
GetHelp()11250b57cec5SDimitry Andric   llvm::StringRef GetHelp() override {
11260b57cec5SDimitry Andric     if (m_fetched_help_short)
11270b57cec5SDimitry Andric       return CommandObjectRaw::GetHelp();
11280b57cec5SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
11290b57cec5SDimitry Andric     if (!scripter)
11300b57cec5SDimitry Andric       return CommandObjectRaw::GetHelp();
11310b57cec5SDimitry Andric     std::string docstring;
11320b57cec5SDimitry Andric     m_fetched_help_short =
11330b57cec5SDimitry Andric         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
11340b57cec5SDimitry Andric     if (!docstring.empty())
11350b57cec5SDimitry Andric       SetHelp(docstring);
11360b57cec5SDimitry Andric 
11370b57cec5SDimitry Andric     return CommandObjectRaw::GetHelp();
11380b57cec5SDimitry Andric   }
11390b57cec5SDimitry Andric 
GetHelpLong()11400b57cec5SDimitry Andric   llvm::StringRef GetHelpLong() override {
11410b57cec5SDimitry Andric     if (m_fetched_help_long)
11420b57cec5SDimitry Andric       return CommandObjectRaw::GetHelpLong();
11430b57cec5SDimitry Andric 
11440b57cec5SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
11450b57cec5SDimitry Andric     if (!scripter)
11460b57cec5SDimitry Andric       return CommandObjectRaw::GetHelpLong();
11470b57cec5SDimitry Andric 
11480b57cec5SDimitry Andric     std::string docstring;
11490b57cec5SDimitry Andric     m_fetched_help_long =
11500b57cec5SDimitry Andric         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
11510b57cec5SDimitry Andric     if (!docstring.empty())
11520b57cec5SDimitry Andric       SetHelpLong(docstring);
11530b57cec5SDimitry Andric     return CommandObjectRaw::GetHelpLong();
11540b57cec5SDimitry Andric   }
11550b57cec5SDimitry Andric 
11560b57cec5SDimitry Andric protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)11570b57cec5SDimitry Andric   bool DoExecute(llvm::StringRef raw_command_line,
11580b57cec5SDimitry Andric                  CommandReturnObject &result) override {
11590b57cec5SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
11600b57cec5SDimitry Andric 
11610b57cec5SDimitry Andric     Status error;
11620b57cec5SDimitry Andric 
11630b57cec5SDimitry Andric     result.SetStatus(eReturnStatusInvalid);
11640b57cec5SDimitry Andric 
11650b57cec5SDimitry Andric     if (!scripter ||
11660b57cec5SDimitry Andric         !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
11670b57cec5SDimitry Andric                                          m_synchro, result, error, m_exe_ctx)) {
11680b57cec5SDimitry Andric       result.AppendError(error.AsCString());
11690b57cec5SDimitry Andric     } else {
11700b57cec5SDimitry Andric       // Don't change the status if the command already set it...
11710b57cec5SDimitry Andric       if (result.GetStatus() == eReturnStatusInvalid) {
11720b57cec5SDimitry Andric         if (result.GetOutputData().empty())
11730b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishNoResult);
11740b57cec5SDimitry Andric         else
11750b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
11760b57cec5SDimitry Andric       }
11770b57cec5SDimitry Andric     }
11780b57cec5SDimitry Andric 
11790b57cec5SDimitry Andric     return result.Succeeded();
11800b57cec5SDimitry Andric   }
11810b57cec5SDimitry Andric 
11820b57cec5SDimitry Andric private:
11830b57cec5SDimitry Andric   StructuredData::GenericSP m_cmd_obj_sp;
11840b57cec5SDimitry Andric   ScriptedCommandSynchronicity m_synchro;
11850b57cec5SDimitry Andric   bool m_fetched_help_short : 1;
11860b57cec5SDimitry Andric   bool m_fetched_help_long : 1;
11870b57cec5SDimitry Andric };
11880b57cec5SDimitry Andric 
11890b57cec5SDimitry Andric // CommandObjectCommandsScriptImport
11909dba64beSDimitry Andric #define LLDB_OPTIONS_script_import
11919dba64beSDimitry Andric #include "CommandOptions.inc"
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric class CommandObjectCommandsScriptImport : public CommandObjectParsed {
11940b57cec5SDimitry Andric public:
CommandObjectCommandsScriptImport(CommandInterpreter & interpreter)11950b57cec5SDimitry Andric   CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
11960b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "command script import",
11970b57cec5SDimitry Andric                             "Import a scripting module in LLDB.", nullptr),
11980b57cec5SDimitry Andric         m_options() {
11990b57cec5SDimitry Andric     CommandArgumentEntry arg1;
12000b57cec5SDimitry Andric     CommandArgumentData cmd_arg;
12010b57cec5SDimitry Andric 
12020b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
12030b57cec5SDimitry Andric     cmd_arg.arg_type = eArgTypeFilename;
12040b57cec5SDimitry Andric     cmd_arg.arg_repetition = eArgRepeatPlus;
12050b57cec5SDimitry Andric 
12060b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
12070b57cec5SDimitry Andric     // argument entry.
12080b57cec5SDimitry Andric     arg1.push_back(cmd_arg);
12090b57cec5SDimitry Andric 
12100b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
12110b57cec5SDimitry Andric     m_arguments.push_back(arg1);
12120b57cec5SDimitry Andric   }
12130b57cec5SDimitry Andric 
12140b57cec5SDimitry Andric   ~CommandObjectCommandsScriptImport() override = default;
12150b57cec5SDimitry Andric 
12169dba64beSDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)12179dba64beSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
12180b57cec5SDimitry Andric                            OptionElementVector &opt_element_vector) override {
12190b57cec5SDimitry Andric     CommandCompletions::InvokeCommonCompletionCallbacks(
12200b57cec5SDimitry Andric         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
12210b57cec5SDimitry Andric         request, nullptr);
12220b57cec5SDimitry Andric   }
12230b57cec5SDimitry Andric 
GetOptions()12240b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
12250b57cec5SDimitry Andric 
12260b57cec5SDimitry Andric protected:
12270b57cec5SDimitry Andric   class CommandOptions : public Options {
12280b57cec5SDimitry Andric   public:
CommandOptions()12290b57cec5SDimitry Andric     CommandOptions() : Options() {}
12300b57cec5SDimitry Andric 
12310b57cec5SDimitry Andric     ~CommandOptions() override = default;
12320b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)12330b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
12340b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
12350b57cec5SDimitry Andric       Status error;
12360b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
12370b57cec5SDimitry Andric 
12380b57cec5SDimitry Andric       switch (short_option) {
12390b57cec5SDimitry Andric       case 'r':
1240480093f4SDimitry Andric         // NO-OP
12410b57cec5SDimitry Andric         break;
1242af732203SDimitry Andric       case 'c':
1243af732203SDimitry Andric         relative_to_command_file = true;
1244af732203SDimitry Andric         break;
1245*5f7ddb14SDimitry Andric       case 's':
1246*5f7ddb14SDimitry Andric         silent = true;
1247*5f7ddb14SDimitry Andric         break;
12480b57cec5SDimitry Andric       default:
12499dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
12500b57cec5SDimitry Andric       }
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric       return error;
12530b57cec5SDimitry Andric     }
12540b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)12550b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
1256af732203SDimitry Andric       relative_to_command_file = false;
12570b57cec5SDimitry Andric     }
12580b57cec5SDimitry Andric 
GetDefinitions()12590b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
12600b57cec5SDimitry Andric       return llvm::makeArrayRef(g_script_import_options);
12610b57cec5SDimitry Andric     }
1262af732203SDimitry Andric     bool relative_to_command_file = false;
1263*5f7ddb14SDimitry Andric     bool silent = false;
12640b57cec5SDimitry Andric   };
12650b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)12660b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
12670b57cec5SDimitry Andric     if (command.empty()) {
12680b57cec5SDimitry Andric       result.AppendError("command script import needs one or more arguments");
12690b57cec5SDimitry Andric       return false;
12700b57cec5SDimitry Andric     }
12710b57cec5SDimitry Andric 
1272af732203SDimitry Andric     FileSpec source_dir = {};
1273af732203SDimitry Andric     if (m_options.relative_to_command_file) {
1274af732203SDimitry Andric       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1275af732203SDimitry Andric       if (!source_dir) {
1276af732203SDimitry Andric         result.AppendError("command script import -c can only be specified "
1277af732203SDimitry Andric                            "from a command file");
1278af732203SDimitry Andric         return false;
1279af732203SDimitry Andric       }
1280af732203SDimitry Andric     }
1281af732203SDimitry Andric 
12820b57cec5SDimitry Andric     for (auto &entry : command.entries()) {
12830b57cec5SDimitry Andric       Status error;
12840b57cec5SDimitry Andric 
1285*5f7ddb14SDimitry Andric       LoadScriptOptions options;
1286*5f7ddb14SDimitry Andric       options.SetInitSession(true);
1287*5f7ddb14SDimitry Andric       options.SetSilent(m_options.silent);
1288*5f7ddb14SDimitry Andric 
12890b57cec5SDimitry Andric       // FIXME: this is necessary because CommandObject::CheckRequirements()
12900b57cec5SDimitry Andric       // assumes that commands won't ever be recursively invoked, but it's
12910b57cec5SDimitry Andric       // actually possible to craft a Python script that does other "command
12920b57cec5SDimitry Andric       // script imports" in __lldb_init_module the real fix is to have
12930b57cec5SDimitry Andric       // recursive commands possible with a CommandInvocation object separate
12940b57cec5SDimitry Andric       // from the CommandObject itself, so that recursive command invocations
12950b57cec5SDimitry Andric       // won't stomp on each other (wrt to execution contents, options, and
12960b57cec5SDimitry Andric       // more)
12970b57cec5SDimitry Andric       m_exe_ctx.Clear();
12980b57cec5SDimitry Andric       if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
1299*5f7ddb14SDimitry Andric               entry.c_str(), options, error, /*module_sp=*/nullptr,
1300*5f7ddb14SDimitry Andric               source_dir)) {
13010b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
13020b57cec5SDimitry Andric       } else {
13030b57cec5SDimitry Andric         result.AppendErrorWithFormat("module importing failed: %s",
13040b57cec5SDimitry Andric                                      error.AsCString());
13050b57cec5SDimitry Andric       }
13060b57cec5SDimitry Andric     }
13070b57cec5SDimitry Andric 
13080b57cec5SDimitry Andric     return result.Succeeded();
13090b57cec5SDimitry Andric   }
13100b57cec5SDimitry Andric 
13110b57cec5SDimitry Andric   CommandOptions m_options;
13120b57cec5SDimitry Andric };
13130b57cec5SDimitry Andric 
13140b57cec5SDimitry Andric // CommandObjectCommandsScriptAdd
13150b57cec5SDimitry Andric static constexpr OptionEnumValueElement g_script_synchro_type[] = {
13169dba64beSDimitry Andric     {
13179dba64beSDimitry Andric         eScriptedCommandSynchronicitySynchronous,
13189dba64beSDimitry Andric         "synchronous",
13199dba64beSDimitry Andric         "Run synchronous",
13209dba64beSDimitry Andric     },
13219dba64beSDimitry Andric     {
13229dba64beSDimitry Andric         eScriptedCommandSynchronicityAsynchronous,
13239dba64beSDimitry Andric         "asynchronous",
13249dba64beSDimitry Andric         "Run asynchronous",
13259dba64beSDimitry Andric     },
13269dba64beSDimitry Andric     {
13279dba64beSDimitry Andric         eScriptedCommandSynchronicityCurrentValue,
13289dba64beSDimitry Andric         "current",
13299dba64beSDimitry Andric         "Do not alter current setting",
13309dba64beSDimitry Andric     },
13319dba64beSDimitry Andric };
13320b57cec5SDimitry Andric 
ScriptSynchroType()13330b57cec5SDimitry Andric static constexpr OptionEnumValues ScriptSynchroType() {
13340b57cec5SDimitry Andric   return OptionEnumValues(g_script_synchro_type);
13350b57cec5SDimitry Andric }
13360b57cec5SDimitry Andric 
13379dba64beSDimitry Andric #define LLDB_OPTIONS_script_add
13389dba64beSDimitry Andric #include "CommandOptions.inc"
13390b57cec5SDimitry Andric 
13400b57cec5SDimitry Andric class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
13410b57cec5SDimitry Andric                                        public IOHandlerDelegateMultiline {
13420b57cec5SDimitry Andric public:
CommandObjectCommandsScriptAdd(CommandInterpreter & interpreter)13430b57cec5SDimitry Andric   CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
13440b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "command script add",
13450b57cec5SDimitry Andric                             "Add a scripted function as an LLDB command.",
13460b57cec5SDimitry Andric                             nullptr),
13470b57cec5SDimitry Andric         IOHandlerDelegateMultiline("DONE"), m_options() {
13480b57cec5SDimitry Andric     CommandArgumentEntry arg1;
13490b57cec5SDimitry Andric     CommandArgumentData cmd_arg;
13500b57cec5SDimitry Andric 
13510b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
13520b57cec5SDimitry Andric     cmd_arg.arg_type = eArgTypeCommandName;
13530b57cec5SDimitry Andric     cmd_arg.arg_repetition = eArgRepeatPlain;
13540b57cec5SDimitry Andric 
13550b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
13560b57cec5SDimitry Andric     // argument entry.
13570b57cec5SDimitry Andric     arg1.push_back(cmd_arg);
13580b57cec5SDimitry Andric 
13590b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
13600b57cec5SDimitry Andric     m_arguments.push_back(arg1);
13610b57cec5SDimitry Andric   }
13620b57cec5SDimitry Andric 
13630b57cec5SDimitry Andric   ~CommandObjectCommandsScriptAdd() override = default;
13640b57cec5SDimitry Andric 
GetOptions()13650b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
13660b57cec5SDimitry Andric 
13670b57cec5SDimitry Andric protected:
13680b57cec5SDimitry Andric   class CommandOptions : public Options {
13690b57cec5SDimitry Andric   public:
CommandOptions()13700b57cec5SDimitry Andric     CommandOptions()
1371*5f7ddb14SDimitry Andric         : Options(), m_class_name(), m_funct_name(), m_short_help() {}
13720b57cec5SDimitry Andric 
13730b57cec5SDimitry Andric     ~CommandOptions() override = default;
13740b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)13750b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
13760b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
13770b57cec5SDimitry Andric       Status error;
13780b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
13790b57cec5SDimitry Andric 
13800b57cec5SDimitry Andric       switch (short_option) {
13810b57cec5SDimitry Andric       case 'f':
13820b57cec5SDimitry Andric         if (!option_arg.empty())
13835ffd83dbSDimitry Andric           m_funct_name = std::string(option_arg);
13840b57cec5SDimitry Andric         break;
13850b57cec5SDimitry Andric       case 'c':
13860b57cec5SDimitry Andric         if (!option_arg.empty())
13875ffd83dbSDimitry Andric           m_class_name = std::string(option_arg);
13880b57cec5SDimitry Andric         break;
13890b57cec5SDimitry Andric       case 'h':
13900b57cec5SDimitry Andric         if (!option_arg.empty())
13915ffd83dbSDimitry Andric           m_short_help = std::string(option_arg);
13920b57cec5SDimitry Andric         break;
13930b57cec5SDimitry Andric       case 's':
13940b57cec5SDimitry Andric         m_synchronicity =
13950b57cec5SDimitry Andric             (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
13960b57cec5SDimitry Andric                 option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
13970b57cec5SDimitry Andric         if (!error.Success())
13980b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
13990b57cec5SDimitry Andric               "unrecognized value for synchronicity '%s'",
14000b57cec5SDimitry Andric               option_arg.str().c_str());
14010b57cec5SDimitry Andric         break;
14020b57cec5SDimitry Andric       default:
14039dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
14040b57cec5SDimitry Andric       }
14050b57cec5SDimitry Andric 
14060b57cec5SDimitry Andric       return error;
14070b57cec5SDimitry Andric     }
14080b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)14090b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
14100b57cec5SDimitry Andric       m_class_name.clear();
14110b57cec5SDimitry Andric       m_funct_name.clear();
14120b57cec5SDimitry Andric       m_short_help.clear();
14130b57cec5SDimitry Andric       m_synchronicity = eScriptedCommandSynchronicitySynchronous;
14140b57cec5SDimitry Andric     }
14150b57cec5SDimitry Andric 
GetDefinitions()14160b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
14170b57cec5SDimitry Andric       return llvm::makeArrayRef(g_script_add_options);
14180b57cec5SDimitry Andric     }
14190b57cec5SDimitry Andric 
14200b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
14210b57cec5SDimitry Andric 
14220b57cec5SDimitry Andric     std::string m_class_name;
14230b57cec5SDimitry Andric     std::string m_funct_name;
14240b57cec5SDimitry Andric     std::string m_short_help;
1425*5f7ddb14SDimitry Andric     ScriptedCommandSynchronicity m_synchronicity =
1426*5f7ddb14SDimitry Andric         eScriptedCommandSynchronicitySynchronous;
14270b57cec5SDimitry Andric   };
14280b57cec5SDimitry Andric 
IOHandlerActivated(IOHandler & io_handler,bool interactive)14290b57cec5SDimitry Andric   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
14309dba64beSDimitry Andric     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
14310b57cec5SDimitry Andric     if (output_sp && interactive) {
14320b57cec5SDimitry Andric       output_sp->PutCString(g_python_command_instructions);
14330b57cec5SDimitry Andric       output_sp->Flush();
14340b57cec5SDimitry Andric     }
14350b57cec5SDimitry Andric   }
14360b57cec5SDimitry Andric 
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)14370b57cec5SDimitry Andric   void IOHandlerInputComplete(IOHandler &io_handler,
14380b57cec5SDimitry Andric                               std::string &data) override {
14399dba64beSDimitry Andric     StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
14400b57cec5SDimitry Andric 
14410b57cec5SDimitry Andric     ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
14420b57cec5SDimitry Andric     if (interpreter) {
14430b57cec5SDimitry Andric 
14440b57cec5SDimitry Andric       StringList lines;
14450b57cec5SDimitry Andric       lines.SplitIntoLines(data);
14460b57cec5SDimitry Andric       if (lines.GetSize() > 0) {
14470b57cec5SDimitry Andric         std::string funct_name_str;
14480b57cec5SDimitry Andric         if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
14490b57cec5SDimitry Andric           if (funct_name_str.empty()) {
14500b57cec5SDimitry Andric             error_sp->Printf("error: unable to obtain a function name, didn't "
14510b57cec5SDimitry Andric                              "add python command.\n");
14520b57cec5SDimitry Andric             error_sp->Flush();
14530b57cec5SDimitry Andric           } else {
14540b57cec5SDimitry Andric             // everything should be fine now, let's add this alias
14550b57cec5SDimitry Andric 
14560b57cec5SDimitry Andric             CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
14570b57cec5SDimitry Andric                 m_interpreter, m_cmd_name, funct_name_str, m_short_help,
14580b57cec5SDimitry Andric                 m_synchronicity));
14590b57cec5SDimitry Andric 
14600b57cec5SDimitry Andric             if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp,
14610b57cec5SDimitry Andric                                               true)) {
14620b57cec5SDimitry Andric               error_sp->Printf("error: unable to add selected command, didn't "
14630b57cec5SDimitry Andric                                "add python command.\n");
14640b57cec5SDimitry Andric               error_sp->Flush();
14650b57cec5SDimitry Andric             }
14660b57cec5SDimitry Andric           }
14670b57cec5SDimitry Andric         } else {
14680b57cec5SDimitry Andric           error_sp->Printf(
14690b57cec5SDimitry Andric               "error: unable to create function, didn't add python command.\n");
14700b57cec5SDimitry Andric           error_sp->Flush();
14710b57cec5SDimitry Andric         }
14720b57cec5SDimitry Andric       } else {
14730b57cec5SDimitry Andric         error_sp->Printf("error: empty function, didn't add python command.\n");
14740b57cec5SDimitry Andric         error_sp->Flush();
14750b57cec5SDimitry Andric       }
14760b57cec5SDimitry Andric     } else {
14770b57cec5SDimitry Andric       error_sp->Printf(
14780b57cec5SDimitry Andric           "error: script interpreter missing, didn't add python command.\n");
14790b57cec5SDimitry Andric       error_sp->Flush();
14800b57cec5SDimitry Andric     }
14810b57cec5SDimitry Andric 
14820b57cec5SDimitry Andric     io_handler.SetIsDone(true);
14830b57cec5SDimitry Andric   }
14840b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)14850b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
14860b57cec5SDimitry Andric     if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
14870b57cec5SDimitry Andric       result.AppendError("only scripting language supported for scripted "
14880b57cec5SDimitry Andric                          "commands is currently Python");
14890b57cec5SDimitry Andric       return false;
14900b57cec5SDimitry Andric     }
14910b57cec5SDimitry Andric 
14920b57cec5SDimitry Andric     if (command.GetArgumentCount() != 1) {
14930b57cec5SDimitry Andric       result.AppendError("'command script add' requires one argument");
14940b57cec5SDimitry Andric       return false;
14950b57cec5SDimitry Andric     }
14960b57cec5SDimitry Andric 
14970b57cec5SDimitry Andric     // Store the options in case we get multi-line input
14985ffd83dbSDimitry Andric     m_cmd_name = std::string(command[0].ref());
14990b57cec5SDimitry Andric     m_short_help.assign(m_options.m_short_help);
15000b57cec5SDimitry Andric     m_synchronicity = m_options.m_synchronicity;
15010b57cec5SDimitry Andric 
15020b57cec5SDimitry Andric     if (m_options.m_class_name.empty()) {
15030b57cec5SDimitry Andric       if (m_options.m_funct_name.empty()) {
15040b57cec5SDimitry Andric         m_interpreter.GetPythonCommandsFromIOHandler(
15050b57cec5SDimitry Andric             "     ", // Prompt
1506480093f4SDimitry Andric             *this);  // IOHandlerDelegate
15070b57cec5SDimitry Andric       } else {
15080b57cec5SDimitry Andric         CommandObjectSP new_cmd(new CommandObjectPythonFunction(
15090b57cec5SDimitry Andric             m_interpreter, m_cmd_name, m_options.m_funct_name,
15100b57cec5SDimitry Andric             m_options.m_short_help, m_synchronicity));
15110b57cec5SDimitry Andric         if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) {
15120b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishNoResult);
15130b57cec5SDimitry Andric         } else {
15140b57cec5SDimitry Andric           result.AppendError("cannot add command");
15150b57cec5SDimitry Andric         }
15160b57cec5SDimitry Andric       }
15170b57cec5SDimitry Andric     } else {
15180b57cec5SDimitry Andric       ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
15190b57cec5SDimitry Andric       if (!interpreter) {
15200b57cec5SDimitry Andric         result.AppendError("cannot find ScriptInterpreter");
15210b57cec5SDimitry Andric         return false;
15220b57cec5SDimitry Andric       }
15230b57cec5SDimitry Andric 
15240b57cec5SDimitry Andric       auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
15250b57cec5SDimitry Andric           m_options.m_class_name.c_str());
15260b57cec5SDimitry Andric       if (!cmd_obj_sp) {
15270b57cec5SDimitry Andric         result.AppendError("cannot create helper object");
15280b57cec5SDimitry Andric         return false;
15290b57cec5SDimitry Andric       }
15300b57cec5SDimitry Andric 
15310b57cec5SDimitry Andric       CommandObjectSP new_cmd(new CommandObjectScriptingObject(
15320b57cec5SDimitry Andric           m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity));
15330b57cec5SDimitry Andric       if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) {
15340b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
15350b57cec5SDimitry Andric       } else {
15360b57cec5SDimitry Andric         result.AppendError("cannot add command");
15370b57cec5SDimitry Andric       }
15380b57cec5SDimitry Andric     }
15390b57cec5SDimitry Andric 
15400b57cec5SDimitry Andric     return result.Succeeded();
15410b57cec5SDimitry Andric   }
15420b57cec5SDimitry Andric 
15430b57cec5SDimitry Andric   CommandOptions m_options;
15440b57cec5SDimitry Andric   std::string m_cmd_name;
15450b57cec5SDimitry Andric   std::string m_short_help;
15460b57cec5SDimitry Andric   ScriptedCommandSynchronicity m_synchronicity;
15470b57cec5SDimitry Andric };
15480b57cec5SDimitry Andric 
15490b57cec5SDimitry Andric // CommandObjectCommandsScriptList
15500b57cec5SDimitry Andric 
15510b57cec5SDimitry Andric class CommandObjectCommandsScriptList : public CommandObjectParsed {
15520b57cec5SDimitry Andric public:
CommandObjectCommandsScriptList(CommandInterpreter & interpreter)15530b57cec5SDimitry Andric   CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
15540b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "command script list",
15550b57cec5SDimitry Andric                             "List defined scripted commands.", nullptr) {}
15560b57cec5SDimitry Andric 
15570b57cec5SDimitry Andric   ~CommandObjectCommandsScriptList() override = default;
15580b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)15590b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
15609dba64beSDimitry Andric     if (command.GetArgumentCount() != 0) {
15619dba64beSDimitry Andric       result.AppendError("'command script list' doesn't take any arguments");
15629dba64beSDimitry Andric       return false;
15639dba64beSDimitry Andric     }
15649dba64beSDimitry Andric 
15650b57cec5SDimitry Andric     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
15660b57cec5SDimitry Andric 
15670b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
15680b57cec5SDimitry Andric 
15690b57cec5SDimitry Andric     return true;
15700b57cec5SDimitry Andric   }
15710b57cec5SDimitry Andric };
15720b57cec5SDimitry Andric 
15730b57cec5SDimitry Andric // CommandObjectCommandsScriptClear
15740b57cec5SDimitry Andric 
15750b57cec5SDimitry Andric class CommandObjectCommandsScriptClear : public CommandObjectParsed {
15760b57cec5SDimitry Andric public:
CommandObjectCommandsScriptClear(CommandInterpreter & interpreter)15770b57cec5SDimitry Andric   CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
15780b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "command script clear",
15790b57cec5SDimitry Andric                             "Delete all scripted commands.", nullptr) {}
15800b57cec5SDimitry Andric 
15810b57cec5SDimitry Andric   ~CommandObjectCommandsScriptClear() override = default;
15820b57cec5SDimitry Andric 
15830b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)15840b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
15859dba64beSDimitry Andric     if (command.GetArgumentCount() != 0) {
15869dba64beSDimitry Andric       result.AppendError("'command script clear' doesn't take any arguments");
15879dba64beSDimitry Andric       return false;
15889dba64beSDimitry Andric     }
15899dba64beSDimitry Andric 
15900b57cec5SDimitry Andric     m_interpreter.RemoveAllUser();
15910b57cec5SDimitry Andric 
15920b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
15930b57cec5SDimitry Andric 
15940b57cec5SDimitry Andric     return true;
15950b57cec5SDimitry Andric   }
15960b57cec5SDimitry Andric };
15970b57cec5SDimitry Andric 
15980b57cec5SDimitry Andric // CommandObjectCommandsScriptDelete
15990b57cec5SDimitry Andric 
16000b57cec5SDimitry Andric class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
16010b57cec5SDimitry Andric public:
CommandObjectCommandsScriptDelete(CommandInterpreter & interpreter)16020b57cec5SDimitry Andric   CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
16030b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "command script delete",
16040b57cec5SDimitry Andric                             "Delete a scripted command.", nullptr) {
16050b57cec5SDimitry Andric     CommandArgumentEntry arg1;
16060b57cec5SDimitry Andric     CommandArgumentData cmd_arg;
16070b57cec5SDimitry Andric 
16080b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
16090b57cec5SDimitry Andric     cmd_arg.arg_type = eArgTypeCommandName;
16100b57cec5SDimitry Andric     cmd_arg.arg_repetition = eArgRepeatPlain;
16110b57cec5SDimitry Andric 
16120b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
16130b57cec5SDimitry Andric     // argument entry.
16140b57cec5SDimitry Andric     arg1.push_back(cmd_arg);
16150b57cec5SDimitry Andric 
16160b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
16170b57cec5SDimitry Andric     m_arguments.push_back(arg1);
16180b57cec5SDimitry Andric   }
16190b57cec5SDimitry Andric 
16200b57cec5SDimitry Andric   ~CommandObjectCommandsScriptDelete() override = default;
16210b57cec5SDimitry Andric 
16225ffd83dbSDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)16235ffd83dbSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
16245ffd83dbSDimitry Andric                            OptionElementVector &opt_element_vector) override {
16255ffd83dbSDimitry Andric     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
16265ffd83dbSDimitry Andric       return;
16275ffd83dbSDimitry Andric 
16285ffd83dbSDimitry Andric     for (const auto &c : m_interpreter.GetUserCommands())
16295ffd83dbSDimitry Andric       request.TryCompleteCurrentArg(c.first, c.second->GetHelp());
16305ffd83dbSDimitry Andric   }
16315ffd83dbSDimitry Andric 
16320b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)16330b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
16340b57cec5SDimitry Andric 
16350b57cec5SDimitry Andric     if (command.GetArgumentCount() != 1) {
16360b57cec5SDimitry Andric       result.AppendError("'command script delete' requires one argument");
16370b57cec5SDimitry Andric       return false;
16380b57cec5SDimitry Andric     }
16390b57cec5SDimitry Andric 
16409dba64beSDimitry Andric     auto cmd_name = command[0].ref();
16410b57cec5SDimitry Andric 
16420b57cec5SDimitry Andric     if (cmd_name.empty() || !m_interpreter.HasUserCommands() ||
16430b57cec5SDimitry Andric         !m_interpreter.UserCommandExists(cmd_name)) {
16440b57cec5SDimitry Andric       result.AppendErrorWithFormat("command %s not found", command[0].c_str());
16450b57cec5SDimitry Andric       return false;
16460b57cec5SDimitry Andric     }
16470b57cec5SDimitry Andric 
16480b57cec5SDimitry Andric     m_interpreter.RemoveUser(cmd_name);
16490b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
16500b57cec5SDimitry Andric     return true;
16510b57cec5SDimitry Andric   }
16520b57cec5SDimitry Andric };
16530b57cec5SDimitry Andric 
16540b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordCommandsScript
16550b57cec5SDimitry Andric 
16560b57cec5SDimitry Andric // CommandObjectMultiwordCommandsScript
16570b57cec5SDimitry Andric 
16580b57cec5SDimitry Andric class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
16590b57cec5SDimitry Andric public:
CommandObjectMultiwordCommandsScript(CommandInterpreter & interpreter)16600b57cec5SDimitry Andric   CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
16610b57cec5SDimitry Andric       : CommandObjectMultiword(
1662480093f4SDimitry Andric             interpreter, "command script",
1663480093f4SDimitry Andric             "Commands for managing custom "
16640b57cec5SDimitry Andric             "commands implemented by "
16650b57cec5SDimitry Andric             "interpreter scripts.",
16660b57cec5SDimitry Andric             "command script <subcommand> [<subcommand-options>]") {
16670b57cec5SDimitry Andric     LoadSubCommand("add", CommandObjectSP(
16680b57cec5SDimitry Andric                               new CommandObjectCommandsScriptAdd(interpreter)));
16690b57cec5SDimitry Andric     LoadSubCommand(
16700b57cec5SDimitry Andric         "delete",
16710b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
16720b57cec5SDimitry Andric     LoadSubCommand(
16730b57cec5SDimitry Andric         "clear",
16740b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
16750b57cec5SDimitry Andric     LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
16760b57cec5SDimitry Andric                                interpreter)));
16770b57cec5SDimitry Andric     LoadSubCommand(
16780b57cec5SDimitry Andric         "import",
16790b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
16800b57cec5SDimitry Andric   }
16810b57cec5SDimitry Andric 
16820b57cec5SDimitry Andric   ~CommandObjectMultiwordCommandsScript() override = default;
16830b57cec5SDimitry Andric };
16840b57cec5SDimitry Andric 
16850b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordCommands
16860b57cec5SDimitry Andric 
16870b57cec5SDimitry Andric // CommandObjectMultiwordCommands
16880b57cec5SDimitry Andric 
CommandObjectMultiwordCommands(CommandInterpreter & interpreter)16890b57cec5SDimitry Andric CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
16900b57cec5SDimitry Andric     CommandInterpreter &interpreter)
16910b57cec5SDimitry Andric     : CommandObjectMultiword(interpreter, "command",
16920b57cec5SDimitry Andric                              "Commands for managing custom LLDB commands.",
16930b57cec5SDimitry Andric                              "command <subcommand> [<subcommand-options>]") {
16940b57cec5SDimitry Andric   LoadSubCommand("source",
16950b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
16960b57cec5SDimitry Andric   LoadSubCommand("alias",
16970b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
16980b57cec5SDimitry Andric   LoadSubCommand("unalias", CommandObjectSP(
16990b57cec5SDimitry Andric                                 new CommandObjectCommandsUnalias(interpreter)));
17000b57cec5SDimitry Andric   LoadSubCommand("delete",
17010b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
17020b57cec5SDimitry Andric   LoadSubCommand(
17030b57cec5SDimitry Andric       "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
17040b57cec5SDimitry Andric   LoadSubCommand(
17050b57cec5SDimitry Andric       "script",
17060b57cec5SDimitry Andric       CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
17070b57cec5SDimitry Andric }
17080b57cec5SDimitry Andric 
17090b57cec5SDimitry Andric CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
1710