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