xref: /llvm-project/lldb/source/Commands/CommandObjectCommands.cpp (revision b9c1b51e45b845debb76d8658edabca70ca56079)
1 //===-- CommandObjectSource.cpp ---------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 #include "llvm/ADT/StringRef.h"
14 
15 // Project includes
16 #include "CommandObjectCommands.h"
17 #include "CommandObjectHelp.h"
18 #include "lldb/Core/Debugger.h"
19 #include "lldb/Core/IOHandler.h"
20 #include "lldb/Core/StringList.h"
21 #include "lldb/Interpreter/Args.h"
22 #include "lldb/Interpreter/CommandHistory.h"
23 #include "lldb/Interpreter/CommandInterpreter.h"
24 #include "lldb/Interpreter/CommandObjectRegexCommand.h"
25 #include "lldb/Interpreter/CommandReturnObject.h"
26 #include "lldb/Interpreter/OptionValueBoolean.h"
27 #include "lldb/Interpreter/OptionValueString.h"
28 #include "lldb/Interpreter/OptionValueUInt64.h"
29 #include "lldb/Interpreter/Options.h"
30 #include "lldb/Interpreter/ScriptInterpreter.h"
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 
35 //-------------------------------------------------------------------------
36 // CommandObjectCommandsSource
37 //-------------------------------------------------------------------------
38 
39 class CommandObjectCommandsHistory : public CommandObjectParsed {
40 public:
41   CommandObjectCommandsHistory(CommandInterpreter &interpreter)
42       : CommandObjectParsed(interpreter, "command history",
43                             "Dump the history of commands in this session.",
44                             nullptr),
45         m_options() {}
46 
47   ~CommandObjectCommandsHistory() override = default;
48 
49   Options *GetOptions() override { return &m_options; }
50 
51 protected:
52   class CommandOptions : public Options {
53   public:
54     CommandOptions()
55         : Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) {
56     }
57 
58     ~CommandOptions() override = default;
59 
60     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
61                          ExecutionContext *execution_context) override {
62       Error error;
63       const int short_option = m_getopt_table[option_idx].val;
64 
65       switch (short_option) {
66       case 'c':
67         error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign);
68         break;
69       case 's':
70         if (option_arg && strcmp("end", option_arg) == 0) {
71           m_start_idx.SetCurrentValue(UINT64_MAX);
72           m_start_idx.SetOptionWasSet();
73         } else
74           error = m_start_idx.SetValueFromString(option_arg,
75                                                  eVarSetOperationAssign);
76         break;
77       case 'e':
78         error =
79             m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign);
80         break;
81       case 'C':
82         m_clear.SetCurrentValue(true);
83         m_clear.SetOptionWasSet();
84         break;
85       default:
86         error.SetErrorStringWithFormat("unrecognized option '%c'",
87                                        short_option);
88         break;
89       }
90 
91       return error;
92     }
93 
94     void OptionParsingStarting(ExecutionContext *execution_context) override {
95       m_start_idx.Clear();
96       m_stop_idx.Clear();
97       m_count.Clear();
98       m_clear.Clear();
99     }
100 
101     const OptionDefinition *GetDefinitions() override { return g_option_table; }
102 
103     // Options table: Required for subclasses of Options.
104 
105     static OptionDefinition g_option_table[];
106 
107     // Instance variables to hold the values for command options.
108 
109     OptionValueUInt64 m_start_idx;
110     OptionValueUInt64 m_stop_idx;
111     OptionValueUInt64 m_count;
112     OptionValueBoolean m_clear;
113   };
114 
115   bool DoExecute(Args &command, CommandReturnObject &result) override {
116     if (m_options.m_clear.GetCurrentValue() &&
117         m_options.m_clear.OptionWasSet()) {
118       m_interpreter.GetCommandHistory().Clear();
119       result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
120     } else {
121       if (m_options.m_start_idx.OptionWasSet() &&
122           m_options.m_stop_idx.OptionWasSet() &&
123           m_options.m_count.OptionWasSet()) {
124         result.AppendError("--count, --start-index and --end-index cannot be "
125                            "all specified in the same invocation");
126         result.SetStatus(lldb::eReturnStatusFailed);
127       } else {
128         std::pair<bool, uint64_t> start_idx(
129             m_options.m_start_idx.OptionWasSet(),
130             m_options.m_start_idx.GetCurrentValue());
131         std::pair<bool, uint64_t> stop_idx(
132             m_options.m_stop_idx.OptionWasSet(),
133             m_options.m_stop_idx.GetCurrentValue());
134         std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(),
135                                         m_options.m_count.GetCurrentValue());
136 
137         const CommandHistory &history(m_interpreter.GetCommandHistory());
138 
139         if (start_idx.first && start_idx.second == UINT64_MAX) {
140           if (count.first) {
141             start_idx.second = history.GetSize() - count.second;
142             stop_idx.second = history.GetSize() - 1;
143           } else if (stop_idx.first) {
144             start_idx.second = stop_idx.second;
145             stop_idx.second = history.GetSize() - 1;
146           } else {
147             start_idx.second = 0;
148             stop_idx.second = history.GetSize() - 1;
149           }
150         } else {
151           if (!start_idx.first && !stop_idx.first && !count.first) {
152             start_idx.second = 0;
153             stop_idx.second = history.GetSize() - 1;
154           } else if (start_idx.first) {
155             if (count.first) {
156               stop_idx.second = start_idx.second + count.second - 1;
157             } else if (!stop_idx.first) {
158               stop_idx.second = history.GetSize() - 1;
159             }
160           } else if (stop_idx.first) {
161             if (count.first) {
162               if (stop_idx.second >= count.second)
163                 start_idx.second = stop_idx.second - count.second + 1;
164               else
165                 start_idx.second = 0;
166             }
167           } else /* if (count.first) */
168           {
169             start_idx.second = 0;
170             stop_idx.second = count.second - 1;
171           }
172         }
173         history.Dump(result.GetOutputStream(), start_idx.second,
174                      stop_idx.second);
175       }
176     }
177     return result.Succeeded();
178   }
179 
180   CommandOptions m_options;
181 };
182 
183 OptionDefinition
184     CommandObjectCommandsHistory::CommandOptions::g_option_table[] = {
185         // clang-format off
186   {LLDB_OPT_SET_1, false, "count",       'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "How many history commands to print."},
187   {LLDB_OPT_SET_1, false, "start-index", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)."},
188   {LLDB_OPT_SET_1, false, "end-index",   'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands."},
189   {LLDB_OPT_SET_2, false, "clear",       'C', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeBoolean,         "Clears the current command history."},
190   {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
191         // clang-format on
192 };
193 
194 //-------------------------------------------------------------------------
195 // CommandObjectCommandsSource
196 //-------------------------------------------------------------------------
197 
198 class CommandObjectCommandsSource : public CommandObjectParsed {
199 public:
200   CommandObjectCommandsSource(CommandInterpreter &interpreter)
201       : CommandObjectParsed(
202             interpreter, "command source",
203             "Read and execute LLDB commands from the file <filename>.",
204             nullptr),
205         m_options() {
206     CommandArgumentEntry arg;
207     CommandArgumentData file_arg;
208 
209     // Define the first (and only) variant of this arg.
210     file_arg.arg_type = eArgTypeFilename;
211     file_arg.arg_repetition = eArgRepeatPlain;
212 
213     // There is only one variant this argument could be; put it into the
214     // argument entry.
215     arg.push_back(file_arg);
216 
217     // Push the data for the first argument into the m_arguments vector.
218     m_arguments.push_back(arg);
219   }
220 
221   ~CommandObjectCommandsSource() override = default;
222 
223   const char *GetRepeatCommand(Args &current_command_args,
224                                uint32_t index) override {
225     return "";
226   }
227 
228   int HandleArgumentCompletion(Args &input, int &cursor_index,
229                                int &cursor_char_position,
230                                OptionElementVector &opt_element_vector,
231                                int match_start_point, int max_return_elements,
232                                bool &word_complete,
233                                StringList &matches) override {
234     std::string completion_str(input.GetArgumentAtIndex(cursor_index));
235     completion_str.erase(cursor_char_position);
236 
237     CommandCompletions::InvokeCommonCompletionCallbacks(
238         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
239         completion_str.c_str(), match_start_point, max_return_elements, nullptr,
240         word_complete, matches);
241     return matches.GetSize();
242   }
243 
244   Options *GetOptions() override { return &m_options; }
245 
246 protected:
247   class CommandOptions : public Options {
248   public:
249     CommandOptions()
250         : Options(), m_stop_on_error(true), m_silent_run(false),
251           m_stop_on_continue(true) {}
252 
253     ~CommandOptions() override = default;
254 
255     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
256                          ExecutionContext *execution_context) override {
257       Error error;
258       const int short_option = m_getopt_table[option_idx].val;
259 
260       switch (short_option) {
261       case 'e':
262         error = m_stop_on_error.SetValueFromString(option_arg);
263         break;
264 
265       case 'c':
266         error = m_stop_on_continue.SetValueFromString(option_arg);
267         break;
268 
269       case 's':
270         error = m_silent_run.SetValueFromString(option_arg);
271         break;
272 
273       default:
274         error.SetErrorStringWithFormat("unrecognized option '%c'",
275                                        short_option);
276         break;
277       }
278 
279       return error;
280     }
281 
282     void OptionParsingStarting(ExecutionContext *execution_context) override {
283       m_stop_on_error.Clear();
284       m_silent_run.Clear();
285       m_stop_on_continue.Clear();
286     }
287 
288     const OptionDefinition *GetDefinitions() override { return g_option_table; }
289 
290     // Options table: Required for subclasses of Options.
291 
292     static OptionDefinition g_option_table[];
293 
294     // Instance variables to hold the values for command options.
295 
296     OptionValueBoolean m_stop_on_error;
297     OptionValueBoolean m_silent_run;
298     OptionValueBoolean m_stop_on_continue;
299   };
300 
301   bool DoExecute(Args &command, CommandReturnObject &result) override {
302     const size_t argc = command.GetArgumentCount();
303     if (argc == 1) {
304       const char *filename = command.GetArgumentAtIndex(0);
305 
306       FileSpec cmd_file(filename, true);
307       ExecutionContext *exe_ctx = nullptr; // Just use the default context.
308 
309       // If any options were set, then use them
310       if (m_options.m_stop_on_error.OptionWasSet() ||
311           m_options.m_silent_run.OptionWasSet() ||
312           m_options.m_stop_on_continue.OptionWasSet()) {
313         // Use user set settings
314         CommandInterpreterRunOptions options;
315         options.SetStopOnContinue(
316             m_options.m_stop_on_continue.GetCurrentValue());
317         options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
318         options.SetEchoCommands(!m_options.m_silent_run.GetCurrentValue());
319         options.SetPrintResults(!m_options.m_silent_run.GetCurrentValue());
320 
321         m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options,
322                                              result);
323       } else {
324         // No options were set, inherit any settings from nested "command
325         // source" commands,
326         // or set to sane default settings...
327         CommandInterpreterRunOptions options;
328         m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options,
329                                              result);
330       }
331     } else {
332       result.AppendErrorWithFormat(
333           "'%s' takes exactly one executable filename argument.\n",
334           GetCommandName());
335       result.SetStatus(eReturnStatusFailed);
336     }
337     return result.Succeeded();
338   }
339 
340   CommandOptions m_options;
341 };
342 
343 OptionDefinition CommandObjectCommandsSource::CommandOptions::g_option_table[] =
344     {
345         // clang-format off
346   {LLDB_OPT_SET_ALL, false, "stop-on-error",    'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on error."},
347   {LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on continue."},
348   {LLDB_OPT_SET_ALL, false, "silent-run",       's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true don't echo commands while executing."},
349   {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
350         // clang-format on
351 };
352 
353 #pragma mark CommandObjectCommandsAlias
354 //-------------------------------------------------------------------------
355 // CommandObjectCommandsAlias
356 //-------------------------------------------------------------------------
357 
358 static const char *g_python_command_instructions =
359     "Enter your Python command(s). Type 'DONE' to end.\n"
360     "You must define a Python function with this signature:\n"
361     "def my_command_impl(debugger, args, result, internal_dict):\n";
362 
363 class CommandObjectCommandsAlias : public CommandObjectRaw {
364 protected:
365   class CommandOptions : public OptionGroup {
366   public:
367     CommandOptions() : OptionGroup(), m_help(), m_long_help() {}
368 
369     ~CommandOptions() override = default;
370 
371     uint32_t GetNumDefinitions() override { return 3; }
372 
373     const OptionDefinition *GetDefinitions() override { return g_option_table; }
374 
375     Error SetOptionValue(uint32_t option_idx, const char *option_value,
376                          ExecutionContext *execution_context) override {
377       Error error;
378 
379       const int short_option = g_option_table[option_idx].short_option;
380 
381       switch (short_option) {
382       case 'h':
383         m_help.SetCurrentValue(option_value);
384         m_help.SetOptionWasSet();
385         break;
386 
387       case 'H':
388         m_long_help.SetCurrentValue(option_value);
389         m_long_help.SetOptionWasSet();
390         break;
391 
392       default:
393         error.SetErrorStringWithFormat("invalid short option character '%c'",
394                                        short_option);
395         break;
396       }
397 
398       return error;
399     }
400 
401     void OptionParsingStarting(ExecutionContext *execution_context) override {
402       m_help.Clear();
403       m_long_help.Clear();
404     }
405 
406     // Options table: Required for subclasses of Options.
407 
408     static OptionDefinition g_option_table[];
409     OptionValueString m_help;
410     OptionValueString m_long_help;
411   };
412 
413   OptionGroupOptions m_option_group;
414   CommandOptions m_command_options;
415 
416 public:
417   Options *GetOptions() override { return &m_option_group; }
418 
419   CommandObjectCommandsAlias(CommandInterpreter &interpreter)
420       : CommandObjectRaw(
421             interpreter, "command alias",
422             "Define a custom command in terms of an existing command.",
423             nullptr),
424         m_option_group(), m_command_options() {
425     m_option_group.Append(&m_command_options);
426     m_option_group.Finalize();
427 
428     SetHelpLong(
429         "'alias' allows the user to create a short-cut or abbreviation for long \
430 commands, multi-word commands, and commands that take particular options.  \
431 Below are some simple examples of how one might use the 'alias' command:"
432         R"(
433 
434 (lldb) command alias sc script
435 
436     Creates the abbreviation 'sc' for the 'script' command.
437 
438 (lldb) command alias bp breakpoint
439 
440 )"
441         "    Creates the abbreviation 'bp' for the 'breakpoint' command.  Since \
442 breakpoint commands are two-word commands, the user would still need to \
443 enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
444         R"(
445 
446 (lldb) command alias bpl breakpoint list
447 
448     Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
449 
450 )"
451         "An alias can include some options for the command, with the values either \
452 filled in at the time the alias is created, or specified as positional \
453 arguments, to be filled in when the alias is invoked.  The following example \
454 shows how to create aliases with options:"
455         R"(
456 
457 (lldb) command alias bfl breakpoint set -f %1 -l %2
458 
459 )"
460         "    Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
461 options already part of the alias.  So if the user wants to set a breakpoint \
462 by file and line without explicitly having to use the -f and -l options, the \
463 user can now use 'bfl' instead.  The '%1' and '%2' are positional placeholders \
464 for the actual arguments that will be passed when the alias command is used.  \
465 The number in the placeholder refers to the position/order the actual value \
466 occupies when the alias is used.  All the occurrences of '%1' in the alias \
467 will be replaced with the first argument, all the occurrences of '%2' in the \
468 alias will be replaced with the second argument, and so on.  This also allows \
469 actual arguments to be used multiple times within an alias (see 'process \
470 launch' example below)."
471         R"(
472 
473 )"
474         "Note: the positional arguments must substitute as whole words in the resultant \
475 command, so you can't at present do something like this to append the file extension \
476 \".cpp\":"
477         R"(
478 
479 (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
480 
481 )"
482         "For more complex aliasing, use the \"command regex\" command instead.  In the \
483 'bfl' case above, the actual file value will be filled in with the first argument \
484 following 'bfl' and the actual line number value will be filled in with the second \
485 argument.  The user would use this alias as follows:"
486         R"(
487 
488 (lldb) command alias bfl breakpoint set -f %1 -l %2
489 (lldb) bfl my-file.c 137
490 
491 This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
492 
493 Another example:
494 
495 (lldb) command alias pltty process launch -s -o %1 -e %1
496 (lldb) pltty /dev/tty0
497 
498     Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
499 
500 )"
501         "If the user always wanted to pass the same value to a particular option, the \
502 alias could be defined with that value directly in the alias as a constant, \
503 rather than using a positional placeholder:"
504         R"(
505 
506 (lldb) command alias bl3 breakpoint set -f %1 -l 3
507 
508     Always sets a breakpoint on line 3 of whatever file is indicated.)");
509 
510     CommandArgumentEntry arg1;
511     CommandArgumentEntry arg2;
512     CommandArgumentEntry arg3;
513     CommandArgumentData alias_arg;
514     CommandArgumentData cmd_arg;
515     CommandArgumentData options_arg;
516 
517     // Define the first (and only) variant of this arg.
518     alias_arg.arg_type = eArgTypeAliasName;
519     alias_arg.arg_repetition = eArgRepeatPlain;
520 
521     // There is only one variant this argument could be; put it into the
522     // argument entry.
523     arg1.push_back(alias_arg);
524 
525     // Define the first (and only) variant of this arg.
526     cmd_arg.arg_type = eArgTypeCommandName;
527     cmd_arg.arg_repetition = eArgRepeatPlain;
528 
529     // There is only one variant this argument could be; put it into the
530     // argument entry.
531     arg2.push_back(cmd_arg);
532 
533     // Define the first (and only) variant of this arg.
534     options_arg.arg_type = eArgTypeAliasOptions;
535     options_arg.arg_repetition = eArgRepeatOptional;
536 
537     // There is only one variant this argument could be; put it into the
538     // argument entry.
539     arg3.push_back(options_arg);
540 
541     // Push the data for the first argument into the m_arguments vector.
542     m_arguments.push_back(arg1);
543     m_arguments.push_back(arg2);
544     m_arguments.push_back(arg3);
545   }
546 
547   ~CommandObjectCommandsAlias() override = default;
548 
549 protected:
550   bool DoExecute(const char *raw_command_line,
551                  CommandReturnObject &result) override {
552     if (!raw_command_line || !raw_command_line[0]) {
553       result.AppendError("'command alias' requires at least two arguments");
554       return false;
555     }
556 
557     ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
558     m_option_group.NotifyOptionParsingStarting(&exe_ctx);
559 
560     const char *remainder = nullptr;
561 
562     if (raw_command_line[0] == '-') {
563       // We have some options and these options MUST end with --.
564       const char *end_options = nullptr;
565       const char *s = raw_command_line;
566       while (s && s[0]) {
567         end_options = ::strstr(s, "--");
568         if (end_options) {
569           end_options += 2; // Get past the "--"
570           if (::isspace(end_options[0])) {
571             remainder = end_options;
572             while (::isspace(*remainder))
573               ++remainder;
574             break;
575           }
576         }
577         s = end_options;
578       }
579 
580       if (end_options) {
581         Args args(
582             llvm::StringRef(raw_command_line, end_options - raw_command_line));
583         if (!ParseOptions(args, result))
584           return false;
585 
586         Error error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
587         if (error.Fail()) {
588           result.AppendError(error.AsCString());
589           result.SetStatus(eReturnStatusFailed);
590           return false;
591         }
592       }
593     }
594     if (nullptr == remainder)
595       remainder = raw_command_line;
596 
597     std::string raw_command_string(remainder);
598     Args args(raw_command_string.c_str());
599 
600     size_t argc = args.GetArgumentCount();
601 
602     if (argc < 2) {
603       result.AppendError("'command alias' requires at least two arguments");
604       result.SetStatus(eReturnStatusFailed);
605       return false;
606     }
607 
608     // Get the alias command.
609 
610     const std::string alias_command = args.GetArgumentAtIndex(0);
611     if (alias_command.size() > 1 && alias_command[0] == '-') {
612       result.AppendError("aliases starting with a dash are not supported");
613       if (alias_command == "--help" || alias_command == "--long-help") {
614         result.AppendWarning("if trying to pass options to 'command alias' add "
615                              "a -- at the end of the options");
616       }
617       result.SetStatus(eReturnStatusFailed);
618       return false;
619     }
620 
621     // Strip the new alias name off 'raw_command_string'  (leave it on args,
622     // which gets passed to 'Execute', which
623     // does the stripping itself.
624     size_t pos = raw_command_string.find(alias_command);
625     if (pos == 0) {
626       raw_command_string = raw_command_string.substr(alias_command.size());
627       pos = raw_command_string.find_first_not_of(' ');
628       if ((pos != std::string::npos) && (pos > 0))
629         raw_command_string = raw_command_string.substr(pos);
630     } else {
631       result.AppendError("Error parsing command string.  No alias created.");
632       result.SetStatus(eReturnStatusFailed);
633       return false;
634     }
635 
636     // Verify that the command is alias-able.
637     if (m_interpreter.CommandExists(alias_command.c_str())) {
638       result.AppendErrorWithFormat(
639           "'%s' is a permanent debugger command and cannot be redefined.\n",
640           alias_command.c_str());
641       result.SetStatus(eReturnStatusFailed);
642       return false;
643     }
644 
645     // Get CommandObject that is being aliased. The command name is read from
646     // the front of raw_command_string.
647     // raw_command_string is returned with the name of the command object
648     // stripped off the front.
649     std::string original_raw_command_string(raw_command_string);
650     CommandObject *cmd_obj =
651         m_interpreter.GetCommandObjectForCommand(raw_command_string);
652 
653     if (!cmd_obj) {
654       result.AppendErrorWithFormat("invalid command given to 'command alias'. "
655                                    "'%s' does not begin with a valid command."
656                                    "  No alias created.",
657                                    original_raw_command_string.c_str());
658       result.SetStatus(eReturnStatusFailed);
659       return false;
660     } else if (!cmd_obj->WantsRawCommandString()) {
661       // Note that args was initialized with the original command, and has not
662       // been updated to this point.
663       // Therefore can we pass it to the version of Execute that does not
664       // need/expect raw input in the alias.
665       return HandleAliasingNormalCommand(args, result);
666     } else {
667       return HandleAliasingRawCommand(alias_command, raw_command_string,
668                                       *cmd_obj, result);
669     }
670     return result.Succeeded();
671   }
672 
673   bool HandleAliasingRawCommand(const std::string &alias_command,
674                                 std::string &raw_command_string,
675                                 CommandObject &cmd_obj,
676                                 CommandReturnObject &result) {
677     // Verify & handle any options/arguments passed to the alias command
678 
679     OptionArgVectorSP option_arg_vector_sp =
680         OptionArgVectorSP(new OptionArgVector);
681 
682     if (CommandObjectSP cmd_obj_sp =
683             m_interpreter.GetCommandSPExact(cmd_obj.GetCommandName(), false)) {
684       if (m_interpreter.AliasExists(alias_command.c_str()) ||
685           m_interpreter.UserCommandExists(alias_command.c_str())) {
686         result.AppendWarningWithFormat(
687             "Overwriting existing definition for '%s'.\n",
688             alias_command.c_str());
689       }
690       if (CommandAlias *alias = m_interpreter.AddAlias(
691               alias_command.c_str(), cmd_obj_sp, raw_command_string.c_str())) {
692         if (m_command_options.m_help.OptionWasSet())
693           alias->SetHelp(m_command_options.m_help.GetCurrentValue());
694         if (m_command_options.m_long_help.OptionWasSet())
695           alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
696         result.SetStatus(eReturnStatusSuccessFinishNoResult);
697       } else {
698         result.AppendError("Unable to create requested alias.\n");
699         result.SetStatus(eReturnStatusFailed);
700       }
701 
702     } else {
703       result.AppendError("Unable to create requested alias.\n");
704       result.SetStatus(eReturnStatusFailed);
705     }
706 
707     return result.Succeeded();
708   }
709 
710   bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
711     size_t argc = args.GetArgumentCount();
712 
713     if (argc < 2) {
714       result.AppendError("'command alias' requires at least two arguments");
715       result.SetStatus(eReturnStatusFailed);
716       return false;
717     }
718 
719     const std::string alias_command = args.GetArgumentAtIndex(0);
720     const std::string actual_command = args.GetArgumentAtIndex(1);
721 
722     args.Shift(); // Shift the alias command word off the argument vector.
723     args.Shift(); // Shift the old command word off the argument vector.
724 
725     // Verify that the command is alias'able, and get the appropriate command
726     // object.
727 
728     if (m_interpreter.CommandExists(alias_command.c_str())) {
729       result.AppendErrorWithFormat(
730           "'%s' is a permanent debugger command and cannot be redefined.\n",
731           alias_command.c_str());
732       result.SetStatus(eReturnStatusFailed);
733     } else {
734       CommandObjectSP command_obj_sp(
735           m_interpreter.GetCommandSPExact(actual_command.c_str(), true));
736       CommandObjectSP subcommand_obj_sp;
737       bool use_subcommand = false;
738       if (command_obj_sp) {
739         CommandObject *cmd_obj = command_obj_sp.get();
740         CommandObject *sub_cmd_obj = nullptr;
741         OptionArgVectorSP option_arg_vector_sp =
742             OptionArgVectorSP(new OptionArgVector);
743 
744         while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0) {
745           if (argc >= 3) {
746             const std::string sub_command = args.GetArgumentAtIndex(0);
747             assert(sub_command.length() != 0);
748             subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command.c_str());
749             if (subcommand_obj_sp) {
750               sub_cmd_obj = subcommand_obj_sp.get();
751               use_subcommand = true;
752               args.Shift(); // Shift the sub_command word off the argument
753                             // vector.
754               cmd_obj = sub_cmd_obj;
755             } else {
756               result.AppendErrorWithFormat(
757                   "'%s' is not a valid sub-command of '%s'.  "
758                   "Unable to create alias.\n",
759                   sub_command.c_str(), actual_command.c_str());
760               result.SetStatus(eReturnStatusFailed);
761               return false;
762             }
763           }
764         }
765 
766         // Verify & handle any options/arguments passed to the alias command
767 
768         std::string args_string;
769 
770         if (args.GetArgumentCount() > 0) {
771           CommandObjectSP tmp_sp =
772               m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName(), false);
773           if (use_subcommand)
774             tmp_sp = m_interpreter.GetCommandSPExact(
775                 sub_cmd_obj->GetCommandName(), false);
776 
777           args.GetCommandString(args_string);
778         }
779 
780         if (m_interpreter.AliasExists(alias_command.c_str()) ||
781             m_interpreter.UserCommandExists(alias_command.c_str())) {
782           result.AppendWarningWithFormat(
783               "Overwriting existing definition for '%s'.\n",
784               alias_command.c_str());
785         }
786 
787         if (CommandAlias *alias = m_interpreter.AddAlias(
788                 alias_command.c_str(),
789                 use_subcommand ? subcommand_obj_sp : command_obj_sp,
790                 args_string.c_str())) {
791           if (m_command_options.m_help.OptionWasSet())
792             alias->SetHelp(m_command_options.m_help.GetCurrentValue());
793           if (m_command_options.m_long_help.OptionWasSet())
794             alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
795           result.SetStatus(eReturnStatusSuccessFinishNoResult);
796         } else {
797           result.AppendError("Unable to create requested alias.\n");
798           result.SetStatus(eReturnStatusFailed);
799           return false;
800         }
801       } else {
802         result.AppendErrorWithFormat("'%s' is not an existing command.\n",
803                                      actual_command.c_str());
804         result.SetStatus(eReturnStatusFailed);
805         return false;
806       }
807     }
808 
809     return result.Succeeded();
810   }
811 };
812 
813 OptionDefinition CommandObjectCommandsAlias::CommandOptions::g_option_table[] =
814     {
815         // clang-format off
816   {LLDB_OPT_SET_ALL, false, "help",      'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Help text for this command"},
817   {LLDB_OPT_SET_ALL, false, "long-help", 'H', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Long help text for this command"},
818   {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
819         // clang-format on
820 };
821 
822 #pragma mark CommandObjectCommandsUnalias
823 //-------------------------------------------------------------------------
824 // CommandObjectCommandsUnalias
825 //-------------------------------------------------------------------------
826 
827 class CommandObjectCommandsUnalias : public CommandObjectParsed {
828 public:
829   CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
830       : CommandObjectParsed(
831             interpreter, "command unalias",
832             "Delete one or more custom commands defined by 'command alias'.",
833             nullptr) {
834     CommandArgumentEntry arg;
835     CommandArgumentData alias_arg;
836 
837     // Define the first (and only) variant of this arg.
838     alias_arg.arg_type = eArgTypeAliasName;
839     alias_arg.arg_repetition = eArgRepeatPlain;
840 
841     // There is only one variant this argument could be; put it into the
842     // argument entry.
843     arg.push_back(alias_arg);
844 
845     // Push the data for the first argument into the m_arguments vector.
846     m_arguments.push_back(arg);
847   }
848 
849   ~CommandObjectCommandsUnalias() override = default;
850 
851 protected:
852   bool DoExecute(Args &args, CommandReturnObject &result) override {
853     CommandObject::CommandMap::iterator pos;
854     CommandObject *cmd_obj;
855 
856     if (args.GetArgumentCount() != 0) {
857       const char *command_name = args.GetArgumentAtIndex(0);
858       cmd_obj = m_interpreter.GetCommandObject(command_name);
859       if (cmd_obj) {
860         if (m_interpreter.CommandExists(command_name)) {
861           if (cmd_obj->IsRemovable()) {
862             result.AppendErrorWithFormat(
863                 "'%s' is not an alias, it is a debugger command which can be "
864                 "removed using the 'command delete' command.\n",
865                 command_name);
866           } else {
867             result.AppendErrorWithFormat(
868                 "'%s' is a permanent debugger command and cannot be removed.\n",
869                 command_name);
870           }
871           result.SetStatus(eReturnStatusFailed);
872         } else {
873           if (!m_interpreter.RemoveAlias(command_name)) {
874             if (m_interpreter.AliasExists(command_name))
875               result.AppendErrorWithFormat(
876                   "Error occurred while attempting to unalias '%s'.\n",
877                   command_name);
878             else
879               result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
880                                            command_name);
881             result.SetStatus(eReturnStatusFailed);
882           } else
883             result.SetStatus(eReturnStatusSuccessFinishNoResult);
884         }
885       } else {
886         result.AppendErrorWithFormat(
887             "'%s' is not a known command.\nTry 'help' to see a "
888             "current list of commands.\n",
889             command_name);
890         result.SetStatus(eReturnStatusFailed);
891       }
892     } else {
893       result.AppendError("must call 'unalias' with a valid alias");
894       result.SetStatus(eReturnStatusFailed);
895     }
896 
897     return result.Succeeded();
898   }
899 };
900 
901 #pragma mark CommandObjectCommandsDelete
902 //-------------------------------------------------------------------------
903 // CommandObjectCommandsDelete
904 //-------------------------------------------------------------------------
905 
906 class CommandObjectCommandsDelete : public CommandObjectParsed {
907 public:
908   CommandObjectCommandsDelete(CommandInterpreter &interpreter)
909       : CommandObjectParsed(
910             interpreter, "command delete",
911             "Delete one or more custom commands defined by 'command regex'.",
912             nullptr) {
913     CommandArgumentEntry arg;
914     CommandArgumentData alias_arg;
915 
916     // Define the first (and only) variant of this arg.
917     alias_arg.arg_type = eArgTypeCommandName;
918     alias_arg.arg_repetition = eArgRepeatPlain;
919 
920     // There is only one variant this argument could be; put it into the
921     // argument entry.
922     arg.push_back(alias_arg);
923 
924     // Push the data for the first argument into the m_arguments vector.
925     m_arguments.push_back(arg);
926   }
927 
928   ~CommandObjectCommandsDelete() override = default;
929 
930 protected:
931   bool DoExecute(Args &args, CommandReturnObject &result) override {
932     CommandObject::CommandMap::iterator pos;
933 
934     if (args.GetArgumentCount() != 0) {
935       const char *command_name = args.GetArgumentAtIndex(0);
936       if (m_interpreter.CommandExists(command_name)) {
937         if (m_interpreter.RemoveCommand(command_name)) {
938           result.SetStatus(eReturnStatusSuccessFinishNoResult);
939         } else {
940           result.AppendErrorWithFormat(
941               "'%s' is a permanent debugger command and cannot be removed.\n",
942               command_name);
943           result.SetStatus(eReturnStatusFailed);
944         }
945       } else {
946         StreamString error_msg_stream;
947         const bool generate_apropos = true;
948         const bool generate_type_lookup = false;
949         CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
950             &error_msg_stream, command_name, nullptr, nullptr, generate_apropos,
951             generate_type_lookup);
952         result.AppendErrorWithFormat("%s", error_msg_stream.GetData());
953         result.SetStatus(eReturnStatusFailed);
954       }
955     } else {
956       result.AppendErrorWithFormat("must call '%s' with one or more valid user "
957                                    "defined regular expression command names",
958                                    GetCommandName());
959       result.SetStatus(eReturnStatusFailed);
960     }
961 
962     return result.Succeeded();
963   }
964 };
965 
966 //-------------------------------------------------------------------------
967 // CommandObjectCommandsAddRegex
968 //-------------------------------------------------------------------------
969 #pragma mark CommandObjectCommandsAddRegex
970 
971 class CommandObjectCommandsAddRegex : public CommandObjectParsed,
972                                       public IOHandlerDelegateMultiline {
973 public:
974   CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
975       : CommandObjectParsed(
976             interpreter, "command regex", "Define a custom command in terms of "
977                                           "existing commands by matching "
978                                           "regular expressions.",
979             "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
980         IOHandlerDelegateMultiline("",
981                                    IOHandlerDelegate::Completion::LLDBCommand),
982         m_options() {
983     SetHelpLong(
984         R"(
985 )"
986         "This command allows the user to create powerful regular expression commands \
987 with substitutions. The regular expressions and substitutions are specified \
988 using the regular expression substitution format of:"
989         R"(
990 
991     s/<regex>/<subst>/
992 
993 )"
994         "<regex> is a regular expression that can use parenthesis to capture regular \
995 expression input and substitute the captured matches in the output using %1 \
996 for the first match, %2 for the second, and so on."
997         R"(
998 
999 )"
1000         "The regular expressions can all be specified on the command line if more than \
1001 one argument is provided. If just the command name is provided on the command \
1002 line, then the regular expressions and substitutions can be entered on separate \
1003 lines, followed by an empty line to terminate the command definition."
1004         R"(
1005 
1006 EXAMPLES
1007 
1008 )"
1009         "The following example will define a regular expression command named 'f' that \
1010 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
1011 a number follows 'f':"
1012         R"(
1013 
1014     (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
1015   }
1016 
1017   ~CommandObjectCommandsAddRegex() override = default;
1018 
1019 protected:
1020   void IOHandlerActivated(IOHandler &io_handler) override {
1021     StreamFileSP output_sp(io_handler.GetOutputStreamFile());
1022     if (output_sp) {
1023       output_sp->PutCString("Enter one of more sed substitution commands in "
1024                             "the form: 's/<regex>/<subst>/'.\nTerminate the "
1025                             "substitution list with an empty line.\n");
1026       output_sp->Flush();
1027     }
1028   }
1029 
1030   void IOHandlerInputComplete(IOHandler &io_handler,
1031                               std::string &data) override {
1032     io_handler.SetIsDone(true);
1033     if (m_regex_cmd_ap) {
1034       StringList lines;
1035       if (lines.SplitIntoLines(data)) {
1036         const size_t num_lines = lines.GetSize();
1037         bool check_only = false;
1038         for (size_t i = 0; i < num_lines; ++i) {
1039           llvm::StringRef bytes_strref(lines[i]);
1040           Error error = AppendRegexSubstitution(bytes_strref, check_only);
1041           if (error.Fail()) {
1042             if (!m_interpreter.GetDebugger()
1043                      .GetCommandInterpreter()
1044                      .GetBatchCommandMode()) {
1045               StreamSP out_stream =
1046                   m_interpreter.GetDebugger().GetAsyncOutputStream();
1047               out_stream->Printf("error: %s\n", error.AsCString());
1048             }
1049           }
1050         }
1051       }
1052       if (m_regex_cmd_ap->HasRegexEntries()) {
1053         CommandObjectSP cmd_sp(m_regex_cmd_ap.release());
1054         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1055       }
1056     }
1057   }
1058 
1059   bool DoExecute(Args &command, CommandReturnObject &result) override {
1060     const size_t argc = command.GetArgumentCount();
1061     if (argc == 0) {
1062       result.AppendError("usage: 'command regex <command-name> "
1063                          "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
1064       result.SetStatus(eReturnStatusFailed);
1065     } else {
1066       Error error;
1067       const char *name = command.GetArgumentAtIndex(0);
1068       m_regex_cmd_ap.reset(new CommandObjectRegexCommand(
1069           m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10,
1070           0, true));
1071 
1072       if (argc == 1) {
1073         Debugger &debugger = m_interpreter.GetDebugger();
1074         bool color_prompt = debugger.GetUseColor();
1075         const bool multiple_lines = true; // Get multiple lines
1076         IOHandlerSP io_handler_sp(new IOHandlerEditline(
1077             debugger, IOHandler::Type::Other,
1078             "lldb-regex", // Name of input reader for history
1079             "> ",         // Prompt
1080             nullptr,      // Continuation prompt
1081             multiple_lines, color_prompt,
1082             0, // Don't show line numbers
1083             *this));
1084 
1085         if (io_handler_sp) {
1086           debugger.PushIOHandler(io_handler_sp);
1087           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1088         }
1089       } else {
1090         for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx) {
1091           llvm::StringRef arg_strref(command.GetArgumentAtIndex(arg_idx));
1092           bool check_only = false;
1093           error = AppendRegexSubstitution(arg_strref, check_only);
1094           if (error.Fail())
1095             break;
1096         }
1097 
1098         if (error.Success()) {
1099           AddRegexCommandToInterpreter();
1100         }
1101       }
1102       if (error.Fail()) {
1103         result.AppendError(error.AsCString());
1104         result.SetStatus(eReturnStatusFailed);
1105       }
1106     }
1107 
1108     return result.Succeeded();
1109   }
1110 
1111   Error AppendRegexSubstitution(const llvm::StringRef &regex_sed,
1112                                 bool check_only) {
1113     Error error;
1114 
1115     if (!m_regex_cmd_ap) {
1116       error.SetErrorStringWithFormat(
1117           "invalid regular expression command object for: '%.*s'",
1118           (int)regex_sed.size(), regex_sed.data());
1119       return error;
1120     }
1121 
1122     size_t regex_sed_size = regex_sed.size();
1123 
1124     if (regex_sed_size <= 1) {
1125       error.SetErrorStringWithFormat(
1126           "regular expression substitution string is too short: '%.*s'",
1127           (int)regex_sed.size(), regex_sed.data());
1128       return error;
1129     }
1130 
1131     if (regex_sed[0] != 's') {
1132       error.SetErrorStringWithFormat("regular expression substitution string "
1133                                      "doesn't start with 's': '%.*s'",
1134                                      (int)regex_sed.size(), regex_sed.data());
1135       return error;
1136     }
1137     const size_t first_separator_char_pos = 1;
1138     // use the char that follows 's' as the regex separator character
1139     // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
1140     const char separator_char = regex_sed[first_separator_char_pos];
1141     const size_t second_separator_char_pos =
1142         regex_sed.find(separator_char, first_separator_char_pos + 1);
1143 
1144     if (second_separator_char_pos == std::string::npos) {
1145       error.SetErrorStringWithFormat(
1146           "missing second '%c' separator char after '%.*s' in '%.*s'",
1147           separator_char,
1148           (int)(regex_sed.size() - first_separator_char_pos - 1),
1149           regex_sed.data() + (first_separator_char_pos + 1),
1150           (int)regex_sed.size(), regex_sed.data());
1151       return error;
1152     }
1153 
1154     const size_t third_separator_char_pos =
1155         regex_sed.find(separator_char, second_separator_char_pos + 1);
1156 
1157     if (third_separator_char_pos == std::string::npos) {
1158       error.SetErrorStringWithFormat(
1159           "missing third '%c' separator char after '%.*s' in '%.*s'",
1160           separator_char,
1161           (int)(regex_sed.size() - second_separator_char_pos - 1),
1162           regex_sed.data() + (second_separator_char_pos + 1),
1163           (int)regex_sed.size(), regex_sed.data());
1164       return error;
1165     }
1166 
1167     if (third_separator_char_pos != regex_sed_size - 1) {
1168       // Make sure that everything that follows the last regex
1169       // separator char
1170       if (regex_sed.find_first_not_of("\t\n\v\f\r ",
1171                                       third_separator_char_pos + 1) !=
1172           std::string::npos) {
1173         error.SetErrorStringWithFormat(
1174             "extra data found after the '%.*s' regular expression substitution "
1175             "string: '%.*s'",
1176             (int)third_separator_char_pos + 1, regex_sed.data(),
1177             (int)(regex_sed.size() - third_separator_char_pos - 1),
1178             regex_sed.data() + (third_separator_char_pos + 1));
1179         return error;
1180       }
1181     } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
1182       error.SetErrorStringWithFormat(
1183           "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
1184           separator_char, separator_char, separator_char, (int)regex_sed.size(),
1185           regex_sed.data());
1186       return error;
1187     } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
1188       error.SetErrorStringWithFormat(
1189           "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
1190           separator_char, separator_char, separator_char, (int)regex_sed.size(),
1191           regex_sed.data());
1192       return error;
1193     }
1194 
1195     if (!check_only) {
1196       std::string regex(regex_sed.substr(first_separator_char_pos + 1,
1197                                          second_separator_char_pos -
1198                                              first_separator_char_pos - 1));
1199       std::string subst(regex_sed.substr(second_separator_char_pos + 1,
1200                                          third_separator_char_pos -
1201                                              second_separator_char_pos - 1));
1202       m_regex_cmd_ap->AddRegexCommand(regex.c_str(), subst.c_str());
1203     }
1204     return error;
1205   }
1206 
1207   void AddRegexCommandToInterpreter() {
1208     if (m_regex_cmd_ap) {
1209       if (m_regex_cmd_ap->HasRegexEntries()) {
1210         CommandObjectSP cmd_sp(m_regex_cmd_ap.release());
1211         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1212       }
1213     }
1214   }
1215 
1216 private:
1217   std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_ap;
1218 
1219   class CommandOptions : public Options {
1220   public:
1221     CommandOptions() : Options() {}
1222 
1223     ~CommandOptions() override = default;
1224 
1225     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
1226                          ExecutionContext *execution_context) override {
1227       Error error;
1228       const int short_option = m_getopt_table[option_idx].val;
1229 
1230       switch (short_option) {
1231       case 'h':
1232         m_help.assign(option_arg);
1233         break;
1234       case 's':
1235         m_syntax.assign(option_arg);
1236         break;
1237       default:
1238         error.SetErrorStringWithFormat("unrecognized option '%c'",
1239                                        short_option);
1240         break;
1241       }
1242 
1243       return error;
1244     }
1245 
1246     void OptionParsingStarting(ExecutionContext *execution_context) override {
1247       m_help.clear();
1248       m_syntax.clear();
1249     }
1250 
1251     const OptionDefinition *GetDefinitions() override { return g_option_table; }
1252 
1253     // Options table: Required for subclasses of Options.
1254 
1255     static OptionDefinition g_option_table[];
1256 
1257     const char *GetHelp() {
1258       return (m_help.empty() ? nullptr : m_help.c_str());
1259     }
1260 
1261     const char *GetSyntax() {
1262       return (m_syntax.empty() ? nullptr : m_syntax.c_str());
1263     }
1264 
1265   protected:
1266     // Instance variables to hold the values for command options.
1267 
1268     std::string m_help;
1269     std::string m_syntax;
1270   };
1271 
1272   Options *GetOptions() override { return &m_options; }
1273 
1274   CommandOptions m_options;
1275 };
1276 
1277 OptionDefinition
1278     CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] = {
1279         // clang-format off
1280   {LLDB_OPT_SET_1, false, "help"  , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "The help text to display for this command."},
1281   {LLDB_OPT_SET_1, false, "syntax", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."},
1282   {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
1283         // clang-format on
1284 };
1285 
1286 class CommandObjectPythonFunction : public CommandObjectRaw {
1287 public:
1288   CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
1289                               std::string funct, std::string help,
1290                               ScriptedCommandSynchronicity synch)
1291       : CommandObjectRaw(interpreter, name.c_str(), nullptr, nullptr),
1292         m_function_name(funct), m_synchro(synch), m_fetched_help_long(false) {
1293     if (!help.empty())
1294       SetHelp(help.c_str());
1295     else {
1296       StreamString stream;
1297       stream.Printf("For more information run 'help %s'", name.c_str());
1298       SetHelp(stream.GetData());
1299     }
1300   }
1301 
1302   ~CommandObjectPythonFunction() override = default;
1303 
1304   bool IsRemovable() const override { return true; }
1305 
1306   const std::string &GetFunctionName() { return m_function_name; }
1307 
1308   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1309 
1310   const char *GetHelpLong() override {
1311     if (!m_fetched_help_long) {
1312       ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
1313       if (scripter) {
1314         std::string docstring;
1315         m_fetched_help_long = scripter->GetDocumentationForItem(
1316             m_function_name.c_str(), docstring);
1317         if (!docstring.empty())
1318           SetHelpLong(docstring.c_str());
1319       }
1320     }
1321     return CommandObjectRaw::GetHelpLong();
1322   }
1323 
1324 protected:
1325   bool DoExecute(const char *raw_command_line,
1326                  CommandReturnObject &result) override {
1327     ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
1328 
1329     Error error;
1330 
1331     result.SetStatus(eReturnStatusInvalid);
1332 
1333     if (!scripter ||
1334         !scripter->RunScriptBasedCommand(m_function_name.c_str(),
1335                                          raw_command_line, m_synchro, result,
1336                                          error, m_exe_ctx)) {
1337       result.AppendError(error.AsCString());
1338       result.SetStatus(eReturnStatusFailed);
1339     } else {
1340       // Don't change the status if the command already set it...
1341       if (result.GetStatus() == eReturnStatusInvalid) {
1342         if (result.GetOutputData() == nullptr ||
1343             result.GetOutputData()[0] == '\0')
1344           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1345         else
1346           result.SetStatus(eReturnStatusSuccessFinishResult);
1347       }
1348     }
1349 
1350     return result.Succeeded();
1351   }
1352 
1353 private:
1354   std::string m_function_name;
1355   ScriptedCommandSynchronicity m_synchro;
1356   bool m_fetched_help_long;
1357 };
1358 
1359 class CommandObjectScriptingObject : public CommandObjectRaw {
1360 public:
1361   CommandObjectScriptingObject(CommandInterpreter &interpreter,
1362                                std::string name,
1363                                StructuredData::GenericSP cmd_obj_sp,
1364                                ScriptedCommandSynchronicity synch)
1365       : CommandObjectRaw(interpreter, name.c_str(), nullptr, nullptr),
1366         m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), m_fetched_help_short(false),
1367         m_fetched_help_long(false) {
1368     StreamString stream;
1369     stream.Printf("For more information run 'help %s'", name.c_str());
1370     SetHelp(stream.GetData());
1371     if (ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter())
1372       GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1373   }
1374 
1375   ~CommandObjectScriptingObject() override = default;
1376 
1377   bool IsRemovable() const override { return true; }
1378 
1379   StructuredData::GenericSP GetImplementingObject() { return m_cmd_obj_sp; }
1380 
1381   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1382 
1383   const char *GetHelp() override {
1384     if (!m_fetched_help_short) {
1385       ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
1386       if (scripter) {
1387         std::string docstring;
1388         m_fetched_help_short =
1389             scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1390         if (!docstring.empty())
1391           SetHelp(docstring.c_str());
1392       }
1393     }
1394     return CommandObjectRaw::GetHelp();
1395   }
1396 
1397   const char *GetHelpLong() override {
1398     if (!m_fetched_help_long) {
1399       ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
1400       if (scripter) {
1401         std::string docstring;
1402         m_fetched_help_long =
1403             scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1404         if (!docstring.empty())
1405           SetHelpLong(docstring.c_str());
1406       }
1407     }
1408     return CommandObjectRaw::GetHelpLong();
1409   }
1410 
1411 protected:
1412   bool DoExecute(const char *raw_command_line,
1413                  CommandReturnObject &result) override {
1414     ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
1415 
1416     Error error;
1417 
1418     result.SetStatus(eReturnStatusInvalid);
1419 
1420     if (!scripter ||
1421         !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
1422                                          m_synchro, result, error, m_exe_ctx)) {
1423       result.AppendError(error.AsCString());
1424       result.SetStatus(eReturnStatusFailed);
1425     } else {
1426       // Don't change the status if the command already set it...
1427       if (result.GetStatus() == eReturnStatusInvalid) {
1428         if (result.GetOutputData() == nullptr ||
1429             result.GetOutputData()[0] == '\0')
1430           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1431         else
1432           result.SetStatus(eReturnStatusSuccessFinishResult);
1433       }
1434     }
1435 
1436     return result.Succeeded();
1437   }
1438 
1439 private:
1440   StructuredData::GenericSP m_cmd_obj_sp;
1441   ScriptedCommandSynchronicity m_synchro;
1442   bool m_fetched_help_short : 1;
1443   bool m_fetched_help_long : 1;
1444 };
1445 
1446 //-------------------------------------------------------------------------
1447 // CommandObjectCommandsScriptImport
1448 //-------------------------------------------------------------------------
1449 
1450 class CommandObjectCommandsScriptImport : public CommandObjectParsed {
1451 public:
1452   CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
1453       : CommandObjectParsed(interpreter, "command script import",
1454                             "Import a scripting module in LLDB.", nullptr),
1455         m_options() {
1456     CommandArgumentEntry arg1;
1457     CommandArgumentData cmd_arg;
1458 
1459     // Define the first (and only) variant of this arg.
1460     cmd_arg.arg_type = eArgTypeFilename;
1461     cmd_arg.arg_repetition = eArgRepeatPlus;
1462 
1463     // There is only one variant this argument could be; put it into the
1464     // argument entry.
1465     arg1.push_back(cmd_arg);
1466 
1467     // Push the data for the first argument into the m_arguments vector.
1468     m_arguments.push_back(arg1);
1469   }
1470 
1471   ~CommandObjectCommandsScriptImport() override = default;
1472 
1473   int HandleArgumentCompletion(Args &input, int &cursor_index,
1474                                int &cursor_char_position,
1475                                OptionElementVector &opt_element_vector,
1476                                int match_start_point, int max_return_elements,
1477                                bool &word_complete,
1478                                StringList &matches) override {
1479     std::string completion_str(input.GetArgumentAtIndex(cursor_index));
1480     completion_str.erase(cursor_char_position);
1481 
1482     CommandCompletions::InvokeCommonCompletionCallbacks(
1483         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
1484         completion_str.c_str(), match_start_point, max_return_elements, nullptr,
1485         word_complete, matches);
1486     return matches.GetSize();
1487   }
1488 
1489   Options *GetOptions() override { return &m_options; }
1490 
1491 protected:
1492   class CommandOptions : public Options {
1493   public:
1494     CommandOptions() : Options() {}
1495 
1496     ~CommandOptions() override = default;
1497 
1498     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
1499                          ExecutionContext *execution_context) override {
1500       Error error;
1501       const int short_option = m_getopt_table[option_idx].val;
1502 
1503       switch (short_option) {
1504       case 'r':
1505         m_allow_reload = true;
1506         break;
1507       default:
1508         error.SetErrorStringWithFormat("unrecognized option '%c'",
1509                                        short_option);
1510         break;
1511       }
1512 
1513       return error;
1514     }
1515 
1516     void OptionParsingStarting(ExecutionContext *execution_context) override {
1517       m_allow_reload = true;
1518     }
1519 
1520     const OptionDefinition *GetDefinitions() override { return g_option_table; }
1521 
1522     // Options table: Required for subclasses of Options.
1523 
1524     static OptionDefinition g_option_table[];
1525 
1526     // Instance variables to hold the values for command options.
1527 
1528     bool m_allow_reload;
1529   };
1530 
1531   bool DoExecute(Args &command, CommandReturnObject &result) override {
1532     if (m_interpreter.GetDebugger().GetScriptLanguage() !=
1533         lldb::eScriptLanguagePython) {
1534       result.AppendError("only scripting language supported for module "
1535                          "importing is currently Python");
1536       result.SetStatus(eReturnStatusFailed);
1537       return false;
1538     }
1539 
1540     size_t argc = command.GetArgumentCount();
1541     if (0 == argc) {
1542       result.AppendError("command script import needs one or more arguments");
1543       result.SetStatus(eReturnStatusFailed);
1544       return false;
1545     }
1546 
1547     for (size_t i = 0; i < argc; i++) {
1548       std::string path = command.GetArgumentAtIndex(i);
1549       Error error;
1550 
1551       const bool init_session = true;
1552       // FIXME: this is necessary because CommandObject::CheckRequirements()
1553       // assumes that
1554       // commands won't ever be recursively invoked, but it's actually possible
1555       // to craft
1556       // a Python script that does other "command script imports" in
1557       // __lldb_init_module
1558       // the real fix is to have recursive commands possible with a
1559       // CommandInvocation object
1560       // separate from the CommandObject itself, so that recursive command
1561       // invocations
1562       // won't stomp on each other (wrt to execution contents, options, and
1563       // more)
1564       m_exe_ctx.Clear();
1565       if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(
1566               path.c_str(), m_options.m_allow_reload, init_session, error)) {
1567         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1568       } else {
1569         result.AppendErrorWithFormat("module importing failed: %s",
1570                                      error.AsCString());
1571         result.SetStatus(eReturnStatusFailed);
1572       }
1573     }
1574 
1575     return result.Succeeded();
1576   }
1577 
1578   CommandOptions m_options;
1579 };
1580 
1581 OptionDefinition
1582     CommandObjectCommandsScriptImport::CommandOptions::g_option_table[] = {
1583         // clang-format off
1584   {LLDB_OPT_SET_1, false, "allow-reload", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not."},
1585   {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr }
1586         // clang-format on
1587 };
1588 
1589 //-------------------------------------------------------------------------
1590 // CommandObjectCommandsScriptAdd
1591 //-------------------------------------------------------------------------
1592 
1593 class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
1594                                        public IOHandlerDelegateMultiline {
1595 public:
1596   CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
1597       : CommandObjectParsed(interpreter, "command script add",
1598                             "Add a scripted function as an LLDB command.",
1599                             nullptr),
1600         IOHandlerDelegateMultiline("DONE"), m_options() {
1601     CommandArgumentEntry arg1;
1602     CommandArgumentData cmd_arg;
1603 
1604     // Define the first (and only) variant of this arg.
1605     cmd_arg.arg_type = eArgTypeCommandName;
1606     cmd_arg.arg_repetition = eArgRepeatPlain;
1607 
1608     // There is only one variant this argument could be; put it into the
1609     // argument entry.
1610     arg1.push_back(cmd_arg);
1611 
1612     // Push the data for the first argument into the m_arguments vector.
1613     m_arguments.push_back(arg1);
1614   }
1615 
1616   ~CommandObjectCommandsScriptAdd() override = default;
1617 
1618   Options *GetOptions() override { return &m_options; }
1619 
1620 protected:
1621   class CommandOptions : public Options {
1622   public:
1623     CommandOptions()
1624         : Options(), m_class_name(), m_funct_name(), m_short_help(),
1625           m_synchronicity(eScriptedCommandSynchronicitySynchronous) {}
1626 
1627     ~CommandOptions() override = default;
1628 
1629     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
1630                          ExecutionContext *execution_context) override {
1631       Error error;
1632       const int short_option = m_getopt_table[option_idx].val;
1633 
1634       switch (short_option) {
1635       case 'f':
1636         if (option_arg)
1637           m_funct_name.assign(option_arg);
1638         break;
1639       case 'c':
1640         if (option_arg)
1641           m_class_name.assign(option_arg);
1642         break;
1643       case 'h':
1644         if (option_arg)
1645           m_short_help.assign(option_arg);
1646         break;
1647       case 's':
1648         m_synchronicity =
1649             (ScriptedCommandSynchronicity)Args::StringToOptionEnum(
1650                 option_arg, g_option_table[option_idx].enum_values, 0, error);
1651         if (!error.Success())
1652           error.SetErrorStringWithFormat(
1653               "unrecognized value for synchronicity '%s'", option_arg);
1654         break;
1655       default:
1656         error.SetErrorStringWithFormat("unrecognized option '%c'",
1657                                        short_option);
1658         break;
1659       }
1660 
1661       return error;
1662     }
1663 
1664     void OptionParsingStarting(ExecutionContext *execution_context) override {
1665       m_class_name.clear();
1666       m_funct_name.clear();
1667       m_short_help.clear();
1668       m_synchronicity = eScriptedCommandSynchronicitySynchronous;
1669     }
1670 
1671     const OptionDefinition *GetDefinitions() override { return g_option_table; }
1672 
1673     // Options table: Required for subclasses of Options.
1674 
1675     static OptionDefinition g_option_table[];
1676 
1677     // Instance variables to hold the values for command options.
1678 
1679     std::string m_class_name;
1680     std::string m_funct_name;
1681     std::string m_short_help;
1682     ScriptedCommandSynchronicity m_synchronicity;
1683   };
1684 
1685   void IOHandlerActivated(IOHandler &io_handler) override {
1686     StreamFileSP output_sp(io_handler.GetOutputStreamFile());
1687     if (output_sp) {
1688       output_sp->PutCString(g_python_command_instructions);
1689       output_sp->Flush();
1690     }
1691   }
1692 
1693   void IOHandlerInputComplete(IOHandler &io_handler,
1694                               std::string &data) override {
1695     StreamFileSP error_sp = io_handler.GetErrorStreamFile();
1696 
1697     ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
1698     if (interpreter) {
1699 
1700       StringList lines;
1701       lines.SplitIntoLines(data);
1702       if (lines.GetSize() > 0) {
1703         std::string funct_name_str;
1704         if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
1705           if (funct_name_str.empty()) {
1706             error_sp->Printf("error: unable to obtain a function name, didn't "
1707                              "add python command.\n");
1708             error_sp->Flush();
1709           } else {
1710             // everything should be fine now, let's add this alias
1711 
1712             CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
1713                 m_interpreter, m_cmd_name, funct_name_str.c_str(), m_short_help,
1714                 m_synchronicity));
1715 
1716             if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp,
1717                                               true)) {
1718               error_sp->Printf("error: unable to add selected command, didn't "
1719                                "add python command.\n");
1720               error_sp->Flush();
1721             }
1722           }
1723         } else {
1724           error_sp->Printf(
1725               "error: unable to create function, didn't add python command.\n");
1726           error_sp->Flush();
1727         }
1728       } else {
1729         error_sp->Printf("error: empty function, didn't add python command.\n");
1730         error_sp->Flush();
1731       }
1732     } else {
1733       error_sp->Printf(
1734           "error: script interpreter missing, didn't add python command.\n");
1735       error_sp->Flush();
1736     }
1737 
1738     io_handler.SetIsDone(true);
1739   }
1740 
1741 protected:
1742   bool DoExecute(Args &command, CommandReturnObject &result) override {
1743     if (m_interpreter.GetDebugger().GetScriptLanguage() !=
1744         lldb::eScriptLanguagePython) {
1745       result.AppendError("only scripting language supported for scripted "
1746                          "commands is currently Python");
1747       result.SetStatus(eReturnStatusFailed);
1748       return false;
1749     }
1750 
1751     size_t argc = command.GetArgumentCount();
1752 
1753     if (argc != 1) {
1754       result.AppendError("'command script add' requires one argument");
1755       result.SetStatus(eReturnStatusFailed);
1756       return false;
1757     }
1758 
1759     // Store the options in case we get multi-line input
1760     m_cmd_name = command.GetArgumentAtIndex(0);
1761     m_short_help.assign(m_options.m_short_help);
1762     m_synchronicity = m_options.m_synchronicity;
1763 
1764     if (m_options.m_class_name.empty()) {
1765       if (m_options.m_funct_name.empty()) {
1766         m_interpreter.GetPythonCommandsFromIOHandler(
1767             "     ",  // Prompt
1768             *this,    // IOHandlerDelegate
1769             true,     // Run IOHandler in async mode
1770             nullptr); // Baton for the "io_handler" that will be passed back
1771                       // into our IOHandlerDelegate functions
1772       } else {
1773         CommandObjectSP new_cmd(new CommandObjectPythonFunction(
1774             m_interpreter, m_cmd_name, m_options.m_funct_name,
1775             m_options.m_short_help, m_synchronicity));
1776         if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) {
1777           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1778         } else {
1779           result.AppendError("cannot add command");
1780           result.SetStatus(eReturnStatusFailed);
1781         }
1782       }
1783     } else {
1784       ScriptInterpreter *interpreter =
1785           GetCommandInterpreter().GetScriptInterpreter();
1786       if (!interpreter) {
1787         result.AppendError("cannot find ScriptInterpreter");
1788         result.SetStatus(eReturnStatusFailed);
1789         return false;
1790       }
1791 
1792       auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
1793           m_options.m_class_name.c_str());
1794       if (!cmd_obj_sp) {
1795         result.AppendError("cannot create helper object");
1796         result.SetStatus(eReturnStatusFailed);
1797         return false;
1798       }
1799 
1800       CommandObjectSP new_cmd(new CommandObjectScriptingObject(
1801           m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity));
1802       if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) {
1803         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1804       } else {
1805         result.AppendError("cannot add command");
1806         result.SetStatus(eReturnStatusFailed);
1807       }
1808     }
1809 
1810     return result.Succeeded();
1811   }
1812 
1813   CommandOptions m_options;
1814   std::string m_cmd_name;
1815   std::string m_short_help;
1816   ScriptedCommandSynchronicity m_synchronicity;
1817 };
1818 
1819 static OptionEnumValueElement g_script_synchro_type[] = {
1820     {eScriptedCommandSynchronicitySynchronous, "synchronous",
1821      "Run synchronous"},
1822     {eScriptedCommandSynchronicityAsynchronous, "asynchronous",
1823      "Run asynchronous"},
1824     {eScriptedCommandSynchronicityCurrentValue, "current",
1825      "Do not alter current setting"},
1826     {0, nullptr, nullptr}};
1827 
1828 OptionDefinition
1829     CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] = {
1830         // clang-format off
1831   {LLDB_OPT_SET_1,   false, "function",      'f', OptionParser::eRequiredArgument, nullptr, nullptr,               0, eArgTypePythonFunction,               "Name of the Python function to bind to this command name."},
1832   {LLDB_OPT_SET_2,   false, "class",         'c', OptionParser::eRequiredArgument, nullptr, nullptr,               0, eArgTypePythonClass,                  "Name of the Python class to bind to this command name."},
1833   {LLDB_OPT_SET_1,   false, "help"  ,        'h', OptionParser::eRequiredArgument, nullptr, nullptr,               0, eArgTypeHelpText,                     "The help text to display for this command."},
1834   {LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, nullptr, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."},
1835   {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
1836         // clang-format on
1837 };
1838 
1839 //-------------------------------------------------------------------------
1840 // CommandObjectCommandsScriptList
1841 //-------------------------------------------------------------------------
1842 
1843 class CommandObjectCommandsScriptList : public CommandObjectParsed {
1844 public:
1845   CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
1846       : CommandObjectParsed(interpreter, "command script list",
1847                             "List defined scripted commands.", nullptr) {}
1848 
1849   ~CommandObjectCommandsScriptList() override = default;
1850 
1851   bool DoExecute(Args &command, CommandReturnObject &result) override {
1852     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
1853 
1854     result.SetStatus(eReturnStatusSuccessFinishResult);
1855 
1856     return true;
1857   }
1858 };
1859 
1860 //-------------------------------------------------------------------------
1861 // CommandObjectCommandsScriptClear
1862 //-------------------------------------------------------------------------
1863 
1864 class CommandObjectCommandsScriptClear : public CommandObjectParsed {
1865 public:
1866   CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
1867       : CommandObjectParsed(interpreter, "command script clear",
1868                             "Delete all scripted commands.", nullptr) {}
1869 
1870   ~CommandObjectCommandsScriptClear() override = default;
1871 
1872 protected:
1873   bool DoExecute(Args &command, CommandReturnObject &result) override {
1874     m_interpreter.RemoveAllUser();
1875 
1876     result.SetStatus(eReturnStatusSuccessFinishResult);
1877 
1878     return true;
1879   }
1880 };
1881 
1882 //-------------------------------------------------------------------------
1883 // CommandObjectCommandsScriptDelete
1884 //-------------------------------------------------------------------------
1885 
1886 class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
1887 public:
1888   CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
1889       : CommandObjectParsed(interpreter, "command script delete",
1890                             "Delete a scripted command.", nullptr) {
1891     CommandArgumentEntry arg1;
1892     CommandArgumentData cmd_arg;
1893 
1894     // Define the first (and only) variant of this arg.
1895     cmd_arg.arg_type = eArgTypeCommandName;
1896     cmd_arg.arg_repetition = eArgRepeatPlain;
1897 
1898     // There is only one variant this argument could be; put it into the
1899     // argument entry.
1900     arg1.push_back(cmd_arg);
1901 
1902     // Push the data for the first argument into the m_arguments vector.
1903     m_arguments.push_back(arg1);
1904   }
1905 
1906   ~CommandObjectCommandsScriptDelete() override = default;
1907 
1908 protected:
1909   bool DoExecute(Args &command, CommandReturnObject &result) override {
1910 
1911     size_t argc = command.GetArgumentCount();
1912 
1913     if (argc != 1) {
1914       result.AppendError("'command script delete' requires one argument");
1915       result.SetStatus(eReturnStatusFailed);
1916       return false;
1917     }
1918 
1919     const char *cmd_name = command.GetArgumentAtIndex(0);
1920 
1921     if (cmd_name && *cmd_name && m_interpreter.HasUserCommands() &&
1922         m_interpreter.UserCommandExists(cmd_name)) {
1923       m_interpreter.RemoveUser(cmd_name);
1924       result.SetStatus(eReturnStatusSuccessFinishResult);
1925     } else {
1926       result.AppendErrorWithFormat("command %s not found", cmd_name);
1927       result.SetStatus(eReturnStatusFailed);
1928     }
1929 
1930     return result.Succeeded();
1931   }
1932 };
1933 
1934 #pragma mark CommandObjectMultiwordCommandsScript
1935 
1936 //-------------------------------------------------------------------------
1937 // CommandObjectMultiwordCommandsScript
1938 //-------------------------------------------------------------------------
1939 
1940 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
1941 public:
1942   CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
1943       : CommandObjectMultiword(
1944             interpreter, "command script", "Commands for managing custom "
1945                                            "commands implemented by "
1946                                            "interpreter scripts.",
1947             "command script <subcommand> [<subcommand-options>]") {
1948     LoadSubCommand("add", CommandObjectSP(
1949                               new CommandObjectCommandsScriptAdd(interpreter)));
1950     LoadSubCommand(
1951         "delete",
1952         CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
1953     LoadSubCommand(
1954         "clear",
1955         CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
1956     LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
1957                                interpreter)));
1958     LoadSubCommand(
1959         "import",
1960         CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
1961   }
1962 
1963   ~CommandObjectMultiwordCommandsScript() override = default;
1964 };
1965 
1966 #pragma mark CommandObjectMultiwordCommands
1967 
1968 //-------------------------------------------------------------------------
1969 // CommandObjectMultiwordCommands
1970 //-------------------------------------------------------------------------
1971 
1972 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
1973     CommandInterpreter &interpreter)
1974     : CommandObjectMultiword(interpreter, "command",
1975                              "Commands for managing custom LLDB commands.",
1976                              "command <subcommand> [<subcommand-options>]") {
1977   LoadSubCommand("source",
1978                  CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
1979   LoadSubCommand("alias",
1980                  CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
1981   LoadSubCommand("unalias", CommandObjectSP(
1982                                 new CommandObjectCommandsUnalias(interpreter)));
1983   LoadSubCommand("delete",
1984                  CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
1985   LoadSubCommand(
1986       "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
1987   LoadSubCommand("history", CommandObjectSP(
1988                                 new CommandObjectCommandsHistory(interpreter)));
1989   LoadSubCommand(
1990       "script",
1991       CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
1992 }
1993 
1994 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
1995