xref: /freebsd-src/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
11e8d8bef9SDimitry 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"
16fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
170b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
180b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
190b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueBoolean.h"
200b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueString.h"
210b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueUInt64.h"
220b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
230b57cec5SDimitry Andric #include "lldb/Interpreter/ScriptInterpreter.h"
240b57cec5SDimitry Andric #include "lldb/Utility/Args.h"
250b57cec5SDimitry Andric #include "lldb/Utility/StringList.h"
26e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h"
27bdd1243dSDimitry Andric #include <optional>
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace lldb;
300b57cec5SDimitry Andric using namespace lldb_private;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric // CommandObjectCommandsSource
330b57cec5SDimitry Andric 
349dba64beSDimitry Andric #define LLDB_OPTIONS_source
359dba64beSDimitry Andric #include "CommandOptions.inc"
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric class CommandObjectCommandsSource : public CommandObjectParsed {
380b57cec5SDimitry Andric public:
390b57cec5SDimitry Andric   CommandObjectCommandsSource(CommandInterpreter &interpreter)
400b57cec5SDimitry Andric       : CommandObjectParsed(
410b57cec5SDimitry Andric             interpreter, "command source",
420b57cec5SDimitry Andric             "Read and execute LLDB commands from the file <filename>.",
4304eeddc0SDimitry Andric             nullptr) {
44*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeFilename);
450b57cec5SDimitry Andric   }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   ~CommandObjectCommandsSource() override = default;
480b57cec5SDimitry Andric 
49bdd1243dSDimitry Andric   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
500b57cec5SDimitry Andric                                               uint32_t index) override {
5181ad6265SDimitry Andric     return std::string("");
520b57cec5SDimitry Andric   }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric protected:
570b57cec5SDimitry Andric   class CommandOptions : public Options {
580b57cec5SDimitry Andric   public:
590b57cec5SDimitry Andric     CommandOptions()
6004eeddc0SDimitry Andric         : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
6104eeddc0SDimitry Andric           m_cmd_relative_to_command_file(false) {}
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric     ~CommandOptions() override = default;
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
660b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
670b57cec5SDimitry Andric       Status error;
680b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric       switch (short_option) {
710b57cec5SDimitry Andric       case 'e':
720b57cec5SDimitry Andric         error = m_stop_on_error.SetValueFromString(option_arg);
730b57cec5SDimitry Andric         break;
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric       case 'c':
760b57cec5SDimitry Andric         error = m_stop_on_continue.SetValueFromString(option_arg);
770b57cec5SDimitry Andric         break;
780b57cec5SDimitry Andric 
79349cc55cSDimitry Andric       case 'C':
80349cc55cSDimitry Andric         m_cmd_relative_to_command_file = true;
81349cc55cSDimitry Andric         break;
82349cc55cSDimitry Andric 
830b57cec5SDimitry Andric       case 's':
840b57cec5SDimitry Andric         error = m_silent_run.SetValueFromString(option_arg);
850b57cec5SDimitry Andric         break;
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric       default:
889dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
890b57cec5SDimitry Andric       }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric       return error;
920b57cec5SDimitry Andric     }
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
950b57cec5SDimitry Andric       m_stop_on_error.Clear();
960b57cec5SDimitry Andric       m_silent_run.Clear();
970b57cec5SDimitry Andric       m_stop_on_continue.Clear();
98349cc55cSDimitry Andric       m_cmd_relative_to_command_file.Clear();
990b57cec5SDimitry Andric     }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
102bdd1243dSDimitry Andric       return llvm::ArrayRef(g_source_options);
1030b57cec5SDimitry Andric     }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric     OptionValueBoolean m_stop_on_error;
1080b57cec5SDimitry Andric     OptionValueBoolean m_silent_run;
1090b57cec5SDimitry Andric     OptionValueBoolean m_stop_on_continue;
110349cc55cSDimitry Andric     OptionValueBoolean m_cmd_relative_to_command_file;
1110b57cec5SDimitry Andric   };
1120b57cec5SDimitry Andric 
1135f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
1140b57cec5SDimitry Andric     if (command.GetArgumentCount() != 1) {
1150b57cec5SDimitry Andric       result.AppendErrorWithFormat(
1160b57cec5SDimitry Andric           "'%s' takes exactly one executable filename argument.\n",
1170b57cec5SDimitry Andric           GetCommandName().str().c_str());
1185f757f3fSDimitry Andric       return;
1190b57cec5SDimitry Andric     }
1200b57cec5SDimitry Andric 
121349cc55cSDimitry Andric     FileSpec source_dir = {};
122349cc55cSDimitry Andric     if (m_options.m_cmd_relative_to_command_file) {
123349cc55cSDimitry Andric       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
124349cc55cSDimitry Andric       if (!source_dir) {
125349cc55cSDimitry Andric         result.AppendError("command source -C can only be specified "
126349cc55cSDimitry Andric                            "from a command file");
127349cc55cSDimitry Andric         result.SetStatus(eReturnStatusFailed);
1285f757f3fSDimitry Andric         return;
129349cc55cSDimitry Andric       }
130349cc55cSDimitry Andric     }
131349cc55cSDimitry Andric 
1329dba64beSDimitry Andric     FileSpec cmd_file(command[0].ref());
133349cc55cSDimitry Andric     if (source_dir) {
134349cc55cSDimitry Andric       // Prepend the source_dir to the cmd_file path:
135349cc55cSDimitry Andric       if (!cmd_file.IsRelative()) {
136349cc55cSDimitry Andric         result.AppendError("command source -C can only be used "
137349cc55cSDimitry Andric                            "with a relative path.");
138349cc55cSDimitry Andric         result.SetStatus(eReturnStatusFailed);
1395f757f3fSDimitry Andric         return;
140349cc55cSDimitry Andric       }
141349cc55cSDimitry Andric       cmd_file.MakeAbsolute(source_dir);
142349cc55cSDimitry Andric     }
143349cc55cSDimitry Andric 
1440b57cec5SDimitry Andric     FileSystem::Instance().Resolve(cmd_file);
1450b57cec5SDimitry Andric 
146fe6060f1SDimitry Andric     CommandInterpreterRunOptions options;
1470b57cec5SDimitry Andric     // If any options were set, then use them
1480b57cec5SDimitry Andric     if (m_options.m_stop_on_error.OptionWasSet() ||
1490b57cec5SDimitry Andric         m_options.m_silent_run.OptionWasSet() ||
1500b57cec5SDimitry Andric         m_options.m_stop_on_continue.OptionWasSet()) {
1510b57cec5SDimitry Andric       if (m_options.m_stop_on_continue.OptionWasSet())
1520b57cec5SDimitry Andric         options.SetStopOnContinue(
1530b57cec5SDimitry Andric             m_options.m_stop_on_continue.GetCurrentValue());
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric       if (m_options.m_stop_on_error.OptionWasSet())
1560b57cec5SDimitry Andric         options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric       // Individual silent setting is override for global command echo settings.
1590b57cec5SDimitry Andric       if (m_options.m_silent_run.GetCurrentValue()) {
1600b57cec5SDimitry Andric         options.SetSilent(true);
1610b57cec5SDimitry Andric       } else {
1620b57cec5SDimitry Andric         options.SetPrintResults(true);
1630b57cec5SDimitry Andric         options.SetPrintErrors(true);
1640b57cec5SDimitry Andric         options.SetEchoCommands(m_interpreter.GetEchoCommands());
1650b57cec5SDimitry Andric         options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
1660b57cec5SDimitry Andric       }
1670b57cec5SDimitry Andric     }
168fe6060f1SDimitry Andric 
169fe6060f1SDimitry Andric     m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   CommandOptions m_options;
1730b57cec5SDimitry Andric };
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric #pragma mark CommandObjectCommandsAlias
1760b57cec5SDimitry Andric // CommandObjectCommandsAlias
1770b57cec5SDimitry Andric 
1789dba64beSDimitry Andric #define LLDB_OPTIONS_alias
1799dba64beSDimitry Andric #include "CommandOptions.inc"
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric static const char *g_python_command_instructions =
1820b57cec5SDimitry Andric     "Enter your Python command(s). Type 'DONE' to end.\n"
1830b57cec5SDimitry Andric     "You must define a Python function with this signature:\n"
184bdd1243dSDimitry Andric     "def my_command_impl(debugger, args, exe_ctx, result, internal_dict):\n";
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric class CommandObjectCommandsAlias : public CommandObjectRaw {
1870b57cec5SDimitry Andric protected:
1880b57cec5SDimitry Andric   class CommandOptions : public OptionGroup {
1890b57cec5SDimitry Andric   public:
19081ad6265SDimitry Andric     CommandOptions() = default;
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric     ~CommandOptions() override = default;
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
195bdd1243dSDimitry Andric       return llvm::ArrayRef(g_alias_options);
1960b57cec5SDimitry Andric     }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
1990b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
2000b57cec5SDimitry Andric       Status error;
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric       const int short_option = GetDefinitions()[option_idx].short_option;
2030b57cec5SDimitry Andric       std::string option_str(option_value);
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric       switch (short_option) {
2060b57cec5SDimitry Andric       case 'h':
2070b57cec5SDimitry Andric         m_help.SetCurrentValue(option_str);
2080b57cec5SDimitry Andric         m_help.SetOptionWasSet();
2090b57cec5SDimitry Andric         break;
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric       case 'H':
2120b57cec5SDimitry Andric         m_long_help.SetCurrentValue(option_str);
2130b57cec5SDimitry Andric         m_long_help.SetOptionWasSet();
2140b57cec5SDimitry Andric         break;
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric       default:
2179dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
2180b57cec5SDimitry Andric       }
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric       return error;
2210b57cec5SDimitry Andric     }
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
2240b57cec5SDimitry Andric       m_help.Clear();
2250b57cec5SDimitry Andric       m_long_help.Clear();
2260b57cec5SDimitry Andric     }
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric     OptionValueString m_help;
2290b57cec5SDimitry Andric     OptionValueString m_long_help;
2300b57cec5SDimitry Andric   };
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   OptionGroupOptions m_option_group;
2330b57cec5SDimitry Andric   CommandOptions m_command_options;
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric public:
2360b57cec5SDimitry Andric   Options *GetOptions() override { return &m_option_group; }
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   CommandObjectCommandsAlias(CommandInterpreter &interpreter)
2390b57cec5SDimitry Andric       : CommandObjectRaw(
2400b57cec5SDimitry Andric             interpreter, "command alias",
24104eeddc0SDimitry Andric             "Define a custom command in terms of an existing command.") {
2420b57cec5SDimitry Andric     m_option_group.Append(&m_command_options);
2430b57cec5SDimitry Andric     m_option_group.Finalize();
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric     SetHelpLong(
2460b57cec5SDimitry Andric         "'alias' allows the user to create a short-cut or abbreviation for long \
2470b57cec5SDimitry Andric commands, multi-word commands, and commands that take particular options.  \
2480b57cec5SDimitry Andric Below are some simple examples of how one might use the 'alias' command:"
2490b57cec5SDimitry Andric         R"(
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric (lldb) command alias sc script
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric     Creates the abbreviation 'sc' for the 'script' command.
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric (lldb) command alias bp breakpoint
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric )"
2580b57cec5SDimitry Andric         "    Creates the abbreviation 'bp' for the 'breakpoint' command.  Since \
2590b57cec5SDimitry Andric breakpoint commands are two-word commands, the user would still need to \
2600b57cec5SDimitry Andric enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
2610b57cec5SDimitry Andric         R"(
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric (lldb) command alias bpl breakpoint list
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric     Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric )"
2680b57cec5SDimitry Andric         "An alias can include some options for the command, with the values either \
2690b57cec5SDimitry Andric filled in at the time the alias is created, or specified as positional \
2700b57cec5SDimitry Andric arguments, to be filled in when the alias is invoked.  The following example \
2710b57cec5SDimitry Andric shows how to create aliases with options:"
2720b57cec5SDimitry Andric         R"(
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric (lldb) command alias bfl breakpoint set -f %1 -l %2
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric )"
2770b57cec5SDimitry Andric         "    Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
2780b57cec5SDimitry Andric options already part of the alias.  So if the user wants to set a breakpoint \
2790b57cec5SDimitry Andric by file and line without explicitly having to use the -f and -l options, the \
2800b57cec5SDimitry Andric user can now use 'bfl' instead.  The '%1' and '%2' are positional placeholders \
2810b57cec5SDimitry Andric for the actual arguments that will be passed when the alias command is used.  \
2820b57cec5SDimitry Andric The number in the placeholder refers to the position/order the actual value \
2830b57cec5SDimitry Andric occupies when the alias is used.  All the occurrences of '%1' in the alias \
2840b57cec5SDimitry Andric will be replaced with the first argument, all the occurrences of '%2' in the \
2850b57cec5SDimitry Andric alias will be replaced with the second argument, and so on.  This also allows \
2860b57cec5SDimitry Andric actual arguments to be used multiple times within an alias (see 'process \
2870b57cec5SDimitry Andric launch' example below)."
2880b57cec5SDimitry Andric         R"(
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric )"
2910b57cec5SDimitry Andric         "Note: the positional arguments must substitute as whole words in the resultant \
2920b57cec5SDimitry Andric command, so you can't at present do something like this to append the file extension \
2930b57cec5SDimitry Andric \".cpp\":"
2940b57cec5SDimitry Andric         R"(
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric )"
2990b57cec5SDimitry Andric         "For more complex aliasing, use the \"command regex\" command instead.  In the \
3000b57cec5SDimitry Andric 'bfl' case above, the actual file value will be filled in with the first argument \
3010b57cec5SDimitry Andric following 'bfl' and the actual line number value will be filled in with the second \
3020b57cec5SDimitry Andric argument.  The user would use this alias as follows:"
3030b57cec5SDimitry Andric         R"(
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric (lldb) command alias bfl breakpoint set -f %1 -l %2
3060b57cec5SDimitry Andric (lldb) bfl my-file.c 137
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric Another example:
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric (lldb) command alias pltty process launch -s -o %1 -e %1
3130b57cec5SDimitry Andric (lldb) pltty /dev/tty0
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric     Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric )"
3180b57cec5SDimitry Andric         "If the user always wanted to pass the same value to a particular option, the \
3190b57cec5SDimitry Andric alias could be defined with that value directly in the alias as a constant, \
3200b57cec5SDimitry Andric rather than using a positional placeholder:"
3210b57cec5SDimitry Andric         R"(
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric (lldb) command alias bl3 breakpoint set -f %1 -l 3
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric     Always sets a breakpoint on line 3 of whatever file is indicated.)");
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric     CommandArgumentEntry arg1;
3280b57cec5SDimitry Andric     CommandArgumentEntry arg2;
3290b57cec5SDimitry Andric     CommandArgumentEntry arg3;
3300b57cec5SDimitry Andric     CommandArgumentData alias_arg;
3310b57cec5SDimitry Andric     CommandArgumentData cmd_arg;
3320b57cec5SDimitry Andric     CommandArgumentData options_arg;
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
3350b57cec5SDimitry Andric     alias_arg.arg_type = eArgTypeAliasName;
3360b57cec5SDimitry Andric     alias_arg.arg_repetition = eArgRepeatPlain;
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
3390b57cec5SDimitry Andric     // argument entry.
3400b57cec5SDimitry Andric     arg1.push_back(alias_arg);
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
3430b57cec5SDimitry Andric     cmd_arg.arg_type = eArgTypeCommandName;
3440b57cec5SDimitry Andric     cmd_arg.arg_repetition = eArgRepeatPlain;
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
3470b57cec5SDimitry Andric     // argument entry.
3480b57cec5SDimitry Andric     arg2.push_back(cmd_arg);
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
3510b57cec5SDimitry Andric     options_arg.arg_type = eArgTypeAliasOptions;
3520b57cec5SDimitry Andric     options_arg.arg_repetition = eArgRepeatOptional;
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
3550b57cec5SDimitry Andric     // argument entry.
3560b57cec5SDimitry Andric     arg3.push_back(options_arg);
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
3590b57cec5SDimitry Andric     m_arguments.push_back(arg1);
3600b57cec5SDimitry Andric     m_arguments.push_back(arg2);
3610b57cec5SDimitry Andric     m_arguments.push_back(arg3);
3620b57cec5SDimitry Andric   }
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric   ~CommandObjectCommandsAlias() override = default;
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric protected:
3675f757f3fSDimitry Andric   void DoExecute(llvm::StringRef raw_command_line,
3680b57cec5SDimitry Andric                  CommandReturnObject &result) override {
3690b57cec5SDimitry Andric     if (raw_command_line.empty()) {
3700b57cec5SDimitry Andric       result.AppendError("'command alias' requires at least two arguments");
3715f757f3fSDimitry Andric       return;
3720b57cec5SDimitry Andric     }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric     ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
3750b57cec5SDimitry Andric     m_option_group.NotifyOptionParsingStarting(&exe_ctx);
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric     OptionsWithRaw args_with_suffix(raw_command_line);
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric     if (args_with_suffix.HasArgs())
3800b57cec5SDimitry Andric       if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
3810b57cec5SDimitry Andric                                  m_option_group, exe_ctx))
3825f757f3fSDimitry Andric         return;
3830b57cec5SDimitry Andric 
3845ffd83dbSDimitry Andric     llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
3850b57cec5SDimitry Andric     Args args(raw_command_string);
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric     if (args.GetArgumentCount() < 2) {
3880b57cec5SDimitry Andric       result.AppendError("'command alias' requires at least two arguments");
3895f757f3fSDimitry Andric       return;
3900b57cec5SDimitry Andric     }
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric     // Get the alias command.
3930b57cec5SDimitry Andric 
3949dba64beSDimitry Andric     auto alias_command = args[0].ref();
3955f757f3fSDimitry Andric     if (alias_command.starts_with("-")) {
3960b57cec5SDimitry Andric       result.AppendError("aliases starting with a dash are not supported");
3970b57cec5SDimitry Andric       if (alias_command == "--help" || alias_command == "--long-help") {
3980b57cec5SDimitry Andric         result.AppendWarning("if trying to pass options to 'command alias' add "
3990b57cec5SDimitry Andric                              "a -- at the end of the options");
4000b57cec5SDimitry Andric       }
4015f757f3fSDimitry Andric       return;
4020b57cec5SDimitry Andric     }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric     // Strip the new alias name off 'raw_command_string'  (leave it on args,
4050b57cec5SDimitry Andric     // which gets passed to 'Execute', which does the stripping itself.
4060b57cec5SDimitry Andric     size_t pos = raw_command_string.find(alias_command);
4070b57cec5SDimitry Andric     if (pos == 0) {
4080b57cec5SDimitry Andric       raw_command_string = raw_command_string.substr(alias_command.size());
4090b57cec5SDimitry Andric       pos = raw_command_string.find_first_not_of(' ');
4100b57cec5SDimitry Andric       if ((pos != std::string::npos) && (pos > 0))
4110b57cec5SDimitry Andric         raw_command_string = raw_command_string.substr(pos);
4120b57cec5SDimitry Andric     } else {
4130b57cec5SDimitry Andric       result.AppendError("Error parsing command string.  No alias created.");
4145f757f3fSDimitry Andric       return;
4150b57cec5SDimitry Andric     }
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric     // Verify that the command is alias-able.
4180b57cec5SDimitry Andric     if (m_interpreter.CommandExists(alias_command)) {
4190b57cec5SDimitry Andric       result.AppendErrorWithFormat(
4200b57cec5SDimitry Andric           "'%s' is a permanent debugger command and cannot be redefined.\n",
4210b57cec5SDimitry Andric           args[0].c_str());
4225f757f3fSDimitry Andric       return;
4230b57cec5SDimitry Andric     }
4240b57cec5SDimitry Andric 
425349cc55cSDimitry Andric     if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
426349cc55cSDimitry Andric       result.AppendErrorWithFormat(
427349cc55cSDimitry Andric           "'%s' is a user container command and cannot be overwritten.\n"
428349cc55cSDimitry Andric           "Delete it first with 'command container delete'\n",
429349cc55cSDimitry Andric           args[0].c_str());
4305f757f3fSDimitry Andric       return;
431349cc55cSDimitry Andric     }
432349cc55cSDimitry Andric 
4330b57cec5SDimitry Andric     // Get CommandObject that is being aliased. The command name is read from
4340b57cec5SDimitry Andric     // the front of raw_command_string. raw_command_string is returned with the
4350b57cec5SDimitry Andric     // name of the command object stripped off the front.
4360b57cec5SDimitry Andric     llvm::StringRef original_raw_command_string = raw_command_string;
4370b57cec5SDimitry Andric     CommandObject *cmd_obj =
4380b57cec5SDimitry Andric         m_interpreter.GetCommandObjectForCommand(raw_command_string);
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric     if (!cmd_obj) {
4410b57cec5SDimitry Andric       result.AppendErrorWithFormat("invalid command given to 'command alias'. "
4420b57cec5SDimitry Andric                                    "'%s' does not begin with a valid command."
4430b57cec5SDimitry Andric                                    "  No alias created.",
4440b57cec5SDimitry Andric                                    original_raw_command_string.str().c_str());
4450b57cec5SDimitry Andric     } else if (!cmd_obj->WantsRawCommandString()) {
4460b57cec5SDimitry Andric       // Note that args was initialized with the original command, and has not
4470b57cec5SDimitry Andric       // been updated to this point. Therefore can we pass it to the version of
4480b57cec5SDimitry Andric       // Execute that does not need/expect raw input in the alias.
4495f757f3fSDimitry Andric       HandleAliasingNormalCommand(args, result);
4500b57cec5SDimitry Andric     } else {
4515f757f3fSDimitry Andric       HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj,
4525f757f3fSDimitry Andric                                result);
4530b57cec5SDimitry Andric     }
4540b57cec5SDimitry Andric   }
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric   bool HandleAliasingRawCommand(llvm::StringRef alias_command,
4570b57cec5SDimitry Andric                                 llvm::StringRef raw_command_string,
4580b57cec5SDimitry Andric                                 CommandObject &cmd_obj,
4590b57cec5SDimitry Andric                                 CommandReturnObject &result) {
4600b57cec5SDimitry Andric     // Verify & handle any options/arguments passed to the alias command
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric     OptionArgVectorSP option_arg_vector_sp =
4630b57cec5SDimitry Andric         OptionArgVectorSP(new OptionArgVector);
4640b57cec5SDimitry Andric 
46504eeddc0SDimitry Andric     const bool include_aliases = true;
466bdd1243dSDimitry Andric     // Look up the command using command's name first.  This is to resolve
467bdd1243dSDimitry Andric     // aliases when you are making nested aliases.  But if you don't find
468bdd1243dSDimitry Andric     // it that way, then it wasn't an alias and we can just use the object
469bdd1243dSDimitry Andric     // we were passed in.
470bdd1243dSDimitry Andric     CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
471bdd1243dSDimitry Andric             cmd_obj.GetCommandName(), include_aliases);
472bdd1243dSDimitry Andric     if (!cmd_obj_sp)
473bdd1243dSDimitry Andric       cmd_obj_sp = cmd_obj.shared_from_this();
474bdd1243dSDimitry Andric 
4750b57cec5SDimitry Andric     if (m_interpreter.AliasExists(alias_command) ||
4760b57cec5SDimitry Andric         m_interpreter.UserCommandExists(alias_command)) {
4770b57cec5SDimitry Andric       result.AppendWarningWithFormat(
4780b57cec5SDimitry Andric           "Overwriting existing definition for '%s'.\n",
4790b57cec5SDimitry Andric           alias_command.str().c_str());
4800b57cec5SDimitry Andric     }
4810b57cec5SDimitry Andric     if (CommandAlias *alias = m_interpreter.AddAlias(
4820b57cec5SDimitry Andric             alias_command, cmd_obj_sp, raw_command_string)) {
4830b57cec5SDimitry Andric       if (m_command_options.m_help.OptionWasSet())
4840b57cec5SDimitry Andric         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
4850b57cec5SDimitry Andric       if (m_command_options.m_long_help.OptionWasSet())
4860b57cec5SDimitry Andric         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
4870b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
4880b57cec5SDimitry Andric     } else {
4890b57cec5SDimitry Andric       result.AppendError("Unable to create requested alias.\n");
4900b57cec5SDimitry Andric     }
4910b57cec5SDimitry Andric     return result.Succeeded();
4920b57cec5SDimitry Andric   }
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric   bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
4950b57cec5SDimitry Andric     size_t argc = args.GetArgumentCount();
4960b57cec5SDimitry Andric 
4970b57cec5SDimitry Andric     if (argc < 2) {
4980b57cec5SDimitry Andric       result.AppendError("'command alias' requires at least two arguments");
4990b57cec5SDimitry Andric       return false;
5000b57cec5SDimitry Andric     }
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric     // Save these in std::strings since we're going to shift them off.
5035ffd83dbSDimitry Andric     const std::string alias_command(std::string(args[0].ref()));
5045ffd83dbSDimitry Andric     const std::string actual_command(std::string(args[1].ref()));
5050b57cec5SDimitry Andric 
5060b57cec5SDimitry Andric     args.Shift(); // Shift the alias command word off the argument vector.
5070b57cec5SDimitry Andric     args.Shift(); // Shift the old command word off the argument vector.
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric     // Verify that the command is alias'able, and get the appropriate command
5100b57cec5SDimitry Andric     // object.
5110b57cec5SDimitry Andric 
5120b57cec5SDimitry Andric     if (m_interpreter.CommandExists(alias_command)) {
5130b57cec5SDimitry Andric       result.AppendErrorWithFormat(
5140b57cec5SDimitry Andric           "'%s' is a permanent debugger command and cannot be redefined.\n",
5150b57cec5SDimitry Andric           alias_command.c_str());
5160b57cec5SDimitry Andric       return false;
5170b57cec5SDimitry Andric     }
5180b57cec5SDimitry Andric 
519349cc55cSDimitry Andric     if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
520349cc55cSDimitry Andric       result.AppendErrorWithFormat(
521349cc55cSDimitry Andric           "'%s' is user container command and cannot be overwritten.\n"
522349cc55cSDimitry Andric           "Delete it first with 'command container delete'",
523349cc55cSDimitry Andric           alias_command.c_str());
524349cc55cSDimitry Andric       return false;
525349cc55cSDimitry Andric     }
526349cc55cSDimitry Andric 
5270b57cec5SDimitry Andric     CommandObjectSP command_obj_sp(
5280b57cec5SDimitry Andric         m_interpreter.GetCommandSPExact(actual_command, true));
5290b57cec5SDimitry Andric     CommandObjectSP subcommand_obj_sp;
5300b57cec5SDimitry Andric     bool use_subcommand = false;
5310b57cec5SDimitry Andric     if (!command_obj_sp) {
5320b57cec5SDimitry Andric       result.AppendErrorWithFormat("'%s' is not an existing command.\n",
5330b57cec5SDimitry Andric                                    actual_command.c_str());
5340b57cec5SDimitry Andric       return false;
5350b57cec5SDimitry Andric     }
5360b57cec5SDimitry Andric     CommandObject *cmd_obj = command_obj_sp.get();
5370b57cec5SDimitry Andric     CommandObject *sub_cmd_obj = nullptr;
5380b57cec5SDimitry Andric     OptionArgVectorSP option_arg_vector_sp =
5390b57cec5SDimitry Andric         OptionArgVectorSP(new OptionArgVector);
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric     while (cmd_obj->IsMultiwordObject() && !args.empty()) {
5429dba64beSDimitry Andric       auto sub_command = args[0].ref();
5430b57cec5SDimitry Andric       assert(!sub_command.empty());
5440b57cec5SDimitry Andric       subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
5450b57cec5SDimitry Andric       if (!subcommand_obj_sp) {
5460b57cec5SDimitry Andric         result.AppendErrorWithFormat(
5470b57cec5SDimitry Andric             "'%s' is not a valid sub-command of '%s'.  "
5480b57cec5SDimitry Andric             "Unable to create alias.\n",
5490b57cec5SDimitry Andric             args[0].c_str(), actual_command.c_str());
5500b57cec5SDimitry Andric         return false;
5510b57cec5SDimitry Andric       }
5520b57cec5SDimitry Andric 
5530b57cec5SDimitry Andric       sub_cmd_obj = subcommand_obj_sp.get();
5540b57cec5SDimitry Andric       use_subcommand = true;
5550b57cec5SDimitry Andric       args.Shift(); // Shift the sub_command word off the argument vector.
5560b57cec5SDimitry Andric       cmd_obj = sub_cmd_obj;
5570b57cec5SDimitry Andric     }
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric     // Verify & handle any options/arguments passed to the alias command
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric     std::string args_string;
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric     if (!args.empty()) {
5640b57cec5SDimitry Andric       CommandObjectSP tmp_sp =
565e8d8bef9SDimitry Andric           m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
5660b57cec5SDimitry Andric       if (use_subcommand)
567e8d8bef9SDimitry Andric         tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric       args.GetCommandString(args_string);
5700b57cec5SDimitry Andric     }
5710b57cec5SDimitry Andric 
5720b57cec5SDimitry Andric     if (m_interpreter.AliasExists(alias_command) ||
5730b57cec5SDimitry Andric         m_interpreter.UserCommandExists(alias_command)) {
5740b57cec5SDimitry Andric       result.AppendWarningWithFormat(
5750b57cec5SDimitry Andric           "Overwriting existing definition for '%s'.\n", alias_command.c_str());
5760b57cec5SDimitry Andric     }
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric     if (CommandAlias *alias = m_interpreter.AddAlias(
5790b57cec5SDimitry Andric             alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
5800b57cec5SDimitry Andric             args_string)) {
5810b57cec5SDimitry Andric       if (m_command_options.m_help.OptionWasSet())
5820b57cec5SDimitry Andric         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
5830b57cec5SDimitry Andric       if (m_command_options.m_long_help.OptionWasSet())
5840b57cec5SDimitry Andric         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
5850b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
5860b57cec5SDimitry Andric     } else {
5870b57cec5SDimitry Andric       result.AppendError("Unable to create requested alias.\n");
5880b57cec5SDimitry Andric       return false;
5890b57cec5SDimitry Andric     }
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric     return result.Succeeded();
5920b57cec5SDimitry Andric   }
5930b57cec5SDimitry Andric };
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric #pragma mark CommandObjectCommandsUnalias
5960b57cec5SDimitry Andric // CommandObjectCommandsUnalias
5970b57cec5SDimitry Andric 
5980b57cec5SDimitry Andric class CommandObjectCommandsUnalias : public CommandObjectParsed {
5990b57cec5SDimitry Andric public:
6000b57cec5SDimitry Andric   CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
6010b57cec5SDimitry Andric       : CommandObjectParsed(
6020b57cec5SDimitry Andric             interpreter, "command unalias",
6030b57cec5SDimitry Andric             "Delete one or more custom commands defined by 'command alias'.",
6040b57cec5SDimitry Andric             nullptr) {
605*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeAliasName);
6060b57cec5SDimitry Andric   }
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric   ~CommandObjectCommandsUnalias() override = default;
6090b57cec5SDimitry Andric 
610e8d8bef9SDimitry Andric   void
611e8d8bef9SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
612e8d8bef9SDimitry Andric                            OptionElementVector &opt_element_vector) override {
613e8d8bef9SDimitry Andric     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
614e8d8bef9SDimitry Andric       return;
615e8d8bef9SDimitry Andric 
616e8d8bef9SDimitry Andric     for (const auto &ent : m_interpreter.GetAliases()) {
617e8d8bef9SDimitry Andric       request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
618e8d8bef9SDimitry Andric     }
619e8d8bef9SDimitry Andric   }
620e8d8bef9SDimitry Andric 
6210b57cec5SDimitry Andric protected:
6225f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
6230b57cec5SDimitry Andric     CommandObject::CommandMap::iterator pos;
6240b57cec5SDimitry Andric     CommandObject *cmd_obj;
6250b57cec5SDimitry Andric 
6260b57cec5SDimitry Andric     if (args.empty()) {
6270b57cec5SDimitry Andric       result.AppendError("must call 'unalias' with a valid alias");
6285f757f3fSDimitry Andric       return;
6290b57cec5SDimitry Andric     }
6300b57cec5SDimitry Andric 
6319dba64beSDimitry Andric     auto command_name = args[0].ref();
6320b57cec5SDimitry Andric     cmd_obj = m_interpreter.GetCommandObject(command_name);
6330b57cec5SDimitry Andric     if (!cmd_obj) {
6340b57cec5SDimitry Andric       result.AppendErrorWithFormat(
6350b57cec5SDimitry Andric           "'%s' is not a known command.\nTry 'help' to see a "
6360b57cec5SDimitry Andric           "current list of commands.\n",
6370b57cec5SDimitry Andric           args[0].c_str());
6385f757f3fSDimitry Andric       return;
6390b57cec5SDimitry Andric     }
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric     if (m_interpreter.CommandExists(command_name)) {
6420b57cec5SDimitry Andric       if (cmd_obj->IsRemovable()) {
6430b57cec5SDimitry Andric         result.AppendErrorWithFormat(
6440b57cec5SDimitry Andric             "'%s' is not an alias, it is a debugger command which can be "
6450b57cec5SDimitry Andric             "removed using the 'command delete' command.\n",
6460b57cec5SDimitry Andric             args[0].c_str());
6470b57cec5SDimitry Andric       } else {
6480b57cec5SDimitry Andric         result.AppendErrorWithFormat(
6490b57cec5SDimitry Andric             "'%s' is a permanent debugger command and cannot be removed.\n",
6500b57cec5SDimitry Andric             args[0].c_str());
6510b57cec5SDimitry Andric       }
6525f757f3fSDimitry Andric       return;
6530b57cec5SDimitry Andric     }
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric     if (!m_interpreter.RemoveAlias(command_name)) {
6560b57cec5SDimitry Andric       if (m_interpreter.AliasExists(command_name))
6570b57cec5SDimitry Andric         result.AppendErrorWithFormat(
6580b57cec5SDimitry Andric             "Error occurred while attempting to unalias '%s'.\n",
6590b57cec5SDimitry Andric             args[0].c_str());
6600b57cec5SDimitry Andric       else
6610b57cec5SDimitry Andric         result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
6620b57cec5SDimitry Andric                                      args[0].c_str());
6635f757f3fSDimitry Andric       return;
6640b57cec5SDimitry Andric     }
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
6670b57cec5SDimitry Andric   }
6680b57cec5SDimitry Andric };
6690b57cec5SDimitry Andric 
6700b57cec5SDimitry Andric #pragma mark CommandObjectCommandsDelete
6710b57cec5SDimitry Andric // CommandObjectCommandsDelete
6720b57cec5SDimitry Andric 
6730b57cec5SDimitry Andric class CommandObjectCommandsDelete : public CommandObjectParsed {
6740b57cec5SDimitry Andric public:
6750b57cec5SDimitry Andric   CommandObjectCommandsDelete(CommandInterpreter &interpreter)
6760b57cec5SDimitry Andric       : CommandObjectParsed(
6770b57cec5SDimitry Andric             interpreter, "command delete",
6780b57cec5SDimitry Andric             "Delete one or more custom commands defined by 'command regex'.",
6790b57cec5SDimitry Andric             nullptr) {
680*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeCommandName);
6810b57cec5SDimitry Andric   }
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric   ~CommandObjectCommandsDelete() override = default;
6840b57cec5SDimitry Andric 
685e8d8bef9SDimitry Andric   void
686e8d8bef9SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
687e8d8bef9SDimitry Andric                            OptionElementVector &opt_element_vector) override {
688e8d8bef9SDimitry Andric     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
689e8d8bef9SDimitry Andric       return;
690e8d8bef9SDimitry Andric 
691e8d8bef9SDimitry Andric     for (const auto &ent : m_interpreter.GetCommands()) {
692e8d8bef9SDimitry Andric       if (ent.second->IsRemovable())
693e8d8bef9SDimitry Andric         request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
694e8d8bef9SDimitry Andric     }
695e8d8bef9SDimitry Andric   }
696e8d8bef9SDimitry Andric 
6970b57cec5SDimitry Andric protected:
6985f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
6990b57cec5SDimitry Andric     CommandObject::CommandMap::iterator pos;
7000b57cec5SDimitry Andric 
7010b57cec5SDimitry Andric     if (args.empty()) {
7020b57cec5SDimitry Andric       result.AppendErrorWithFormat("must call '%s' with one or more valid user "
7030b57cec5SDimitry Andric                                    "defined regular expression command names",
7040b57cec5SDimitry Andric                                    GetCommandName().str().c_str());
7055f757f3fSDimitry Andric       return;
7060b57cec5SDimitry Andric     }
7070b57cec5SDimitry Andric 
7089dba64beSDimitry Andric     auto command_name = args[0].ref();
7090b57cec5SDimitry Andric     if (!m_interpreter.CommandExists(command_name)) {
7100b57cec5SDimitry Andric       StreamString error_msg_stream;
7110b57cec5SDimitry Andric       const bool generate_upropos = true;
7120b57cec5SDimitry Andric       const bool generate_type_lookup = false;
7130b57cec5SDimitry Andric       CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
7140b57cec5SDimitry Andric           &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
7150b57cec5SDimitry Andric           generate_upropos, generate_type_lookup);
7160b57cec5SDimitry Andric       result.AppendError(error_msg_stream.GetString());
7175f757f3fSDimitry Andric       return;
7180b57cec5SDimitry Andric     }
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric     if (!m_interpreter.RemoveCommand(command_name)) {
7210b57cec5SDimitry Andric       result.AppendErrorWithFormat(
7220b57cec5SDimitry Andric           "'%s' is a permanent debugger command and cannot be removed.\n",
7230b57cec5SDimitry Andric           args[0].c_str());
7245f757f3fSDimitry Andric       return;
7250b57cec5SDimitry Andric     }
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
7280b57cec5SDimitry Andric   }
7290b57cec5SDimitry Andric };
7300b57cec5SDimitry Andric 
7310b57cec5SDimitry Andric // CommandObjectCommandsAddRegex
7320b57cec5SDimitry Andric 
7339dba64beSDimitry Andric #define LLDB_OPTIONS_regex
7349dba64beSDimitry Andric #include "CommandOptions.inc"
7350b57cec5SDimitry Andric 
7360b57cec5SDimitry Andric #pragma mark CommandObjectCommandsAddRegex
7370b57cec5SDimitry Andric 
7380b57cec5SDimitry Andric class CommandObjectCommandsAddRegex : public CommandObjectParsed,
7390b57cec5SDimitry Andric                                       public IOHandlerDelegateMultiline {
7400b57cec5SDimitry Andric public:
7410b57cec5SDimitry Andric   CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
7420b57cec5SDimitry Andric       : CommandObjectParsed(
743480093f4SDimitry Andric             interpreter, "command regex",
744480093f4SDimitry Andric             "Define a custom command in terms of "
7450b57cec5SDimitry Andric             "existing commands by matching "
7460b57cec5SDimitry Andric             "regular expressions.",
7470b57cec5SDimitry Andric             "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
7480b57cec5SDimitry Andric         IOHandlerDelegateMultiline("",
74904eeddc0SDimitry Andric                                    IOHandlerDelegate::Completion::LLDBCommand) {
7500b57cec5SDimitry Andric     SetHelpLong(
7510b57cec5SDimitry Andric         R"(
7520b57cec5SDimitry Andric )"
7530b57cec5SDimitry Andric         "This command allows the user to create powerful regular expression commands \
7540b57cec5SDimitry Andric with substitutions. The regular expressions and substitutions are specified \
7550b57cec5SDimitry Andric using the regular expression substitution format of:"
7560b57cec5SDimitry Andric         R"(
7570b57cec5SDimitry Andric 
7580b57cec5SDimitry Andric     s/<regex>/<subst>/
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric )"
7610b57cec5SDimitry Andric         "<regex> is a regular expression that can use parenthesis to capture regular \
7620b57cec5SDimitry Andric expression input and substitute the captured matches in the output using %1 \
7630b57cec5SDimitry Andric for the first match, %2 for the second, and so on."
7640b57cec5SDimitry Andric         R"(
7650b57cec5SDimitry Andric 
7660b57cec5SDimitry Andric )"
7670b57cec5SDimitry Andric         "The regular expressions can all be specified on the command line if more than \
7680b57cec5SDimitry Andric one argument is provided. If just the command name is provided on the command \
7690b57cec5SDimitry Andric line, then the regular expressions and substitutions can be entered on separate \
7700b57cec5SDimitry Andric lines, followed by an empty line to terminate the command definition."
7710b57cec5SDimitry Andric         R"(
7720b57cec5SDimitry Andric 
7730b57cec5SDimitry Andric EXAMPLES
7740b57cec5SDimitry Andric 
7750b57cec5SDimitry Andric )"
7760b57cec5SDimitry Andric         "The following example will define a regular expression command named 'f' that \
7770b57cec5SDimitry Andric will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
7780b57cec5SDimitry Andric a number follows 'f':"
7790b57cec5SDimitry Andric         R"(
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric     (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
782*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeSEDStylePair, eArgRepeatOptional);
7830b57cec5SDimitry Andric   }
7840b57cec5SDimitry Andric 
7850b57cec5SDimitry Andric   ~CommandObjectCommandsAddRegex() override = default;
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric protected:
7880b57cec5SDimitry Andric   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
7899dba64beSDimitry Andric     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
7900b57cec5SDimitry Andric     if (output_sp && interactive) {
7910b57cec5SDimitry Andric       output_sp->PutCString("Enter one or more sed substitution commands in "
7920b57cec5SDimitry Andric                             "the form: 's/<regex>/<subst>/'.\nTerminate the "
7930b57cec5SDimitry Andric                             "substitution list with an empty line.\n");
7940b57cec5SDimitry Andric       output_sp->Flush();
7950b57cec5SDimitry Andric     }
7960b57cec5SDimitry Andric   }
7970b57cec5SDimitry Andric 
7980b57cec5SDimitry Andric   void IOHandlerInputComplete(IOHandler &io_handler,
7990b57cec5SDimitry Andric                               std::string &data) override {
8000b57cec5SDimitry Andric     io_handler.SetIsDone(true);
8010b57cec5SDimitry Andric     if (m_regex_cmd_up) {
8020b57cec5SDimitry Andric       StringList lines;
8030b57cec5SDimitry Andric       if (lines.SplitIntoLines(data)) {
8040b57cec5SDimitry Andric         bool check_only = false;
8059dba64beSDimitry Andric         for (const std::string &line : lines) {
8069dba64beSDimitry Andric           Status error = AppendRegexSubstitution(line, check_only);
8070b57cec5SDimitry Andric           if (error.Fail()) {
8080b57cec5SDimitry Andric             if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
8090b57cec5SDimitry Andric               StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
8100b57cec5SDimitry Andric               out_stream->Printf("error: %s\n", error.AsCString());
8110b57cec5SDimitry Andric             }
8120b57cec5SDimitry Andric           }
8130b57cec5SDimitry Andric         }
8140b57cec5SDimitry Andric       }
8150b57cec5SDimitry Andric       if (m_regex_cmd_up->HasRegexEntries()) {
8160b57cec5SDimitry Andric         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
8170b57cec5SDimitry Andric         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
8180b57cec5SDimitry Andric       }
8190b57cec5SDimitry Andric     }
8200b57cec5SDimitry Andric   }
8210b57cec5SDimitry Andric 
8225f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
8230b57cec5SDimitry Andric     const size_t argc = command.GetArgumentCount();
8240b57cec5SDimitry Andric     if (argc == 0) {
8250b57cec5SDimitry Andric       result.AppendError("usage: 'command regex <command-name> "
8260b57cec5SDimitry Andric                          "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
8275f757f3fSDimitry Andric       return;
8280b57cec5SDimitry Andric     }
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric     Status error;
8319dba64beSDimitry Andric     auto name = command[0].ref();
8329dba64beSDimitry Andric     m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
83306c3fb27SDimitry Andric         m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 0,
8340b57cec5SDimitry Andric         true);
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric     if (argc == 1) {
8370b57cec5SDimitry Andric       Debugger &debugger = GetDebugger();
8380b57cec5SDimitry Andric       bool color_prompt = debugger.GetUseColor();
8390b57cec5SDimitry Andric       const bool multiple_lines = true; // Get multiple lines
8400b57cec5SDimitry Andric       IOHandlerSP io_handler_sp(new IOHandlerEditline(
8410b57cec5SDimitry Andric           debugger, IOHandler::Type::Other,
8420b57cec5SDimitry Andric           "lldb-regex",          // Name of input reader for history
8430b57cec5SDimitry Andric           llvm::StringRef("> "), // Prompt
8440b57cec5SDimitry Andric           llvm::StringRef(),     // Continuation prompt
8450b57cec5SDimitry Andric           multiple_lines, color_prompt,
8460b57cec5SDimitry Andric           0, // Don't show line numbers
847bdd1243dSDimitry Andric           *this));
8480b57cec5SDimitry Andric 
8490b57cec5SDimitry Andric       if (io_handler_sp) {
8505ffd83dbSDimitry Andric         debugger.RunIOHandlerAsync(io_handler_sp);
8510b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
8520b57cec5SDimitry Andric       }
8530b57cec5SDimitry Andric     } else {
8540b57cec5SDimitry Andric       for (auto &entry : command.entries().drop_front()) {
8550b57cec5SDimitry Andric         bool check_only = false;
8569dba64beSDimitry Andric         error = AppendRegexSubstitution(entry.ref(), check_only);
8570b57cec5SDimitry Andric         if (error.Fail())
8580b57cec5SDimitry Andric           break;
8590b57cec5SDimitry Andric       }
8600b57cec5SDimitry Andric 
8610b57cec5SDimitry Andric       if (error.Success()) {
8620b57cec5SDimitry Andric         AddRegexCommandToInterpreter();
8630b57cec5SDimitry Andric       }
8640b57cec5SDimitry Andric     }
8650b57cec5SDimitry Andric     if (error.Fail()) {
8660b57cec5SDimitry Andric       result.AppendError(error.AsCString());
8670b57cec5SDimitry Andric     }
8680b57cec5SDimitry Andric   }
8690b57cec5SDimitry Andric 
8700b57cec5SDimitry Andric   Status AppendRegexSubstitution(const llvm::StringRef &regex_sed,
8710b57cec5SDimitry Andric                                  bool check_only) {
8720b57cec5SDimitry Andric     Status error;
8730b57cec5SDimitry Andric 
8740b57cec5SDimitry Andric     if (!m_regex_cmd_up) {
8750b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
8760b57cec5SDimitry Andric           "invalid regular expression command object for: '%.*s'",
8770b57cec5SDimitry Andric           (int)regex_sed.size(), regex_sed.data());
8780b57cec5SDimitry Andric       return error;
8790b57cec5SDimitry Andric     }
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric     size_t regex_sed_size = regex_sed.size();
8820b57cec5SDimitry Andric 
8830b57cec5SDimitry Andric     if (regex_sed_size <= 1) {
8840b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
8850b57cec5SDimitry Andric           "regular expression substitution string is too short: '%.*s'",
8860b57cec5SDimitry Andric           (int)regex_sed.size(), regex_sed.data());
8870b57cec5SDimitry Andric       return error;
8880b57cec5SDimitry Andric     }
8890b57cec5SDimitry Andric 
8900b57cec5SDimitry Andric     if (regex_sed[0] != 's') {
8910b57cec5SDimitry Andric       error.SetErrorStringWithFormat("regular expression substitution string "
8920b57cec5SDimitry Andric                                      "doesn't start with 's': '%.*s'",
8930b57cec5SDimitry Andric                                      (int)regex_sed.size(), regex_sed.data());
8940b57cec5SDimitry Andric       return error;
8950b57cec5SDimitry Andric     }
8960b57cec5SDimitry Andric     const size_t first_separator_char_pos = 1;
8970b57cec5SDimitry Andric     // use the char that follows 's' as the regex separator character so we can
8980b57cec5SDimitry Andric     // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
8990b57cec5SDimitry Andric     const char separator_char = regex_sed[first_separator_char_pos];
9000b57cec5SDimitry Andric     const size_t second_separator_char_pos =
9010b57cec5SDimitry Andric         regex_sed.find(separator_char, first_separator_char_pos + 1);
9020b57cec5SDimitry Andric 
9030b57cec5SDimitry Andric     if (second_separator_char_pos == std::string::npos) {
9040b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
9050b57cec5SDimitry Andric           "missing second '%c' separator char after '%.*s' in '%.*s'",
9060b57cec5SDimitry Andric           separator_char,
9070b57cec5SDimitry Andric           (int)(regex_sed.size() - first_separator_char_pos - 1),
9080b57cec5SDimitry Andric           regex_sed.data() + (first_separator_char_pos + 1),
9090b57cec5SDimitry Andric           (int)regex_sed.size(), regex_sed.data());
9100b57cec5SDimitry Andric       return error;
9110b57cec5SDimitry Andric     }
9120b57cec5SDimitry Andric 
9130b57cec5SDimitry Andric     const size_t third_separator_char_pos =
9140b57cec5SDimitry Andric         regex_sed.find(separator_char, second_separator_char_pos + 1);
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric     if (third_separator_char_pos == std::string::npos) {
9170b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
9180b57cec5SDimitry Andric           "missing third '%c' separator char after '%.*s' in '%.*s'",
9190b57cec5SDimitry Andric           separator_char,
9200b57cec5SDimitry Andric           (int)(regex_sed.size() - second_separator_char_pos - 1),
9210b57cec5SDimitry Andric           regex_sed.data() + (second_separator_char_pos + 1),
9220b57cec5SDimitry Andric           (int)regex_sed.size(), regex_sed.data());
9230b57cec5SDimitry Andric       return error;
9240b57cec5SDimitry Andric     }
9250b57cec5SDimitry Andric 
9260b57cec5SDimitry Andric     if (third_separator_char_pos != regex_sed_size - 1) {
9270b57cec5SDimitry Andric       // Make sure that everything that follows the last regex separator char
9280b57cec5SDimitry Andric       if (regex_sed.find_first_not_of("\t\n\v\f\r ",
9290b57cec5SDimitry Andric                                       third_separator_char_pos + 1) !=
9300b57cec5SDimitry Andric           std::string::npos) {
9310b57cec5SDimitry Andric         error.SetErrorStringWithFormat(
9320b57cec5SDimitry Andric             "extra data found after the '%.*s' regular expression substitution "
9330b57cec5SDimitry Andric             "string: '%.*s'",
9340b57cec5SDimitry Andric             (int)third_separator_char_pos + 1, regex_sed.data(),
9350b57cec5SDimitry Andric             (int)(regex_sed.size() - third_separator_char_pos - 1),
9360b57cec5SDimitry Andric             regex_sed.data() + (third_separator_char_pos + 1));
9370b57cec5SDimitry Andric         return error;
9380b57cec5SDimitry Andric       }
9390b57cec5SDimitry Andric     } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
9400b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
9410b57cec5SDimitry Andric           "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
9420b57cec5SDimitry Andric           separator_char, separator_char, separator_char, (int)regex_sed.size(),
9430b57cec5SDimitry Andric           regex_sed.data());
9440b57cec5SDimitry Andric       return error;
9450b57cec5SDimitry Andric     } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
9460b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
9470b57cec5SDimitry Andric           "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
9480b57cec5SDimitry Andric           separator_char, separator_char, separator_char, (int)regex_sed.size(),
9490b57cec5SDimitry Andric           regex_sed.data());
9500b57cec5SDimitry Andric       return error;
9510b57cec5SDimitry Andric     }
9520b57cec5SDimitry Andric 
9530b57cec5SDimitry Andric     if (!check_only) {
9545ffd83dbSDimitry Andric       std::string regex(std::string(regex_sed.substr(
9555ffd83dbSDimitry Andric           first_separator_char_pos + 1,
9565ffd83dbSDimitry Andric           second_separator_char_pos - first_separator_char_pos - 1)));
9575ffd83dbSDimitry Andric       std::string subst(std::string(regex_sed.substr(
9585ffd83dbSDimitry Andric           second_separator_char_pos + 1,
9595ffd83dbSDimitry Andric           third_separator_char_pos - second_separator_char_pos - 1)));
960e8d8bef9SDimitry Andric       m_regex_cmd_up->AddRegexCommand(regex, subst);
9610b57cec5SDimitry Andric     }
9620b57cec5SDimitry Andric     return error;
9630b57cec5SDimitry Andric   }
9640b57cec5SDimitry Andric 
9650b57cec5SDimitry Andric   void AddRegexCommandToInterpreter() {
9660b57cec5SDimitry Andric     if (m_regex_cmd_up) {
9670b57cec5SDimitry Andric       if (m_regex_cmd_up->HasRegexEntries()) {
9680b57cec5SDimitry Andric         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
9690b57cec5SDimitry Andric         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
9700b57cec5SDimitry Andric       }
9710b57cec5SDimitry Andric     }
9720b57cec5SDimitry Andric   }
9730b57cec5SDimitry Andric 
9740b57cec5SDimitry Andric private:
9750b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
9760b57cec5SDimitry Andric 
9770b57cec5SDimitry Andric   class CommandOptions : public Options {
9780b57cec5SDimitry Andric   public:
97981ad6265SDimitry Andric     CommandOptions() = default;
9800b57cec5SDimitry Andric 
9810b57cec5SDimitry Andric     ~CommandOptions() override = default;
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
9840b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
9850b57cec5SDimitry Andric       Status error;
9860b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
9870b57cec5SDimitry Andric 
9880b57cec5SDimitry Andric       switch (short_option) {
9890b57cec5SDimitry Andric       case 'h':
9905ffd83dbSDimitry Andric         m_help.assign(std::string(option_arg));
9910b57cec5SDimitry Andric         break;
9920b57cec5SDimitry Andric       case 's':
9935ffd83dbSDimitry Andric         m_syntax.assign(std::string(option_arg));
9940b57cec5SDimitry Andric         break;
9950b57cec5SDimitry Andric       default:
9969dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
9970b57cec5SDimitry Andric       }
9980b57cec5SDimitry Andric 
9990b57cec5SDimitry Andric       return error;
10000b57cec5SDimitry Andric     }
10010b57cec5SDimitry Andric 
10020b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
10030b57cec5SDimitry Andric       m_help.clear();
10040b57cec5SDimitry Andric       m_syntax.clear();
10050b57cec5SDimitry Andric     }
10060b57cec5SDimitry Andric 
10070b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1008bdd1243dSDimitry Andric       return llvm::ArrayRef(g_regex_options);
10090b57cec5SDimitry Andric     }
10100b57cec5SDimitry Andric 
10115ffd83dbSDimitry Andric     llvm::StringRef GetHelp() { return m_help; }
10120b57cec5SDimitry Andric 
10135ffd83dbSDimitry Andric     llvm::StringRef GetSyntax() { return m_syntax; }
10140b57cec5SDimitry Andric 
10150b57cec5SDimitry Andric   protected:
10160b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
10170b57cec5SDimitry Andric 
10180b57cec5SDimitry Andric     std::string m_help;
10190b57cec5SDimitry Andric     std::string m_syntax;
10200b57cec5SDimitry Andric   };
10210b57cec5SDimitry Andric 
10220b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
10230b57cec5SDimitry Andric 
10240b57cec5SDimitry Andric   CommandOptions m_options;
10250b57cec5SDimitry Andric };
10260b57cec5SDimitry Andric 
10270b57cec5SDimitry Andric class CommandObjectPythonFunction : public CommandObjectRaw {
10280b57cec5SDimitry Andric public:
10290b57cec5SDimitry Andric   CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
10300b57cec5SDimitry Andric                               std::string funct, std::string help,
103106c3fb27SDimitry Andric                               ScriptedCommandSynchronicity synch,
103206c3fb27SDimitry Andric                               CompletionType completion_type)
1033480093f4SDimitry Andric       : CommandObjectRaw(interpreter, name), m_function_name(funct),
103406c3fb27SDimitry Andric         m_synchro(synch), m_completion_type(completion_type) {
10350b57cec5SDimitry Andric     if (!help.empty())
10360b57cec5SDimitry Andric       SetHelp(help);
10370b57cec5SDimitry Andric     else {
10380b57cec5SDimitry Andric       StreamString stream;
10390b57cec5SDimitry Andric       stream.Printf("For more information run 'help %s'", name.c_str());
10400b57cec5SDimitry Andric       SetHelp(stream.GetString());
10410b57cec5SDimitry Andric     }
10420b57cec5SDimitry Andric   }
10430b57cec5SDimitry Andric 
10440b57cec5SDimitry Andric   ~CommandObjectPythonFunction() override = default;
10450b57cec5SDimitry Andric 
10460b57cec5SDimitry Andric   bool IsRemovable() const override { return true; }
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric   const std::string &GetFunctionName() { return m_function_name; }
10490b57cec5SDimitry Andric 
10500b57cec5SDimitry Andric   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
10510b57cec5SDimitry Andric 
10520b57cec5SDimitry Andric   llvm::StringRef GetHelpLong() override {
10530b57cec5SDimitry Andric     if (m_fetched_help_long)
10540b57cec5SDimitry Andric       return CommandObjectRaw::GetHelpLong();
10550b57cec5SDimitry Andric 
10560b57cec5SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
10570b57cec5SDimitry Andric     if (!scripter)
10580b57cec5SDimitry Andric       return CommandObjectRaw::GetHelpLong();
10590b57cec5SDimitry Andric 
10600b57cec5SDimitry Andric     std::string docstring;
10610b57cec5SDimitry Andric     m_fetched_help_long =
10620b57cec5SDimitry Andric         scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
10630b57cec5SDimitry Andric     if (!docstring.empty())
10640b57cec5SDimitry Andric       SetHelpLong(docstring);
10650b57cec5SDimitry Andric     return CommandObjectRaw::GetHelpLong();
10660b57cec5SDimitry Andric   }
10670b57cec5SDimitry Andric 
106806c3fb27SDimitry Andric   void
106906c3fb27SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
107006c3fb27SDimitry Andric                            OptionElementVector &opt_element_vector) override {
107106c3fb27SDimitry Andric     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
107206c3fb27SDimitry Andric         GetCommandInterpreter(), m_completion_type, request, nullptr);
107306c3fb27SDimitry Andric   }
107406c3fb27SDimitry Andric 
107506c3fb27SDimitry Andric   bool WantsCompletion() override { return true; }
107606c3fb27SDimitry Andric 
10770b57cec5SDimitry Andric protected:
10785f757f3fSDimitry Andric   void DoExecute(llvm::StringRef raw_command_line,
10790b57cec5SDimitry Andric                  CommandReturnObject &result) override {
10800b57cec5SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
10810b57cec5SDimitry Andric 
1082*0fca6ea1SDimitry Andric     m_interpreter.IncreaseCommandUsage(*this);
1083*0fca6ea1SDimitry Andric 
10840b57cec5SDimitry Andric     Status error;
10850b57cec5SDimitry Andric 
10860b57cec5SDimitry Andric     result.SetStatus(eReturnStatusInvalid);
10870b57cec5SDimitry Andric 
1088480093f4SDimitry Andric     if (!scripter || !scripter->RunScriptBasedCommand(
1089480093f4SDimitry Andric                          m_function_name.c_str(), raw_command_line, m_synchro,
1090480093f4SDimitry Andric                          result, error, m_exe_ctx)) {
10910b57cec5SDimitry Andric       result.AppendError(error.AsCString());
10920b57cec5SDimitry Andric     } else {
10930b57cec5SDimitry Andric       // Don't change the status if the command already set it...
10940b57cec5SDimitry Andric       if (result.GetStatus() == eReturnStatusInvalid) {
10950b57cec5SDimitry Andric         if (result.GetOutputData().empty())
10960b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishNoResult);
10970b57cec5SDimitry Andric         else
10980b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
10990b57cec5SDimitry Andric       }
11000b57cec5SDimitry Andric     }
11010b57cec5SDimitry Andric   }
11020b57cec5SDimitry Andric 
11030b57cec5SDimitry Andric private:
11040b57cec5SDimitry Andric   std::string m_function_name;
11050b57cec5SDimitry Andric   ScriptedCommandSynchronicity m_synchro;
110681ad6265SDimitry Andric   bool m_fetched_help_long = false;
110706c3fb27SDimitry Andric   CompletionType m_completion_type = eNoCompletion;
11080b57cec5SDimitry Andric };
11090b57cec5SDimitry Andric 
1110*0fca6ea1SDimitry Andric /// This class implements a "raw" scripted command.  lldb does no parsing of the
1111*0fca6ea1SDimitry Andric /// command line, instead passing the line unaltered (except for backtick
1112*0fca6ea1SDimitry Andric /// substitution).
1113*0fca6ea1SDimitry Andric class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
11140b57cec5SDimitry Andric public:
1115*0fca6ea1SDimitry Andric   CommandObjectScriptingObjectRaw(CommandInterpreter &interpreter,
11160b57cec5SDimitry Andric                                   std::string name,
11170b57cec5SDimitry Andric                                   StructuredData::GenericSP cmd_obj_sp,
111806c3fb27SDimitry Andric                                   ScriptedCommandSynchronicity synch,
111906c3fb27SDimitry Andric                                   CompletionType completion_type)
1120480093f4SDimitry Andric       : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1121480093f4SDimitry Andric         m_synchro(synch), m_fetched_help_short(false),
112206c3fb27SDimitry Andric         m_fetched_help_long(false), m_completion_type(completion_type) {
11230b57cec5SDimitry Andric     StreamString stream;
11240b57cec5SDimitry Andric     stream.Printf("For more information run 'help %s'", name.c_str());
11250b57cec5SDimitry Andric     SetHelp(stream.GetString());
11260b57cec5SDimitry Andric     if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
11270b57cec5SDimitry Andric       GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
11280b57cec5SDimitry Andric   }
11290b57cec5SDimitry Andric 
1130*0fca6ea1SDimitry Andric   ~CommandObjectScriptingObjectRaw() override = default;
11310b57cec5SDimitry Andric 
113206c3fb27SDimitry Andric   void
113306c3fb27SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
113406c3fb27SDimitry Andric                            OptionElementVector &opt_element_vector) override {
113506c3fb27SDimitry Andric     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
113606c3fb27SDimitry Andric         GetCommandInterpreter(), m_completion_type, request, nullptr);
113706c3fb27SDimitry Andric   }
113806c3fb27SDimitry Andric 
113906c3fb27SDimitry Andric   bool WantsCompletion() override { return true; }
114006c3fb27SDimitry Andric 
11410b57cec5SDimitry Andric   bool IsRemovable() const override { return true; }
11420b57cec5SDimitry Andric 
11430b57cec5SDimitry Andric   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
11440b57cec5SDimitry Andric 
1145*0fca6ea1SDimitry Andric   std::optional<std::string> GetRepeatCommand(Args &args,
1146*0fca6ea1SDimitry Andric                                               uint32_t index) override {
1147*0fca6ea1SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1148*0fca6ea1SDimitry Andric     if (!scripter)
1149*0fca6ea1SDimitry Andric       return std::nullopt;
1150*0fca6ea1SDimitry Andric 
1151*0fca6ea1SDimitry Andric     return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
1152*0fca6ea1SDimitry Andric   }
1153*0fca6ea1SDimitry Andric 
11540b57cec5SDimitry Andric   llvm::StringRef GetHelp() override {
11550b57cec5SDimitry Andric     if (m_fetched_help_short)
11560b57cec5SDimitry Andric       return CommandObjectRaw::GetHelp();
11570b57cec5SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
11580b57cec5SDimitry Andric     if (!scripter)
11590b57cec5SDimitry Andric       return CommandObjectRaw::GetHelp();
11600b57cec5SDimitry Andric     std::string docstring;
11610b57cec5SDimitry Andric     m_fetched_help_short =
11620b57cec5SDimitry Andric         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
11630b57cec5SDimitry Andric     if (!docstring.empty())
11640b57cec5SDimitry Andric       SetHelp(docstring);
11650b57cec5SDimitry Andric 
11660b57cec5SDimitry Andric     return CommandObjectRaw::GetHelp();
11670b57cec5SDimitry Andric   }
11680b57cec5SDimitry Andric 
11690b57cec5SDimitry Andric   llvm::StringRef GetHelpLong() override {
11700b57cec5SDimitry Andric     if (m_fetched_help_long)
11710b57cec5SDimitry Andric       return CommandObjectRaw::GetHelpLong();
11720b57cec5SDimitry Andric 
11730b57cec5SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
11740b57cec5SDimitry Andric     if (!scripter)
11750b57cec5SDimitry Andric       return CommandObjectRaw::GetHelpLong();
11760b57cec5SDimitry Andric 
11770b57cec5SDimitry Andric     std::string docstring;
11780b57cec5SDimitry Andric     m_fetched_help_long =
11790b57cec5SDimitry Andric         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
11800b57cec5SDimitry Andric     if (!docstring.empty())
11810b57cec5SDimitry Andric       SetHelpLong(docstring);
11820b57cec5SDimitry Andric     return CommandObjectRaw::GetHelpLong();
11830b57cec5SDimitry Andric   }
11840b57cec5SDimitry Andric 
11850b57cec5SDimitry Andric protected:
11865f757f3fSDimitry Andric   void DoExecute(llvm::StringRef raw_command_line,
11870b57cec5SDimitry Andric                  CommandReturnObject &result) override {
11880b57cec5SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
11890b57cec5SDimitry Andric 
11900b57cec5SDimitry Andric     Status error;
11910b57cec5SDimitry Andric 
11920b57cec5SDimitry Andric     result.SetStatus(eReturnStatusInvalid);
11930b57cec5SDimitry Andric 
11940b57cec5SDimitry Andric     if (!scripter ||
11950b57cec5SDimitry Andric         !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
11960b57cec5SDimitry Andric                                          m_synchro, result, error, m_exe_ctx)) {
11970b57cec5SDimitry Andric       result.AppendError(error.AsCString());
11980b57cec5SDimitry Andric     } else {
11990b57cec5SDimitry Andric       // Don't change the status if the command already set it...
12000b57cec5SDimitry Andric       if (result.GetStatus() == eReturnStatusInvalid) {
12010b57cec5SDimitry Andric         if (result.GetOutputData().empty())
12020b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishNoResult);
12030b57cec5SDimitry Andric         else
12040b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
12050b57cec5SDimitry Andric       }
12060b57cec5SDimitry Andric     }
12070b57cec5SDimitry Andric   }
12080b57cec5SDimitry Andric 
12090b57cec5SDimitry Andric private:
12100b57cec5SDimitry Andric   StructuredData::GenericSP m_cmd_obj_sp;
12110b57cec5SDimitry Andric   ScriptedCommandSynchronicity m_synchro;
12120b57cec5SDimitry Andric   bool m_fetched_help_short : 1;
12130b57cec5SDimitry Andric   bool m_fetched_help_long : 1;
121406c3fb27SDimitry Andric   CompletionType m_completion_type = eNoCompletion;
12150b57cec5SDimitry Andric };
12160b57cec5SDimitry Andric 
1217*0fca6ea1SDimitry Andric 
1218*0fca6ea1SDimitry Andric /// This command implements a lldb parsed scripted command.  The command
1219*0fca6ea1SDimitry Andric /// provides a definition of the options and arguments, and a option value
1220*0fca6ea1SDimitry Andric /// setting callback, and then the command's execution function gets passed
1221*0fca6ea1SDimitry Andric /// just the parsed arguments.
1222*0fca6ea1SDimitry Andric /// Note, implementing a command in Python using these base interfaces is a bit
1223*0fca6ea1SDimitry Andric /// of a pain, but it is much easier to export this low level interface, and
1224*0fca6ea1SDimitry Andric /// then make it nicer on the Python side, than to try to do that in a
1225*0fca6ea1SDimitry Andric /// script language neutral way.
1226*0fca6ea1SDimitry Andric /// So I've also added a base class in Python that provides a table-driven
1227*0fca6ea1SDimitry Andric /// way of defining the options and arguments, which automatically fills the
1228*0fca6ea1SDimitry Andric /// option values, making them available as properties in Python.
1229*0fca6ea1SDimitry Andric ///
1230*0fca6ea1SDimitry Andric class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
1231*0fca6ea1SDimitry Andric private:
1232*0fca6ea1SDimitry Andric   class CommandOptions : public Options {
1233*0fca6ea1SDimitry Andric   public:
1234*0fca6ea1SDimitry Andric     CommandOptions(CommandInterpreter &interpreter,
1235*0fca6ea1SDimitry Andric         StructuredData::GenericSP cmd_obj_sp) : m_interpreter(interpreter),
1236*0fca6ea1SDimitry Andric             m_cmd_obj_sp(cmd_obj_sp) {}
1237*0fca6ea1SDimitry Andric 
1238*0fca6ea1SDimitry Andric     ~CommandOptions() override = default;
1239*0fca6ea1SDimitry Andric 
1240*0fca6ea1SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1241*0fca6ea1SDimitry Andric                           ExecutionContext *execution_context) override {
1242*0fca6ea1SDimitry Andric       Status error;
1243*0fca6ea1SDimitry Andric       ScriptInterpreter *scripter =
1244*0fca6ea1SDimitry Andric         m_interpreter.GetDebugger().GetScriptInterpreter();
1245*0fca6ea1SDimitry Andric       if (!scripter) {
1246*0fca6ea1SDimitry Andric         error.SetErrorString("No script interpreter for SetOptionValue.");
1247*0fca6ea1SDimitry Andric         return error;
1248*0fca6ea1SDimitry Andric       }
1249*0fca6ea1SDimitry Andric       if (!m_cmd_obj_sp) {
1250*0fca6ea1SDimitry Andric         error.SetErrorString("SetOptionValue called with empty cmd_obj.");
1251*0fca6ea1SDimitry Andric         return error;
1252*0fca6ea1SDimitry Andric       }
1253*0fca6ea1SDimitry Andric       if (!m_options_definition_up) {
1254*0fca6ea1SDimitry Andric         error.SetErrorString("SetOptionValue called before options definitions "
1255*0fca6ea1SDimitry Andric                              "were created.");
1256*0fca6ea1SDimitry Andric         return error;
1257*0fca6ea1SDimitry Andric       }
1258*0fca6ea1SDimitry Andric       // Pass the long option, since you aren't actually required to have a
1259*0fca6ea1SDimitry Andric       // short_option, and for those options the index or short option character
1260*0fca6ea1SDimitry Andric       // aren't meaningful on the python side.
1261*0fca6ea1SDimitry Andric       const char * long_option =
1262*0fca6ea1SDimitry Andric         m_options_definition_up.get()[option_idx].long_option;
1263*0fca6ea1SDimitry Andric       bool success = scripter->SetOptionValueForCommandObject(m_cmd_obj_sp,
1264*0fca6ea1SDimitry Andric         execution_context, long_option, option_arg);
1265*0fca6ea1SDimitry Andric       if (!success)
1266*0fca6ea1SDimitry Andric         error.SetErrorStringWithFormatv("Error setting option: {0} to {1}",
1267*0fca6ea1SDimitry Andric                                         long_option, option_arg);
1268*0fca6ea1SDimitry Andric       return error;
1269*0fca6ea1SDimitry Andric     }
1270*0fca6ea1SDimitry Andric 
1271*0fca6ea1SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
1272*0fca6ea1SDimitry Andric       ScriptInterpreter *scripter =
1273*0fca6ea1SDimitry Andric         m_interpreter.GetDebugger().GetScriptInterpreter();
1274*0fca6ea1SDimitry Andric       if (!scripter || !m_cmd_obj_sp)
1275*0fca6ea1SDimitry Andric         return;
1276*0fca6ea1SDimitry Andric 
1277*0fca6ea1SDimitry Andric       scripter->OptionParsingStartedForCommandObject(m_cmd_obj_sp);
1278*0fca6ea1SDimitry Andric     }
1279*0fca6ea1SDimitry Andric 
1280*0fca6ea1SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1281*0fca6ea1SDimitry Andric       if (!m_options_definition_up)
1282*0fca6ea1SDimitry Andric         return {};
1283*0fca6ea1SDimitry Andric       return llvm::ArrayRef(m_options_definition_up.get(), m_num_options);
1284*0fca6ea1SDimitry Andric     }
1285*0fca6ea1SDimitry Andric 
1286*0fca6ea1SDimitry Andric     static Status ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,
1287*0fca6ea1SDimitry Andric         size_t counter, uint32_t &usage_mask) {
1288*0fca6ea1SDimitry Andric       // If the usage entry is not provided, we use LLDB_OPT_SET_ALL.
1289*0fca6ea1SDimitry Andric       // If the usage mask is a UINT, the option belongs to that group.
1290*0fca6ea1SDimitry Andric       // If the usage mask is a vector of UINT's, the option belongs to all the
1291*0fca6ea1SDimitry Andric       // groups listed.
1292*0fca6ea1SDimitry Andric       // If a subelement of the vector is a vector of two ints, then the option
1293*0fca6ea1SDimitry Andric       // belongs to the inclusive range from the first to the second element.
1294*0fca6ea1SDimitry Andric       Status error;
1295*0fca6ea1SDimitry Andric       if (!obj_sp) {
1296*0fca6ea1SDimitry Andric         usage_mask = LLDB_OPT_SET_ALL;
1297*0fca6ea1SDimitry Andric         return error;
1298*0fca6ea1SDimitry Andric       }
1299*0fca6ea1SDimitry Andric 
1300*0fca6ea1SDimitry Andric       usage_mask = 0;
1301*0fca6ea1SDimitry Andric 
1302*0fca6ea1SDimitry Andric       StructuredData::UnsignedInteger *uint_val =
1303*0fca6ea1SDimitry Andric           obj_sp->GetAsUnsignedInteger();
1304*0fca6ea1SDimitry Andric       if (uint_val) {
1305*0fca6ea1SDimitry Andric         // If this is an integer, then this specifies a single group:
1306*0fca6ea1SDimitry Andric         uint32_t value = uint_val->GetValue();
1307*0fca6ea1SDimitry Andric         if (value == 0) {
1308*0fca6ea1SDimitry Andric           error.SetErrorStringWithFormatv(
1309*0fca6ea1SDimitry Andric               "0 is not a valid group for option {0}", counter);
1310*0fca6ea1SDimitry Andric           return error;
1311*0fca6ea1SDimitry Andric         }
1312*0fca6ea1SDimitry Andric         usage_mask = (1 << (value - 1));
1313*0fca6ea1SDimitry Andric         return error;
1314*0fca6ea1SDimitry Andric       }
1315*0fca6ea1SDimitry Andric       // Otherwise it has to be an array:
1316*0fca6ea1SDimitry Andric       StructuredData::Array *array_val = obj_sp->GetAsArray();
1317*0fca6ea1SDimitry Andric       if (!array_val) {
1318*0fca6ea1SDimitry Andric         error.SetErrorStringWithFormatv(
1319*0fca6ea1SDimitry Andric             "required field is not a array for option {0}", counter);
1320*0fca6ea1SDimitry Andric         return error;
1321*0fca6ea1SDimitry Andric       }
1322*0fca6ea1SDimitry Andric       // This is the array ForEach for accumulating a group usage mask from
1323*0fca6ea1SDimitry Andric       // an array of string descriptions of groups.
1324*0fca6ea1SDimitry Andric       auto groups_accumulator
1325*0fca6ea1SDimitry Andric           = [counter, &usage_mask, &error]
1326*0fca6ea1SDimitry Andric             (StructuredData::Object *obj) -> bool {
1327*0fca6ea1SDimitry Andric         StructuredData::UnsignedInteger *int_val = obj->GetAsUnsignedInteger();
1328*0fca6ea1SDimitry Andric         if (int_val) {
1329*0fca6ea1SDimitry Andric           uint32_t value = int_val->GetValue();
1330*0fca6ea1SDimitry Andric           if (value == 0) {
1331*0fca6ea1SDimitry Andric             error.SetErrorStringWithFormatv(
1332*0fca6ea1SDimitry Andric                 "0 is not a valid group for element {0}", counter);
1333*0fca6ea1SDimitry Andric             return false;
1334*0fca6ea1SDimitry Andric           }
1335*0fca6ea1SDimitry Andric           usage_mask |= (1 << (value - 1));
1336*0fca6ea1SDimitry Andric           return true;
1337*0fca6ea1SDimitry Andric         }
1338*0fca6ea1SDimitry Andric         StructuredData::Array *arr_val = obj->GetAsArray();
1339*0fca6ea1SDimitry Andric         if (!arr_val) {
1340*0fca6ea1SDimitry Andric           error.SetErrorStringWithFormatv(
1341*0fca6ea1SDimitry Andric               "Group element not an int or array of integers for element {0}",
1342*0fca6ea1SDimitry Andric               counter);
1343*0fca6ea1SDimitry Andric           return false;
1344*0fca6ea1SDimitry Andric         }
1345*0fca6ea1SDimitry Andric         size_t num_range_elem = arr_val->GetSize();
1346*0fca6ea1SDimitry Andric         if (num_range_elem != 2) {
1347*0fca6ea1SDimitry Andric           error.SetErrorStringWithFormatv(
1348*0fca6ea1SDimitry Andric               "Subranges of a group not a start and a stop for element {0}",
1349*0fca6ea1SDimitry Andric               counter);
1350*0fca6ea1SDimitry Andric           return false;
1351*0fca6ea1SDimitry Andric         }
1352*0fca6ea1SDimitry Andric         int_val = arr_val->GetItemAtIndex(0)->GetAsUnsignedInteger();
1353*0fca6ea1SDimitry Andric         if (!int_val) {
1354*0fca6ea1SDimitry Andric           error.SetErrorStringWithFormatv("Start element of a subrange of a "
1355*0fca6ea1SDimitry Andric               "group not unsigned int for element {0}", counter);
1356*0fca6ea1SDimitry Andric           return false;
1357*0fca6ea1SDimitry Andric         }
1358*0fca6ea1SDimitry Andric         uint32_t start = int_val->GetValue();
1359*0fca6ea1SDimitry Andric         int_val = arr_val->GetItemAtIndex(1)->GetAsUnsignedInteger();
1360*0fca6ea1SDimitry Andric         if (!int_val) {
1361*0fca6ea1SDimitry Andric           error.SetErrorStringWithFormatv("End element of a subrange of a group"
1362*0fca6ea1SDimitry Andric               " not unsigned int for element {0}", counter);
1363*0fca6ea1SDimitry Andric           return false;
1364*0fca6ea1SDimitry Andric         }
1365*0fca6ea1SDimitry Andric         uint32_t end = int_val->GetValue();
1366*0fca6ea1SDimitry Andric         if (start == 0 || end == 0 || start > end) {
1367*0fca6ea1SDimitry Andric           error.SetErrorStringWithFormatv("Invalid subrange of a group: {0} - "
1368*0fca6ea1SDimitry Andric               "{1} for element {2}", start, end, counter);
1369*0fca6ea1SDimitry Andric           return false;
1370*0fca6ea1SDimitry Andric         }
1371*0fca6ea1SDimitry Andric         for (uint32_t i = start; i <= end; i++) {
1372*0fca6ea1SDimitry Andric           usage_mask |= (1 << (i - 1));
1373*0fca6ea1SDimitry Andric         }
1374*0fca6ea1SDimitry Andric         return true;
1375*0fca6ea1SDimitry Andric       };
1376*0fca6ea1SDimitry Andric       array_val->ForEach(groups_accumulator);
1377*0fca6ea1SDimitry Andric       return error;
1378*0fca6ea1SDimitry Andric     }
1379*0fca6ea1SDimitry Andric 
1380*0fca6ea1SDimitry Andric 
1381*0fca6ea1SDimitry Andric     Status SetOptionsFromArray(StructuredData::Dictionary &options) {
1382*0fca6ea1SDimitry Andric       Status error;
1383*0fca6ea1SDimitry Andric       m_num_options = options.GetSize();
1384*0fca6ea1SDimitry Andric       m_options_definition_up.reset(new OptionDefinition[m_num_options]);
1385*0fca6ea1SDimitry Andric       // We need to hand out pointers to contents of these vectors; we reserve
1386*0fca6ea1SDimitry Andric       // as much as we'll need up front so they don't get freed on resize...
1387*0fca6ea1SDimitry Andric       m_usage_container.resize(m_num_options);
1388*0fca6ea1SDimitry Andric       m_enum_storage.resize(m_num_options);
1389*0fca6ea1SDimitry Andric       m_enum_vector.resize(m_num_options);
1390*0fca6ea1SDimitry Andric 
1391*0fca6ea1SDimitry Andric       size_t counter = 0;
1392*0fca6ea1SDimitry Andric       size_t short_opt_counter = 0;
1393*0fca6ea1SDimitry Andric       // This is the Array::ForEach function for adding option elements:
1394*0fca6ea1SDimitry Andric       auto add_element = [this, &error, &counter, &short_opt_counter]
1395*0fca6ea1SDimitry Andric           (llvm::StringRef long_option, StructuredData::Object *object) -> bool {
1396*0fca6ea1SDimitry Andric         StructuredData::Dictionary *opt_dict = object->GetAsDictionary();
1397*0fca6ea1SDimitry Andric         if (!opt_dict) {
1398*0fca6ea1SDimitry Andric           error.SetErrorString("Value in options dictionary is not a dictionary");
1399*0fca6ea1SDimitry Andric           return false;
1400*0fca6ea1SDimitry Andric         }
1401*0fca6ea1SDimitry Andric         OptionDefinition &option_def = m_options_definition_up.get()[counter];
1402*0fca6ea1SDimitry Andric 
1403*0fca6ea1SDimitry Andric         // We aren't exposing the validator yet, set it to null
1404*0fca6ea1SDimitry Andric         option_def.validator = nullptr;
1405*0fca6ea1SDimitry Andric         // We don't require usage masks, so set it to one group by default:
1406*0fca6ea1SDimitry Andric         option_def.usage_mask = 1;
1407*0fca6ea1SDimitry Andric 
1408*0fca6ea1SDimitry Andric         // Now set the fields of the OptionDefinition Array from the dictionary:
1409*0fca6ea1SDimitry Andric         //
1410*0fca6ea1SDimitry Andric         // Note that I don't check for unknown fields in the option dictionaries
1411*0fca6ea1SDimitry Andric         // so a scriptor can add extra elements that are helpful when they go to
1412*0fca6ea1SDimitry Andric         // do "set_option_value"
1413*0fca6ea1SDimitry Andric 
1414*0fca6ea1SDimitry Andric         // Usage Mask:
1415*0fca6ea1SDimitry Andric         StructuredData::ObjectSP obj_sp = opt_dict->GetValueForKey("groups");
1416*0fca6ea1SDimitry Andric         if (obj_sp) {
1417*0fca6ea1SDimitry Andric           error = ParseUsageMaskFromArray(obj_sp, counter,
1418*0fca6ea1SDimitry Andric                                           option_def.usage_mask);
1419*0fca6ea1SDimitry Andric           if (error.Fail())
1420*0fca6ea1SDimitry Andric             return false;
1421*0fca6ea1SDimitry Andric         }
1422*0fca6ea1SDimitry Andric 
1423*0fca6ea1SDimitry Andric         // Required:
1424*0fca6ea1SDimitry Andric         option_def.required = false;
1425*0fca6ea1SDimitry Andric         obj_sp = opt_dict->GetValueForKey("required");
1426*0fca6ea1SDimitry Andric         if (obj_sp) {
1427*0fca6ea1SDimitry Andric           StructuredData::Boolean *boolean_val = obj_sp->GetAsBoolean();
1428*0fca6ea1SDimitry Andric           if (!boolean_val) {
1429*0fca6ea1SDimitry Andric             error.SetErrorStringWithFormatv("'required' field is not a boolean "
1430*0fca6ea1SDimitry Andric                 "for option {0}", counter);
1431*0fca6ea1SDimitry Andric             return false;
1432*0fca6ea1SDimitry Andric           }
1433*0fca6ea1SDimitry Andric           option_def.required = boolean_val->GetValue();
1434*0fca6ea1SDimitry Andric         }
1435*0fca6ea1SDimitry Andric 
1436*0fca6ea1SDimitry Andric         // Short Option:
1437*0fca6ea1SDimitry Andric         int short_option;
1438*0fca6ea1SDimitry Andric         obj_sp = opt_dict->GetValueForKey("short_option");
1439*0fca6ea1SDimitry Andric         if (obj_sp) {
1440*0fca6ea1SDimitry Andric           // The value is a string, so pull the
1441*0fca6ea1SDimitry Andric           llvm::StringRef short_str = obj_sp->GetStringValue();
1442*0fca6ea1SDimitry Andric           if (short_str.empty()) {
1443*0fca6ea1SDimitry Andric             error.SetErrorStringWithFormatv("short_option field empty for "
1444*0fca6ea1SDimitry Andric                 "option {0}", counter);
1445*0fca6ea1SDimitry Andric             return false;
1446*0fca6ea1SDimitry Andric           } else if (short_str.size() != 1) {
1447*0fca6ea1SDimitry Andric             error.SetErrorStringWithFormatv("short_option field has extra "
1448*0fca6ea1SDimitry Andric                 "characters for option {0}", counter);
1449*0fca6ea1SDimitry Andric             return false;
1450*0fca6ea1SDimitry Andric           }
1451*0fca6ea1SDimitry Andric           short_option = (int) short_str[0];
1452*0fca6ea1SDimitry Andric         } else {
1453*0fca6ea1SDimitry Andric           // If the short option is not provided, then we need a unique value
1454*0fca6ea1SDimitry Andric           // less than the lowest printable ASCII character.
1455*0fca6ea1SDimitry Andric           short_option = short_opt_counter++;
1456*0fca6ea1SDimitry Andric         }
1457*0fca6ea1SDimitry Andric         option_def.short_option = short_option;
1458*0fca6ea1SDimitry Andric 
1459*0fca6ea1SDimitry Andric         // Long Option is the key from the outer dict:
1460*0fca6ea1SDimitry Andric         if (long_option.empty()) {
1461*0fca6ea1SDimitry Andric           error.SetErrorStringWithFormatv("empty long_option for option {0}",
1462*0fca6ea1SDimitry Andric               counter);
1463*0fca6ea1SDimitry Andric           return false;
1464*0fca6ea1SDimitry Andric         }
1465*0fca6ea1SDimitry Andric         auto inserted = g_string_storer.insert(long_option.str());
1466*0fca6ea1SDimitry Andric         option_def.long_option = ((*(inserted.first)).data());
1467*0fca6ea1SDimitry Andric 
1468*0fca6ea1SDimitry Andric         // Value Type:
1469*0fca6ea1SDimitry Andric         obj_sp = opt_dict->GetValueForKey("value_type");
1470*0fca6ea1SDimitry Andric         if (obj_sp) {
1471*0fca6ea1SDimitry Andric           StructuredData::UnsignedInteger *uint_val
1472*0fca6ea1SDimitry Andric               = obj_sp->GetAsUnsignedInteger();
1473*0fca6ea1SDimitry Andric           if (!uint_val) {
1474*0fca6ea1SDimitry Andric             error.SetErrorStringWithFormatv("Value type must be an unsigned "
1475*0fca6ea1SDimitry Andric                 "integer");
1476*0fca6ea1SDimitry Andric             return false;
1477*0fca6ea1SDimitry Andric           }
1478*0fca6ea1SDimitry Andric           uint64_t val_type = uint_val->GetValue();
1479*0fca6ea1SDimitry Andric           if (val_type >= eArgTypeLastArg) {
1480*0fca6ea1SDimitry Andric             error.SetErrorStringWithFormatv("Value type {0} beyond the "
1481*0fca6ea1SDimitry Andric                 "CommandArgumentType bounds", val_type);
1482*0fca6ea1SDimitry Andric             return false;
1483*0fca6ea1SDimitry Andric           }
1484*0fca6ea1SDimitry Andric           option_def.argument_type = (CommandArgumentType) val_type;
1485*0fca6ea1SDimitry Andric           option_def.option_has_arg = true;
1486*0fca6ea1SDimitry Andric         } else {
1487*0fca6ea1SDimitry Andric           option_def.argument_type = eArgTypeNone;
1488*0fca6ea1SDimitry Andric           option_def.option_has_arg = false;
1489*0fca6ea1SDimitry Andric         }
1490*0fca6ea1SDimitry Andric 
1491*0fca6ea1SDimitry Andric         // Completion Type:
1492*0fca6ea1SDimitry Andric         obj_sp = opt_dict->GetValueForKey("completion_type");
1493*0fca6ea1SDimitry Andric         if (obj_sp) {
1494*0fca6ea1SDimitry Andric           StructuredData::UnsignedInteger *uint_val = obj_sp->GetAsUnsignedInteger();
1495*0fca6ea1SDimitry Andric           if (!uint_val) {
1496*0fca6ea1SDimitry Andric             error.SetErrorStringWithFormatv("Completion type must be an "
1497*0fca6ea1SDimitry Andric                 "unsigned integer for option {0}", counter);
1498*0fca6ea1SDimitry Andric             return false;
1499*0fca6ea1SDimitry Andric           }
1500*0fca6ea1SDimitry Andric           uint64_t completion_type = uint_val->GetValue();
1501*0fca6ea1SDimitry Andric           if (completion_type > eCustomCompletion) {
1502*0fca6ea1SDimitry Andric             error.SetErrorStringWithFormatv("Completion type for option {0} "
1503*0fca6ea1SDimitry Andric                 "beyond the CompletionType bounds", completion_type);
1504*0fca6ea1SDimitry Andric             return false;
1505*0fca6ea1SDimitry Andric           }
1506*0fca6ea1SDimitry Andric           option_def.completion_type = (CommandArgumentType) completion_type;
1507*0fca6ea1SDimitry Andric         } else
1508*0fca6ea1SDimitry Andric           option_def.completion_type = eNoCompletion;
1509*0fca6ea1SDimitry Andric 
1510*0fca6ea1SDimitry Andric         // Usage Text:
1511*0fca6ea1SDimitry Andric         std::string usage_text;
1512*0fca6ea1SDimitry Andric         obj_sp = opt_dict->GetValueForKey("help");
1513*0fca6ea1SDimitry Andric         if (!obj_sp) {
1514*0fca6ea1SDimitry Andric           error.SetErrorStringWithFormatv("required usage missing from option "
1515*0fca6ea1SDimitry Andric               "{0}", counter);
1516*0fca6ea1SDimitry Andric           return false;
1517*0fca6ea1SDimitry Andric         }
1518*0fca6ea1SDimitry Andric         llvm::StringRef usage_stref;
1519*0fca6ea1SDimitry Andric         usage_stref = obj_sp->GetStringValue();
1520*0fca6ea1SDimitry Andric         if (usage_stref.empty()) {
1521*0fca6ea1SDimitry Andric           error.SetErrorStringWithFormatv("empty usage text for option {0}",
1522*0fca6ea1SDimitry Andric               counter);
1523*0fca6ea1SDimitry Andric           return false;
1524*0fca6ea1SDimitry Andric         }
1525*0fca6ea1SDimitry Andric         m_usage_container[counter] = usage_stref.str().c_str();
1526*0fca6ea1SDimitry Andric         option_def.usage_text = m_usage_container[counter].data();
1527*0fca6ea1SDimitry Andric 
1528*0fca6ea1SDimitry Andric         // Enum Values:
1529*0fca6ea1SDimitry Andric 
1530*0fca6ea1SDimitry Andric         obj_sp = opt_dict->GetValueForKey("enum_values");
1531*0fca6ea1SDimitry Andric         if (obj_sp) {
1532*0fca6ea1SDimitry Andric           StructuredData::Array *array = obj_sp->GetAsArray();
1533*0fca6ea1SDimitry Andric           if (!array) {
1534*0fca6ea1SDimitry Andric             error.SetErrorStringWithFormatv("enum values must be an array for "
1535*0fca6ea1SDimitry Andric                 "option {0}", counter);
1536*0fca6ea1SDimitry Andric             return false;
1537*0fca6ea1SDimitry Andric           }
1538*0fca6ea1SDimitry Andric           size_t num_elem = array->GetSize();
1539*0fca6ea1SDimitry Andric           size_t enum_ctr = 0;
1540*0fca6ea1SDimitry Andric           m_enum_storage[counter] = std::vector<EnumValueStorage>(num_elem);
1541*0fca6ea1SDimitry Andric           std::vector<EnumValueStorage> &curr_elem = m_enum_storage[counter];
1542*0fca6ea1SDimitry Andric 
1543*0fca6ea1SDimitry Andric           // This is the Array::ForEach function for adding enum elements:
1544*0fca6ea1SDimitry Andric           // Since there are only two fields to specify the enum, use a simple
1545*0fca6ea1SDimitry Andric           // two element array with value first, usage second.
1546*0fca6ea1SDimitry Andric           // counter is only used for reporting so I pass it by value here.
1547*0fca6ea1SDimitry Andric           auto add_enum = [&enum_ctr, &curr_elem, counter, &error]
1548*0fca6ea1SDimitry Andric               (StructuredData::Object *object) -> bool {
1549*0fca6ea1SDimitry Andric             StructuredData::Array *enum_arr = object->GetAsArray();
1550*0fca6ea1SDimitry Andric             if (!enum_arr) {
1551*0fca6ea1SDimitry Andric               error.SetErrorStringWithFormatv("Enum values for option {0} not "
1552*0fca6ea1SDimitry Andric                   "an array", counter);
1553*0fca6ea1SDimitry Andric               return false;
1554*0fca6ea1SDimitry Andric             }
1555*0fca6ea1SDimitry Andric             size_t num_enum_elements = enum_arr->GetSize();
1556*0fca6ea1SDimitry Andric             if (num_enum_elements != 2) {
1557*0fca6ea1SDimitry Andric               error.SetErrorStringWithFormatv("Wrong number of elements: {0} "
1558*0fca6ea1SDimitry Andric                   "for enum {1} in option {2}",
1559*0fca6ea1SDimitry Andric                   num_enum_elements, enum_ctr, counter);
1560*0fca6ea1SDimitry Andric               return false;
1561*0fca6ea1SDimitry Andric             }
1562*0fca6ea1SDimitry Andric             // Enum Value:
1563*0fca6ea1SDimitry Andric             StructuredData::ObjectSP obj_sp = enum_arr->GetItemAtIndex(0);
1564*0fca6ea1SDimitry Andric             llvm::StringRef val_stref = obj_sp->GetStringValue();
1565*0fca6ea1SDimitry Andric             std::string value_cstr_str = val_stref.str().c_str();
1566*0fca6ea1SDimitry Andric 
1567*0fca6ea1SDimitry Andric             // Enum Usage:
1568*0fca6ea1SDimitry Andric             obj_sp = enum_arr->GetItemAtIndex(1);
1569*0fca6ea1SDimitry Andric             if (!obj_sp) {
1570*0fca6ea1SDimitry Andric               error.SetErrorStringWithFormatv("No usage for enum {0} in option "
1571*0fca6ea1SDimitry Andric                   "{1}",  enum_ctr, counter);
1572*0fca6ea1SDimitry Andric               return false;
1573*0fca6ea1SDimitry Andric             }
1574*0fca6ea1SDimitry Andric             llvm::StringRef usage_stref = obj_sp->GetStringValue();
1575*0fca6ea1SDimitry Andric             std::string usage_cstr_str = usage_stref.str().c_str();
1576*0fca6ea1SDimitry Andric             curr_elem[enum_ctr] = EnumValueStorage(value_cstr_str,
1577*0fca6ea1SDimitry Andric                 usage_cstr_str, enum_ctr);
1578*0fca6ea1SDimitry Andric 
1579*0fca6ea1SDimitry Andric             enum_ctr++;
1580*0fca6ea1SDimitry Andric             return true;
1581*0fca6ea1SDimitry Andric           }; // end of add_enum
1582*0fca6ea1SDimitry Andric 
1583*0fca6ea1SDimitry Andric           array->ForEach(add_enum);
1584*0fca6ea1SDimitry Andric           if (!error.Success())
1585*0fca6ea1SDimitry Andric             return false;
1586*0fca6ea1SDimitry Andric           // We have to have a vector of elements to set in the options, make
1587*0fca6ea1SDimitry Andric           // that here:
1588*0fca6ea1SDimitry Andric           for (auto &elem : curr_elem)
1589*0fca6ea1SDimitry Andric             m_enum_vector[counter].emplace_back(elem.element);
1590*0fca6ea1SDimitry Andric 
1591*0fca6ea1SDimitry Andric           option_def.enum_values = llvm::ArrayRef(m_enum_vector[counter]);
1592*0fca6ea1SDimitry Andric         }
1593*0fca6ea1SDimitry Andric         counter++;
1594*0fca6ea1SDimitry Andric         return true;
1595*0fca6ea1SDimitry Andric       }; // end of add_element
1596*0fca6ea1SDimitry Andric 
1597*0fca6ea1SDimitry Andric       options.ForEach(add_element);
1598*0fca6ea1SDimitry Andric       return error;
1599*0fca6ea1SDimitry Andric     }
1600*0fca6ea1SDimitry Andric 
1601*0fca6ea1SDimitry Andric     size_t GetNumOptions() { return m_num_options; }
1602*0fca6ea1SDimitry Andric 
1603*0fca6ea1SDimitry Andric   private:
1604*0fca6ea1SDimitry Andric     struct EnumValueStorage {
1605*0fca6ea1SDimitry Andric       EnumValueStorage() {
1606*0fca6ea1SDimitry Andric         element.string_value = "value not set";
1607*0fca6ea1SDimitry Andric         element.usage = "usage not set";
1608*0fca6ea1SDimitry Andric         element.value = 0;
1609*0fca6ea1SDimitry Andric       }
1610*0fca6ea1SDimitry Andric 
1611*0fca6ea1SDimitry Andric       EnumValueStorage(std::string in_str_val, std::string in_usage,
1612*0fca6ea1SDimitry Andric           size_t in_value) : value(std::move(in_str_val)), usage(std::move(in_usage)) {
1613*0fca6ea1SDimitry Andric         SetElement(in_value);
1614*0fca6ea1SDimitry Andric       }
1615*0fca6ea1SDimitry Andric 
1616*0fca6ea1SDimitry Andric       EnumValueStorage(const EnumValueStorage &in) : value(in.value),
1617*0fca6ea1SDimitry Andric           usage(in.usage) {
1618*0fca6ea1SDimitry Andric         SetElement(in.element.value);
1619*0fca6ea1SDimitry Andric       }
1620*0fca6ea1SDimitry Andric 
1621*0fca6ea1SDimitry Andric       EnumValueStorage &operator=(const EnumValueStorage &in) {
1622*0fca6ea1SDimitry Andric         value = in.value;
1623*0fca6ea1SDimitry Andric         usage = in.usage;
1624*0fca6ea1SDimitry Andric         SetElement(in.element.value);
1625*0fca6ea1SDimitry Andric         return *this;
1626*0fca6ea1SDimitry Andric       }
1627*0fca6ea1SDimitry Andric 
1628*0fca6ea1SDimitry Andric       void SetElement(size_t in_value) {
1629*0fca6ea1SDimitry Andric         element.value = in_value;
1630*0fca6ea1SDimitry Andric         element.string_value = value.data();
1631*0fca6ea1SDimitry Andric         element.usage = usage.data();
1632*0fca6ea1SDimitry Andric       }
1633*0fca6ea1SDimitry Andric 
1634*0fca6ea1SDimitry Andric       std::string value;
1635*0fca6ea1SDimitry Andric       std::string usage;
1636*0fca6ea1SDimitry Andric       OptionEnumValueElement element;
1637*0fca6ea1SDimitry Andric     };
1638*0fca6ea1SDimitry Andric     // We have to provide char * values for the long option, usage and enum
1639*0fca6ea1SDimitry Andric     // values, that's what the option definitions hold.
1640*0fca6ea1SDimitry Andric     // The long option strings are quite likely to be reused in other added
1641*0fca6ea1SDimitry Andric     // commands, so those are stored in a global set: g_string_storer.
1642*0fca6ea1SDimitry Andric     // But the usages are much less likely to be reused, so those are stored in
1643*0fca6ea1SDimitry Andric     // a vector in the command instance.  It gets resized to the correct size
1644*0fca6ea1SDimitry Andric     // and then filled with null-terminated strings in the std::string, so the
1645*0fca6ea1SDimitry Andric     // are valid C-strings that won't move around.
1646*0fca6ea1SDimitry Andric     // The enum values and descriptions are treated similarly - these aren't
1647*0fca6ea1SDimitry Andric     // all that common so it's not worth the effort to dedup them.
1648*0fca6ea1SDimitry Andric     size_t m_num_options = 0;
1649*0fca6ea1SDimitry Andric     std::unique_ptr<OptionDefinition> m_options_definition_up;
1650*0fca6ea1SDimitry Andric     std::vector<std::vector<EnumValueStorage>> m_enum_storage;
1651*0fca6ea1SDimitry Andric     std::vector<std::vector<OptionEnumValueElement>> m_enum_vector;
1652*0fca6ea1SDimitry Andric     std::vector<std::string> m_usage_container;
1653*0fca6ea1SDimitry Andric     CommandInterpreter &m_interpreter;
1654*0fca6ea1SDimitry Andric     StructuredData::GenericSP m_cmd_obj_sp;
1655*0fca6ea1SDimitry Andric     static std::unordered_set<std::string> g_string_storer;
1656*0fca6ea1SDimitry Andric   };
1657*0fca6ea1SDimitry Andric 
1658*0fca6ea1SDimitry Andric public:
1659*0fca6ea1SDimitry Andric   static CommandObjectSP Create(CommandInterpreter &interpreter,
1660*0fca6ea1SDimitry Andric                 std::string name,
1661*0fca6ea1SDimitry Andric                 StructuredData::GenericSP cmd_obj_sp,
1662*0fca6ea1SDimitry Andric                 ScriptedCommandSynchronicity synch,
1663*0fca6ea1SDimitry Andric                 CommandReturnObject &result) {
1664*0fca6ea1SDimitry Andric     CommandObjectSP new_cmd_sp(new CommandObjectScriptingObjectParsed(
1665*0fca6ea1SDimitry Andric         interpreter, name, cmd_obj_sp, synch));
1666*0fca6ea1SDimitry Andric 
1667*0fca6ea1SDimitry Andric     CommandObjectScriptingObjectParsed *parsed_cmd
1668*0fca6ea1SDimitry Andric         = static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get());
1669*0fca6ea1SDimitry Andric     // Now check all the failure modes, and report if found.
1670*0fca6ea1SDimitry Andric     Status opt_error = parsed_cmd->GetOptionsError();
1671*0fca6ea1SDimitry Andric     Status arg_error = parsed_cmd->GetArgsError();
1672*0fca6ea1SDimitry Andric 
1673*0fca6ea1SDimitry Andric     if (opt_error.Fail())
1674*0fca6ea1SDimitry Andric       result.AppendErrorWithFormat("failed to parse option definitions: %s",
1675*0fca6ea1SDimitry Andric                                    opt_error.AsCString());
1676*0fca6ea1SDimitry Andric     if (arg_error.Fail())
1677*0fca6ea1SDimitry Andric       result.AppendErrorWithFormat("%sfailed to parse argument definitions: %s",
1678*0fca6ea1SDimitry Andric                                    opt_error.Fail() ? ", also " : "",
1679*0fca6ea1SDimitry Andric                                    arg_error.AsCString());
1680*0fca6ea1SDimitry Andric 
1681*0fca6ea1SDimitry Andric     if (!result.Succeeded())
1682*0fca6ea1SDimitry Andric       return {};
1683*0fca6ea1SDimitry Andric 
1684*0fca6ea1SDimitry Andric     return new_cmd_sp;
1685*0fca6ea1SDimitry Andric   }
1686*0fca6ea1SDimitry Andric 
1687*0fca6ea1SDimitry Andric   CommandObjectScriptingObjectParsed(CommandInterpreter &interpreter,
1688*0fca6ea1SDimitry Andric                                std::string name,
1689*0fca6ea1SDimitry Andric                                StructuredData::GenericSP cmd_obj_sp,
1690*0fca6ea1SDimitry Andric                                ScriptedCommandSynchronicity synch)
1691*0fca6ea1SDimitry Andric       : CommandObjectParsed(interpreter, name.c_str()),
1692*0fca6ea1SDimitry Andric         m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch),
1693*0fca6ea1SDimitry Andric         m_options(interpreter, cmd_obj_sp), m_fetched_help_short(false),
1694*0fca6ea1SDimitry Andric         m_fetched_help_long(false) {
1695*0fca6ea1SDimitry Andric     StreamString stream;
1696*0fca6ea1SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1697*0fca6ea1SDimitry Andric     if (!scripter) {
1698*0fca6ea1SDimitry Andric       m_options_error.SetErrorString("No script interpreter");
1699*0fca6ea1SDimitry Andric       return;
1700*0fca6ea1SDimitry Andric     }
1701*0fca6ea1SDimitry Andric 
1702*0fca6ea1SDimitry Andric     // Set the flags:
1703*0fca6ea1SDimitry Andric     GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1704*0fca6ea1SDimitry Andric 
1705*0fca6ea1SDimitry Andric     // Now set up the options definitions from the options:
1706*0fca6ea1SDimitry Andric     StructuredData::ObjectSP options_object_sp
1707*0fca6ea1SDimitry Andric         = scripter->GetOptionsForCommandObject(cmd_obj_sp);
1708*0fca6ea1SDimitry Andric     // It's okay not to have an options dict.
1709*0fca6ea1SDimitry Andric     if (options_object_sp) {
1710*0fca6ea1SDimitry Andric       // The options come as a dictionary of dictionaries.  The key of the
1711*0fca6ea1SDimitry Andric       // outer dict is the long option name (since that's required).  The
1712*0fca6ea1SDimitry Andric       // value holds all the other option specification bits.
1713*0fca6ea1SDimitry Andric       StructuredData::Dictionary *options_dict
1714*0fca6ea1SDimitry Andric           = options_object_sp->GetAsDictionary();
1715*0fca6ea1SDimitry Andric       // but if it exists, it has to be an array.
1716*0fca6ea1SDimitry Andric       if (options_dict) {
1717*0fca6ea1SDimitry Andric         m_options_error = m_options.SetOptionsFromArray(*(options_dict));
1718*0fca6ea1SDimitry Andric         // If we got an error don't bother with the arguments...
1719*0fca6ea1SDimitry Andric         if (m_options_error.Fail())
1720*0fca6ea1SDimitry Andric           return;
1721*0fca6ea1SDimitry Andric       } else {
1722*0fca6ea1SDimitry Andric         m_options_error.SetErrorString("Options array not an array");
1723*0fca6ea1SDimitry Andric         return;
1724*0fca6ea1SDimitry Andric       }
1725*0fca6ea1SDimitry Andric     }
1726*0fca6ea1SDimitry Andric     // Then fetch the args.  Since the arguments can have usage masks you need
1727*0fca6ea1SDimitry Andric     // an array of arrays.
1728*0fca6ea1SDimitry Andric     StructuredData::ObjectSP args_object_sp
1729*0fca6ea1SDimitry Andric       = scripter->GetArgumentsForCommandObject(cmd_obj_sp);
1730*0fca6ea1SDimitry Andric     if (args_object_sp) {
1731*0fca6ea1SDimitry Andric       StructuredData::Array *args_array = args_object_sp->GetAsArray();
1732*0fca6ea1SDimitry Andric       if (!args_array) {
1733*0fca6ea1SDimitry Andric         m_args_error.SetErrorString("Argument specification is not an array");
1734*0fca6ea1SDimitry Andric         return;
1735*0fca6ea1SDimitry Andric       }
1736*0fca6ea1SDimitry Andric       size_t counter = 0;
1737*0fca6ea1SDimitry Andric 
1738*0fca6ea1SDimitry Andric       // This is the Array::ForEach function that handles the
1739*0fca6ea1SDimitry Andric       // CommandArgumentEntry arrays one by one:
1740*0fca6ea1SDimitry Andric       auto arg_array_adder = [this, &counter] (StructuredData::Object *object)
1741*0fca6ea1SDimitry Andric           -> bool {
1742*0fca6ea1SDimitry Andric         // This is the Array::ForEach function to add argument entries:
1743*0fca6ea1SDimitry Andric         CommandArgumentEntry this_entry;
1744*0fca6ea1SDimitry Andric         size_t elem_counter = 0;
1745*0fca6ea1SDimitry Andric         auto args_adder = [this, counter, &elem_counter, &this_entry]
1746*0fca6ea1SDimitry Andric             (StructuredData::Object *object) -> bool {
1747*0fca6ea1SDimitry Andric           // The arguments definition has three fields, the argument type, the
1748*0fca6ea1SDimitry Andric           // repeat and the usage mask.
1749*0fca6ea1SDimitry Andric           CommandArgumentType arg_type = eArgTypeNone;
1750*0fca6ea1SDimitry Andric           ArgumentRepetitionType arg_repetition = eArgRepeatOptional;
1751*0fca6ea1SDimitry Andric           uint32_t arg_opt_set_association;
1752*0fca6ea1SDimitry Andric 
1753*0fca6ea1SDimitry Andric           auto report_error = [this, elem_counter, counter]
1754*0fca6ea1SDimitry Andric               (const char *err_txt) -> bool {
1755*0fca6ea1SDimitry Andric             m_args_error.SetErrorStringWithFormatv("Element {0} of arguments "
1756*0fca6ea1SDimitry Andric                 "list element {1}: %s.", elem_counter, counter, err_txt);
1757*0fca6ea1SDimitry Andric             return false;
1758*0fca6ea1SDimitry Andric           };
1759*0fca6ea1SDimitry Andric 
1760*0fca6ea1SDimitry Andric           StructuredData::Dictionary *arg_dict = object->GetAsDictionary();
1761*0fca6ea1SDimitry Andric           if (!arg_dict) {
1762*0fca6ea1SDimitry Andric             report_error("is not a dictionary.");
1763*0fca6ea1SDimitry Andric             return false;
1764*0fca6ea1SDimitry Andric           }
1765*0fca6ea1SDimitry Andric           // Argument Type:
1766*0fca6ea1SDimitry Andric           StructuredData::ObjectSP obj_sp
1767*0fca6ea1SDimitry Andric               = arg_dict->GetValueForKey("arg_type");
1768*0fca6ea1SDimitry Andric           if (obj_sp) {
1769*0fca6ea1SDimitry Andric             StructuredData::UnsignedInteger *uint_val
1770*0fca6ea1SDimitry Andric                 = obj_sp->GetAsUnsignedInteger();
1771*0fca6ea1SDimitry Andric             if (!uint_val) {
1772*0fca6ea1SDimitry Andric               report_error("value type must be an unsigned integer");
1773*0fca6ea1SDimitry Andric               return false;
1774*0fca6ea1SDimitry Andric             }
1775*0fca6ea1SDimitry Andric             uint64_t arg_type_int = uint_val->GetValue();
1776*0fca6ea1SDimitry Andric             if (arg_type_int >= eArgTypeLastArg) {
1777*0fca6ea1SDimitry Andric               report_error("value type beyond ArgumentRepetitionType bounds");
1778*0fca6ea1SDimitry Andric               return false;
1779*0fca6ea1SDimitry Andric             }
1780*0fca6ea1SDimitry Andric             arg_type = (CommandArgumentType) arg_type_int;
1781*0fca6ea1SDimitry Andric           }
1782*0fca6ea1SDimitry Andric           // Repeat Value:
1783*0fca6ea1SDimitry Andric           obj_sp = arg_dict->GetValueForKey("repeat");
1784*0fca6ea1SDimitry Andric           std::optional<ArgumentRepetitionType> repeat;
1785*0fca6ea1SDimitry Andric           if (obj_sp) {
1786*0fca6ea1SDimitry Andric             llvm::StringRef repeat_str = obj_sp->GetStringValue();
1787*0fca6ea1SDimitry Andric             if (repeat_str.empty()) {
1788*0fca6ea1SDimitry Andric               report_error("repeat value is empty");
1789*0fca6ea1SDimitry Andric               return false;
1790*0fca6ea1SDimitry Andric             }
1791*0fca6ea1SDimitry Andric             repeat = ArgRepetitionFromString(repeat_str);
1792*0fca6ea1SDimitry Andric             if (!repeat) {
1793*0fca6ea1SDimitry Andric               report_error("invalid repeat value");
1794*0fca6ea1SDimitry Andric               return false;
1795*0fca6ea1SDimitry Andric             }
1796*0fca6ea1SDimitry Andric             arg_repetition = *repeat;
1797*0fca6ea1SDimitry Andric           }
1798*0fca6ea1SDimitry Andric 
1799*0fca6ea1SDimitry Andric           // Usage Mask:
1800*0fca6ea1SDimitry Andric           obj_sp = arg_dict->GetValueForKey("groups");
1801*0fca6ea1SDimitry Andric           m_args_error = CommandOptions::ParseUsageMaskFromArray(obj_sp,
1802*0fca6ea1SDimitry Andric               counter, arg_opt_set_association);
1803*0fca6ea1SDimitry Andric           this_entry.emplace_back(arg_type, arg_repetition,
1804*0fca6ea1SDimitry Andric               arg_opt_set_association);
1805*0fca6ea1SDimitry Andric           elem_counter++;
1806*0fca6ea1SDimitry Andric           return true;
1807*0fca6ea1SDimitry Andric         };
1808*0fca6ea1SDimitry Andric         StructuredData::Array *args_array = object->GetAsArray();
1809*0fca6ea1SDimitry Andric         if (!args_array) {
1810*0fca6ea1SDimitry Andric           m_args_error.SetErrorStringWithFormatv("Argument definition element "
1811*0fca6ea1SDimitry Andric               "{0} is not an array", counter);
1812*0fca6ea1SDimitry Andric         }
1813*0fca6ea1SDimitry Andric 
1814*0fca6ea1SDimitry Andric         args_array->ForEach(args_adder);
1815*0fca6ea1SDimitry Andric         if (m_args_error.Fail())
1816*0fca6ea1SDimitry Andric           return false;
1817*0fca6ea1SDimitry Andric         if (this_entry.empty()) {
1818*0fca6ea1SDimitry Andric           m_args_error.SetErrorStringWithFormatv("Argument definition element "
1819*0fca6ea1SDimitry Andric               "{0} is empty", counter);
1820*0fca6ea1SDimitry Andric           return false;
1821*0fca6ea1SDimitry Andric         }
1822*0fca6ea1SDimitry Andric         m_arguments.push_back(this_entry);
1823*0fca6ea1SDimitry Andric         counter++;
1824*0fca6ea1SDimitry Andric         return true;
1825*0fca6ea1SDimitry Andric       }; // end of arg_array_adder
1826*0fca6ea1SDimitry Andric       // Here we actually parse the args definition:
1827*0fca6ea1SDimitry Andric       args_array->ForEach(arg_array_adder);
1828*0fca6ea1SDimitry Andric     }
1829*0fca6ea1SDimitry Andric   }
1830*0fca6ea1SDimitry Andric 
1831*0fca6ea1SDimitry Andric   ~CommandObjectScriptingObjectParsed() override = default;
1832*0fca6ea1SDimitry Andric 
1833*0fca6ea1SDimitry Andric   Status GetOptionsError() { return m_options_error; }
1834*0fca6ea1SDimitry Andric   Status GetArgsError() { return m_args_error; }
1835*0fca6ea1SDimitry Andric   bool WantsCompletion() override { return true; }
1836*0fca6ea1SDimitry Andric 
1837*0fca6ea1SDimitry Andric   bool IsRemovable() const override { return true; }
1838*0fca6ea1SDimitry Andric 
1839*0fca6ea1SDimitry Andric   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1840*0fca6ea1SDimitry Andric 
1841*0fca6ea1SDimitry Andric   std::optional<std::string> GetRepeatCommand(Args &args,
1842*0fca6ea1SDimitry Andric                                               uint32_t index) override {
1843*0fca6ea1SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1844*0fca6ea1SDimitry Andric     if (!scripter)
1845*0fca6ea1SDimitry Andric       return std::nullopt;
1846*0fca6ea1SDimitry Andric 
1847*0fca6ea1SDimitry Andric     return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
1848*0fca6ea1SDimitry Andric   }
1849*0fca6ea1SDimitry Andric 
1850*0fca6ea1SDimitry Andric   llvm::StringRef GetHelp() override {
1851*0fca6ea1SDimitry Andric     if (m_fetched_help_short)
1852*0fca6ea1SDimitry Andric       return CommandObjectParsed::GetHelp();
1853*0fca6ea1SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1854*0fca6ea1SDimitry Andric     if (!scripter)
1855*0fca6ea1SDimitry Andric       return CommandObjectParsed::GetHelp();
1856*0fca6ea1SDimitry Andric     std::string docstring;
1857*0fca6ea1SDimitry Andric     m_fetched_help_short =
1858*0fca6ea1SDimitry Andric         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1859*0fca6ea1SDimitry Andric     if (!docstring.empty())
1860*0fca6ea1SDimitry Andric       SetHelp(docstring);
1861*0fca6ea1SDimitry Andric 
1862*0fca6ea1SDimitry Andric     return CommandObjectParsed::GetHelp();
1863*0fca6ea1SDimitry Andric   }
1864*0fca6ea1SDimitry Andric 
1865*0fca6ea1SDimitry Andric   llvm::StringRef GetHelpLong() override {
1866*0fca6ea1SDimitry Andric     if (m_fetched_help_long)
1867*0fca6ea1SDimitry Andric       return CommandObjectParsed::GetHelpLong();
1868*0fca6ea1SDimitry Andric 
1869*0fca6ea1SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1870*0fca6ea1SDimitry Andric     if (!scripter)
1871*0fca6ea1SDimitry Andric       return CommandObjectParsed::GetHelpLong();
1872*0fca6ea1SDimitry Andric 
1873*0fca6ea1SDimitry Andric     std::string docstring;
1874*0fca6ea1SDimitry Andric     m_fetched_help_long =
1875*0fca6ea1SDimitry Andric         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1876*0fca6ea1SDimitry Andric     if (!docstring.empty())
1877*0fca6ea1SDimitry Andric       SetHelpLong(docstring);
1878*0fca6ea1SDimitry Andric     return CommandObjectParsed::GetHelpLong();
1879*0fca6ea1SDimitry Andric   }
1880*0fca6ea1SDimitry Andric 
1881*0fca6ea1SDimitry Andric   Options *GetOptions() override {
1882*0fca6ea1SDimitry Andric     // CommandObjectParsed requires that a command with no options return
1883*0fca6ea1SDimitry Andric     // nullptr.
1884*0fca6ea1SDimitry Andric     if (m_options.GetNumOptions() == 0)
1885*0fca6ea1SDimitry Andric       return nullptr;
1886*0fca6ea1SDimitry Andric     return &m_options;
1887*0fca6ea1SDimitry Andric   }
1888*0fca6ea1SDimitry Andric 
1889*0fca6ea1SDimitry Andric protected:
1890*0fca6ea1SDimitry Andric   void DoExecute(Args &args,
1891*0fca6ea1SDimitry Andric                  CommandReturnObject &result) override {
1892*0fca6ea1SDimitry Andric     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1893*0fca6ea1SDimitry Andric 
1894*0fca6ea1SDimitry Andric     Status error;
1895*0fca6ea1SDimitry Andric 
1896*0fca6ea1SDimitry Andric     result.SetStatus(eReturnStatusInvalid);
1897*0fca6ea1SDimitry Andric 
1898*0fca6ea1SDimitry Andric     if (!scripter ||
1899*0fca6ea1SDimitry Andric         !scripter->RunScriptBasedParsedCommand(m_cmd_obj_sp, args,
1900*0fca6ea1SDimitry Andric                                          m_synchro, result, error, m_exe_ctx)) {
1901*0fca6ea1SDimitry Andric       result.AppendError(error.AsCString());
1902*0fca6ea1SDimitry Andric     } else {
1903*0fca6ea1SDimitry Andric       // Don't change the status if the command already set it...
1904*0fca6ea1SDimitry Andric       if (result.GetStatus() == eReturnStatusInvalid) {
1905*0fca6ea1SDimitry Andric         if (result.GetOutputData().empty())
1906*0fca6ea1SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1907*0fca6ea1SDimitry Andric         else
1908*0fca6ea1SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
1909*0fca6ea1SDimitry Andric       }
1910*0fca6ea1SDimitry Andric     }
1911*0fca6ea1SDimitry Andric   }
1912*0fca6ea1SDimitry Andric 
1913*0fca6ea1SDimitry Andric private:
1914*0fca6ea1SDimitry Andric   StructuredData::GenericSP m_cmd_obj_sp;
1915*0fca6ea1SDimitry Andric   ScriptedCommandSynchronicity m_synchro;
1916*0fca6ea1SDimitry Andric   CommandOptions m_options;
1917*0fca6ea1SDimitry Andric   Status m_options_error;
1918*0fca6ea1SDimitry Andric   Status m_args_error;
1919*0fca6ea1SDimitry Andric   bool m_fetched_help_short : 1;
1920*0fca6ea1SDimitry Andric   bool m_fetched_help_long : 1;
1921*0fca6ea1SDimitry Andric };
1922*0fca6ea1SDimitry Andric 
1923*0fca6ea1SDimitry Andric std::unordered_set<std::string>
1924*0fca6ea1SDimitry Andric     CommandObjectScriptingObjectParsed::CommandOptions::g_string_storer;
1925*0fca6ea1SDimitry Andric 
19260b57cec5SDimitry Andric // CommandObjectCommandsScriptImport
19279dba64beSDimitry Andric #define LLDB_OPTIONS_script_import
19289dba64beSDimitry Andric #include "CommandOptions.inc"
19290b57cec5SDimitry Andric 
19300b57cec5SDimitry Andric class CommandObjectCommandsScriptImport : public CommandObjectParsed {
19310b57cec5SDimitry Andric public:
19320b57cec5SDimitry Andric   CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
19330b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "command script import",
193404eeddc0SDimitry Andric                             "Import a scripting module in LLDB.", nullptr) {
1935*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeFilename, eArgRepeatPlus);
19360b57cec5SDimitry Andric   }
19370b57cec5SDimitry Andric 
19380b57cec5SDimitry Andric   ~CommandObjectCommandsScriptImport() override = default;
19390b57cec5SDimitry Andric 
19400b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
19410b57cec5SDimitry Andric 
19420b57cec5SDimitry Andric protected:
19430b57cec5SDimitry Andric   class CommandOptions : public Options {
19440b57cec5SDimitry Andric   public:
194581ad6265SDimitry Andric     CommandOptions() = default;
19460b57cec5SDimitry Andric 
19470b57cec5SDimitry Andric     ~CommandOptions() override = default;
19480b57cec5SDimitry Andric 
19490b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
19500b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
19510b57cec5SDimitry Andric       Status error;
19520b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
19530b57cec5SDimitry Andric 
19540b57cec5SDimitry Andric       switch (short_option) {
19550b57cec5SDimitry Andric       case 'r':
1956480093f4SDimitry Andric         // NO-OP
19570b57cec5SDimitry Andric         break;
1958e8d8bef9SDimitry Andric       case 'c':
1959e8d8bef9SDimitry Andric         relative_to_command_file = true;
1960e8d8bef9SDimitry Andric         break;
1961fe6060f1SDimitry Andric       case 's':
1962fe6060f1SDimitry Andric         silent = true;
1963fe6060f1SDimitry Andric         break;
19640b57cec5SDimitry Andric       default:
19659dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
19660b57cec5SDimitry Andric       }
19670b57cec5SDimitry Andric 
19680b57cec5SDimitry Andric       return error;
19690b57cec5SDimitry Andric     }
19700b57cec5SDimitry Andric 
19710b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
1972e8d8bef9SDimitry Andric       relative_to_command_file = false;
19730b57cec5SDimitry Andric     }
19740b57cec5SDimitry Andric 
19750b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1976bdd1243dSDimitry Andric       return llvm::ArrayRef(g_script_import_options);
19770b57cec5SDimitry Andric     }
1978e8d8bef9SDimitry Andric     bool relative_to_command_file = false;
1979fe6060f1SDimitry Andric     bool silent = false;
19800b57cec5SDimitry Andric   };
19810b57cec5SDimitry Andric 
19825f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
19830b57cec5SDimitry Andric     if (command.empty()) {
19840b57cec5SDimitry Andric       result.AppendError("command script import needs one or more arguments");
19855f757f3fSDimitry Andric       return;
19860b57cec5SDimitry Andric     }
19870b57cec5SDimitry Andric 
1988e8d8bef9SDimitry Andric     FileSpec source_dir = {};
1989e8d8bef9SDimitry Andric     if (m_options.relative_to_command_file) {
1990e8d8bef9SDimitry Andric       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1991e8d8bef9SDimitry Andric       if (!source_dir) {
1992e8d8bef9SDimitry Andric         result.AppendError("command script import -c can only be specified "
1993e8d8bef9SDimitry Andric                            "from a command file");
19945f757f3fSDimitry Andric         return;
1995e8d8bef9SDimitry Andric       }
1996e8d8bef9SDimitry Andric     }
1997e8d8bef9SDimitry Andric 
19980b57cec5SDimitry Andric     for (auto &entry : command.entries()) {
19990b57cec5SDimitry Andric       Status error;
20000b57cec5SDimitry Andric 
2001fe6060f1SDimitry Andric       LoadScriptOptions options;
2002fe6060f1SDimitry Andric       options.SetInitSession(true);
2003fe6060f1SDimitry Andric       options.SetSilent(m_options.silent);
2004fe6060f1SDimitry Andric 
20050b57cec5SDimitry Andric       // FIXME: this is necessary because CommandObject::CheckRequirements()
20060b57cec5SDimitry Andric       // assumes that commands won't ever be recursively invoked, but it's
20070b57cec5SDimitry Andric       // actually possible to craft a Python script that does other "command
20080b57cec5SDimitry Andric       // script imports" in __lldb_init_module the real fix is to have
20090b57cec5SDimitry Andric       // recursive commands possible with a CommandInvocation object separate
20100b57cec5SDimitry Andric       // from the CommandObject itself, so that recursive command invocations
20110b57cec5SDimitry Andric       // won't stomp on each other (wrt to execution contents, options, and
20120b57cec5SDimitry Andric       // more)
20130b57cec5SDimitry Andric       m_exe_ctx.Clear();
20140b57cec5SDimitry Andric       if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
2015fe6060f1SDimitry Andric               entry.c_str(), options, error, /*module_sp=*/nullptr,
2016fe6060f1SDimitry Andric               source_dir)) {
20170b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
20180b57cec5SDimitry Andric       } else {
20190b57cec5SDimitry Andric         result.AppendErrorWithFormat("module importing failed: %s",
20200b57cec5SDimitry Andric                                      error.AsCString());
20210b57cec5SDimitry Andric       }
20220b57cec5SDimitry Andric     }
20230b57cec5SDimitry Andric   }
20240b57cec5SDimitry Andric 
20250b57cec5SDimitry Andric   CommandOptions m_options;
20260b57cec5SDimitry Andric };
20270b57cec5SDimitry Andric 
20289dba64beSDimitry Andric #define LLDB_OPTIONS_script_add
20299dba64beSDimitry Andric #include "CommandOptions.inc"
20300b57cec5SDimitry Andric 
20310b57cec5SDimitry Andric class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
20320b57cec5SDimitry Andric                                        public IOHandlerDelegateMultiline {
20330b57cec5SDimitry Andric public:
20340b57cec5SDimitry Andric   CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
20350b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "command script add",
20360b57cec5SDimitry Andric                             "Add a scripted function as an LLDB command.",
2037349cc55cSDimitry Andric                             "Add a scripted function as an lldb command. "
2038349cc55cSDimitry Andric                             "If you provide a single argument, the command "
2039349cc55cSDimitry Andric                             "will be added at the root level of the command "
2040349cc55cSDimitry Andric                             "hierarchy.  If there are more arguments they "
2041349cc55cSDimitry Andric                             "must be a path to a user-added container "
2042349cc55cSDimitry Andric                             "command, and the last element will be the new "
2043349cc55cSDimitry Andric                             "command name."),
204404eeddc0SDimitry Andric         IOHandlerDelegateMultiline("DONE") {
2045*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
20460b57cec5SDimitry Andric   }
20470b57cec5SDimitry Andric 
20480b57cec5SDimitry Andric   ~CommandObjectCommandsScriptAdd() override = default;
20490b57cec5SDimitry Andric 
20500b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
20510b57cec5SDimitry Andric 
2052349cc55cSDimitry Andric   void
2053349cc55cSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
2054349cc55cSDimitry Andric                            OptionElementVector &opt_element_vector) override {
2055349cc55cSDimitry Andric     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
2056349cc55cSDimitry Andric                                                       opt_element_vector);
2057349cc55cSDimitry Andric   }
2058349cc55cSDimitry Andric 
20590b57cec5SDimitry Andric protected:
20600b57cec5SDimitry Andric   class CommandOptions : public Options {
20610b57cec5SDimitry Andric   public:
206281ad6265SDimitry Andric     CommandOptions() = default;
20630b57cec5SDimitry Andric 
20640b57cec5SDimitry Andric     ~CommandOptions() override = default;
20650b57cec5SDimitry Andric 
20660b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
20670b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
20680b57cec5SDimitry Andric       Status error;
20690b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
20700b57cec5SDimitry Andric 
20710b57cec5SDimitry Andric       switch (short_option) {
20720b57cec5SDimitry Andric       case 'f':
20730b57cec5SDimitry Andric         if (!option_arg.empty())
20745ffd83dbSDimitry Andric           m_funct_name = std::string(option_arg);
20750b57cec5SDimitry Andric         break;
20760b57cec5SDimitry Andric       case 'c':
20770b57cec5SDimitry Andric         if (!option_arg.empty())
20785ffd83dbSDimitry Andric           m_class_name = std::string(option_arg);
20790b57cec5SDimitry Andric         break;
20800b57cec5SDimitry Andric       case 'h':
20810b57cec5SDimitry Andric         if (!option_arg.empty())
20825ffd83dbSDimitry Andric           m_short_help = std::string(option_arg);
20830b57cec5SDimitry Andric         break;
2084349cc55cSDimitry Andric       case 'o':
208581ad6265SDimitry Andric         m_overwrite_lazy = eLazyBoolYes;
2086349cc55cSDimitry Andric         break;
2087*0fca6ea1SDimitry Andric       case 'p':
2088*0fca6ea1SDimitry Andric         m_parsed_command = true;
2089*0fca6ea1SDimitry Andric         break;
20900b57cec5SDimitry Andric       case 's':
20910b57cec5SDimitry Andric         m_synchronicity =
20920b57cec5SDimitry Andric             (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
20930b57cec5SDimitry Andric                 option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
20940b57cec5SDimitry Andric         if (!error.Success())
20950b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
20960b57cec5SDimitry Andric               "unrecognized value for synchronicity '%s'",
20970b57cec5SDimitry Andric               option_arg.str().c_str());
20980b57cec5SDimitry Andric         break;
209906c3fb27SDimitry Andric       case 'C': {
210006c3fb27SDimitry Andric         Status error;
210106c3fb27SDimitry Andric         OptionDefinition definition = GetDefinitions()[option_idx];
210206c3fb27SDimitry Andric         lldb::CompletionType completion_type =
210306c3fb27SDimitry Andric             static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum(
210406c3fb27SDimitry Andric                 option_arg, definition.enum_values, eNoCompletion, error));
210506c3fb27SDimitry Andric         if (!error.Success())
210606c3fb27SDimitry Andric           error.SetErrorStringWithFormat(
210706c3fb27SDimitry Andric               "unrecognized value for command completion type '%s'",
210806c3fb27SDimitry Andric               option_arg.str().c_str());
210906c3fb27SDimitry Andric         m_completion_type = completion_type;
211006c3fb27SDimitry Andric       } break;
21110b57cec5SDimitry Andric       default:
21129dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
21130b57cec5SDimitry Andric       }
21140b57cec5SDimitry Andric 
21150b57cec5SDimitry Andric       return error;
21160b57cec5SDimitry Andric     }
21170b57cec5SDimitry Andric 
21180b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
21190b57cec5SDimitry Andric       m_class_name.clear();
21200b57cec5SDimitry Andric       m_funct_name.clear();
21210b57cec5SDimitry Andric       m_short_help.clear();
212206c3fb27SDimitry Andric       m_completion_type = eNoCompletion;
212381ad6265SDimitry Andric       m_overwrite_lazy = eLazyBoolCalculate;
21240b57cec5SDimitry Andric       m_synchronicity = eScriptedCommandSynchronicitySynchronous;
2125*0fca6ea1SDimitry Andric       m_parsed_command = false;
21260b57cec5SDimitry Andric     }
21270b57cec5SDimitry Andric 
21280b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2129bdd1243dSDimitry Andric       return llvm::ArrayRef(g_script_add_options);
21300b57cec5SDimitry Andric     }
21310b57cec5SDimitry Andric 
21320b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
21330b57cec5SDimitry Andric 
21340b57cec5SDimitry Andric     std::string m_class_name;
21350b57cec5SDimitry Andric     std::string m_funct_name;
21360b57cec5SDimitry Andric     std::string m_short_help;
213781ad6265SDimitry Andric     LazyBool m_overwrite_lazy = eLazyBoolCalculate;
2138fe6060f1SDimitry Andric     ScriptedCommandSynchronicity m_synchronicity =
2139fe6060f1SDimitry Andric         eScriptedCommandSynchronicitySynchronous;
214006c3fb27SDimitry Andric     CompletionType m_completion_type = eNoCompletion;
2141*0fca6ea1SDimitry Andric     bool m_parsed_command = false;
21420b57cec5SDimitry Andric   };
21430b57cec5SDimitry Andric 
21440b57cec5SDimitry Andric   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
21459dba64beSDimitry Andric     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
21460b57cec5SDimitry Andric     if (output_sp && interactive) {
21470b57cec5SDimitry Andric       output_sp->PutCString(g_python_command_instructions);
21480b57cec5SDimitry Andric       output_sp->Flush();
21490b57cec5SDimitry Andric     }
21500b57cec5SDimitry Andric   }
21510b57cec5SDimitry Andric 
21520b57cec5SDimitry Andric   void IOHandlerInputComplete(IOHandler &io_handler,
21530b57cec5SDimitry Andric                               std::string &data) override {
21549dba64beSDimitry Andric     StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
21550b57cec5SDimitry Andric 
21560b57cec5SDimitry Andric     ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
21570b57cec5SDimitry Andric     if (interpreter) {
21580b57cec5SDimitry Andric       StringList lines;
21590b57cec5SDimitry Andric       lines.SplitIntoLines(data);
21600b57cec5SDimitry Andric       if (lines.GetSize() > 0) {
21610b57cec5SDimitry Andric         std::string funct_name_str;
21620b57cec5SDimitry Andric         if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
21630b57cec5SDimitry Andric           if (funct_name_str.empty()) {
21640b57cec5SDimitry Andric             error_sp->Printf("error: unable to obtain a function name, didn't "
21650b57cec5SDimitry Andric                              "add python command.\n");
21660b57cec5SDimitry Andric             error_sp->Flush();
21670b57cec5SDimitry Andric           } else {
21680b57cec5SDimitry Andric             // everything should be fine now, let's add this alias
21690b57cec5SDimitry Andric 
21700b57cec5SDimitry Andric             CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
21710b57cec5SDimitry Andric                 m_interpreter, m_cmd_name, funct_name_str, m_short_help,
217206c3fb27SDimitry Andric                 m_synchronicity, m_completion_type));
2173349cc55cSDimitry Andric             if (!m_container) {
2174349cc55cSDimitry Andric               Status error = m_interpreter.AddUserCommand(
2175349cc55cSDimitry Andric                   m_cmd_name, command_obj_sp, m_overwrite);
2176349cc55cSDimitry Andric               if (error.Fail()) {
2177349cc55cSDimitry Andric                 error_sp->Printf("error: unable to add selected command: '%s'",
2178349cc55cSDimitry Andric                                  error.AsCString());
21790b57cec5SDimitry Andric                 error_sp->Flush();
21800b57cec5SDimitry Andric               }
2181349cc55cSDimitry Andric             } else {
2182349cc55cSDimitry Andric               llvm::Error llvm_error = m_container->LoadUserSubcommand(
2183349cc55cSDimitry Andric                   m_cmd_name, command_obj_sp, m_overwrite);
2184349cc55cSDimitry Andric               if (llvm_error) {
2185349cc55cSDimitry Andric                 error_sp->Printf("error: unable to add selected command: '%s'",
2186349cc55cSDimitry Andric                                llvm::toString(std::move(llvm_error)).c_str());
2187349cc55cSDimitry Andric                 error_sp->Flush();
2188349cc55cSDimitry Andric               }
2189349cc55cSDimitry Andric             }
21900b57cec5SDimitry Andric           }
21910b57cec5SDimitry Andric         } else {
21920b57cec5SDimitry Andric           error_sp->Printf(
2193349cc55cSDimitry Andric               "error: unable to create function, didn't add python command\n");
21940b57cec5SDimitry Andric           error_sp->Flush();
21950b57cec5SDimitry Andric         }
21960b57cec5SDimitry Andric       } else {
2197349cc55cSDimitry Andric         error_sp->Printf("error: empty function, didn't add python command\n");
21980b57cec5SDimitry Andric         error_sp->Flush();
21990b57cec5SDimitry Andric       }
22000b57cec5SDimitry Andric     } else {
22010b57cec5SDimitry Andric       error_sp->Printf(
2202349cc55cSDimitry Andric           "error: script interpreter missing, didn't add python command\n");
22030b57cec5SDimitry Andric       error_sp->Flush();
22040b57cec5SDimitry Andric     }
22050b57cec5SDimitry Andric 
22060b57cec5SDimitry Andric     io_handler.SetIsDone(true);
22070b57cec5SDimitry Andric   }
22080b57cec5SDimitry Andric 
22095f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
22100b57cec5SDimitry Andric     if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
22110b57cec5SDimitry Andric       result.AppendError("only scripting language supported for scripted "
22120b57cec5SDimitry Andric                          "commands is currently Python");
22135f757f3fSDimitry Andric       return;
22140b57cec5SDimitry Andric     }
22150b57cec5SDimitry Andric 
2216349cc55cSDimitry Andric     if (command.GetArgumentCount() == 0) {
2217349cc55cSDimitry Andric       result.AppendError("'command script add' requires at least one argument");
22185f757f3fSDimitry Andric       return;
2219349cc55cSDimitry Andric     }
222081ad6265SDimitry Andric     // Store the options in case we get multi-line input, also figure out the
222181ad6265SDimitry Andric     // default if not user supplied:
222281ad6265SDimitry Andric     switch (m_options.m_overwrite_lazy) {
222381ad6265SDimitry Andric       case eLazyBoolCalculate:
222481ad6265SDimitry Andric         m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
222581ad6265SDimitry Andric         break;
222681ad6265SDimitry Andric       case eLazyBoolYes:
222781ad6265SDimitry Andric         m_overwrite = true;
222881ad6265SDimitry Andric         break;
222981ad6265SDimitry Andric       case eLazyBoolNo:
223081ad6265SDimitry Andric         m_overwrite = false;
223181ad6265SDimitry Andric     }
223281ad6265SDimitry Andric 
2233349cc55cSDimitry Andric     Status path_error;
2234349cc55cSDimitry Andric     m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
2235349cc55cSDimitry Andric         command, true, path_error);
2236349cc55cSDimitry Andric 
2237349cc55cSDimitry Andric     if (path_error.Fail()) {
2238349cc55cSDimitry Andric       result.AppendErrorWithFormat("error in command path: %s",
2239349cc55cSDimitry Andric                                    path_error.AsCString());
22405f757f3fSDimitry Andric       return;
22410b57cec5SDimitry Andric     }
22420b57cec5SDimitry Andric 
2243349cc55cSDimitry Andric     if (!m_container) {
2244349cc55cSDimitry Andric       // This is getting inserted into the root of the interpreter.
22455ffd83dbSDimitry Andric       m_cmd_name = std::string(command[0].ref());
2246349cc55cSDimitry Andric     } else {
2247349cc55cSDimitry Andric       size_t num_args = command.GetArgumentCount();
2248349cc55cSDimitry Andric       m_cmd_name = std::string(command[num_args - 1].ref());
2249349cc55cSDimitry Andric     }
2250349cc55cSDimitry Andric 
22510b57cec5SDimitry Andric     m_short_help.assign(m_options.m_short_help);
22520b57cec5SDimitry Andric     m_synchronicity = m_options.m_synchronicity;
225306c3fb27SDimitry Andric     m_completion_type = m_options.m_completion_type;
22540b57cec5SDimitry Andric 
2255349cc55cSDimitry Andric     // Handle the case where we prompt for the script code first:
2256349cc55cSDimitry Andric     if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
2257349cc55cSDimitry Andric       m_interpreter.GetPythonCommandsFromIOHandler("     ", // Prompt
2258480093f4SDimitry Andric                                                    *this);  // IOHandlerDelegate
22595f757f3fSDimitry Andric       return;
2260349cc55cSDimitry Andric     }
2261349cc55cSDimitry Andric 
2262349cc55cSDimitry Andric     CommandObjectSP new_cmd_sp;
2263349cc55cSDimitry Andric     if (m_options.m_class_name.empty()) {
2264349cc55cSDimitry Andric       new_cmd_sp.reset(new CommandObjectPythonFunction(
22650b57cec5SDimitry Andric           m_interpreter, m_cmd_name, m_options.m_funct_name,
226606c3fb27SDimitry Andric           m_options.m_short_help, m_synchronicity, m_completion_type));
22670b57cec5SDimitry Andric     } else {
22680b57cec5SDimitry Andric       ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
22690b57cec5SDimitry Andric       if (!interpreter) {
22700b57cec5SDimitry Andric         result.AppendError("cannot find ScriptInterpreter");
22715f757f3fSDimitry Andric         return;
22720b57cec5SDimitry Andric       }
22730b57cec5SDimitry Andric 
22740b57cec5SDimitry Andric       auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
22750b57cec5SDimitry Andric           m_options.m_class_name.c_str());
22760b57cec5SDimitry Andric       if (!cmd_obj_sp) {
227706c3fb27SDimitry Andric         result.AppendErrorWithFormatv("cannot create helper object for: "
227806c3fb27SDimitry Andric                                       "'{0}'", m_options.m_class_name);
22795f757f3fSDimitry Andric         return;
22800b57cec5SDimitry Andric       }
22810b57cec5SDimitry Andric 
2282*0fca6ea1SDimitry Andric       if (m_options.m_parsed_command) {
2283*0fca6ea1SDimitry Andric         new_cmd_sp = CommandObjectScriptingObjectParsed::Create(m_interpreter,
2284*0fca6ea1SDimitry Andric             m_cmd_name, cmd_obj_sp, m_synchronicity, result);
2285*0fca6ea1SDimitry Andric         if (!result.Succeeded())
2286*0fca6ea1SDimitry Andric           return;
2287*0fca6ea1SDimitry Andric       } else
2288*0fca6ea1SDimitry Andric         new_cmd_sp.reset(new CommandObjectScriptingObjectRaw(
228906c3fb27SDimitry Andric             m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity,
229006c3fb27SDimitry Andric             m_completion_type));
22910b57cec5SDimitry Andric     }
22920b57cec5SDimitry Andric 
2293349cc55cSDimitry Andric     // Assume we're going to succeed...
2294349cc55cSDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2295349cc55cSDimitry Andric     if (!m_container) {
2296349cc55cSDimitry Andric       Status add_error =
2297349cc55cSDimitry Andric           m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
2298349cc55cSDimitry Andric       if (add_error.Fail())
2299349cc55cSDimitry Andric         result.AppendErrorWithFormat("cannot add command: %s",
2300349cc55cSDimitry Andric                                      add_error.AsCString());
2301349cc55cSDimitry Andric     } else {
2302349cc55cSDimitry Andric       llvm::Error llvm_error =
2303349cc55cSDimitry Andric           m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
2304349cc55cSDimitry Andric       if (llvm_error)
2305*0fca6ea1SDimitry Andric         result.AppendErrorWithFormat(
2306*0fca6ea1SDimitry Andric             "cannot add command: %s",
2307349cc55cSDimitry Andric             llvm::toString(std::move(llvm_error)).c_str());
2308349cc55cSDimitry Andric     }
23090b57cec5SDimitry Andric   }
23100b57cec5SDimitry Andric 
23110b57cec5SDimitry Andric   CommandOptions m_options;
23120b57cec5SDimitry Andric   std::string m_cmd_name;
2313349cc55cSDimitry Andric   CommandObjectMultiword *m_container = nullptr;
23140b57cec5SDimitry Andric   std::string m_short_help;
231581ad6265SDimitry Andric   bool m_overwrite = false;
231681ad6265SDimitry Andric   ScriptedCommandSynchronicity m_synchronicity =
231781ad6265SDimitry Andric       eScriptedCommandSynchronicitySynchronous;
231806c3fb27SDimitry Andric   CompletionType m_completion_type = eNoCompletion;
23190b57cec5SDimitry Andric };
23200b57cec5SDimitry Andric 
23210b57cec5SDimitry Andric // CommandObjectCommandsScriptList
23220b57cec5SDimitry Andric 
23230b57cec5SDimitry Andric class CommandObjectCommandsScriptList : public CommandObjectParsed {
23240b57cec5SDimitry Andric public:
23250b57cec5SDimitry Andric   CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
23260b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "command script list",
2327349cc55cSDimitry Andric                             "List defined top-level scripted commands.",
2328349cc55cSDimitry Andric                             nullptr) {}
23290b57cec5SDimitry Andric 
23300b57cec5SDimitry Andric   ~CommandObjectCommandsScriptList() override = default;
23310b57cec5SDimitry Andric 
23325f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
23330b57cec5SDimitry Andric     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
23340b57cec5SDimitry Andric 
23350b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
23360b57cec5SDimitry Andric   }
23370b57cec5SDimitry Andric };
23380b57cec5SDimitry Andric 
23390b57cec5SDimitry Andric // CommandObjectCommandsScriptClear
23400b57cec5SDimitry Andric 
23410b57cec5SDimitry Andric class CommandObjectCommandsScriptClear : public CommandObjectParsed {
23420b57cec5SDimitry Andric public:
23430b57cec5SDimitry Andric   CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
23440b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "command script clear",
23450b57cec5SDimitry Andric                             "Delete all scripted commands.", nullptr) {}
23460b57cec5SDimitry Andric 
23470b57cec5SDimitry Andric   ~CommandObjectCommandsScriptClear() override = default;
23480b57cec5SDimitry Andric 
23490b57cec5SDimitry Andric protected:
23505f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
23510b57cec5SDimitry Andric     m_interpreter.RemoveAllUser();
23520b57cec5SDimitry Andric 
23530b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
23540b57cec5SDimitry Andric   }
23550b57cec5SDimitry Andric };
23560b57cec5SDimitry Andric 
23570b57cec5SDimitry Andric // CommandObjectCommandsScriptDelete
23580b57cec5SDimitry Andric 
23590b57cec5SDimitry Andric class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
23600b57cec5SDimitry Andric public:
23610b57cec5SDimitry Andric   CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
2362349cc55cSDimitry Andric       : CommandObjectParsed(
2363349cc55cSDimitry Andric             interpreter, "command script delete",
2364349cc55cSDimitry Andric             "Delete a scripted command by specifying the path to the command.",
2365349cc55cSDimitry Andric             nullptr) {
2366*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
23670b57cec5SDimitry Andric   }
23680b57cec5SDimitry Andric 
23690b57cec5SDimitry Andric   ~CommandObjectCommandsScriptDelete() override = default;
23700b57cec5SDimitry Andric 
23715ffd83dbSDimitry Andric   void
23725ffd83dbSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
23735ffd83dbSDimitry Andric                            OptionElementVector &opt_element_vector) override {
237406c3fb27SDimitry Andric     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
237506c3fb27SDimitry Andric         m_interpreter, request, opt_element_vector);
23765ffd83dbSDimitry Andric   }
23775ffd83dbSDimitry Andric 
23780b57cec5SDimitry Andric protected:
23795f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
23800b57cec5SDimitry Andric 
2381349cc55cSDimitry Andric     llvm::StringRef root_cmd = command[0].ref();
2382349cc55cSDimitry Andric     size_t num_args = command.GetArgumentCount();
2383349cc55cSDimitry Andric 
2384349cc55cSDimitry Andric     if (root_cmd.empty()) {
2385349cc55cSDimitry Andric       result.AppendErrorWithFormat("empty root command name");
23865f757f3fSDimitry Andric       return;
2387349cc55cSDimitry Andric     }
2388349cc55cSDimitry Andric     if (!m_interpreter.HasUserCommands() &&
2389349cc55cSDimitry Andric         !m_interpreter.HasUserMultiwordCommands()) {
2390349cc55cSDimitry Andric       result.AppendErrorWithFormat("can only delete user defined commands, "
2391349cc55cSDimitry Andric                                    "but no user defined commands found");
23925f757f3fSDimitry Andric       return;
23930b57cec5SDimitry Andric     }
23940b57cec5SDimitry Andric 
2395349cc55cSDimitry Andric     CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
2396349cc55cSDimitry Andric     if (!cmd_sp) {
2397349cc55cSDimitry Andric       result.AppendErrorWithFormat("command '%s' not found.",
2398349cc55cSDimitry Andric                                    command[0].c_str());
23995f757f3fSDimitry Andric       return;
2400349cc55cSDimitry Andric     }
2401349cc55cSDimitry Andric     if (!cmd_sp->IsUserCommand()) {
2402349cc55cSDimitry Andric       result.AppendErrorWithFormat("command '%s' is not a user command.",
2403349cc55cSDimitry Andric                                    command[0].c_str());
24045f757f3fSDimitry Andric       return;
2405349cc55cSDimitry Andric     }
2406349cc55cSDimitry Andric     if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
2407349cc55cSDimitry Andric       result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
2408349cc55cSDimitry Andric                                    "Delete with \"command container delete\"",
2409349cc55cSDimitry Andric                                    command[0].c_str());
24105f757f3fSDimitry Andric       return;
24110b57cec5SDimitry Andric     }
24120b57cec5SDimitry Andric 
2413349cc55cSDimitry Andric     if (command.GetArgumentCount() == 1) {
2414349cc55cSDimitry Andric       m_interpreter.RemoveUser(root_cmd);
2415349cc55cSDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
24165f757f3fSDimitry Andric       return;
2417349cc55cSDimitry Andric     }
2418349cc55cSDimitry Andric     // We're deleting a command from a multiword command.  Verify the command
2419349cc55cSDimitry Andric     // path:
2420349cc55cSDimitry Andric     Status error;
2421349cc55cSDimitry Andric     CommandObjectMultiword *container =
2422349cc55cSDimitry Andric         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2423349cc55cSDimitry Andric                                                            error);
2424349cc55cSDimitry Andric     if (error.Fail()) {
2425349cc55cSDimitry Andric       result.AppendErrorWithFormat("could not resolve command path: %s",
2426349cc55cSDimitry Andric                                    error.AsCString());
24275f757f3fSDimitry Andric       return;
2428349cc55cSDimitry Andric     }
2429349cc55cSDimitry Andric     if (!container) {
2430349cc55cSDimitry Andric       // This means that command only had a leaf command, so the container is
2431349cc55cSDimitry Andric       // the root.  That should have been handled above.
2432349cc55cSDimitry Andric       result.AppendErrorWithFormat("could not find a container for '%s'",
2433349cc55cSDimitry Andric                                    command[0].c_str());
24345f757f3fSDimitry Andric       return;
2435349cc55cSDimitry Andric     }
2436349cc55cSDimitry Andric     const char *leaf_cmd = command[num_args - 1].c_str();
2437*0fca6ea1SDimitry Andric     llvm::Error llvm_error =
2438*0fca6ea1SDimitry Andric         container->RemoveUserSubcommand(leaf_cmd,
2439349cc55cSDimitry Andric                                         /* multiword not okay */ false);
2440349cc55cSDimitry Andric     if (llvm_error) {
2441*0fca6ea1SDimitry Andric       result.AppendErrorWithFormat(
2442*0fca6ea1SDimitry Andric           "could not delete command '%s': %s", leaf_cmd,
2443349cc55cSDimitry Andric           llvm::toString(std::move(llvm_error)).c_str());
24445f757f3fSDimitry Andric       return;
2445349cc55cSDimitry Andric     }
2446349cc55cSDimitry Andric 
2447349cc55cSDimitry Andric     Stream &out_stream = result.GetOutputStream();
2448349cc55cSDimitry Andric 
2449349cc55cSDimitry Andric     out_stream << "Deleted command:";
2450349cc55cSDimitry Andric     for (size_t idx = 0; idx < num_args; idx++) {
2451349cc55cSDimitry Andric       out_stream << ' ';
2452349cc55cSDimitry Andric       out_stream << command[idx].c_str();
2453349cc55cSDimitry Andric     }
2454349cc55cSDimitry Andric     out_stream << '\n';
24550b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
24560b57cec5SDimitry Andric   }
24570b57cec5SDimitry Andric };
24580b57cec5SDimitry Andric 
24590b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordCommandsScript
24600b57cec5SDimitry Andric 
24610b57cec5SDimitry Andric // CommandObjectMultiwordCommandsScript
24620b57cec5SDimitry Andric 
24630b57cec5SDimitry Andric class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
24640b57cec5SDimitry Andric public:
24650b57cec5SDimitry Andric   CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
24660b57cec5SDimitry Andric       : CommandObjectMultiword(
2467480093f4SDimitry Andric             interpreter, "command script",
2468480093f4SDimitry Andric             "Commands for managing custom "
24690b57cec5SDimitry Andric             "commands implemented by "
24700b57cec5SDimitry Andric             "interpreter scripts.",
24710b57cec5SDimitry Andric             "command script <subcommand> [<subcommand-options>]") {
24720b57cec5SDimitry Andric     LoadSubCommand("add", CommandObjectSP(
24730b57cec5SDimitry Andric                               new CommandObjectCommandsScriptAdd(interpreter)));
24740b57cec5SDimitry Andric     LoadSubCommand(
24750b57cec5SDimitry Andric         "delete",
24760b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
24770b57cec5SDimitry Andric     LoadSubCommand(
24780b57cec5SDimitry Andric         "clear",
24790b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
24800b57cec5SDimitry Andric     LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
24810b57cec5SDimitry Andric                                interpreter)));
24820b57cec5SDimitry Andric     LoadSubCommand(
24830b57cec5SDimitry Andric         "import",
24840b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
24850b57cec5SDimitry Andric   }
24860b57cec5SDimitry Andric 
24870b57cec5SDimitry Andric   ~CommandObjectMultiwordCommandsScript() override = default;
24880b57cec5SDimitry Andric };
24890b57cec5SDimitry Andric 
2490349cc55cSDimitry Andric #pragma mark CommandObjectCommandContainer
2491349cc55cSDimitry Andric #define LLDB_OPTIONS_container_add
2492349cc55cSDimitry Andric #include "CommandOptions.inc"
2493349cc55cSDimitry Andric 
2494349cc55cSDimitry Andric class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
2495349cc55cSDimitry Andric public:
2496349cc55cSDimitry Andric   CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter)
2497349cc55cSDimitry Andric       : CommandObjectParsed(
2498349cc55cSDimitry Andric             interpreter, "command container add",
2499349cc55cSDimitry Andric             "Add a container command to lldb.  Adding to built-"
2500349cc55cSDimitry Andric             "in container commands is not allowed.",
2501349cc55cSDimitry Andric             "command container add [[path1]...] container-name") {
2502*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2503349cc55cSDimitry Andric   }
2504349cc55cSDimitry Andric 
2505349cc55cSDimitry Andric   ~CommandObjectCommandsContainerAdd() override = default;
2506349cc55cSDimitry Andric 
2507349cc55cSDimitry Andric   Options *GetOptions() override { return &m_options; }
2508349cc55cSDimitry Andric 
2509349cc55cSDimitry Andric   void
2510349cc55cSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
2511349cc55cSDimitry Andric                            OptionElementVector &opt_element_vector) override {
251206c3fb27SDimitry Andric     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
251306c3fb27SDimitry Andric         m_interpreter, request, opt_element_vector);
2514349cc55cSDimitry Andric   }
2515349cc55cSDimitry Andric 
2516349cc55cSDimitry Andric protected:
2517349cc55cSDimitry Andric   class CommandOptions : public Options {
2518349cc55cSDimitry Andric   public:
251981ad6265SDimitry Andric     CommandOptions() = default;
2520349cc55cSDimitry Andric 
2521349cc55cSDimitry Andric     ~CommandOptions() override = default;
2522349cc55cSDimitry Andric 
2523349cc55cSDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2524349cc55cSDimitry Andric                           ExecutionContext *execution_context) override {
2525349cc55cSDimitry Andric       Status error;
2526349cc55cSDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
2527349cc55cSDimitry Andric 
2528349cc55cSDimitry Andric       switch (short_option) {
2529349cc55cSDimitry Andric       case 'h':
2530349cc55cSDimitry Andric         if (!option_arg.empty())
2531349cc55cSDimitry Andric           m_short_help = std::string(option_arg);
2532349cc55cSDimitry Andric         break;
2533349cc55cSDimitry Andric       case 'o':
2534349cc55cSDimitry Andric         m_overwrite = true;
2535349cc55cSDimitry Andric         break;
2536349cc55cSDimitry Andric       case 'H':
2537349cc55cSDimitry Andric         if (!option_arg.empty())
2538349cc55cSDimitry Andric           m_long_help = std::string(option_arg);
2539349cc55cSDimitry Andric         break;
2540349cc55cSDimitry Andric       default:
2541349cc55cSDimitry Andric         llvm_unreachable("Unimplemented option");
2542349cc55cSDimitry Andric       }
2543349cc55cSDimitry Andric 
2544349cc55cSDimitry Andric       return error;
2545349cc55cSDimitry Andric     }
2546349cc55cSDimitry Andric 
2547349cc55cSDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
2548349cc55cSDimitry Andric       m_short_help.clear();
2549349cc55cSDimitry Andric       m_long_help.clear();
2550349cc55cSDimitry Andric       m_overwrite = false;
2551349cc55cSDimitry Andric     }
2552349cc55cSDimitry Andric 
2553349cc55cSDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2554bdd1243dSDimitry Andric       return llvm::ArrayRef(g_container_add_options);
2555349cc55cSDimitry Andric     }
2556349cc55cSDimitry Andric 
2557349cc55cSDimitry Andric     // Instance variables to hold the values for command options.
2558349cc55cSDimitry Andric 
2559349cc55cSDimitry Andric     std::string m_short_help;
2560349cc55cSDimitry Andric     std::string m_long_help;
2561349cc55cSDimitry Andric     bool m_overwrite = false;
2562349cc55cSDimitry Andric   };
25635f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
2564349cc55cSDimitry Andric     size_t num_args = command.GetArgumentCount();
2565349cc55cSDimitry Andric 
2566349cc55cSDimitry Andric     if (num_args == 0) {
2567349cc55cSDimitry Andric       result.AppendError("no command was specified");
25685f757f3fSDimitry Andric       return;
2569349cc55cSDimitry Andric     }
2570349cc55cSDimitry Andric 
2571349cc55cSDimitry Andric     if (num_args == 1) {
2572349cc55cSDimitry Andric       // We're adding this as a root command, so use the interpreter.
2573349cc55cSDimitry Andric       const char *cmd_name = command.GetArgumentAtIndex(0);
2574349cc55cSDimitry Andric       auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
2575349cc55cSDimitry Andric           GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
2576349cc55cSDimitry Andric           m_options.m_long_help.c_str()));
2577349cc55cSDimitry Andric       cmd_sp->GetAsMultiwordCommand()->SetRemovable(true);
2578349cc55cSDimitry Andric       Status add_error = GetCommandInterpreter().AddUserCommand(
2579349cc55cSDimitry Andric           cmd_name, cmd_sp, m_options.m_overwrite);
2580349cc55cSDimitry Andric       if (add_error.Fail()) {
2581349cc55cSDimitry Andric         result.AppendErrorWithFormat("error adding command: %s",
2582349cc55cSDimitry Andric                                      add_error.AsCString());
25835f757f3fSDimitry Andric         return;
2584349cc55cSDimitry Andric       }
2585349cc55cSDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
25865f757f3fSDimitry Andric       return;
2587349cc55cSDimitry Andric     }
2588349cc55cSDimitry Andric 
2589349cc55cSDimitry Andric     // We're adding this to a subcommand, first find the subcommand:
2590349cc55cSDimitry Andric     Status path_error;
2591349cc55cSDimitry Andric     CommandObjectMultiword *add_to_me =
2592349cc55cSDimitry Andric         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2593349cc55cSDimitry Andric                                                            path_error);
2594349cc55cSDimitry Andric 
2595349cc55cSDimitry Andric     if (!add_to_me) {
2596349cc55cSDimitry Andric       result.AppendErrorWithFormat("error adding command: %s",
2597349cc55cSDimitry Andric                                    path_error.AsCString());
25985f757f3fSDimitry Andric       return;
2599349cc55cSDimitry Andric     }
2600349cc55cSDimitry Andric 
2601349cc55cSDimitry Andric     const char *cmd_name = command.GetArgumentAtIndex(num_args - 1);
2602349cc55cSDimitry Andric     auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
2603349cc55cSDimitry Andric         GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
2604349cc55cSDimitry Andric         m_options.m_long_help.c_str()));
2605349cc55cSDimitry Andric     llvm::Error llvm_error =
2606349cc55cSDimitry Andric         add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite);
2607349cc55cSDimitry Andric     if (llvm_error) {
2608349cc55cSDimitry Andric       result.AppendErrorWithFormat("error adding subcommand: %s",
2609349cc55cSDimitry Andric                                    llvm::toString(std::move(llvm_error)).c_str());
26105f757f3fSDimitry Andric       return;
2611349cc55cSDimitry Andric     }
2612349cc55cSDimitry Andric 
2613349cc55cSDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2614349cc55cSDimitry Andric   }
2615349cc55cSDimitry Andric 
2616349cc55cSDimitry Andric private:
2617349cc55cSDimitry Andric   CommandOptions m_options;
2618349cc55cSDimitry Andric };
2619349cc55cSDimitry Andric 
2620349cc55cSDimitry Andric #define LLDB_OPTIONS_multiword_delete
2621349cc55cSDimitry Andric #include "CommandOptions.inc"
2622349cc55cSDimitry Andric class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
2623349cc55cSDimitry Andric public:
2624349cc55cSDimitry Andric   CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
2625349cc55cSDimitry Andric       : CommandObjectParsed(
2626349cc55cSDimitry Andric             interpreter, "command container delete",
2627349cc55cSDimitry Andric             "Delete a container command previously added to "
2628349cc55cSDimitry Andric             "lldb.",
2629349cc55cSDimitry Andric             "command container delete [[path1] ...] container-cmd") {
2630*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2631349cc55cSDimitry Andric   }
2632349cc55cSDimitry Andric 
2633349cc55cSDimitry Andric   ~CommandObjectCommandsContainerDelete() override = default;
2634349cc55cSDimitry Andric 
2635349cc55cSDimitry Andric   void
2636349cc55cSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
2637349cc55cSDimitry Andric                            OptionElementVector &opt_element_vector) override {
263806c3fb27SDimitry Andric     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
263906c3fb27SDimitry Andric         m_interpreter, request, opt_element_vector);
2640349cc55cSDimitry Andric   }
2641349cc55cSDimitry Andric 
2642349cc55cSDimitry Andric protected:
26435f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
2644349cc55cSDimitry Andric     size_t num_args = command.GetArgumentCount();
2645349cc55cSDimitry Andric 
2646349cc55cSDimitry Andric     if (num_args == 0) {
2647349cc55cSDimitry Andric       result.AppendError("No command was specified.");
26485f757f3fSDimitry Andric       return;
2649349cc55cSDimitry Andric     }
2650349cc55cSDimitry Andric 
2651349cc55cSDimitry Andric     if (num_args == 1) {
2652349cc55cSDimitry Andric       // We're removing a root command, so we need to delete it from the
2653349cc55cSDimitry Andric       // interpreter.
2654349cc55cSDimitry Andric       const char *cmd_name = command.GetArgumentAtIndex(0);
2655349cc55cSDimitry Andric       // Let's do a little more work here so we can do better error reporting.
2656349cc55cSDimitry Andric       CommandInterpreter &interp = GetCommandInterpreter();
2657349cc55cSDimitry Andric       CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2658349cc55cSDimitry Andric       if (!cmd_sp) {
2659349cc55cSDimitry Andric         result.AppendErrorWithFormat("container command %s doesn't exist.",
2660349cc55cSDimitry Andric                                      cmd_name);
26615f757f3fSDimitry Andric         return;
2662349cc55cSDimitry Andric       }
2663349cc55cSDimitry Andric       if (!cmd_sp->IsUserCommand()) {
2664349cc55cSDimitry Andric         result.AppendErrorWithFormat(
2665349cc55cSDimitry Andric             "container command %s is not a user command", cmd_name);
26665f757f3fSDimitry Andric         return;
2667349cc55cSDimitry Andric       }
2668349cc55cSDimitry Andric       if (!cmd_sp->GetAsMultiwordCommand()) {
2669349cc55cSDimitry Andric         result.AppendErrorWithFormat("command %s is not a container command",
2670349cc55cSDimitry Andric                                      cmd_name);
26715f757f3fSDimitry Andric         return;
2672349cc55cSDimitry Andric       }
2673349cc55cSDimitry Andric 
2674349cc55cSDimitry Andric       bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2675349cc55cSDimitry Andric       if (!did_remove) {
2676349cc55cSDimitry Andric         result.AppendErrorWithFormat("error removing command %s.", cmd_name);
26775f757f3fSDimitry Andric         return;
2678349cc55cSDimitry Andric       }
2679349cc55cSDimitry Andric 
2680349cc55cSDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
26815f757f3fSDimitry Andric       return;
2682349cc55cSDimitry Andric     }
2683349cc55cSDimitry Andric 
2684349cc55cSDimitry Andric     // We're removing a subcommand, first find the subcommand's owner:
2685349cc55cSDimitry Andric     Status path_error;
2686349cc55cSDimitry Andric     CommandObjectMultiword *container =
2687349cc55cSDimitry Andric         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2688349cc55cSDimitry Andric                                                            path_error);
2689349cc55cSDimitry Andric 
2690349cc55cSDimitry Andric     if (!container) {
2691349cc55cSDimitry Andric       result.AppendErrorWithFormat("error removing container command: %s",
2692349cc55cSDimitry Andric                                    path_error.AsCString());
26935f757f3fSDimitry Andric       return;
2694349cc55cSDimitry Andric     }
2695349cc55cSDimitry Andric     const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2696349cc55cSDimitry Andric     llvm::Error llvm_error =
2697349cc55cSDimitry Andric         container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2698349cc55cSDimitry Andric     if (llvm_error) {
2699349cc55cSDimitry Andric       result.AppendErrorWithFormat("error removing container command: %s",
2700349cc55cSDimitry Andric                                    llvm::toString(std::move(llvm_error)).c_str());
27015f757f3fSDimitry Andric       return;
2702349cc55cSDimitry Andric     }
2703349cc55cSDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2704349cc55cSDimitry Andric   }
2705349cc55cSDimitry Andric };
2706349cc55cSDimitry Andric 
2707349cc55cSDimitry Andric class CommandObjectCommandContainer : public CommandObjectMultiword {
2708349cc55cSDimitry Andric public:
2709349cc55cSDimitry Andric   CommandObjectCommandContainer(CommandInterpreter &interpreter)
2710349cc55cSDimitry Andric       : CommandObjectMultiword(
2711349cc55cSDimitry Andric             interpreter, "command container",
2712349cc55cSDimitry Andric             "Commands for adding container commands to lldb.  "
2713349cc55cSDimitry Andric             "Container commands are containers for other commands.  You can "
271481ad6265SDimitry Andric             "add nested container commands by specifying a command path, "
2715349cc55cSDimitry Andric             "but you can't add commands into the built-in command hierarchy.",
2716349cc55cSDimitry Andric             "command container <subcommand> [<subcommand-options>]") {
2717349cc55cSDimitry Andric     LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2718349cc55cSDimitry Andric                               interpreter)));
2719349cc55cSDimitry Andric     LoadSubCommand(
2720349cc55cSDimitry Andric         "delete",
2721349cc55cSDimitry Andric         CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2722349cc55cSDimitry Andric   }
2723349cc55cSDimitry Andric 
2724349cc55cSDimitry Andric   ~CommandObjectCommandContainer() override = default;
2725349cc55cSDimitry Andric };
2726349cc55cSDimitry Andric 
27270b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordCommands
27280b57cec5SDimitry Andric 
27290b57cec5SDimitry Andric // CommandObjectMultiwordCommands
27300b57cec5SDimitry Andric 
27310b57cec5SDimitry Andric CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
27320b57cec5SDimitry Andric     CommandInterpreter &interpreter)
27330b57cec5SDimitry Andric     : CommandObjectMultiword(interpreter, "command",
27340b57cec5SDimitry Andric                              "Commands for managing custom LLDB commands.",
27350b57cec5SDimitry Andric                              "command <subcommand> [<subcommand-options>]") {
27360b57cec5SDimitry Andric   LoadSubCommand("source",
27370b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
27380b57cec5SDimitry Andric   LoadSubCommand("alias",
27390b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
27400b57cec5SDimitry Andric   LoadSubCommand("unalias", CommandObjectSP(
27410b57cec5SDimitry Andric                                 new CommandObjectCommandsUnalias(interpreter)));
27420b57cec5SDimitry Andric   LoadSubCommand("delete",
27430b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2744349cc55cSDimitry Andric   LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2745349cc55cSDimitry Andric                                   interpreter)));
27460b57cec5SDimitry Andric   LoadSubCommand(
27470b57cec5SDimitry Andric       "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
27480b57cec5SDimitry Andric   LoadSubCommand(
27490b57cec5SDimitry Andric       "script",
27500b57cec5SDimitry Andric       CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
27510b57cec5SDimitry Andric }
27520b57cec5SDimitry Andric 
27530b57cec5SDimitry Andric CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2754