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