1dda28197Spatrick //===-- CommandObjectCommands.cpp -----------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "CommandObjectCommands.h"
10061da546Spatrick #include "CommandObjectHelp.h"
11be691f3bSpatrick #include "CommandObjectRegexCommand.h"
12061da546Spatrick #include "lldb/Core/Debugger.h"
13061da546Spatrick #include "lldb/Core/IOHandler.h"
14061da546Spatrick #include "lldb/Interpreter/CommandHistory.h"
15061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
16*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
18061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
19061da546Spatrick #include "lldb/Interpreter/OptionValueBoolean.h"
20061da546Spatrick #include "lldb/Interpreter/OptionValueString.h"
21061da546Spatrick #include "lldb/Interpreter/OptionValueUInt64.h"
22061da546Spatrick #include "lldb/Interpreter/Options.h"
23061da546Spatrick #include "lldb/Interpreter/ScriptInterpreter.h"
24061da546Spatrick #include "lldb/Utility/Args.h"
25061da546Spatrick #include "lldb/Utility/StringList.h"
26be691f3bSpatrick #include "llvm/ADT/StringRef.h"
27*f6aab3d8Srobert #include <optional>
28061da546Spatrick
29061da546Spatrick using namespace lldb;
30061da546Spatrick using namespace lldb_private;
31061da546Spatrick
32061da546Spatrick // CommandObjectCommandsSource
33061da546Spatrick
34061da546Spatrick #define LLDB_OPTIONS_source
35061da546Spatrick #include "CommandOptions.inc"
36061da546Spatrick
37061da546Spatrick class CommandObjectCommandsSource : public CommandObjectParsed {
38061da546Spatrick public:
CommandObjectCommandsSource(CommandInterpreter & interpreter)39061da546Spatrick CommandObjectCommandsSource(CommandInterpreter &interpreter)
40061da546Spatrick : CommandObjectParsed(
41061da546Spatrick interpreter, "command source",
42061da546Spatrick "Read and execute LLDB commands from the file <filename>.",
43*f6aab3d8Srobert nullptr) {
44061da546Spatrick CommandArgumentEntry arg;
45061da546Spatrick CommandArgumentData file_arg;
46061da546Spatrick
47061da546Spatrick // Define the first (and only) variant of this arg.
48061da546Spatrick file_arg.arg_type = eArgTypeFilename;
49061da546Spatrick file_arg.arg_repetition = eArgRepeatPlain;
50061da546Spatrick
51061da546Spatrick // There is only one variant this argument could be; put it into the
52061da546Spatrick // argument entry.
53061da546Spatrick arg.push_back(file_arg);
54061da546Spatrick
55061da546Spatrick // Push the data for the first argument into the m_arguments vector.
56061da546Spatrick m_arguments.push_back(arg);
57061da546Spatrick }
58061da546Spatrick
59061da546Spatrick ~CommandObjectCommandsSource() override = default;
60061da546Spatrick
GetRepeatCommand(Args & current_command_args,uint32_t index)61*f6aab3d8Srobert std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
62061da546Spatrick uint32_t index) override {
63*f6aab3d8Srobert return std::string("");
64061da546Spatrick }
65061da546Spatrick
66061da546Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)67061da546Spatrick HandleArgumentCompletion(CompletionRequest &request,
68061da546Spatrick OptionElementVector &opt_element_vector) override {
69061da546Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
70061da546Spatrick GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
71061da546Spatrick request, nullptr);
72061da546Spatrick }
73061da546Spatrick
GetOptions()74061da546Spatrick Options *GetOptions() override { return &m_options; }
75061da546Spatrick
76061da546Spatrick protected:
77061da546Spatrick class CommandOptions : public Options {
78061da546Spatrick public:
CommandOptions()79061da546Spatrick CommandOptions()
80*f6aab3d8Srobert : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
81*f6aab3d8Srobert m_cmd_relative_to_command_file(false) {}
82061da546Spatrick
83061da546Spatrick ~CommandOptions() override = default;
84061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)85061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
86061da546Spatrick ExecutionContext *execution_context) override {
87061da546Spatrick Status error;
88061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
89061da546Spatrick
90061da546Spatrick switch (short_option) {
91061da546Spatrick case 'e':
92061da546Spatrick error = m_stop_on_error.SetValueFromString(option_arg);
93061da546Spatrick break;
94061da546Spatrick
95061da546Spatrick case 'c':
96061da546Spatrick error = m_stop_on_continue.SetValueFromString(option_arg);
97061da546Spatrick break;
98061da546Spatrick
99*f6aab3d8Srobert case 'C':
100*f6aab3d8Srobert m_cmd_relative_to_command_file = true;
101*f6aab3d8Srobert break;
102*f6aab3d8Srobert
103061da546Spatrick case 's':
104061da546Spatrick error = m_silent_run.SetValueFromString(option_arg);
105061da546Spatrick break;
106061da546Spatrick
107061da546Spatrick default:
108061da546Spatrick llvm_unreachable("Unimplemented option");
109061da546Spatrick }
110061da546Spatrick
111061da546Spatrick return error;
112061da546Spatrick }
113061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)114061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
115061da546Spatrick m_stop_on_error.Clear();
116061da546Spatrick m_silent_run.Clear();
117061da546Spatrick m_stop_on_continue.Clear();
118*f6aab3d8Srobert m_cmd_relative_to_command_file.Clear();
119061da546Spatrick }
120061da546Spatrick
GetDefinitions()121061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
122*f6aab3d8Srobert return llvm::ArrayRef(g_source_options);
123061da546Spatrick }
124061da546Spatrick
125061da546Spatrick // Instance variables to hold the values for command options.
126061da546Spatrick
127061da546Spatrick OptionValueBoolean m_stop_on_error;
128061da546Spatrick OptionValueBoolean m_silent_run;
129061da546Spatrick OptionValueBoolean m_stop_on_continue;
130*f6aab3d8Srobert OptionValueBoolean m_cmd_relative_to_command_file;
131061da546Spatrick };
132061da546Spatrick
DoExecute(Args & command,CommandReturnObject & result)133061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
134061da546Spatrick if (command.GetArgumentCount() != 1) {
135061da546Spatrick result.AppendErrorWithFormat(
136061da546Spatrick "'%s' takes exactly one executable filename argument.\n",
137061da546Spatrick GetCommandName().str().c_str());
138061da546Spatrick return false;
139061da546Spatrick }
140061da546Spatrick
141*f6aab3d8Srobert FileSpec source_dir = {};
142*f6aab3d8Srobert if (m_options.m_cmd_relative_to_command_file) {
143*f6aab3d8Srobert source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
144*f6aab3d8Srobert if (!source_dir) {
145*f6aab3d8Srobert result.AppendError("command source -C can only be specified "
146*f6aab3d8Srobert "from a command file");
147*f6aab3d8Srobert result.SetStatus(eReturnStatusFailed);
148*f6aab3d8Srobert return false;
149*f6aab3d8Srobert }
150*f6aab3d8Srobert }
151*f6aab3d8Srobert
152061da546Spatrick FileSpec cmd_file(command[0].ref());
153*f6aab3d8Srobert if (source_dir) {
154*f6aab3d8Srobert // Prepend the source_dir to the cmd_file path:
155*f6aab3d8Srobert if (!cmd_file.IsRelative()) {
156*f6aab3d8Srobert result.AppendError("command source -C can only be used "
157*f6aab3d8Srobert "with a relative path.");
158*f6aab3d8Srobert result.SetStatus(eReturnStatusFailed);
159*f6aab3d8Srobert return false;
160*f6aab3d8Srobert }
161*f6aab3d8Srobert cmd_file.MakeAbsolute(source_dir);
162*f6aab3d8Srobert }
163*f6aab3d8Srobert
164061da546Spatrick FileSystem::Instance().Resolve(cmd_file);
165061da546Spatrick
166be691f3bSpatrick CommandInterpreterRunOptions options;
167061da546Spatrick // If any options were set, then use them
168061da546Spatrick if (m_options.m_stop_on_error.OptionWasSet() ||
169061da546Spatrick m_options.m_silent_run.OptionWasSet() ||
170061da546Spatrick m_options.m_stop_on_continue.OptionWasSet()) {
171061da546Spatrick if (m_options.m_stop_on_continue.OptionWasSet())
172061da546Spatrick options.SetStopOnContinue(
173061da546Spatrick m_options.m_stop_on_continue.GetCurrentValue());
174061da546Spatrick
175061da546Spatrick if (m_options.m_stop_on_error.OptionWasSet())
176061da546Spatrick options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
177061da546Spatrick
178061da546Spatrick // Individual silent setting is override for global command echo settings.
179061da546Spatrick if (m_options.m_silent_run.GetCurrentValue()) {
180061da546Spatrick options.SetSilent(true);
181061da546Spatrick } else {
182061da546Spatrick options.SetPrintResults(true);
183061da546Spatrick options.SetPrintErrors(true);
184061da546Spatrick options.SetEchoCommands(m_interpreter.GetEchoCommands());
185061da546Spatrick options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
186061da546Spatrick }
187061da546Spatrick }
188be691f3bSpatrick
189be691f3bSpatrick m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
190061da546Spatrick return result.Succeeded();
191061da546Spatrick }
192061da546Spatrick
193061da546Spatrick CommandOptions m_options;
194061da546Spatrick };
195061da546Spatrick
196061da546Spatrick #pragma mark CommandObjectCommandsAlias
197061da546Spatrick // CommandObjectCommandsAlias
198061da546Spatrick
199061da546Spatrick #define LLDB_OPTIONS_alias
200061da546Spatrick #include "CommandOptions.inc"
201061da546Spatrick
202061da546Spatrick static const char *g_python_command_instructions =
203061da546Spatrick "Enter your Python command(s). Type 'DONE' to end.\n"
204061da546Spatrick "You must define a Python function with this signature:\n"
205*f6aab3d8Srobert "def my_command_impl(debugger, args, exe_ctx, result, internal_dict):\n";
206061da546Spatrick
207061da546Spatrick class CommandObjectCommandsAlias : public CommandObjectRaw {
208061da546Spatrick protected:
209061da546Spatrick class CommandOptions : public OptionGroup {
210061da546Spatrick public:
211*f6aab3d8Srobert CommandOptions() = default;
212061da546Spatrick
213061da546Spatrick ~CommandOptions() override = default;
214061da546Spatrick
GetDefinitions()215061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
216*f6aab3d8Srobert return llvm::ArrayRef(g_alias_options);
217061da546Spatrick }
218061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)219061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
220061da546Spatrick ExecutionContext *execution_context) override {
221061da546Spatrick Status error;
222061da546Spatrick
223061da546Spatrick const int short_option = GetDefinitions()[option_idx].short_option;
224061da546Spatrick std::string option_str(option_value);
225061da546Spatrick
226061da546Spatrick switch (short_option) {
227061da546Spatrick case 'h':
228061da546Spatrick m_help.SetCurrentValue(option_str);
229061da546Spatrick m_help.SetOptionWasSet();
230061da546Spatrick break;
231061da546Spatrick
232061da546Spatrick case 'H':
233061da546Spatrick m_long_help.SetCurrentValue(option_str);
234061da546Spatrick m_long_help.SetOptionWasSet();
235061da546Spatrick break;
236061da546Spatrick
237061da546Spatrick default:
238061da546Spatrick llvm_unreachable("Unimplemented option");
239061da546Spatrick }
240061da546Spatrick
241061da546Spatrick return error;
242061da546Spatrick }
243061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)244061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
245061da546Spatrick m_help.Clear();
246061da546Spatrick m_long_help.Clear();
247061da546Spatrick }
248061da546Spatrick
249061da546Spatrick OptionValueString m_help;
250061da546Spatrick OptionValueString m_long_help;
251061da546Spatrick };
252061da546Spatrick
253061da546Spatrick OptionGroupOptions m_option_group;
254061da546Spatrick CommandOptions m_command_options;
255061da546Spatrick
256061da546Spatrick public:
GetOptions()257061da546Spatrick Options *GetOptions() override { return &m_option_group; }
258061da546Spatrick
CommandObjectCommandsAlias(CommandInterpreter & interpreter)259061da546Spatrick CommandObjectCommandsAlias(CommandInterpreter &interpreter)
260061da546Spatrick : CommandObjectRaw(
261061da546Spatrick interpreter, "command alias",
262*f6aab3d8Srobert "Define a custom command in terms of an existing command.") {
263061da546Spatrick m_option_group.Append(&m_command_options);
264061da546Spatrick m_option_group.Finalize();
265061da546Spatrick
266061da546Spatrick SetHelpLong(
267061da546Spatrick "'alias' allows the user to create a short-cut or abbreviation for long \
268061da546Spatrick commands, multi-word commands, and commands that take particular options. \
269061da546Spatrick Below are some simple examples of how one might use the 'alias' command:"
270061da546Spatrick R"(
271061da546Spatrick
272061da546Spatrick (lldb) command alias sc script
273061da546Spatrick
274061da546Spatrick Creates the abbreviation 'sc' for the 'script' command.
275061da546Spatrick
276061da546Spatrick (lldb) command alias bp breakpoint
277061da546Spatrick
278061da546Spatrick )"
279061da546Spatrick " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \
280061da546Spatrick breakpoint commands are two-word commands, the user would still need to \
281061da546Spatrick enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
282061da546Spatrick R"(
283061da546Spatrick
284061da546Spatrick (lldb) command alias bpl breakpoint list
285061da546Spatrick
286061da546Spatrick Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
287061da546Spatrick
288061da546Spatrick )"
289061da546Spatrick "An alias can include some options for the command, with the values either \
290061da546Spatrick filled in at the time the alias is created, or specified as positional \
291061da546Spatrick arguments, to be filled in when the alias is invoked. The following example \
292061da546Spatrick shows how to create aliases with options:"
293061da546Spatrick R"(
294061da546Spatrick
295061da546Spatrick (lldb) command alias bfl breakpoint set -f %1 -l %2
296061da546Spatrick
297061da546Spatrick )"
298061da546Spatrick " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
299061da546Spatrick options already part of the alias. So if the user wants to set a breakpoint \
300061da546Spatrick by file and line without explicitly having to use the -f and -l options, the \
301061da546Spatrick user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \
302061da546Spatrick for the actual arguments that will be passed when the alias command is used. \
303061da546Spatrick The number in the placeholder refers to the position/order the actual value \
304061da546Spatrick occupies when the alias is used. All the occurrences of '%1' in the alias \
305061da546Spatrick will be replaced with the first argument, all the occurrences of '%2' in the \
306061da546Spatrick alias will be replaced with the second argument, and so on. This also allows \
307061da546Spatrick actual arguments to be used multiple times within an alias (see 'process \
308061da546Spatrick launch' example below)."
309061da546Spatrick R"(
310061da546Spatrick
311061da546Spatrick )"
312061da546Spatrick "Note: the positional arguments must substitute as whole words in the resultant \
313061da546Spatrick command, so you can't at present do something like this to append the file extension \
314061da546Spatrick \".cpp\":"
315061da546Spatrick R"(
316061da546Spatrick
317061da546Spatrick (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
318061da546Spatrick
319061da546Spatrick )"
320061da546Spatrick "For more complex aliasing, use the \"command regex\" command instead. In the \
321061da546Spatrick 'bfl' case above, the actual file value will be filled in with the first argument \
322061da546Spatrick following 'bfl' and the actual line number value will be filled in with the second \
323061da546Spatrick argument. The user would use this alias as follows:"
324061da546Spatrick R"(
325061da546Spatrick
326061da546Spatrick (lldb) command alias bfl breakpoint set -f %1 -l %2
327061da546Spatrick (lldb) bfl my-file.c 137
328061da546Spatrick
329061da546Spatrick This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
330061da546Spatrick
331061da546Spatrick Another example:
332061da546Spatrick
333061da546Spatrick (lldb) command alias pltty process launch -s -o %1 -e %1
334061da546Spatrick (lldb) pltty /dev/tty0
335061da546Spatrick
336061da546Spatrick Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
337061da546Spatrick
338061da546Spatrick )"
339061da546Spatrick "If the user always wanted to pass the same value to a particular option, the \
340061da546Spatrick alias could be defined with that value directly in the alias as a constant, \
341061da546Spatrick rather than using a positional placeholder:"
342061da546Spatrick R"(
343061da546Spatrick
344061da546Spatrick (lldb) command alias bl3 breakpoint set -f %1 -l 3
345061da546Spatrick
346061da546Spatrick Always sets a breakpoint on line 3 of whatever file is indicated.)");
347061da546Spatrick
348061da546Spatrick CommandArgumentEntry arg1;
349061da546Spatrick CommandArgumentEntry arg2;
350061da546Spatrick CommandArgumentEntry arg3;
351061da546Spatrick CommandArgumentData alias_arg;
352061da546Spatrick CommandArgumentData cmd_arg;
353061da546Spatrick CommandArgumentData options_arg;
354061da546Spatrick
355061da546Spatrick // Define the first (and only) variant of this arg.
356061da546Spatrick alias_arg.arg_type = eArgTypeAliasName;
357061da546Spatrick alias_arg.arg_repetition = eArgRepeatPlain;
358061da546Spatrick
359061da546Spatrick // There is only one variant this argument could be; put it into the
360061da546Spatrick // argument entry.
361061da546Spatrick arg1.push_back(alias_arg);
362061da546Spatrick
363061da546Spatrick // Define the first (and only) variant of this arg.
364061da546Spatrick cmd_arg.arg_type = eArgTypeCommandName;
365061da546Spatrick cmd_arg.arg_repetition = eArgRepeatPlain;
366061da546Spatrick
367061da546Spatrick // There is only one variant this argument could be; put it into the
368061da546Spatrick // argument entry.
369061da546Spatrick arg2.push_back(cmd_arg);
370061da546Spatrick
371061da546Spatrick // Define the first (and only) variant of this arg.
372061da546Spatrick options_arg.arg_type = eArgTypeAliasOptions;
373061da546Spatrick options_arg.arg_repetition = eArgRepeatOptional;
374061da546Spatrick
375061da546Spatrick // There is only one variant this argument could be; put it into the
376061da546Spatrick // argument entry.
377061da546Spatrick arg3.push_back(options_arg);
378061da546Spatrick
379061da546Spatrick // Push the data for the first argument into the m_arguments vector.
380061da546Spatrick m_arguments.push_back(arg1);
381061da546Spatrick m_arguments.push_back(arg2);
382061da546Spatrick m_arguments.push_back(arg3);
383061da546Spatrick }
384061da546Spatrick
385061da546Spatrick ~CommandObjectCommandsAlias() override = default;
386061da546Spatrick
387061da546Spatrick protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)388061da546Spatrick bool DoExecute(llvm::StringRef raw_command_line,
389061da546Spatrick CommandReturnObject &result) override {
390061da546Spatrick if (raw_command_line.empty()) {
391061da546Spatrick result.AppendError("'command alias' requires at least two arguments");
392061da546Spatrick return false;
393061da546Spatrick }
394061da546Spatrick
395061da546Spatrick ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
396061da546Spatrick m_option_group.NotifyOptionParsingStarting(&exe_ctx);
397061da546Spatrick
398061da546Spatrick OptionsWithRaw args_with_suffix(raw_command_line);
399061da546Spatrick
400061da546Spatrick if (args_with_suffix.HasArgs())
401061da546Spatrick if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
402061da546Spatrick m_option_group, exe_ctx))
403061da546Spatrick return false;
404061da546Spatrick
405dda28197Spatrick llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
406061da546Spatrick Args args(raw_command_string);
407061da546Spatrick
408061da546Spatrick if (args.GetArgumentCount() < 2) {
409061da546Spatrick result.AppendError("'command alias' requires at least two arguments");
410061da546Spatrick return false;
411061da546Spatrick }
412061da546Spatrick
413061da546Spatrick // Get the alias command.
414061da546Spatrick
415061da546Spatrick auto alias_command = args[0].ref();
416061da546Spatrick if (alias_command.startswith("-")) {
417061da546Spatrick result.AppendError("aliases starting with a dash are not supported");
418061da546Spatrick if (alias_command == "--help" || alias_command == "--long-help") {
419061da546Spatrick result.AppendWarning("if trying to pass options to 'command alias' add "
420061da546Spatrick "a -- at the end of the options");
421061da546Spatrick }
422061da546Spatrick return false;
423061da546Spatrick }
424061da546Spatrick
425061da546Spatrick // Strip the new alias name off 'raw_command_string' (leave it on args,
426061da546Spatrick // which gets passed to 'Execute', which does the stripping itself.
427061da546Spatrick size_t pos = raw_command_string.find(alias_command);
428061da546Spatrick if (pos == 0) {
429061da546Spatrick raw_command_string = raw_command_string.substr(alias_command.size());
430061da546Spatrick pos = raw_command_string.find_first_not_of(' ');
431061da546Spatrick if ((pos != std::string::npos) && (pos > 0))
432061da546Spatrick raw_command_string = raw_command_string.substr(pos);
433061da546Spatrick } else {
434061da546Spatrick result.AppendError("Error parsing command string. No alias created.");
435061da546Spatrick return false;
436061da546Spatrick }
437061da546Spatrick
438061da546Spatrick // Verify that the command is alias-able.
439061da546Spatrick if (m_interpreter.CommandExists(alias_command)) {
440061da546Spatrick result.AppendErrorWithFormat(
441061da546Spatrick "'%s' is a permanent debugger command and cannot be redefined.\n",
442061da546Spatrick args[0].c_str());
443061da546Spatrick return false;
444061da546Spatrick }
445061da546Spatrick
446*f6aab3d8Srobert if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
447*f6aab3d8Srobert result.AppendErrorWithFormat(
448*f6aab3d8Srobert "'%s' is a user container command and cannot be overwritten.\n"
449*f6aab3d8Srobert "Delete it first with 'command container delete'\n",
450*f6aab3d8Srobert args[0].c_str());
451*f6aab3d8Srobert return false;
452*f6aab3d8Srobert }
453*f6aab3d8Srobert
454061da546Spatrick // Get CommandObject that is being aliased. The command name is read from
455061da546Spatrick // the front of raw_command_string. raw_command_string is returned with the
456061da546Spatrick // name of the command object stripped off the front.
457061da546Spatrick llvm::StringRef original_raw_command_string = raw_command_string;
458061da546Spatrick CommandObject *cmd_obj =
459061da546Spatrick m_interpreter.GetCommandObjectForCommand(raw_command_string);
460061da546Spatrick
461061da546Spatrick if (!cmd_obj) {
462061da546Spatrick result.AppendErrorWithFormat("invalid command given to 'command alias'. "
463061da546Spatrick "'%s' does not begin with a valid command."
464061da546Spatrick " No alias created.",
465061da546Spatrick original_raw_command_string.str().c_str());
466061da546Spatrick return false;
467061da546Spatrick } else if (!cmd_obj->WantsRawCommandString()) {
468061da546Spatrick // Note that args was initialized with the original command, and has not
469061da546Spatrick // been updated to this point. Therefore can we pass it to the version of
470061da546Spatrick // Execute that does not need/expect raw input in the alias.
471061da546Spatrick return HandleAliasingNormalCommand(args, result);
472061da546Spatrick } else {
473061da546Spatrick return HandleAliasingRawCommand(alias_command, raw_command_string,
474061da546Spatrick *cmd_obj, result);
475061da546Spatrick }
476061da546Spatrick return result.Succeeded();
477061da546Spatrick }
478061da546Spatrick
HandleAliasingRawCommand(llvm::StringRef alias_command,llvm::StringRef raw_command_string,CommandObject & cmd_obj,CommandReturnObject & result)479061da546Spatrick bool HandleAliasingRawCommand(llvm::StringRef alias_command,
480061da546Spatrick llvm::StringRef raw_command_string,
481061da546Spatrick CommandObject &cmd_obj,
482061da546Spatrick CommandReturnObject &result) {
483061da546Spatrick // Verify & handle any options/arguments passed to the alias command
484061da546Spatrick
485061da546Spatrick OptionArgVectorSP option_arg_vector_sp =
486061da546Spatrick OptionArgVectorSP(new OptionArgVector);
487061da546Spatrick
488*f6aab3d8Srobert const bool include_aliases = true;
489*f6aab3d8Srobert // Look up the command using command's name first. This is to resolve
490*f6aab3d8Srobert // aliases when you are making nested aliases. But if you don't find
491*f6aab3d8Srobert // it that way, then it wasn't an alias and we can just use the object
492*f6aab3d8Srobert // we were passed in.
493*f6aab3d8Srobert CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
494*f6aab3d8Srobert cmd_obj.GetCommandName(), include_aliases);
495*f6aab3d8Srobert if (!cmd_obj_sp)
496*f6aab3d8Srobert cmd_obj_sp = cmd_obj.shared_from_this();
497*f6aab3d8Srobert
498061da546Spatrick if (m_interpreter.AliasExists(alias_command) ||
499061da546Spatrick m_interpreter.UserCommandExists(alias_command)) {
500061da546Spatrick result.AppendWarningWithFormat(
501061da546Spatrick "Overwriting existing definition for '%s'.\n",
502061da546Spatrick alias_command.str().c_str());
503061da546Spatrick }
504061da546Spatrick if (CommandAlias *alias = m_interpreter.AddAlias(
505061da546Spatrick alias_command, cmd_obj_sp, raw_command_string)) {
506061da546Spatrick if (m_command_options.m_help.OptionWasSet())
507061da546Spatrick alias->SetHelp(m_command_options.m_help.GetCurrentValue());
508061da546Spatrick if (m_command_options.m_long_help.OptionWasSet())
509061da546Spatrick alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
510061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
511061da546Spatrick } else {
512061da546Spatrick result.AppendError("Unable to create requested alias.\n");
513061da546Spatrick }
514061da546Spatrick return result.Succeeded();
515061da546Spatrick }
516061da546Spatrick
HandleAliasingNormalCommand(Args & args,CommandReturnObject & result)517061da546Spatrick bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
518061da546Spatrick size_t argc = args.GetArgumentCount();
519061da546Spatrick
520061da546Spatrick if (argc < 2) {
521061da546Spatrick result.AppendError("'command alias' requires at least two arguments");
522061da546Spatrick return false;
523061da546Spatrick }
524061da546Spatrick
525061da546Spatrick // Save these in std::strings since we're going to shift them off.
526dda28197Spatrick const std::string alias_command(std::string(args[0].ref()));
527dda28197Spatrick const std::string actual_command(std::string(args[1].ref()));
528061da546Spatrick
529061da546Spatrick args.Shift(); // Shift the alias command word off the argument vector.
530061da546Spatrick args.Shift(); // Shift the old command word off the argument vector.
531061da546Spatrick
532061da546Spatrick // Verify that the command is alias'able, and get the appropriate command
533061da546Spatrick // object.
534061da546Spatrick
535061da546Spatrick if (m_interpreter.CommandExists(alias_command)) {
536061da546Spatrick result.AppendErrorWithFormat(
537061da546Spatrick "'%s' is a permanent debugger command and cannot be redefined.\n",
538061da546Spatrick alias_command.c_str());
539061da546Spatrick return false;
540061da546Spatrick }
541061da546Spatrick
542*f6aab3d8Srobert if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
543*f6aab3d8Srobert result.AppendErrorWithFormat(
544*f6aab3d8Srobert "'%s' is user container command and cannot be overwritten.\n"
545*f6aab3d8Srobert "Delete it first with 'command container delete'",
546*f6aab3d8Srobert alias_command.c_str());
547*f6aab3d8Srobert return false;
548*f6aab3d8Srobert }
549*f6aab3d8Srobert
550061da546Spatrick CommandObjectSP command_obj_sp(
551061da546Spatrick m_interpreter.GetCommandSPExact(actual_command, true));
552061da546Spatrick CommandObjectSP subcommand_obj_sp;
553061da546Spatrick bool use_subcommand = false;
554061da546Spatrick if (!command_obj_sp) {
555061da546Spatrick result.AppendErrorWithFormat("'%s' is not an existing command.\n",
556061da546Spatrick actual_command.c_str());
557061da546Spatrick return false;
558061da546Spatrick }
559061da546Spatrick CommandObject *cmd_obj = command_obj_sp.get();
560061da546Spatrick CommandObject *sub_cmd_obj = nullptr;
561061da546Spatrick OptionArgVectorSP option_arg_vector_sp =
562061da546Spatrick OptionArgVectorSP(new OptionArgVector);
563061da546Spatrick
564061da546Spatrick while (cmd_obj->IsMultiwordObject() && !args.empty()) {
565061da546Spatrick auto sub_command = args[0].ref();
566061da546Spatrick assert(!sub_command.empty());
567061da546Spatrick subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
568061da546Spatrick if (!subcommand_obj_sp) {
569061da546Spatrick result.AppendErrorWithFormat(
570061da546Spatrick "'%s' is not a valid sub-command of '%s'. "
571061da546Spatrick "Unable to create alias.\n",
572061da546Spatrick args[0].c_str(), actual_command.c_str());
573061da546Spatrick return false;
574061da546Spatrick }
575061da546Spatrick
576061da546Spatrick sub_cmd_obj = subcommand_obj_sp.get();
577061da546Spatrick use_subcommand = true;
578061da546Spatrick args.Shift(); // Shift the sub_command word off the argument vector.
579061da546Spatrick cmd_obj = sub_cmd_obj;
580061da546Spatrick }
581061da546Spatrick
582061da546Spatrick // Verify & handle any options/arguments passed to the alias command
583061da546Spatrick
584061da546Spatrick std::string args_string;
585061da546Spatrick
586061da546Spatrick if (!args.empty()) {
587061da546Spatrick CommandObjectSP tmp_sp =
588be691f3bSpatrick m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
589061da546Spatrick if (use_subcommand)
590be691f3bSpatrick tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
591061da546Spatrick
592061da546Spatrick args.GetCommandString(args_string);
593061da546Spatrick }
594061da546Spatrick
595061da546Spatrick if (m_interpreter.AliasExists(alias_command) ||
596061da546Spatrick m_interpreter.UserCommandExists(alias_command)) {
597061da546Spatrick result.AppendWarningWithFormat(
598061da546Spatrick "Overwriting existing definition for '%s'.\n", alias_command.c_str());
599061da546Spatrick }
600061da546Spatrick
601061da546Spatrick if (CommandAlias *alias = m_interpreter.AddAlias(
602061da546Spatrick alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
603061da546Spatrick args_string)) {
604061da546Spatrick if (m_command_options.m_help.OptionWasSet())
605061da546Spatrick alias->SetHelp(m_command_options.m_help.GetCurrentValue());
606061da546Spatrick if (m_command_options.m_long_help.OptionWasSet())
607061da546Spatrick alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
608061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
609061da546Spatrick } else {
610061da546Spatrick result.AppendError("Unable to create requested alias.\n");
611061da546Spatrick return false;
612061da546Spatrick }
613061da546Spatrick
614061da546Spatrick return result.Succeeded();
615061da546Spatrick }
616061da546Spatrick };
617061da546Spatrick
618061da546Spatrick #pragma mark CommandObjectCommandsUnalias
619061da546Spatrick // CommandObjectCommandsUnalias
620061da546Spatrick
621061da546Spatrick class CommandObjectCommandsUnalias : public CommandObjectParsed {
622061da546Spatrick public:
CommandObjectCommandsUnalias(CommandInterpreter & interpreter)623061da546Spatrick CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
624061da546Spatrick : CommandObjectParsed(
625061da546Spatrick interpreter, "command unalias",
626061da546Spatrick "Delete one or more custom commands defined by 'command alias'.",
627061da546Spatrick nullptr) {
628061da546Spatrick CommandArgumentEntry arg;
629061da546Spatrick CommandArgumentData alias_arg;
630061da546Spatrick
631061da546Spatrick // Define the first (and only) variant of this arg.
632061da546Spatrick alias_arg.arg_type = eArgTypeAliasName;
633061da546Spatrick alias_arg.arg_repetition = eArgRepeatPlain;
634061da546Spatrick
635061da546Spatrick // There is only one variant this argument could be; put it into the
636061da546Spatrick // argument entry.
637061da546Spatrick arg.push_back(alias_arg);
638061da546Spatrick
639061da546Spatrick // Push the data for the first argument into the m_arguments vector.
640061da546Spatrick m_arguments.push_back(arg);
641061da546Spatrick }
642061da546Spatrick
643061da546Spatrick ~CommandObjectCommandsUnalias() override = default;
644061da546Spatrick
645be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)646be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
647be691f3bSpatrick OptionElementVector &opt_element_vector) override {
648be691f3bSpatrick if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
649be691f3bSpatrick return;
650be691f3bSpatrick
651be691f3bSpatrick for (const auto &ent : m_interpreter.GetAliases()) {
652be691f3bSpatrick request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
653be691f3bSpatrick }
654be691f3bSpatrick }
655be691f3bSpatrick
656061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)657061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
658061da546Spatrick CommandObject::CommandMap::iterator pos;
659061da546Spatrick CommandObject *cmd_obj;
660061da546Spatrick
661061da546Spatrick if (args.empty()) {
662061da546Spatrick result.AppendError("must call 'unalias' with a valid alias");
663061da546Spatrick return false;
664061da546Spatrick }
665061da546Spatrick
666061da546Spatrick auto command_name = args[0].ref();
667061da546Spatrick cmd_obj = m_interpreter.GetCommandObject(command_name);
668061da546Spatrick if (!cmd_obj) {
669061da546Spatrick result.AppendErrorWithFormat(
670061da546Spatrick "'%s' is not a known command.\nTry 'help' to see a "
671061da546Spatrick "current list of commands.\n",
672061da546Spatrick args[0].c_str());
673061da546Spatrick return false;
674061da546Spatrick }
675061da546Spatrick
676061da546Spatrick if (m_interpreter.CommandExists(command_name)) {
677061da546Spatrick if (cmd_obj->IsRemovable()) {
678061da546Spatrick result.AppendErrorWithFormat(
679061da546Spatrick "'%s' is not an alias, it is a debugger command which can be "
680061da546Spatrick "removed using the 'command delete' command.\n",
681061da546Spatrick args[0].c_str());
682061da546Spatrick } else {
683061da546Spatrick result.AppendErrorWithFormat(
684061da546Spatrick "'%s' is a permanent debugger command and cannot be removed.\n",
685061da546Spatrick args[0].c_str());
686061da546Spatrick }
687061da546Spatrick return false;
688061da546Spatrick }
689061da546Spatrick
690061da546Spatrick if (!m_interpreter.RemoveAlias(command_name)) {
691061da546Spatrick if (m_interpreter.AliasExists(command_name))
692061da546Spatrick result.AppendErrorWithFormat(
693061da546Spatrick "Error occurred while attempting to unalias '%s'.\n",
694061da546Spatrick args[0].c_str());
695061da546Spatrick else
696061da546Spatrick result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
697061da546Spatrick args[0].c_str());
698061da546Spatrick return false;
699061da546Spatrick }
700061da546Spatrick
701061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
702061da546Spatrick return result.Succeeded();
703061da546Spatrick }
704061da546Spatrick };
705061da546Spatrick
706061da546Spatrick #pragma mark CommandObjectCommandsDelete
707061da546Spatrick // CommandObjectCommandsDelete
708061da546Spatrick
709061da546Spatrick class CommandObjectCommandsDelete : public CommandObjectParsed {
710061da546Spatrick public:
CommandObjectCommandsDelete(CommandInterpreter & interpreter)711061da546Spatrick CommandObjectCommandsDelete(CommandInterpreter &interpreter)
712061da546Spatrick : CommandObjectParsed(
713061da546Spatrick interpreter, "command delete",
714061da546Spatrick "Delete one or more custom commands defined by 'command regex'.",
715061da546Spatrick nullptr) {
716061da546Spatrick CommandArgumentEntry arg;
717061da546Spatrick CommandArgumentData alias_arg;
718061da546Spatrick
719061da546Spatrick // Define the first (and only) variant of this arg.
720061da546Spatrick alias_arg.arg_type = eArgTypeCommandName;
721061da546Spatrick alias_arg.arg_repetition = eArgRepeatPlain;
722061da546Spatrick
723061da546Spatrick // There is only one variant this argument could be; put it into the
724061da546Spatrick // argument entry.
725061da546Spatrick arg.push_back(alias_arg);
726061da546Spatrick
727061da546Spatrick // Push the data for the first argument into the m_arguments vector.
728061da546Spatrick m_arguments.push_back(arg);
729061da546Spatrick }
730061da546Spatrick
731061da546Spatrick ~CommandObjectCommandsDelete() override = default;
732061da546Spatrick
733be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)734be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
735be691f3bSpatrick OptionElementVector &opt_element_vector) override {
736be691f3bSpatrick if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
737be691f3bSpatrick return;
738be691f3bSpatrick
739be691f3bSpatrick for (const auto &ent : m_interpreter.GetCommands()) {
740be691f3bSpatrick if (ent.second->IsRemovable())
741be691f3bSpatrick request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
742be691f3bSpatrick }
743be691f3bSpatrick }
744be691f3bSpatrick
745061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)746061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
747061da546Spatrick CommandObject::CommandMap::iterator pos;
748061da546Spatrick
749061da546Spatrick if (args.empty()) {
750061da546Spatrick result.AppendErrorWithFormat("must call '%s' with one or more valid user "
751061da546Spatrick "defined regular expression command names",
752061da546Spatrick GetCommandName().str().c_str());
753061da546Spatrick return false;
754061da546Spatrick }
755061da546Spatrick
756061da546Spatrick auto command_name = args[0].ref();
757061da546Spatrick if (!m_interpreter.CommandExists(command_name)) {
758061da546Spatrick StreamString error_msg_stream;
759061da546Spatrick const bool generate_upropos = true;
760061da546Spatrick const bool generate_type_lookup = false;
761061da546Spatrick CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
762061da546Spatrick &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
763061da546Spatrick generate_upropos, generate_type_lookup);
764061da546Spatrick result.AppendError(error_msg_stream.GetString());
765061da546Spatrick return false;
766061da546Spatrick }
767061da546Spatrick
768061da546Spatrick if (!m_interpreter.RemoveCommand(command_name)) {
769061da546Spatrick result.AppendErrorWithFormat(
770061da546Spatrick "'%s' is a permanent debugger command and cannot be removed.\n",
771061da546Spatrick args[0].c_str());
772061da546Spatrick return false;
773061da546Spatrick }
774061da546Spatrick
775061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
776061da546Spatrick return true;
777061da546Spatrick }
778061da546Spatrick };
779061da546Spatrick
780061da546Spatrick // CommandObjectCommandsAddRegex
781061da546Spatrick
782061da546Spatrick #define LLDB_OPTIONS_regex
783061da546Spatrick #include "CommandOptions.inc"
784061da546Spatrick
785061da546Spatrick #pragma mark CommandObjectCommandsAddRegex
786061da546Spatrick
787061da546Spatrick class CommandObjectCommandsAddRegex : public CommandObjectParsed,
788061da546Spatrick public IOHandlerDelegateMultiline {
789061da546Spatrick public:
CommandObjectCommandsAddRegex(CommandInterpreter & interpreter)790061da546Spatrick CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
791061da546Spatrick : CommandObjectParsed(
792061da546Spatrick interpreter, "command regex",
793061da546Spatrick "Define a custom command in terms of "
794061da546Spatrick "existing commands by matching "
795061da546Spatrick "regular expressions.",
796061da546Spatrick "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
797061da546Spatrick IOHandlerDelegateMultiline("",
798*f6aab3d8Srobert IOHandlerDelegate::Completion::LLDBCommand) {
799061da546Spatrick SetHelpLong(
800061da546Spatrick R"(
801061da546Spatrick )"
802061da546Spatrick "This command allows the user to create powerful regular expression commands \
803061da546Spatrick with substitutions. The regular expressions and substitutions are specified \
804061da546Spatrick using the regular expression substitution format of:"
805061da546Spatrick R"(
806061da546Spatrick
807061da546Spatrick s/<regex>/<subst>/
808061da546Spatrick
809061da546Spatrick )"
810061da546Spatrick "<regex> is a regular expression that can use parenthesis to capture regular \
811061da546Spatrick expression input and substitute the captured matches in the output using %1 \
812061da546Spatrick for the first match, %2 for the second, and so on."
813061da546Spatrick R"(
814061da546Spatrick
815061da546Spatrick )"
816061da546Spatrick "The regular expressions can all be specified on the command line if more than \
817061da546Spatrick one argument is provided. If just the command name is provided on the command \
818061da546Spatrick line, then the regular expressions and substitutions can be entered on separate \
819061da546Spatrick lines, followed by an empty line to terminate the command definition."
820061da546Spatrick R"(
821061da546Spatrick
822061da546Spatrick EXAMPLES
823061da546Spatrick
824061da546Spatrick )"
825061da546Spatrick "The following example will define a regular expression command named 'f' that \
826061da546Spatrick will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
827061da546Spatrick a number follows 'f':"
828061da546Spatrick R"(
829061da546Spatrick
830061da546Spatrick (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
831*f6aab3d8Srobert CommandArgumentData thread_arg{eArgTypeSEDStylePair, eArgRepeatOptional};
832*f6aab3d8Srobert m_arguments.push_back({thread_arg});
833061da546Spatrick }
834061da546Spatrick
835061da546Spatrick ~CommandObjectCommandsAddRegex() override = default;
836061da546Spatrick
837061da546Spatrick protected:
IOHandlerActivated(IOHandler & io_handler,bool interactive)838061da546Spatrick void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
839061da546Spatrick StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
840061da546Spatrick if (output_sp && interactive) {
841061da546Spatrick output_sp->PutCString("Enter one or more sed substitution commands in "
842061da546Spatrick "the form: 's/<regex>/<subst>/'.\nTerminate the "
843061da546Spatrick "substitution list with an empty line.\n");
844061da546Spatrick output_sp->Flush();
845061da546Spatrick }
846061da546Spatrick }
847061da546Spatrick
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)848061da546Spatrick void IOHandlerInputComplete(IOHandler &io_handler,
849061da546Spatrick std::string &data) override {
850061da546Spatrick io_handler.SetIsDone(true);
851061da546Spatrick if (m_regex_cmd_up) {
852061da546Spatrick StringList lines;
853061da546Spatrick if (lines.SplitIntoLines(data)) {
854061da546Spatrick bool check_only = false;
855061da546Spatrick for (const std::string &line : lines) {
856061da546Spatrick Status error = AppendRegexSubstitution(line, check_only);
857061da546Spatrick if (error.Fail()) {
858061da546Spatrick if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
859061da546Spatrick StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
860061da546Spatrick out_stream->Printf("error: %s\n", error.AsCString());
861061da546Spatrick }
862061da546Spatrick }
863061da546Spatrick }
864061da546Spatrick }
865061da546Spatrick if (m_regex_cmd_up->HasRegexEntries()) {
866061da546Spatrick CommandObjectSP cmd_sp(m_regex_cmd_up.release());
867061da546Spatrick m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
868061da546Spatrick }
869061da546Spatrick }
870061da546Spatrick }
871061da546Spatrick
DoExecute(Args & command,CommandReturnObject & result)872061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
873061da546Spatrick const size_t argc = command.GetArgumentCount();
874061da546Spatrick if (argc == 0) {
875061da546Spatrick result.AppendError("usage: 'command regex <command-name> "
876061da546Spatrick "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
877061da546Spatrick return false;
878061da546Spatrick }
879061da546Spatrick
880061da546Spatrick Status error;
881061da546Spatrick auto name = command[0].ref();
882061da546Spatrick m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
883061da546Spatrick m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0,
884061da546Spatrick true);
885061da546Spatrick
886061da546Spatrick if (argc == 1) {
887061da546Spatrick Debugger &debugger = GetDebugger();
888061da546Spatrick bool color_prompt = debugger.GetUseColor();
889061da546Spatrick const bool multiple_lines = true; // Get multiple lines
890061da546Spatrick IOHandlerSP io_handler_sp(new IOHandlerEditline(
891061da546Spatrick debugger, IOHandler::Type::Other,
892061da546Spatrick "lldb-regex", // Name of input reader for history
893061da546Spatrick llvm::StringRef("> "), // Prompt
894061da546Spatrick llvm::StringRef(), // Continuation prompt
895061da546Spatrick multiple_lines, color_prompt,
896061da546Spatrick 0, // Don't show line numbers
897*f6aab3d8Srobert *this));
898061da546Spatrick
899061da546Spatrick if (io_handler_sp) {
900dda28197Spatrick debugger.RunIOHandlerAsync(io_handler_sp);
901061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
902061da546Spatrick }
903061da546Spatrick } else {
904061da546Spatrick for (auto &entry : command.entries().drop_front()) {
905061da546Spatrick bool check_only = false;
906061da546Spatrick error = AppendRegexSubstitution(entry.ref(), check_only);
907061da546Spatrick if (error.Fail())
908061da546Spatrick break;
909061da546Spatrick }
910061da546Spatrick
911061da546Spatrick if (error.Success()) {
912061da546Spatrick AddRegexCommandToInterpreter();
913061da546Spatrick }
914061da546Spatrick }
915061da546Spatrick if (error.Fail()) {
916061da546Spatrick result.AppendError(error.AsCString());
917061da546Spatrick }
918061da546Spatrick
919061da546Spatrick return result.Succeeded();
920061da546Spatrick }
921061da546Spatrick
AppendRegexSubstitution(const llvm::StringRef & regex_sed,bool check_only)922061da546Spatrick Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed,
923061da546Spatrick bool check_only) {
924061da546Spatrick Status error;
925061da546Spatrick
926061da546Spatrick if (!m_regex_cmd_up) {
927061da546Spatrick error.SetErrorStringWithFormat(
928061da546Spatrick "invalid regular expression command object for: '%.*s'",
929061da546Spatrick (int)regex_sed.size(), regex_sed.data());
930061da546Spatrick return error;
931061da546Spatrick }
932061da546Spatrick
933061da546Spatrick size_t regex_sed_size = regex_sed.size();
934061da546Spatrick
935061da546Spatrick if (regex_sed_size <= 1) {
936061da546Spatrick error.SetErrorStringWithFormat(
937061da546Spatrick "regular expression substitution string is too short: '%.*s'",
938061da546Spatrick (int)regex_sed.size(), regex_sed.data());
939061da546Spatrick return error;
940061da546Spatrick }
941061da546Spatrick
942061da546Spatrick if (regex_sed[0] != 's') {
943061da546Spatrick error.SetErrorStringWithFormat("regular expression substitution string "
944061da546Spatrick "doesn't start with 's': '%.*s'",
945061da546Spatrick (int)regex_sed.size(), regex_sed.data());
946061da546Spatrick return error;
947061da546Spatrick }
948061da546Spatrick const size_t first_separator_char_pos = 1;
949061da546Spatrick // use the char that follows 's' as the regex separator character so we can
950061da546Spatrick // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
951061da546Spatrick const char separator_char = regex_sed[first_separator_char_pos];
952061da546Spatrick const size_t second_separator_char_pos =
953061da546Spatrick regex_sed.find(separator_char, first_separator_char_pos + 1);
954061da546Spatrick
955061da546Spatrick if (second_separator_char_pos == std::string::npos) {
956061da546Spatrick error.SetErrorStringWithFormat(
957061da546Spatrick "missing second '%c' separator char after '%.*s' in '%.*s'",
958061da546Spatrick separator_char,
959061da546Spatrick (int)(regex_sed.size() - first_separator_char_pos - 1),
960061da546Spatrick regex_sed.data() + (first_separator_char_pos + 1),
961061da546Spatrick (int)regex_sed.size(), regex_sed.data());
962061da546Spatrick return error;
963061da546Spatrick }
964061da546Spatrick
965061da546Spatrick const size_t third_separator_char_pos =
966061da546Spatrick regex_sed.find(separator_char, second_separator_char_pos + 1);
967061da546Spatrick
968061da546Spatrick if (third_separator_char_pos == std::string::npos) {
969061da546Spatrick error.SetErrorStringWithFormat(
970061da546Spatrick "missing third '%c' separator char after '%.*s' in '%.*s'",
971061da546Spatrick separator_char,
972061da546Spatrick (int)(regex_sed.size() - second_separator_char_pos - 1),
973061da546Spatrick regex_sed.data() + (second_separator_char_pos + 1),
974061da546Spatrick (int)regex_sed.size(), regex_sed.data());
975061da546Spatrick return error;
976061da546Spatrick }
977061da546Spatrick
978061da546Spatrick if (third_separator_char_pos != regex_sed_size - 1) {
979061da546Spatrick // Make sure that everything that follows the last regex separator char
980061da546Spatrick if (regex_sed.find_first_not_of("\t\n\v\f\r ",
981061da546Spatrick third_separator_char_pos + 1) !=
982061da546Spatrick std::string::npos) {
983061da546Spatrick error.SetErrorStringWithFormat(
984061da546Spatrick "extra data found after the '%.*s' regular expression substitution "
985061da546Spatrick "string: '%.*s'",
986061da546Spatrick (int)third_separator_char_pos + 1, regex_sed.data(),
987061da546Spatrick (int)(regex_sed.size() - third_separator_char_pos - 1),
988061da546Spatrick regex_sed.data() + (third_separator_char_pos + 1));
989061da546Spatrick return error;
990061da546Spatrick }
991061da546Spatrick } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
992061da546Spatrick error.SetErrorStringWithFormat(
993061da546Spatrick "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
994061da546Spatrick separator_char, separator_char, separator_char, (int)regex_sed.size(),
995061da546Spatrick regex_sed.data());
996061da546Spatrick return error;
997061da546Spatrick } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
998061da546Spatrick error.SetErrorStringWithFormat(
999061da546Spatrick "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
1000061da546Spatrick separator_char, separator_char, separator_char, (int)regex_sed.size(),
1001061da546Spatrick regex_sed.data());
1002061da546Spatrick return error;
1003061da546Spatrick }
1004061da546Spatrick
1005061da546Spatrick if (!check_only) {
1006dda28197Spatrick std::string regex(std::string(regex_sed.substr(
1007dda28197Spatrick first_separator_char_pos + 1,
1008dda28197Spatrick second_separator_char_pos - first_separator_char_pos - 1)));
1009dda28197Spatrick std::string subst(std::string(regex_sed.substr(
1010dda28197Spatrick second_separator_char_pos + 1,
1011dda28197Spatrick third_separator_char_pos - second_separator_char_pos - 1)));
1012be691f3bSpatrick m_regex_cmd_up->AddRegexCommand(regex, subst);
1013061da546Spatrick }
1014061da546Spatrick return error;
1015061da546Spatrick }
1016061da546Spatrick
AddRegexCommandToInterpreter()1017061da546Spatrick void AddRegexCommandToInterpreter() {
1018061da546Spatrick if (m_regex_cmd_up) {
1019061da546Spatrick if (m_regex_cmd_up->HasRegexEntries()) {
1020061da546Spatrick CommandObjectSP cmd_sp(m_regex_cmd_up.release());
1021061da546Spatrick m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1022061da546Spatrick }
1023061da546Spatrick }
1024061da546Spatrick }
1025061da546Spatrick
1026061da546Spatrick private:
1027061da546Spatrick std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
1028061da546Spatrick
1029061da546Spatrick class CommandOptions : public Options {
1030061da546Spatrick public:
1031*f6aab3d8Srobert CommandOptions() = default;
1032061da546Spatrick
1033061da546Spatrick ~CommandOptions() override = default;
1034061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1035061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1036061da546Spatrick ExecutionContext *execution_context) override {
1037061da546Spatrick Status error;
1038061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1039061da546Spatrick
1040061da546Spatrick switch (short_option) {
1041061da546Spatrick case 'h':
1042dda28197Spatrick m_help.assign(std::string(option_arg));
1043061da546Spatrick break;
1044061da546Spatrick case 's':
1045dda28197Spatrick m_syntax.assign(std::string(option_arg));
1046061da546Spatrick break;
1047061da546Spatrick default:
1048061da546Spatrick llvm_unreachable("Unimplemented option");
1049061da546Spatrick }
1050061da546Spatrick
1051061da546Spatrick return error;
1052061da546Spatrick }
1053061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1054061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1055061da546Spatrick m_help.clear();
1056061da546Spatrick m_syntax.clear();
1057061da546Spatrick }
1058061da546Spatrick
GetDefinitions()1059061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1060*f6aab3d8Srobert return llvm::ArrayRef(g_regex_options);
1061061da546Spatrick }
1062061da546Spatrick
GetHelp()1063dda28197Spatrick llvm::StringRef GetHelp() { return m_help; }
1064061da546Spatrick
GetSyntax()1065dda28197Spatrick llvm::StringRef GetSyntax() { return m_syntax; }
1066061da546Spatrick
1067061da546Spatrick protected:
1068061da546Spatrick // Instance variables to hold the values for command options.
1069061da546Spatrick
1070061da546Spatrick std::string m_help;
1071061da546Spatrick std::string m_syntax;
1072061da546Spatrick };
1073061da546Spatrick
GetOptions()1074061da546Spatrick Options *GetOptions() override { return &m_options; }
1075061da546Spatrick
1076061da546Spatrick CommandOptions m_options;
1077061da546Spatrick };
1078061da546Spatrick
1079061da546Spatrick class CommandObjectPythonFunction : public CommandObjectRaw {
1080061da546Spatrick public:
CommandObjectPythonFunction(CommandInterpreter & interpreter,std::string name,std::string funct,std::string help,ScriptedCommandSynchronicity synch)1081061da546Spatrick CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
1082061da546Spatrick std::string funct, std::string help,
1083061da546Spatrick ScriptedCommandSynchronicity synch)
1084061da546Spatrick : CommandObjectRaw(interpreter, name), m_function_name(funct),
1085*f6aab3d8Srobert m_synchro(synch) {
1086061da546Spatrick if (!help.empty())
1087061da546Spatrick SetHelp(help);
1088061da546Spatrick else {
1089061da546Spatrick StreamString stream;
1090061da546Spatrick stream.Printf("For more information run 'help %s'", name.c_str());
1091061da546Spatrick SetHelp(stream.GetString());
1092061da546Spatrick }
1093061da546Spatrick }
1094061da546Spatrick
1095061da546Spatrick ~CommandObjectPythonFunction() override = default;
1096061da546Spatrick
IsRemovable() const1097061da546Spatrick bool IsRemovable() const override { return true; }
1098061da546Spatrick
GetFunctionName()1099061da546Spatrick const std::string &GetFunctionName() { return m_function_name; }
1100061da546Spatrick
GetSynchronicity()1101061da546Spatrick ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1102061da546Spatrick
GetHelpLong()1103061da546Spatrick llvm::StringRef GetHelpLong() override {
1104061da546Spatrick if (m_fetched_help_long)
1105061da546Spatrick return CommandObjectRaw::GetHelpLong();
1106061da546Spatrick
1107061da546Spatrick ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1108061da546Spatrick if (!scripter)
1109061da546Spatrick return CommandObjectRaw::GetHelpLong();
1110061da546Spatrick
1111061da546Spatrick std::string docstring;
1112061da546Spatrick m_fetched_help_long =
1113061da546Spatrick scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
1114061da546Spatrick if (!docstring.empty())
1115061da546Spatrick SetHelpLong(docstring);
1116061da546Spatrick return CommandObjectRaw::GetHelpLong();
1117061da546Spatrick }
1118061da546Spatrick
1119061da546Spatrick protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1120061da546Spatrick bool DoExecute(llvm::StringRef raw_command_line,
1121061da546Spatrick CommandReturnObject &result) override {
1122061da546Spatrick ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1123061da546Spatrick
1124061da546Spatrick Status error;
1125061da546Spatrick
1126061da546Spatrick result.SetStatus(eReturnStatusInvalid);
1127061da546Spatrick
1128061da546Spatrick if (!scripter || !scripter->RunScriptBasedCommand(
1129061da546Spatrick m_function_name.c_str(), raw_command_line, m_synchro,
1130061da546Spatrick result, error, m_exe_ctx)) {
1131061da546Spatrick result.AppendError(error.AsCString());
1132061da546Spatrick } else {
1133061da546Spatrick // Don't change the status if the command already set it...
1134061da546Spatrick if (result.GetStatus() == eReturnStatusInvalid) {
1135061da546Spatrick if (result.GetOutputData().empty())
1136061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1137061da546Spatrick else
1138061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1139061da546Spatrick }
1140061da546Spatrick }
1141061da546Spatrick
1142061da546Spatrick return result.Succeeded();
1143061da546Spatrick }
1144061da546Spatrick
1145061da546Spatrick private:
1146061da546Spatrick std::string m_function_name;
1147061da546Spatrick ScriptedCommandSynchronicity m_synchro;
1148*f6aab3d8Srobert bool m_fetched_help_long = false;
1149061da546Spatrick };
1150061da546Spatrick
1151061da546Spatrick class CommandObjectScriptingObject : public CommandObjectRaw {
1152061da546Spatrick public:
CommandObjectScriptingObject(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch)1153061da546Spatrick CommandObjectScriptingObject(CommandInterpreter &interpreter,
1154061da546Spatrick std::string name,
1155061da546Spatrick StructuredData::GenericSP cmd_obj_sp,
1156061da546Spatrick ScriptedCommandSynchronicity synch)
1157061da546Spatrick : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1158061da546Spatrick m_synchro(synch), m_fetched_help_short(false),
1159061da546Spatrick m_fetched_help_long(false) {
1160061da546Spatrick StreamString stream;
1161061da546Spatrick stream.Printf("For more information run 'help %s'", name.c_str());
1162061da546Spatrick SetHelp(stream.GetString());
1163061da546Spatrick if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
1164061da546Spatrick GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1165061da546Spatrick }
1166061da546Spatrick
1167061da546Spatrick ~CommandObjectScriptingObject() override = default;
1168061da546Spatrick
IsRemovable() const1169061da546Spatrick bool IsRemovable() const override { return true; }
1170061da546Spatrick
GetSynchronicity()1171061da546Spatrick ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1172061da546Spatrick
GetHelp()1173061da546Spatrick llvm::StringRef GetHelp() override {
1174061da546Spatrick if (m_fetched_help_short)
1175061da546Spatrick return CommandObjectRaw::GetHelp();
1176061da546Spatrick ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1177061da546Spatrick if (!scripter)
1178061da546Spatrick return CommandObjectRaw::GetHelp();
1179061da546Spatrick std::string docstring;
1180061da546Spatrick m_fetched_help_short =
1181061da546Spatrick scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1182061da546Spatrick if (!docstring.empty())
1183061da546Spatrick SetHelp(docstring);
1184061da546Spatrick
1185061da546Spatrick return CommandObjectRaw::GetHelp();
1186061da546Spatrick }
1187061da546Spatrick
GetHelpLong()1188061da546Spatrick llvm::StringRef GetHelpLong() override {
1189061da546Spatrick if (m_fetched_help_long)
1190061da546Spatrick return CommandObjectRaw::GetHelpLong();
1191061da546Spatrick
1192061da546Spatrick ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1193061da546Spatrick if (!scripter)
1194061da546Spatrick return CommandObjectRaw::GetHelpLong();
1195061da546Spatrick
1196061da546Spatrick std::string docstring;
1197061da546Spatrick m_fetched_help_long =
1198061da546Spatrick scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1199061da546Spatrick if (!docstring.empty())
1200061da546Spatrick SetHelpLong(docstring);
1201061da546Spatrick return CommandObjectRaw::GetHelpLong();
1202061da546Spatrick }
1203061da546Spatrick
1204061da546Spatrick protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1205061da546Spatrick bool DoExecute(llvm::StringRef raw_command_line,
1206061da546Spatrick CommandReturnObject &result) override {
1207061da546Spatrick ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1208061da546Spatrick
1209061da546Spatrick Status error;
1210061da546Spatrick
1211061da546Spatrick result.SetStatus(eReturnStatusInvalid);
1212061da546Spatrick
1213061da546Spatrick if (!scripter ||
1214061da546Spatrick !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
1215061da546Spatrick m_synchro, result, error, m_exe_ctx)) {
1216061da546Spatrick result.AppendError(error.AsCString());
1217061da546Spatrick } else {
1218061da546Spatrick // Don't change the status if the command already set it...
1219061da546Spatrick if (result.GetStatus() == eReturnStatusInvalid) {
1220061da546Spatrick if (result.GetOutputData().empty())
1221061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1222061da546Spatrick else
1223061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1224061da546Spatrick }
1225061da546Spatrick }
1226061da546Spatrick
1227061da546Spatrick return result.Succeeded();
1228061da546Spatrick }
1229061da546Spatrick
1230061da546Spatrick private:
1231061da546Spatrick StructuredData::GenericSP m_cmd_obj_sp;
1232061da546Spatrick ScriptedCommandSynchronicity m_synchro;
1233061da546Spatrick bool m_fetched_help_short : 1;
1234061da546Spatrick bool m_fetched_help_long : 1;
1235061da546Spatrick };
1236061da546Spatrick
1237061da546Spatrick // CommandObjectCommandsScriptImport
1238061da546Spatrick #define LLDB_OPTIONS_script_import
1239061da546Spatrick #include "CommandOptions.inc"
1240061da546Spatrick
1241061da546Spatrick class CommandObjectCommandsScriptImport : public CommandObjectParsed {
1242061da546Spatrick public:
CommandObjectCommandsScriptImport(CommandInterpreter & interpreter)1243061da546Spatrick CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
1244061da546Spatrick : CommandObjectParsed(interpreter, "command script import",
1245*f6aab3d8Srobert "Import a scripting module in LLDB.", nullptr) {
1246061da546Spatrick CommandArgumentEntry arg1;
1247061da546Spatrick CommandArgumentData cmd_arg;
1248061da546Spatrick
1249061da546Spatrick // Define the first (and only) variant of this arg.
1250061da546Spatrick cmd_arg.arg_type = eArgTypeFilename;
1251061da546Spatrick cmd_arg.arg_repetition = eArgRepeatPlus;
1252061da546Spatrick
1253061da546Spatrick // There is only one variant this argument could be; put it into the
1254061da546Spatrick // argument entry.
1255061da546Spatrick arg1.push_back(cmd_arg);
1256061da546Spatrick
1257061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1258061da546Spatrick m_arguments.push_back(arg1);
1259061da546Spatrick }
1260061da546Spatrick
1261061da546Spatrick ~CommandObjectCommandsScriptImport() override = default;
1262061da546Spatrick
1263061da546Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1264061da546Spatrick HandleArgumentCompletion(CompletionRequest &request,
1265061da546Spatrick OptionElementVector &opt_element_vector) override {
1266061da546Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1267061da546Spatrick GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
1268061da546Spatrick request, nullptr);
1269061da546Spatrick }
1270061da546Spatrick
GetOptions()1271061da546Spatrick Options *GetOptions() override { return &m_options; }
1272061da546Spatrick
1273061da546Spatrick protected:
1274061da546Spatrick class CommandOptions : public Options {
1275061da546Spatrick public:
1276*f6aab3d8Srobert CommandOptions() = default;
1277061da546Spatrick
1278061da546Spatrick ~CommandOptions() override = default;
1279061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1280061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1281061da546Spatrick ExecutionContext *execution_context) override {
1282061da546Spatrick Status error;
1283061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1284061da546Spatrick
1285061da546Spatrick switch (short_option) {
1286061da546Spatrick case 'r':
1287061da546Spatrick // NO-OP
1288061da546Spatrick break;
1289be691f3bSpatrick case 'c':
1290be691f3bSpatrick relative_to_command_file = true;
1291be691f3bSpatrick break;
1292be691f3bSpatrick case 's':
1293be691f3bSpatrick silent = true;
1294be691f3bSpatrick break;
1295061da546Spatrick default:
1296061da546Spatrick llvm_unreachable("Unimplemented option");
1297061da546Spatrick }
1298061da546Spatrick
1299061da546Spatrick return error;
1300061da546Spatrick }
1301061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1302061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1303be691f3bSpatrick relative_to_command_file = false;
1304061da546Spatrick }
1305061da546Spatrick
GetDefinitions()1306061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1307*f6aab3d8Srobert return llvm::ArrayRef(g_script_import_options);
1308061da546Spatrick }
1309be691f3bSpatrick bool relative_to_command_file = false;
1310be691f3bSpatrick bool silent = false;
1311061da546Spatrick };
1312061da546Spatrick
DoExecute(Args & command,CommandReturnObject & result)1313061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1314061da546Spatrick if (command.empty()) {
1315061da546Spatrick result.AppendError("command script import needs one or more arguments");
1316061da546Spatrick return false;
1317061da546Spatrick }
1318061da546Spatrick
1319be691f3bSpatrick FileSpec source_dir = {};
1320be691f3bSpatrick if (m_options.relative_to_command_file) {
1321be691f3bSpatrick source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1322be691f3bSpatrick if (!source_dir) {
1323be691f3bSpatrick result.AppendError("command script import -c can only be specified "
1324be691f3bSpatrick "from a command file");
1325be691f3bSpatrick return false;
1326be691f3bSpatrick }
1327be691f3bSpatrick }
1328be691f3bSpatrick
1329061da546Spatrick for (auto &entry : command.entries()) {
1330061da546Spatrick Status error;
1331061da546Spatrick
1332be691f3bSpatrick LoadScriptOptions options;
1333be691f3bSpatrick options.SetInitSession(true);
1334be691f3bSpatrick options.SetSilent(m_options.silent);
1335be691f3bSpatrick
1336061da546Spatrick // FIXME: this is necessary because CommandObject::CheckRequirements()
1337061da546Spatrick // assumes that commands won't ever be recursively invoked, but it's
1338061da546Spatrick // actually possible to craft a Python script that does other "command
1339061da546Spatrick // script imports" in __lldb_init_module the real fix is to have
1340061da546Spatrick // recursive commands possible with a CommandInvocation object separate
1341061da546Spatrick // from the CommandObject itself, so that recursive command invocations
1342061da546Spatrick // won't stomp on each other (wrt to execution contents, options, and
1343061da546Spatrick // more)
1344061da546Spatrick m_exe_ctx.Clear();
1345061da546Spatrick if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
1346be691f3bSpatrick entry.c_str(), options, error, /*module_sp=*/nullptr,
1347be691f3bSpatrick source_dir)) {
1348061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1349061da546Spatrick } else {
1350061da546Spatrick result.AppendErrorWithFormat("module importing failed: %s",
1351061da546Spatrick error.AsCString());
1352061da546Spatrick }
1353061da546Spatrick }
1354061da546Spatrick
1355061da546Spatrick return result.Succeeded();
1356061da546Spatrick }
1357061da546Spatrick
1358061da546Spatrick CommandOptions m_options;
1359061da546Spatrick };
1360061da546Spatrick
1361061da546Spatrick #define LLDB_OPTIONS_script_add
1362061da546Spatrick #include "CommandOptions.inc"
1363061da546Spatrick
1364061da546Spatrick class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
1365061da546Spatrick public IOHandlerDelegateMultiline {
1366061da546Spatrick public:
CommandObjectCommandsScriptAdd(CommandInterpreter & interpreter)1367061da546Spatrick CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
1368061da546Spatrick : CommandObjectParsed(interpreter, "command script add",
1369061da546Spatrick "Add a scripted function as an LLDB command.",
1370*f6aab3d8Srobert "Add a scripted function as an lldb command. "
1371*f6aab3d8Srobert "If you provide a single argument, the command "
1372*f6aab3d8Srobert "will be added at the root level of the command "
1373*f6aab3d8Srobert "hierarchy. If there are more arguments they "
1374*f6aab3d8Srobert "must be a path to a user-added container "
1375*f6aab3d8Srobert "command, and the last element will be the new "
1376*f6aab3d8Srobert "command name."),
1377*f6aab3d8Srobert IOHandlerDelegateMultiline("DONE") {
1378061da546Spatrick CommandArgumentEntry arg1;
1379061da546Spatrick CommandArgumentData cmd_arg;
1380061da546Spatrick
1381*f6aab3d8Srobert // This is one or more command names, which form the path to the command
1382*f6aab3d8Srobert // you want to add.
1383*f6aab3d8Srobert cmd_arg.arg_type = eArgTypeCommand;
1384*f6aab3d8Srobert cmd_arg.arg_repetition = eArgRepeatPlus;
1385061da546Spatrick
1386061da546Spatrick // There is only one variant this argument could be; put it into the
1387061da546Spatrick // argument entry.
1388061da546Spatrick arg1.push_back(cmd_arg);
1389061da546Spatrick
1390061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1391061da546Spatrick m_arguments.push_back(arg1);
1392061da546Spatrick }
1393061da546Spatrick
1394061da546Spatrick ~CommandObjectCommandsScriptAdd() override = default;
1395061da546Spatrick
GetOptions()1396061da546Spatrick Options *GetOptions() override { return &m_options; }
1397061da546Spatrick
1398*f6aab3d8Srobert void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1399*f6aab3d8Srobert HandleArgumentCompletion(CompletionRequest &request,
1400*f6aab3d8Srobert OptionElementVector &opt_element_vector) override {
1401*f6aab3d8Srobert CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1402*f6aab3d8Srobert opt_element_vector);
1403*f6aab3d8Srobert }
1404*f6aab3d8Srobert
1405061da546Spatrick protected:
1406061da546Spatrick class CommandOptions : public Options {
1407061da546Spatrick public:
1408*f6aab3d8Srobert CommandOptions() = default;
1409061da546Spatrick
1410061da546Spatrick ~CommandOptions() override = default;
1411061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1412061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1413061da546Spatrick ExecutionContext *execution_context) override {
1414061da546Spatrick Status error;
1415061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1416061da546Spatrick
1417061da546Spatrick switch (short_option) {
1418061da546Spatrick case 'f':
1419061da546Spatrick if (!option_arg.empty())
1420dda28197Spatrick m_funct_name = std::string(option_arg);
1421061da546Spatrick break;
1422061da546Spatrick case 'c':
1423061da546Spatrick if (!option_arg.empty())
1424dda28197Spatrick m_class_name = std::string(option_arg);
1425061da546Spatrick break;
1426061da546Spatrick case 'h':
1427061da546Spatrick if (!option_arg.empty())
1428dda28197Spatrick m_short_help = std::string(option_arg);
1429061da546Spatrick break;
1430*f6aab3d8Srobert case 'o':
1431*f6aab3d8Srobert m_overwrite_lazy = eLazyBoolYes;
1432*f6aab3d8Srobert break;
1433061da546Spatrick case 's':
1434061da546Spatrick m_synchronicity =
1435061da546Spatrick (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
1436061da546Spatrick option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
1437061da546Spatrick if (!error.Success())
1438061da546Spatrick error.SetErrorStringWithFormat(
1439061da546Spatrick "unrecognized value for synchronicity '%s'",
1440061da546Spatrick option_arg.str().c_str());
1441061da546Spatrick break;
1442061da546Spatrick default:
1443061da546Spatrick llvm_unreachable("Unimplemented option");
1444061da546Spatrick }
1445061da546Spatrick
1446061da546Spatrick return error;
1447061da546Spatrick }
1448061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1449061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1450061da546Spatrick m_class_name.clear();
1451061da546Spatrick m_funct_name.clear();
1452061da546Spatrick m_short_help.clear();
1453*f6aab3d8Srobert m_overwrite_lazy = eLazyBoolCalculate;
1454061da546Spatrick m_synchronicity = eScriptedCommandSynchronicitySynchronous;
1455061da546Spatrick }
1456061da546Spatrick
GetDefinitions()1457061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1458*f6aab3d8Srobert return llvm::ArrayRef(g_script_add_options);
1459061da546Spatrick }
1460061da546Spatrick
1461061da546Spatrick // Instance variables to hold the values for command options.
1462061da546Spatrick
1463061da546Spatrick std::string m_class_name;
1464061da546Spatrick std::string m_funct_name;
1465061da546Spatrick std::string m_short_help;
1466*f6aab3d8Srobert LazyBool m_overwrite_lazy = eLazyBoolCalculate;
1467be691f3bSpatrick ScriptedCommandSynchronicity m_synchronicity =
1468be691f3bSpatrick eScriptedCommandSynchronicitySynchronous;
1469061da546Spatrick };
1470061da546Spatrick
IOHandlerActivated(IOHandler & io_handler,bool interactive)1471061da546Spatrick void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
1472061da546Spatrick StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
1473061da546Spatrick if (output_sp && interactive) {
1474061da546Spatrick output_sp->PutCString(g_python_command_instructions);
1475061da546Spatrick output_sp->Flush();
1476061da546Spatrick }
1477061da546Spatrick }
1478061da546Spatrick
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)1479061da546Spatrick void IOHandlerInputComplete(IOHandler &io_handler,
1480061da546Spatrick std::string &data) override {
1481061da546Spatrick StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
1482061da546Spatrick
1483061da546Spatrick ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1484061da546Spatrick if (interpreter) {
1485061da546Spatrick StringList lines;
1486061da546Spatrick lines.SplitIntoLines(data);
1487061da546Spatrick if (lines.GetSize() > 0) {
1488061da546Spatrick std::string funct_name_str;
1489061da546Spatrick if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
1490061da546Spatrick if (funct_name_str.empty()) {
1491061da546Spatrick error_sp->Printf("error: unable to obtain a function name, didn't "
1492061da546Spatrick "add python command.\n");
1493061da546Spatrick error_sp->Flush();
1494061da546Spatrick } else {
1495061da546Spatrick // everything should be fine now, let's add this alias
1496061da546Spatrick
1497061da546Spatrick CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
1498061da546Spatrick m_interpreter, m_cmd_name, funct_name_str, m_short_help,
1499061da546Spatrick m_synchronicity));
1500*f6aab3d8Srobert if (!m_container) {
1501*f6aab3d8Srobert Status error = m_interpreter.AddUserCommand(
1502*f6aab3d8Srobert m_cmd_name, command_obj_sp, m_overwrite);
1503*f6aab3d8Srobert if (error.Fail()) {
1504*f6aab3d8Srobert error_sp->Printf("error: unable to add selected command: '%s'",
1505*f6aab3d8Srobert error.AsCString());
1506061da546Spatrick error_sp->Flush();
1507061da546Spatrick }
1508*f6aab3d8Srobert } else {
1509*f6aab3d8Srobert llvm::Error llvm_error = m_container->LoadUserSubcommand(
1510*f6aab3d8Srobert m_cmd_name, command_obj_sp, m_overwrite);
1511*f6aab3d8Srobert if (llvm_error) {
1512*f6aab3d8Srobert error_sp->Printf("error: unable to add selected command: '%s'",
1513*f6aab3d8Srobert llvm::toString(std::move(llvm_error)).c_str());
1514*f6aab3d8Srobert error_sp->Flush();
1515*f6aab3d8Srobert }
1516*f6aab3d8Srobert }
1517061da546Spatrick }
1518061da546Spatrick } else {
1519061da546Spatrick error_sp->Printf(
1520*f6aab3d8Srobert "error: unable to create function, didn't add python command\n");
1521061da546Spatrick error_sp->Flush();
1522061da546Spatrick }
1523061da546Spatrick } else {
1524*f6aab3d8Srobert error_sp->Printf("error: empty function, didn't add python command\n");
1525061da546Spatrick error_sp->Flush();
1526061da546Spatrick }
1527061da546Spatrick } else {
1528061da546Spatrick error_sp->Printf(
1529*f6aab3d8Srobert "error: script interpreter missing, didn't add python command\n");
1530061da546Spatrick error_sp->Flush();
1531061da546Spatrick }
1532061da546Spatrick
1533061da546Spatrick io_handler.SetIsDone(true);
1534061da546Spatrick }
1535061da546Spatrick
DoExecute(Args & command,CommandReturnObject & result)1536061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1537061da546Spatrick if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
1538061da546Spatrick result.AppendError("only scripting language supported for scripted "
1539061da546Spatrick "commands is currently Python");
1540061da546Spatrick return false;
1541061da546Spatrick }
1542061da546Spatrick
1543*f6aab3d8Srobert if (command.GetArgumentCount() == 0) {
1544*f6aab3d8Srobert result.AppendError("'command script add' requires at least one argument");
1545*f6aab3d8Srobert return false;
1546*f6aab3d8Srobert }
1547*f6aab3d8Srobert // Store the options in case we get multi-line input, also figure out the
1548*f6aab3d8Srobert // default if not user supplied:
1549*f6aab3d8Srobert switch (m_options.m_overwrite_lazy) {
1550*f6aab3d8Srobert case eLazyBoolCalculate:
1551*f6aab3d8Srobert m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
1552*f6aab3d8Srobert break;
1553*f6aab3d8Srobert case eLazyBoolYes:
1554*f6aab3d8Srobert m_overwrite = true;
1555*f6aab3d8Srobert break;
1556*f6aab3d8Srobert case eLazyBoolNo:
1557*f6aab3d8Srobert m_overwrite = false;
1558*f6aab3d8Srobert }
1559*f6aab3d8Srobert
1560*f6aab3d8Srobert Status path_error;
1561*f6aab3d8Srobert m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
1562*f6aab3d8Srobert command, true, path_error);
1563*f6aab3d8Srobert
1564*f6aab3d8Srobert if (path_error.Fail()) {
1565*f6aab3d8Srobert result.AppendErrorWithFormat("error in command path: %s",
1566*f6aab3d8Srobert path_error.AsCString());
1567061da546Spatrick return false;
1568061da546Spatrick }
1569061da546Spatrick
1570*f6aab3d8Srobert if (!m_container) {
1571*f6aab3d8Srobert // This is getting inserted into the root of the interpreter.
1572dda28197Spatrick m_cmd_name = std::string(command[0].ref());
1573*f6aab3d8Srobert } else {
1574*f6aab3d8Srobert size_t num_args = command.GetArgumentCount();
1575*f6aab3d8Srobert m_cmd_name = std::string(command[num_args - 1].ref());
1576*f6aab3d8Srobert }
1577*f6aab3d8Srobert
1578061da546Spatrick m_short_help.assign(m_options.m_short_help);
1579061da546Spatrick m_synchronicity = m_options.m_synchronicity;
1580061da546Spatrick
1581*f6aab3d8Srobert // Handle the case where we prompt for the script code first:
1582*f6aab3d8Srobert if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
1583*f6aab3d8Srobert m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt
1584061da546Spatrick *this); // IOHandlerDelegate
1585*f6aab3d8Srobert return result.Succeeded();
1586*f6aab3d8Srobert }
1587*f6aab3d8Srobert
1588*f6aab3d8Srobert CommandObjectSP new_cmd_sp;
1589*f6aab3d8Srobert if (m_options.m_class_name.empty()) {
1590*f6aab3d8Srobert new_cmd_sp.reset(new CommandObjectPythonFunction(
1591061da546Spatrick m_interpreter, m_cmd_name, m_options.m_funct_name,
1592061da546Spatrick m_options.m_short_help, m_synchronicity));
1593061da546Spatrick } else {
1594061da546Spatrick ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1595061da546Spatrick if (!interpreter) {
1596061da546Spatrick result.AppendError("cannot find ScriptInterpreter");
1597061da546Spatrick return false;
1598061da546Spatrick }
1599061da546Spatrick
1600061da546Spatrick auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
1601061da546Spatrick m_options.m_class_name.c_str());
1602061da546Spatrick if (!cmd_obj_sp) {
1603061da546Spatrick result.AppendError("cannot create helper object");
1604061da546Spatrick return false;
1605061da546Spatrick }
1606061da546Spatrick
1607*f6aab3d8Srobert new_cmd_sp.reset(new CommandObjectScriptingObject(
1608061da546Spatrick m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity));
1609061da546Spatrick }
1610061da546Spatrick
1611*f6aab3d8Srobert // Assume we're going to succeed...
1612*f6aab3d8Srobert result.SetStatus(eReturnStatusSuccessFinishNoResult);
1613*f6aab3d8Srobert if (!m_container) {
1614*f6aab3d8Srobert Status add_error =
1615*f6aab3d8Srobert m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
1616*f6aab3d8Srobert if (add_error.Fail())
1617*f6aab3d8Srobert result.AppendErrorWithFormat("cannot add command: %s",
1618*f6aab3d8Srobert add_error.AsCString());
1619*f6aab3d8Srobert } else {
1620*f6aab3d8Srobert llvm::Error llvm_error =
1621*f6aab3d8Srobert m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
1622*f6aab3d8Srobert if (llvm_error)
1623*f6aab3d8Srobert result.AppendErrorWithFormat("cannot add command: %s",
1624*f6aab3d8Srobert llvm::toString(std::move(llvm_error)).c_str());
1625*f6aab3d8Srobert }
1626061da546Spatrick return result.Succeeded();
1627061da546Spatrick }
1628061da546Spatrick
1629061da546Spatrick CommandOptions m_options;
1630061da546Spatrick std::string m_cmd_name;
1631*f6aab3d8Srobert CommandObjectMultiword *m_container = nullptr;
1632061da546Spatrick std::string m_short_help;
1633*f6aab3d8Srobert bool m_overwrite = false;
1634*f6aab3d8Srobert ScriptedCommandSynchronicity m_synchronicity =
1635*f6aab3d8Srobert eScriptedCommandSynchronicitySynchronous;
1636061da546Spatrick };
1637061da546Spatrick
1638061da546Spatrick // CommandObjectCommandsScriptList
1639061da546Spatrick
1640061da546Spatrick class CommandObjectCommandsScriptList : public CommandObjectParsed {
1641061da546Spatrick public:
CommandObjectCommandsScriptList(CommandInterpreter & interpreter)1642061da546Spatrick CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
1643061da546Spatrick : CommandObjectParsed(interpreter, "command script list",
1644*f6aab3d8Srobert "List defined top-level scripted commands.",
1645*f6aab3d8Srobert nullptr) {}
1646061da546Spatrick
1647061da546Spatrick ~CommandObjectCommandsScriptList() override = default;
1648061da546Spatrick
DoExecute(Args & command,CommandReturnObject & result)1649061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1650061da546Spatrick m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
1651061da546Spatrick
1652061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1653061da546Spatrick
1654061da546Spatrick return true;
1655061da546Spatrick }
1656061da546Spatrick };
1657061da546Spatrick
1658061da546Spatrick // CommandObjectCommandsScriptClear
1659061da546Spatrick
1660061da546Spatrick class CommandObjectCommandsScriptClear : public CommandObjectParsed {
1661061da546Spatrick public:
CommandObjectCommandsScriptClear(CommandInterpreter & interpreter)1662061da546Spatrick CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
1663061da546Spatrick : CommandObjectParsed(interpreter, "command script clear",
1664061da546Spatrick "Delete all scripted commands.", nullptr) {}
1665061da546Spatrick
1666061da546Spatrick ~CommandObjectCommandsScriptClear() override = default;
1667061da546Spatrick
1668061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1669061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1670061da546Spatrick m_interpreter.RemoveAllUser();
1671061da546Spatrick
1672061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1673061da546Spatrick
1674061da546Spatrick return true;
1675061da546Spatrick }
1676061da546Spatrick };
1677061da546Spatrick
1678061da546Spatrick // CommandObjectCommandsScriptDelete
1679061da546Spatrick
1680061da546Spatrick class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
1681061da546Spatrick public:
CommandObjectCommandsScriptDelete(CommandInterpreter & interpreter)1682061da546Spatrick CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
1683*f6aab3d8Srobert : CommandObjectParsed(
1684*f6aab3d8Srobert interpreter, "command script delete",
1685*f6aab3d8Srobert "Delete a scripted command by specifying the path to the command.",
1686*f6aab3d8Srobert nullptr) {
1687061da546Spatrick CommandArgumentEntry arg1;
1688061da546Spatrick CommandArgumentData cmd_arg;
1689061da546Spatrick
1690*f6aab3d8Srobert // This is a list of command names forming the path to the command
1691*f6aab3d8Srobert // to be deleted.
1692*f6aab3d8Srobert cmd_arg.arg_type = eArgTypeCommand;
1693*f6aab3d8Srobert cmd_arg.arg_repetition = eArgRepeatPlus;
1694061da546Spatrick
1695061da546Spatrick // There is only one variant this argument could be; put it into the
1696061da546Spatrick // argument entry.
1697061da546Spatrick arg1.push_back(cmd_arg);
1698061da546Spatrick
1699061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1700061da546Spatrick m_arguments.push_back(arg1);
1701061da546Spatrick }
1702061da546Spatrick
1703061da546Spatrick ~CommandObjectCommandsScriptDelete() override = default;
1704061da546Spatrick
1705dda28197Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1706dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request,
1707dda28197Spatrick OptionElementVector &opt_element_vector) override {
1708*f6aab3d8Srobert CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1709*f6aab3d8Srobert opt_element_vector);
1710dda28197Spatrick }
1711dda28197Spatrick
1712061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1713061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1714061da546Spatrick
1715*f6aab3d8Srobert llvm::StringRef root_cmd = command[0].ref();
1716*f6aab3d8Srobert size_t num_args = command.GetArgumentCount();
1717*f6aab3d8Srobert
1718*f6aab3d8Srobert if (root_cmd.empty()) {
1719*f6aab3d8Srobert result.AppendErrorWithFormat("empty root command name");
1720*f6aab3d8Srobert return false;
1721*f6aab3d8Srobert }
1722*f6aab3d8Srobert if (!m_interpreter.HasUserCommands() &&
1723*f6aab3d8Srobert !m_interpreter.HasUserMultiwordCommands()) {
1724*f6aab3d8Srobert result.AppendErrorWithFormat("can only delete user defined commands, "
1725*f6aab3d8Srobert "but no user defined commands found");
1726061da546Spatrick return false;
1727061da546Spatrick }
1728061da546Spatrick
1729*f6aab3d8Srobert CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
1730*f6aab3d8Srobert if (!cmd_sp) {
1731*f6aab3d8Srobert result.AppendErrorWithFormat("command '%s' not found.",
1732*f6aab3d8Srobert command[0].c_str());
1733*f6aab3d8Srobert return false;
1734*f6aab3d8Srobert }
1735*f6aab3d8Srobert if (!cmd_sp->IsUserCommand()) {
1736*f6aab3d8Srobert result.AppendErrorWithFormat("command '%s' is not a user command.",
1737*f6aab3d8Srobert command[0].c_str());
1738*f6aab3d8Srobert return false;
1739*f6aab3d8Srobert }
1740*f6aab3d8Srobert if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
1741*f6aab3d8Srobert result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
1742*f6aab3d8Srobert "Delete with \"command container delete\"",
1743*f6aab3d8Srobert command[0].c_str());
1744061da546Spatrick return false;
1745061da546Spatrick }
1746061da546Spatrick
1747*f6aab3d8Srobert if (command.GetArgumentCount() == 1) {
1748*f6aab3d8Srobert m_interpreter.RemoveUser(root_cmd);
1749*f6aab3d8Srobert result.SetStatus(eReturnStatusSuccessFinishResult);
1750*f6aab3d8Srobert return true;
1751*f6aab3d8Srobert }
1752*f6aab3d8Srobert // We're deleting a command from a multiword command. Verify the command
1753*f6aab3d8Srobert // path:
1754*f6aab3d8Srobert Status error;
1755*f6aab3d8Srobert CommandObjectMultiword *container =
1756*f6aab3d8Srobert GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1757*f6aab3d8Srobert error);
1758*f6aab3d8Srobert if (error.Fail()) {
1759*f6aab3d8Srobert result.AppendErrorWithFormat("could not resolve command path: %s",
1760*f6aab3d8Srobert error.AsCString());
1761*f6aab3d8Srobert return false;
1762*f6aab3d8Srobert }
1763*f6aab3d8Srobert if (!container) {
1764*f6aab3d8Srobert // This means that command only had a leaf command, so the container is
1765*f6aab3d8Srobert // the root. That should have been handled above.
1766*f6aab3d8Srobert result.AppendErrorWithFormat("could not find a container for '%s'",
1767*f6aab3d8Srobert command[0].c_str());
1768*f6aab3d8Srobert return false;
1769*f6aab3d8Srobert }
1770*f6aab3d8Srobert const char *leaf_cmd = command[num_args - 1].c_str();
1771*f6aab3d8Srobert llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd,
1772*f6aab3d8Srobert /* multiword not okay */ false);
1773*f6aab3d8Srobert if (llvm_error) {
1774*f6aab3d8Srobert result.AppendErrorWithFormat("could not delete command '%s': %s",
1775*f6aab3d8Srobert leaf_cmd,
1776*f6aab3d8Srobert llvm::toString(std::move(llvm_error)).c_str());
1777*f6aab3d8Srobert return false;
1778*f6aab3d8Srobert }
1779*f6aab3d8Srobert
1780*f6aab3d8Srobert Stream &out_stream = result.GetOutputStream();
1781*f6aab3d8Srobert
1782*f6aab3d8Srobert out_stream << "Deleted command:";
1783*f6aab3d8Srobert for (size_t idx = 0; idx < num_args; idx++) {
1784*f6aab3d8Srobert out_stream << ' ';
1785*f6aab3d8Srobert out_stream << command[idx].c_str();
1786*f6aab3d8Srobert }
1787*f6aab3d8Srobert out_stream << '\n';
1788061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1789061da546Spatrick return true;
1790061da546Spatrick }
1791061da546Spatrick };
1792061da546Spatrick
1793061da546Spatrick #pragma mark CommandObjectMultiwordCommandsScript
1794061da546Spatrick
1795061da546Spatrick // CommandObjectMultiwordCommandsScript
1796061da546Spatrick
1797061da546Spatrick class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
1798061da546Spatrick public:
CommandObjectMultiwordCommandsScript(CommandInterpreter & interpreter)1799061da546Spatrick CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
1800061da546Spatrick : CommandObjectMultiword(
1801061da546Spatrick interpreter, "command script",
1802061da546Spatrick "Commands for managing custom "
1803061da546Spatrick "commands implemented by "
1804061da546Spatrick "interpreter scripts.",
1805061da546Spatrick "command script <subcommand> [<subcommand-options>]") {
1806061da546Spatrick LoadSubCommand("add", CommandObjectSP(
1807061da546Spatrick new CommandObjectCommandsScriptAdd(interpreter)));
1808061da546Spatrick LoadSubCommand(
1809061da546Spatrick "delete",
1810061da546Spatrick CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
1811061da546Spatrick LoadSubCommand(
1812061da546Spatrick "clear",
1813061da546Spatrick CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
1814061da546Spatrick LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
1815061da546Spatrick interpreter)));
1816061da546Spatrick LoadSubCommand(
1817061da546Spatrick "import",
1818061da546Spatrick CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
1819061da546Spatrick }
1820061da546Spatrick
1821061da546Spatrick ~CommandObjectMultiwordCommandsScript() override = default;
1822061da546Spatrick };
1823061da546Spatrick
1824*f6aab3d8Srobert #pragma mark CommandObjectCommandContainer
1825*f6aab3d8Srobert #define LLDB_OPTIONS_container_add
1826*f6aab3d8Srobert #include "CommandOptions.inc"
1827*f6aab3d8Srobert
1828*f6aab3d8Srobert class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
1829*f6aab3d8Srobert public:
CommandObjectCommandsContainerAdd(CommandInterpreter & interpreter)1830*f6aab3d8Srobert CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter)
1831*f6aab3d8Srobert : CommandObjectParsed(
1832*f6aab3d8Srobert interpreter, "command container add",
1833*f6aab3d8Srobert "Add a container command to lldb. Adding to built-"
1834*f6aab3d8Srobert "in container commands is not allowed.",
1835*f6aab3d8Srobert "command container add [[path1]...] container-name") {
1836*f6aab3d8Srobert CommandArgumentEntry arg1;
1837*f6aab3d8Srobert CommandArgumentData cmd_arg;
1838*f6aab3d8Srobert
1839*f6aab3d8Srobert // This is one or more command names, which form the path to the command
1840*f6aab3d8Srobert // you want to add.
1841*f6aab3d8Srobert cmd_arg.arg_type = eArgTypeCommand;
1842*f6aab3d8Srobert cmd_arg.arg_repetition = eArgRepeatPlus;
1843*f6aab3d8Srobert
1844*f6aab3d8Srobert // There is only one variant this argument could be; put it into the
1845*f6aab3d8Srobert // argument entry.
1846*f6aab3d8Srobert arg1.push_back(cmd_arg);
1847*f6aab3d8Srobert
1848*f6aab3d8Srobert // Push the data for the first argument into the m_arguments vector.
1849*f6aab3d8Srobert m_arguments.push_back(arg1);
1850*f6aab3d8Srobert }
1851*f6aab3d8Srobert
1852*f6aab3d8Srobert ~CommandObjectCommandsContainerAdd() override = default;
1853*f6aab3d8Srobert
GetOptions()1854*f6aab3d8Srobert Options *GetOptions() override { return &m_options; }
1855*f6aab3d8Srobert
1856*f6aab3d8Srobert void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1857*f6aab3d8Srobert HandleArgumentCompletion(CompletionRequest &request,
1858*f6aab3d8Srobert OptionElementVector &opt_element_vector) override {
1859*f6aab3d8Srobert CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1860*f6aab3d8Srobert opt_element_vector);
1861*f6aab3d8Srobert }
1862*f6aab3d8Srobert
1863*f6aab3d8Srobert protected:
1864*f6aab3d8Srobert class CommandOptions : public Options {
1865*f6aab3d8Srobert public:
1866*f6aab3d8Srobert CommandOptions() = default;
1867*f6aab3d8Srobert
1868*f6aab3d8Srobert ~CommandOptions() override = default;
1869*f6aab3d8Srobert
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1870*f6aab3d8Srobert Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1871*f6aab3d8Srobert ExecutionContext *execution_context) override {
1872*f6aab3d8Srobert Status error;
1873*f6aab3d8Srobert const int short_option = m_getopt_table[option_idx].val;
1874*f6aab3d8Srobert
1875*f6aab3d8Srobert switch (short_option) {
1876*f6aab3d8Srobert case 'h':
1877*f6aab3d8Srobert if (!option_arg.empty())
1878*f6aab3d8Srobert m_short_help = std::string(option_arg);
1879*f6aab3d8Srobert break;
1880*f6aab3d8Srobert case 'o':
1881*f6aab3d8Srobert m_overwrite = true;
1882*f6aab3d8Srobert break;
1883*f6aab3d8Srobert case 'H':
1884*f6aab3d8Srobert if (!option_arg.empty())
1885*f6aab3d8Srobert m_long_help = std::string(option_arg);
1886*f6aab3d8Srobert break;
1887*f6aab3d8Srobert default:
1888*f6aab3d8Srobert llvm_unreachable("Unimplemented option");
1889*f6aab3d8Srobert }
1890*f6aab3d8Srobert
1891*f6aab3d8Srobert return error;
1892*f6aab3d8Srobert }
1893*f6aab3d8Srobert
OptionParsingStarting(ExecutionContext * execution_context)1894*f6aab3d8Srobert void OptionParsingStarting(ExecutionContext *execution_context) override {
1895*f6aab3d8Srobert m_short_help.clear();
1896*f6aab3d8Srobert m_long_help.clear();
1897*f6aab3d8Srobert m_overwrite = false;
1898*f6aab3d8Srobert }
1899*f6aab3d8Srobert
GetDefinitions()1900*f6aab3d8Srobert llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1901*f6aab3d8Srobert return llvm::ArrayRef(g_container_add_options);
1902*f6aab3d8Srobert }
1903*f6aab3d8Srobert
1904*f6aab3d8Srobert // Instance variables to hold the values for command options.
1905*f6aab3d8Srobert
1906*f6aab3d8Srobert std::string m_short_help;
1907*f6aab3d8Srobert std::string m_long_help;
1908*f6aab3d8Srobert bool m_overwrite = false;
1909*f6aab3d8Srobert };
DoExecute(Args & command,CommandReturnObject & result)1910*f6aab3d8Srobert bool DoExecute(Args &command, CommandReturnObject &result) override {
1911*f6aab3d8Srobert size_t num_args = command.GetArgumentCount();
1912*f6aab3d8Srobert
1913*f6aab3d8Srobert if (num_args == 0) {
1914*f6aab3d8Srobert result.AppendError("no command was specified");
1915*f6aab3d8Srobert return false;
1916*f6aab3d8Srobert }
1917*f6aab3d8Srobert
1918*f6aab3d8Srobert if (num_args == 1) {
1919*f6aab3d8Srobert // We're adding this as a root command, so use the interpreter.
1920*f6aab3d8Srobert const char *cmd_name = command.GetArgumentAtIndex(0);
1921*f6aab3d8Srobert auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
1922*f6aab3d8Srobert GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
1923*f6aab3d8Srobert m_options.m_long_help.c_str()));
1924*f6aab3d8Srobert cmd_sp->GetAsMultiwordCommand()->SetRemovable(true);
1925*f6aab3d8Srobert Status add_error = GetCommandInterpreter().AddUserCommand(
1926*f6aab3d8Srobert cmd_name, cmd_sp, m_options.m_overwrite);
1927*f6aab3d8Srobert if (add_error.Fail()) {
1928*f6aab3d8Srobert result.AppendErrorWithFormat("error adding command: %s",
1929*f6aab3d8Srobert add_error.AsCString());
1930*f6aab3d8Srobert return false;
1931*f6aab3d8Srobert }
1932*f6aab3d8Srobert result.SetStatus(eReturnStatusSuccessFinishNoResult);
1933*f6aab3d8Srobert return true;
1934*f6aab3d8Srobert }
1935*f6aab3d8Srobert
1936*f6aab3d8Srobert // We're adding this to a subcommand, first find the subcommand:
1937*f6aab3d8Srobert Status path_error;
1938*f6aab3d8Srobert CommandObjectMultiword *add_to_me =
1939*f6aab3d8Srobert GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1940*f6aab3d8Srobert path_error);
1941*f6aab3d8Srobert
1942*f6aab3d8Srobert if (!add_to_me) {
1943*f6aab3d8Srobert result.AppendErrorWithFormat("error adding command: %s",
1944*f6aab3d8Srobert path_error.AsCString());
1945*f6aab3d8Srobert return false;
1946*f6aab3d8Srobert }
1947*f6aab3d8Srobert
1948*f6aab3d8Srobert const char *cmd_name = command.GetArgumentAtIndex(num_args - 1);
1949*f6aab3d8Srobert auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
1950*f6aab3d8Srobert GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
1951*f6aab3d8Srobert m_options.m_long_help.c_str()));
1952*f6aab3d8Srobert llvm::Error llvm_error =
1953*f6aab3d8Srobert add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite);
1954*f6aab3d8Srobert if (llvm_error) {
1955*f6aab3d8Srobert result.AppendErrorWithFormat("error adding subcommand: %s",
1956*f6aab3d8Srobert llvm::toString(std::move(llvm_error)).c_str());
1957*f6aab3d8Srobert return false;
1958*f6aab3d8Srobert }
1959*f6aab3d8Srobert
1960*f6aab3d8Srobert result.SetStatus(eReturnStatusSuccessFinishNoResult);
1961*f6aab3d8Srobert return true;
1962*f6aab3d8Srobert }
1963*f6aab3d8Srobert
1964*f6aab3d8Srobert private:
1965*f6aab3d8Srobert CommandOptions m_options;
1966*f6aab3d8Srobert };
1967*f6aab3d8Srobert
1968*f6aab3d8Srobert #define LLDB_OPTIONS_multiword_delete
1969*f6aab3d8Srobert #include "CommandOptions.inc"
1970*f6aab3d8Srobert class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
1971*f6aab3d8Srobert public:
CommandObjectCommandsContainerDelete(CommandInterpreter & interpreter)1972*f6aab3d8Srobert CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
1973*f6aab3d8Srobert : CommandObjectParsed(
1974*f6aab3d8Srobert interpreter, "command container delete",
1975*f6aab3d8Srobert "Delete a container command previously added to "
1976*f6aab3d8Srobert "lldb.",
1977*f6aab3d8Srobert "command container delete [[path1] ...] container-cmd") {
1978*f6aab3d8Srobert CommandArgumentEntry arg1;
1979*f6aab3d8Srobert CommandArgumentData cmd_arg;
1980*f6aab3d8Srobert
1981*f6aab3d8Srobert // This is one or more command names, which form the path to the command
1982*f6aab3d8Srobert // you want to add.
1983*f6aab3d8Srobert cmd_arg.arg_type = eArgTypeCommand;
1984*f6aab3d8Srobert cmd_arg.arg_repetition = eArgRepeatPlus;
1985*f6aab3d8Srobert
1986*f6aab3d8Srobert // There is only one variant this argument could be; put it into the
1987*f6aab3d8Srobert // argument entry.
1988*f6aab3d8Srobert arg1.push_back(cmd_arg);
1989*f6aab3d8Srobert
1990*f6aab3d8Srobert // Push the data for the first argument into the m_arguments vector.
1991*f6aab3d8Srobert m_arguments.push_back(arg1);
1992*f6aab3d8Srobert }
1993*f6aab3d8Srobert
1994*f6aab3d8Srobert ~CommandObjectCommandsContainerDelete() override = default;
1995*f6aab3d8Srobert
1996*f6aab3d8Srobert void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1997*f6aab3d8Srobert HandleArgumentCompletion(CompletionRequest &request,
1998*f6aab3d8Srobert OptionElementVector &opt_element_vector) override {
1999*f6aab3d8Srobert CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
2000*f6aab3d8Srobert opt_element_vector);
2001*f6aab3d8Srobert }
2002*f6aab3d8Srobert
2003*f6aab3d8Srobert protected:
DoExecute(Args & command,CommandReturnObject & result)2004*f6aab3d8Srobert bool DoExecute(Args &command, CommandReturnObject &result) override {
2005*f6aab3d8Srobert size_t num_args = command.GetArgumentCount();
2006*f6aab3d8Srobert
2007*f6aab3d8Srobert if (num_args == 0) {
2008*f6aab3d8Srobert result.AppendError("No command was specified.");
2009*f6aab3d8Srobert return false;
2010*f6aab3d8Srobert }
2011*f6aab3d8Srobert
2012*f6aab3d8Srobert if (num_args == 1) {
2013*f6aab3d8Srobert // We're removing a root command, so we need to delete it from the
2014*f6aab3d8Srobert // interpreter.
2015*f6aab3d8Srobert const char *cmd_name = command.GetArgumentAtIndex(0);
2016*f6aab3d8Srobert // Let's do a little more work here so we can do better error reporting.
2017*f6aab3d8Srobert CommandInterpreter &interp = GetCommandInterpreter();
2018*f6aab3d8Srobert CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2019*f6aab3d8Srobert if (!cmd_sp) {
2020*f6aab3d8Srobert result.AppendErrorWithFormat("container command %s doesn't exist.",
2021*f6aab3d8Srobert cmd_name);
2022*f6aab3d8Srobert return false;
2023*f6aab3d8Srobert }
2024*f6aab3d8Srobert if (!cmd_sp->IsUserCommand()) {
2025*f6aab3d8Srobert result.AppendErrorWithFormat(
2026*f6aab3d8Srobert "container command %s is not a user command", cmd_name);
2027*f6aab3d8Srobert return false;
2028*f6aab3d8Srobert }
2029*f6aab3d8Srobert if (!cmd_sp->GetAsMultiwordCommand()) {
2030*f6aab3d8Srobert result.AppendErrorWithFormat("command %s is not a container command",
2031*f6aab3d8Srobert cmd_name);
2032*f6aab3d8Srobert return false;
2033*f6aab3d8Srobert }
2034*f6aab3d8Srobert
2035*f6aab3d8Srobert bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2036*f6aab3d8Srobert if (!did_remove) {
2037*f6aab3d8Srobert result.AppendErrorWithFormat("error removing command %s.", cmd_name);
2038*f6aab3d8Srobert return false;
2039*f6aab3d8Srobert }
2040*f6aab3d8Srobert
2041*f6aab3d8Srobert result.SetStatus(eReturnStatusSuccessFinishNoResult);
2042*f6aab3d8Srobert return true;
2043*f6aab3d8Srobert }
2044*f6aab3d8Srobert
2045*f6aab3d8Srobert // We're removing a subcommand, first find the subcommand's owner:
2046*f6aab3d8Srobert Status path_error;
2047*f6aab3d8Srobert CommandObjectMultiword *container =
2048*f6aab3d8Srobert GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2049*f6aab3d8Srobert path_error);
2050*f6aab3d8Srobert
2051*f6aab3d8Srobert if (!container) {
2052*f6aab3d8Srobert result.AppendErrorWithFormat("error removing container command: %s",
2053*f6aab3d8Srobert path_error.AsCString());
2054*f6aab3d8Srobert return false;
2055*f6aab3d8Srobert }
2056*f6aab3d8Srobert const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2057*f6aab3d8Srobert llvm::Error llvm_error =
2058*f6aab3d8Srobert container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2059*f6aab3d8Srobert if (llvm_error) {
2060*f6aab3d8Srobert result.AppendErrorWithFormat("error removing container command: %s",
2061*f6aab3d8Srobert llvm::toString(std::move(llvm_error)).c_str());
2062*f6aab3d8Srobert return false;
2063*f6aab3d8Srobert }
2064*f6aab3d8Srobert result.SetStatus(eReturnStatusSuccessFinishNoResult);
2065*f6aab3d8Srobert return true;
2066*f6aab3d8Srobert }
2067*f6aab3d8Srobert };
2068*f6aab3d8Srobert
2069*f6aab3d8Srobert class CommandObjectCommandContainer : public CommandObjectMultiword {
2070*f6aab3d8Srobert public:
CommandObjectCommandContainer(CommandInterpreter & interpreter)2071*f6aab3d8Srobert CommandObjectCommandContainer(CommandInterpreter &interpreter)
2072*f6aab3d8Srobert : CommandObjectMultiword(
2073*f6aab3d8Srobert interpreter, "command container",
2074*f6aab3d8Srobert "Commands for adding container commands to lldb. "
2075*f6aab3d8Srobert "Container commands are containers for other commands. You can "
2076*f6aab3d8Srobert "add nested container commands by specifying a command path, "
2077*f6aab3d8Srobert "but you can't add commands into the built-in command hierarchy.",
2078*f6aab3d8Srobert "command container <subcommand> [<subcommand-options>]") {
2079*f6aab3d8Srobert LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2080*f6aab3d8Srobert interpreter)));
2081*f6aab3d8Srobert LoadSubCommand(
2082*f6aab3d8Srobert "delete",
2083*f6aab3d8Srobert CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2084*f6aab3d8Srobert }
2085*f6aab3d8Srobert
2086*f6aab3d8Srobert ~CommandObjectCommandContainer() override = default;
2087*f6aab3d8Srobert };
2088*f6aab3d8Srobert
2089061da546Spatrick #pragma mark CommandObjectMultiwordCommands
2090061da546Spatrick
2091061da546Spatrick // CommandObjectMultiwordCommands
2092061da546Spatrick
CommandObjectMultiwordCommands(CommandInterpreter & interpreter)2093061da546Spatrick CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
2094061da546Spatrick CommandInterpreter &interpreter)
2095061da546Spatrick : CommandObjectMultiword(interpreter, "command",
2096061da546Spatrick "Commands for managing custom LLDB commands.",
2097061da546Spatrick "command <subcommand> [<subcommand-options>]") {
2098061da546Spatrick LoadSubCommand("source",
2099061da546Spatrick CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
2100061da546Spatrick LoadSubCommand("alias",
2101061da546Spatrick CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
2102061da546Spatrick LoadSubCommand("unalias", CommandObjectSP(
2103061da546Spatrick new CommandObjectCommandsUnalias(interpreter)));
2104061da546Spatrick LoadSubCommand("delete",
2105061da546Spatrick CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2106*f6aab3d8Srobert LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2107*f6aab3d8Srobert interpreter)));
2108061da546Spatrick LoadSubCommand(
2109061da546Spatrick "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
2110061da546Spatrick LoadSubCommand(
2111061da546Spatrick "script",
2112061da546Spatrick CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
2113061da546Spatrick }
2114061da546Spatrick
2115061da546Spatrick CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2116