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 &current_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 &regex_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