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