1cfca06d7SDimitry Andric //===-- CommandObjectCommands.cpp -----------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9f3fbd1c0SDimitry Andric #include "CommandObjectCommands.h"
10f3fbd1c0SDimitry Andric #include "CommandObjectHelp.h"
11b60736ecSDimitry Andric #include "CommandObjectRegexCommand.h"
12f034231aSEd Maste #include "lldb/Core/Debugger.h"
13866dcdacSEd Maste #include "lldb/Core/IOHandler.h"
14f034231aSEd Maste #include "lldb/Interpreter/CommandHistory.h"
15f034231aSEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
164b4fe385SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17f034231aSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
18f73363f1SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
19f034231aSEd Maste #include "lldb/Interpreter/OptionValueBoolean.h"
20f3fbd1c0SDimitry Andric #include "lldb/Interpreter/OptionValueString.h"
21f034231aSEd Maste #include "lldb/Interpreter/OptionValueUInt64.h"
22f034231aSEd Maste #include "lldb/Interpreter/Options.h"
23f034231aSEd Maste #include "lldb/Interpreter/ScriptInterpreter.h"
24f73363f1SDimitry Andric #include "lldb/Utility/Args.h"
2574a628f7SDimitry Andric #include "lldb/Utility/StringList.h"
26b60736ecSDimitry Andric #include "llvm/ADT/StringRef.h"
27e3b55780SDimitry Andric #include <optional>
28f034231aSEd Maste
29f034231aSEd Maste using namespace lldb;
30f034231aSEd Maste using namespace lldb_private;
31f034231aSEd Maste
32f034231aSEd Maste // CommandObjectCommandsSource
33f034231aSEd Maste
34ead24645SDimitry Andric #define LLDB_OPTIONS_source
35ead24645SDimitry Andric #include "CommandOptions.inc"
3614f1b3e8SDimitry Andric
3714f1b3e8SDimitry Andric class CommandObjectCommandsSource : public CommandObjectParsed {
38f034231aSEd Maste public:
CommandObjectCommandsSource(CommandInterpreter & interpreter)39f3fbd1c0SDimitry Andric CommandObjectCommandsSource(CommandInterpreter &interpreter)
4014f1b3e8SDimitry Andric : CommandObjectParsed(
4114f1b3e8SDimitry Andric interpreter, "command source",
4214f1b3e8SDimitry Andric "Read and execute LLDB commands from the file <filename>.",
436f8fc217SDimitry Andric nullptr) {
44ac9a064cSDimitry Andric AddSimpleArgumentList(eArgTypeFilename);
45f034231aSEd Maste }
46f034231aSEd Maste
47f3fbd1c0SDimitry Andric ~CommandObjectCommandsSource() override = default;
48f034231aSEd Maste
GetRepeatCommand(Args & current_command_args,uint32_t index)49e3b55780SDimitry Andric std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
5014f1b3e8SDimitry Andric uint32_t index) override {
51145449b1SDimitry Andric return std::string("");
52f034231aSEd Maste }
53f034231aSEd Maste
GetOptions()5414f1b3e8SDimitry Andric Options *GetOptions() override { return &m_options; }
55f034231aSEd Maste
56f034231aSEd Maste protected:
5714f1b3e8SDimitry Andric class CommandOptions : public Options {
58f034231aSEd Maste public:
CommandOptions()5914f1b3e8SDimitry Andric CommandOptions()
606f8fc217SDimitry Andric : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
616f8fc217SDimitry Andric m_cmd_relative_to_command_file(false) {}
62f034231aSEd Maste
63f3fbd1c0SDimitry Andric ~CommandOptions() override = default;
64f034231aSEd Maste
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)65b76161e4SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
6614f1b3e8SDimitry Andric ExecutionContext *execution_context) override {
67b76161e4SDimitry Andric Status error;
68f034231aSEd Maste const int short_option = m_getopt_table[option_idx].val;
69f034231aSEd Maste
7014f1b3e8SDimitry Andric switch (short_option) {
71f034231aSEd Maste case 'e':
725e95aa85SEd Maste error = m_stop_on_error.SetValueFromString(option_arg);
73f034231aSEd Maste break;
74866dcdacSEd Maste
75f034231aSEd Maste case 'c':
765e95aa85SEd Maste error = m_stop_on_continue.SetValueFromString(option_arg);
77f034231aSEd Maste break;
78866dcdacSEd Maste
79c0981da4SDimitry Andric case 'C':
80c0981da4SDimitry Andric m_cmd_relative_to_command_file = true;
81c0981da4SDimitry Andric break;
82c0981da4SDimitry Andric
83f034231aSEd Maste case 's':
845e95aa85SEd Maste error = m_silent_run.SetValueFromString(option_arg);
85f034231aSEd Maste break;
86866dcdacSEd Maste
87f034231aSEd Maste default:
88ead24645SDimitry Andric llvm_unreachable("Unimplemented option");
89f034231aSEd Maste }
90f034231aSEd Maste
91f034231aSEd Maste return error;
92f034231aSEd Maste }
93f034231aSEd Maste
OptionParsingStarting(ExecutionContext * execution_context)9414f1b3e8SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
95f034231aSEd Maste m_stop_on_error.Clear();
96866dcdacSEd Maste m_silent_run.Clear();
97866dcdacSEd Maste m_stop_on_continue.Clear();
98c0981da4SDimitry Andric m_cmd_relative_to_command_file.Clear();
99f034231aSEd Maste }
100f034231aSEd Maste
GetDefinitions()10114f1b3e8SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
102e3b55780SDimitry Andric return llvm::ArrayRef(g_source_options);
103f034231aSEd Maste }
104f034231aSEd Maste
105f034231aSEd Maste // Instance variables to hold the values for command options.
106f034231aSEd Maste
107f034231aSEd Maste OptionValueBoolean m_stop_on_error;
108866dcdacSEd Maste OptionValueBoolean m_silent_run;
109866dcdacSEd Maste OptionValueBoolean m_stop_on_continue;
110c0981da4SDimitry Andric OptionValueBoolean m_cmd_relative_to_command_file;
111f034231aSEd Maste };
112f034231aSEd Maste
DoExecute(Args & command,CommandReturnObject & result)113b1c73532SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
11414f1b3e8SDimitry Andric if (command.GetArgumentCount() != 1) {
11514f1b3e8SDimitry Andric result.AppendErrorWithFormat(
11614f1b3e8SDimitry Andric "'%s' takes exactly one executable filename argument.\n",
11714f1b3e8SDimitry Andric GetCommandName().str().c_str());
118b1c73532SDimitry Andric return;
11914f1b3e8SDimitry Andric }
120f034231aSEd Maste
121c0981da4SDimitry Andric FileSpec source_dir = {};
122c0981da4SDimitry Andric if (m_options.m_cmd_relative_to_command_file) {
123c0981da4SDimitry Andric source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
124c0981da4SDimitry Andric if (!source_dir) {
125c0981da4SDimitry Andric result.AppendError("command source -C can only be specified "
126c0981da4SDimitry Andric "from a command file");
127c0981da4SDimitry Andric result.SetStatus(eReturnStatusFailed);
128b1c73532SDimitry Andric return;
129c0981da4SDimitry Andric }
130c0981da4SDimitry Andric }
131c0981da4SDimitry Andric
132ead24645SDimitry Andric FileSpec cmd_file(command[0].ref());
133c0981da4SDimitry Andric if (source_dir) {
134c0981da4SDimitry Andric // Prepend the source_dir to the cmd_file path:
135c0981da4SDimitry Andric if (!cmd_file.IsRelative()) {
136c0981da4SDimitry Andric result.AppendError("command source -C can only be used "
137c0981da4SDimitry Andric "with a relative path.");
138c0981da4SDimitry Andric result.SetStatus(eReturnStatusFailed);
139b1c73532SDimitry Andric return;
140c0981da4SDimitry Andric }
141c0981da4SDimitry Andric cmd_file.MakeAbsolute(source_dir);
142c0981da4SDimitry Andric }
143c0981da4SDimitry Andric
14494994d37SDimitry Andric FileSystem::Instance().Resolve(cmd_file);
145f034231aSEd Maste
146344a3780SDimitry Andric CommandInterpreterRunOptions options;
147866dcdacSEd Maste // If any options were set, then use them
148866dcdacSEd Maste if (m_options.m_stop_on_error.OptionWasSet() ||
149866dcdacSEd Maste m_options.m_silent_run.OptionWasSet() ||
15014f1b3e8SDimitry Andric m_options.m_stop_on_continue.OptionWasSet()) {
1515f29bb8aSDimitry Andric if (m_options.m_stop_on_continue.OptionWasSet())
1525f29bb8aSDimitry Andric options.SetStopOnContinue(
1535f29bb8aSDimitry Andric m_options.m_stop_on_continue.GetCurrentValue());
1545f29bb8aSDimitry Andric
1555f29bb8aSDimitry Andric if (m_options.m_stop_on_error.OptionWasSet())
156205afe67SEd Maste options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
15794994d37SDimitry Andric
15894994d37SDimitry Andric // Individual silent setting is override for global command echo settings.
15994994d37SDimitry Andric if (m_options.m_silent_run.GetCurrentValue()) {
16094994d37SDimitry Andric options.SetSilent(true);
16194994d37SDimitry Andric } else {
16294994d37SDimitry Andric options.SetPrintResults(true);
1635f29bb8aSDimitry Andric options.SetPrintErrors(true);
16494994d37SDimitry Andric options.SetEchoCommands(m_interpreter.GetEchoCommands());
16594994d37SDimitry Andric options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
16694994d37SDimitry Andric }
167f034231aSEd Maste }
168344a3780SDimitry Andric
169344a3780SDimitry Andric m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
170f034231aSEd Maste }
171f3fbd1c0SDimitry Andric
172f034231aSEd Maste CommandOptions m_options;
173f034231aSEd Maste };
174f034231aSEd Maste
175f034231aSEd Maste #pragma mark CommandObjectCommandsAlias
176f034231aSEd Maste // CommandObjectCommandsAlias
177f034231aSEd Maste
178ead24645SDimitry Andric #define LLDB_OPTIONS_alias
179ead24645SDimitry Andric #include "CommandOptions.inc"
18014f1b3e8SDimitry Andric
18114f1b3e8SDimitry Andric static const char *g_python_command_instructions =
18214f1b3e8SDimitry Andric "Enter your Python command(s). Type 'DONE' to end.\n"
183f034231aSEd Maste "You must define a Python function with this signature:\n"
184e3b55780SDimitry Andric "def my_command_impl(debugger, args, exe_ctx, result, internal_dict):\n";
185f034231aSEd Maste
18614f1b3e8SDimitry Andric class CommandObjectCommandsAlias : public CommandObjectRaw {
187f3fbd1c0SDimitry Andric protected:
18814f1b3e8SDimitry Andric class CommandOptions : public OptionGroup {
189f3fbd1c0SDimitry Andric public:
190145449b1SDimitry Andric CommandOptions() = default;
191f034231aSEd Maste
192f3fbd1c0SDimitry Andric ~CommandOptions() override = default;
193f3fbd1c0SDimitry Andric
GetDefinitions()19414f1b3e8SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
195e3b55780SDimitry Andric return llvm::ArrayRef(g_alias_options);
196f3fbd1c0SDimitry Andric }
197f3fbd1c0SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)198b76161e4SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
19914f1b3e8SDimitry Andric ExecutionContext *execution_context) override {
200b76161e4SDimitry Andric Status error;
201f3fbd1c0SDimitry Andric
20214f1b3e8SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option;
20314f1b3e8SDimitry Andric std::string option_str(option_value);
204f3fbd1c0SDimitry Andric
20514f1b3e8SDimitry Andric switch (short_option) {
206f3fbd1c0SDimitry Andric case 'h':
20714f1b3e8SDimitry Andric m_help.SetCurrentValue(option_str);
208f3fbd1c0SDimitry Andric m_help.SetOptionWasSet();
209f3fbd1c0SDimitry Andric break;
210f3fbd1c0SDimitry Andric
211f3fbd1c0SDimitry Andric case 'H':
21214f1b3e8SDimitry Andric m_long_help.SetCurrentValue(option_str);
213f3fbd1c0SDimitry Andric m_long_help.SetOptionWasSet();
214f3fbd1c0SDimitry Andric break;
215f3fbd1c0SDimitry Andric
216f3fbd1c0SDimitry Andric default:
217ead24645SDimitry Andric llvm_unreachable("Unimplemented option");
218f3fbd1c0SDimitry Andric }
219f3fbd1c0SDimitry Andric
220f3fbd1c0SDimitry Andric return error;
221f3fbd1c0SDimitry Andric }
222f3fbd1c0SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)22314f1b3e8SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
224f3fbd1c0SDimitry Andric m_help.Clear();
225f3fbd1c0SDimitry Andric m_long_help.Clear();
226f3fbd1c0SDimitry Andric }
227f3fbd1c0SDimitry Andric
228f3fbd1c0SDimitry Andric OptionValueString m_help;
229f3fbd1c0SDimitry Andric OptionValueString m_long_help;
230f3fbd1c0SDimitry Andric };
231f3fbd1c0SDimitry Andric
232f3fbd1c0SDimitry Andric OptionGroupOptions m_option_group;
233f3fbd1c0SDimitry Andric CommandOptions m_command_options;
234f034231aSEd Maste
235f034231aSEd Maste public:
GetOptions()23614f1b3e8SDimitry Andric Options *GetOptions() override { return &m_option_group; }
237f3fbd1c0SDimitry Andric
CommandObjectCommandsAlias(CommandInterpreter & interpreter)238f3fbd1c0SDimitry Andric CommandObjectCommandsAlias(CommandInterpreter &interpreter)
23914f1b3e8SDimitry Andric : CommandObjectRaw(
24014f1b3e8SDimitry Andric interpreter, "command alias",
2416f8fc217SDimitry Andric "Define a custom command in terms of an existing command.") {
242f3fbd1c0SDimitry Andric m_option_group.Append(&m_command_options);
243f3fbd1c0SDimitry Andric m_option_group.Finalize();
244f3fbd1c0SDimitry Andric
245f034231aSEd Maste SetHelpLong(
246027f1c96SDimitry Andric "'alias' allows the user to create a short-cut or abbreviation for long \
247027f1c96SDimitry Andric commands, multi-word commands, and commands that take particular options. \
24814f1b3e8SDimitry Andric Below are some simple examples of how one might use the 'alias' command:"
24914f1b3e8SDimitry Andric R"(
250027f1c96SDimitry Andric
251027f1c96SDimitry Andric (lldb) command alias sc script
252027f1c96SDimitry Andric
253027f1c96SDimitry Andric Creates the abbreviation 'sc' for the 'script' command.
254027f1c96SDimitry Andric
255027f1c96SDimitry Andric (lldb) command alias bp breakpoint
256027f1c96SDimitry Andric
25714f1b3e8SDimitry Andric )"
25814f1b3e8SDimitry Andric " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \
259027f1c96SDimitry Andric breakpoint commands are two-word commands, the user would still need to \
26014f1b3e8SDimitry Andric enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
26114f1b3e8SDimitry Andric R"(
262027f1c96SDimitry Andric
263027f1c96SDimitry Andric (lldb) command alias bpl breakpoint list
264027f1c96SDimitry Andric
265027f1c96SDimitry Andric Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
266027f1c96SDimitry Andric
26714f1b3e8SDimitry Andric )"
26814f1b3e8SDimitry Andric "An alias can include some options for the command, with the values either \
269027f1c96SDimitry Andric filled in at the time the alias is created, or specified as positional \
270027f1c96SDimitry Andric arguments, to be filled in when the alias is invoked. The following example \
27114f1b3e8SDimitry Andric shows how to create aliases with options:"
27214f1b3e8SDimitry Andric R"(
273027f1c96SDimitry Andric
274027f1c96SDimitry Andric (lldb) command alias bfl breakpoint set -f %1 -l %2
275027f1c96SDimitry Andric
27614f1b3e8SDimitry Andric )"
27714f1b3e8SDimitry Andric " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
278027f1c96SDimitry Andric options already part of the alias. So if the user wants to set a breakpoint \
279027f1c96SDimitry Andric by file and line without explicitly having to use the -f and -l options, the \
280027f1c96SDimitry Andric user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \
281027f1c96SDimitry Andric for the actual arguments that will be passed when the alias command is used. \
282027f1c96SDimitry Andric The number in the placeholder refers to the position/order the actual value \
283027f1c96SDimitry Andric occupies when the alias is used. All the occurrences of '%1' in the alias \
284027f1c96SDimitry Andric will be replaced with the first argument, all the occurrences of '%2' in the \
285027f1c96SDimitry Andric alias will be replaced with the second argument, and so on. This also allows \
286027f1c96SDimitry Andric actual arguments to be used multiple times within an alias (see 'process \
28714f1b3e8SDimitry Andric launch' example below)."
28814f1b3e8SDimitry Andric R"(
289027f1c96SDimitry Andric
29014f1b3e8SDimitry Andric )"
29114f1b3e8SDimitry Andric "Note: the positional arguments must substitute as whole words in the resultant \
292027f1c96SDimitry Andric command, so you can't at present do something like this to append the file extension \
29314f1b3e8SDimitry Andric \".cpp\":"
29414f1b3e8SDimitry Andric R"(
295027f1c96SDimitry Andric
296027f1c96SDimitry Andric (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
297027f1c96SDimitry Andric
29814f1b3e8SDimitry Andric )"
29914f1b3e8SDimitry Andric "For more complex aliasing, use the \"command regex\" command instead. In the \
300027f1c96SDimitry Andric 'bfl' case above, the actual file value will be filled in with the first argument \
301027f1c96SDimitry Andric following 'bfl' and the actual line number value will be filled in with the second \
30214f1b3e8SDimitry Andric argument. The user would use this alias as follows:"
30314f1b3e8SDimitry Andric R"(
304027f1c96SDimitry Andric
305027f1c96SDimitry Andric (lldb) command alias bfl breakpoint set -f %1 -l %2
306027f1c96SDimitry Andric (lldb) bfl my-file.c 137
307027f1c96SDimitry Andric
308027f1c96SDimitry Andric This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
309027f1c96SDimitry Andric
310027f1c96SDimitry Andric Another example:
311027f1c96SDimitry Andric
312027f1c96SDimitry Andric (lldb) command alias pltty process launch -s -o %1 -e %1
313027f1c96SDimitry Andric (lldb) pltty /dev/tty0
314027f1c96SDimitry Andric
315027f1c96SDimitry Andric Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
316027f1c96SDimitry Andric
31714f1b3e8SDimitry Andric )"
31814f1b3e8SDimitry Andric "If the user always wanted to pass the same value to a particular option, the \
319027f1c96SDimitry Andric alias could be defined with that value directly in the alias as a constant, \
32014f1b3e8SDimitry Andric rather than using a positional placeholder:"
32114f1b3e8SDimitry Andric R"(
322027f1c96SDimitry Andric
323027f1c96SDimitry Andric (lldb) command alias bl3 breakpoint set -f %1 -l 3
324027f1c96SDimitry Andric
32514f1b3e8SDimitry Andric Always sets a breakpoint on line 3 of whatever file is indicated.)");
326f034231aSEd Maste
327f034231aSEd Maste CommandArgumentEntry arg1;
328f034231aSEd Maste CommandArgumentEntry arg2;
329f034231aSEd Maste CommandArgumentEntry arg3;
330f034231aSEd Maste CommandArgumentData alias_arg;
331f034231aSEd Maste CommandArgumentData cmd_arg;
332f034231aSEd Maste CommandArgumentData options_arg;
333f034231aSEd Maste
334f034231aSEd Maste // Define the first (and only) variant of this arg.
335f034231aSEd Maste alias_arg.arg_type = eArgTypeAliasName;
336f034231aSEd Maste alias_arg.arg_repetition = eArgRepeatPlain;
337f034231aSEd Maste
33814f1b3e8SDimitry Andric // There is only one variant this argument could be; put it into the
33914f1b3e8SDimitry Andric // argument entry.
340f034231aSEd Maste arg1.push_back(alias_arg);
341f034231aSEd Maste
342f034231aSEd Maste // Define the first (and only) variant of this arg.
343f034231aSEd Maste cmd_arg.arg_type = eArgTypeCommandName;
344f034231aSEd Maste cmd_arg.arg_repetition = eArgRepeatPlain;
345f034231aSEd Maste
34614f1b3e8SDimitry Andric // There is only one variant this argument could be; put it into the
34714f1b3e8SDimitry Andric // argument entry.
348f034231aSEd Maste arg2.push_back(cmd_arg);
349f034231aSEd Maste
350f034231aSEd Maste // Define the first (and only) variant of this arg.
351f034231aSEd Maste options_arg.arg_type = eArgTypeAliasOptions;
352f034231aSEd Maste options_arg.arg_repetition = eArgRepeatOptional;
353f034231aSEd Maste
35414f1b3e8SDimitry Andric // There is only one variant this argument could be; put it into the
35514f1b3e8SDimitry Andric // argument entry.
356f034231aSEd Maste arg3.push_back(options_arg);
357f034231aSEd Maste
358f034231aSEd Maste // Push the data for the first argument into the m_arguments vector.
359f034231aSEd Maste m_arguments.push_back(arg1);
360f034231aSEd Maste m_arguments.push_back(arg2);
361f034231aSEd Maste m_arguments.push_back(arg3);
362f034231aSEd Maste }
363f034231aSEd Maste
364f3fbd1c0SDimitry Andric ~CommandObjectCommandsAlias() override = default;
365f034231aSEd Maste
366f034231aSEd Maste protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)367b1c73532SDimitry Andric void DoExecute(llvm::StringRef raw_command_line,
36814f1b3e8SDimitry Andric CommandReturnObject &result) override {
369f73363f1SDimitry Andric if (raw_command_line.empty()) {
370f3fbd1c0SDimitry Andric result.AppendError("'command alias' requires at least two arguments");
371b1c73532SDimitry Andric return;
372f3fbd1c0SDimitry Andric }
373f3fbd1c0SDimitry Andric
37414f1b3e8SDimitry Andric ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
37514f1b3e8SDimitry Andric m_option_group.NotifyOptionParsingStarting(&exe_ctx);
376f3fbd1c0SDimitry Andric
377f73363f1SDimitry Andric OptionsWithRaw args_with_suffix(raw_command_line);
378f3fbd1c0SDimitry Andric
379f73363f1SDimitry Andric if (args_with_suffix.HasArgs())
380f73363f1SDimitry Andric if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
381f73363f1SDimitry Andric m_option_group, exe_ctx))
382b1c73532SDimitry Andric return;
383f3fbd1c0SDimitry Andric
384cfca06d7SDimitry Andric llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
38514f1b3e8SDimitry Andric Args args(raw_command_string);
386f034231aSEd Maste
38714f1b3e8SDimitry Andric if (args.GetArgumentCount() < 2) {
388f3fbd1c0SDimitry Andric result.AppendError("'command alias' requires at least two arguments");
389b1c73532SDimitry Andric return;
390f034231aSEd Maste }
391f034231aSEd Maste
392f034231aSEd Maste // Get the alias command.
393f034231aSEd Maste
394ead24645SDimitry Andric auto alias_command = args[0].ref();
395312c0ed1SDimitry Andric if (alias_command.starts_with("-")) {
396f3fbd1c0SDimitry Andric result.AppendError("aliases starting with a dash are not supported");
39714f1b3e8SDimitry Andric if (alias_command == "--help" || alias_command == "--long-help") {
39814f1b3e8SDimitry Andric result.AppendWarning("if trying to pass options to 'command alias' add "
39914f1b3e8SDimitry Andric "a -- at the end of the options");
400f3fbd1c0SDimitry Andric }
401b1c73532SDimitry Andric return;
402f3fbd1c0SDimitry Andric }
403f034231aSEd Maste
40414f1b3e8SDimitry Andric // Strip the new alias name off 'raw_command_string' (leave it on args,
405f73363f1SDimitry Andric // which gets passed to 'Execute', which does the stripping itself.
406f034231aSEd Maste size_t pos = raw_command_string.find(alias_command);
40714f1b3e8SDimitry Andric if (pos == 0) {
408f034231aSEd Maste raw_command_string = raw_command_string.substr(alias_command.size());
409f034231aSEd Maste pos = raw_command_string.find_first_not_of(' ');
410f034231aSEd Maste if ((pos != std::string::npos) && (pos > 0))
411f034231aSEd Maste raw_command_string = raw_command_string.substr(pos);
41214f1b3e8SDimitry Andric } else {
413f034231aSEd Maste result.AppendError("Error parsing command string. No alias created.");
414b1c73532SDimitry Andric return;
415f034231aSEd Maste }
416f034231aSEd Maste
417f034231aSEd Maste // Verify that the command is alias-able.
41814f1b3e8SDimitry Andric if (m_interpreter.CommandExists(alias_command)) {
41914f1b3e8SDimitry Andric result.AppendErrorWithFormat(
42014f1b3e8SDimitry Andric "'%s' is a permanent debugger command and cannot be redefined.\n",
42114f1b3e8SDimitry Andric args[0].c_str());
422b1c73532SDimitry Andric return;
423f034231aSEd Maste }
424f034231aSEd Maste
425c0981da4SDimitry Andric if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
426c0981da4SDimitry Andric result.AppendErrorWithFormat(
427c0981da4SDimitry Andric "'%s' is a user container command and cannot be overwritten.\n"
428c0981da4SDimitry Andric "Delete it first with 'command container delete'\n",
429c0981da4SDimitry Andric args[0].c_str());
430b1c73532SDimitry Andric return;
431c0981da4SDimitry Andric }
432c0981da4SDimitry Andric
43314f1b3e8SDimitry Andric // Get CommandObject that is being aliased. The command name is read from
43414f1b3e8SDimitry Andric // the front of raw_command_string. raw_command_string is returned with the
43514f1b3e8SDimitry Andric // name of the command object stripped off the front.
43614f1b3e8SDimitry Andric llvm::StringRef original_raw_command_string = raw_command_string;
43714f1b3e8SDimitry Andric CommandObject *cmd_obj =
43814f1b3e8SDimitry Andric m_interpreter.GetCommandObjectForCommand(raw_command_string);
439f034231aSEd Maste
44014f1b3e8SDimitry Andric if (!cmd_obj) {
44114f1b3e8SDimitry Andric result.AppendErrorWithFormat("invalid command given to 'command alias'. "
44214f1b3e8SDimitry Andric "'%s' does not begin with a valid command."
44314f1b3e8SDimitry Andric " No alias created.",
44414f1b3e8SDimitry Andric original_raw_command_string.str().c_str());
44514f1b3e8SDimitry Andric } else if (!cmd_obj->WantsRawCommandString()) {
44614f1b3e8SDimitry Andric // Note that args was initialized with the original command, and has not
447f73363f1SDimitry Andric // been updated to this point. Therefore can we pass it to the version of
448f73363f1SDimitry Andric // Execute that does not need/expect raw input in the alias.
449b1c73532SDimitry Andric HandleAliasingNormalCommand(args, result);
45014f1b3e8SDimitry Andric } else {
451b1c73532SDimitry Andric HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj,
452b1c73532SDimitry Andric result);
453f034231aSEd Maste }
454f034231aSEd Maste }
455f034231aSEd Maste
HandleAliasingRawCommand(llvm::StringRef alias_command,llvm::StringRef raw_command_string,CommandObject & cmd_obj,CommandReturnObject & result)45614f1b3e8SDimitry Andric bool HandleAliasingRawCommand(llvm::StringRef alias_command,
45714f1b3e8SDimitry Andric llvm::StringRef raw_command_string,
45814f1b3e8SDimitry Andric CommandObject &cmd_obj,
45914f1b3e8SDimitry Andric CommandReturnObject &result) {
460f034231aSEd Maste // Verify & handle any options/arguments passed to the alias command
461f034231aSEd Maste
46214f1b3e8SDimitry Andric OptionArgVectorSP option_arg_vector_sp =
46314f1b3e8SDimitry Andric OptionArgVectorSP(new OptionArgVector);
464f034231aSEd Maste
4656f8fc217SDimitry Andric const bool include_aliases = true;
466e3b55780SDimitry Andric // Look up the command using command's name first. This is to resolve
467e3b55780SDimitry Andric // aliases when you are making nested aliases. But if you don't find
468e3b55780SDimitry Andric // it that way, then it wasn't an alias and we can just use the object
469e3b55780SDimitry Andric // we were passed in.
470e3b55780SDimitry Andric CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
471e3b55780SDimitry Andric cmd_obj.GetCommandName(), include_aliases);
472e3b55780SDimitry Andric if (!cmd_obj_sp)
473e3b55780SDimitry Andric cmd_obj_sp = cmd_obj.shared_from_this();
474e3b55780SDimitry Andric
47514f1b3e8SDimitry Andric if (m_interpreter.AliasExists(alias_command) ||
47614f1b3e8SDimitry Andric m_interpreter.UserCommandExists(alias_command)) {
47714f1b3e8SDimitry Andric result.AppendWarningWithFormat(
47814f1b3e8SDimitry Andric "Overwriting existing definition for '%s'.\n",
47914f1b3e8SDimitry Andric alias_command.str().c_str());
480f034231aSEd Maste }
48114f1b3e8SDimitry Andric if (CommandAlias *alias = m_interpreter.AddAlias(
48214f1b3e8SDimitry Andric alias_command, cmd_obj_sp, raw_command_string)) {
483f3fbd1c0SDimitry Andric if (m_command_options.m_help.OptionWasSet())
484f3fbd1c0SDimitry Andric alias->SetHelp(m_command_options.m_help.GetCurrentValue());
485f3fbd1c0SDimitry Andric if (m_command_options.m_long_help.OptionWasSet())
486f3fbd1c0SDimitry Andric alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
487f034231aSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult);
48814f1b3e8SDimitry Andric } else {
489f034231aSEd Maste result.AppendError("Unable to create requested alias.\n");
490f034231aSEd Maste }
491f034231aSEd Maste return result.Succeeded();
492f034231aSEd Maste }
493f034231aSEd Maste
HandleAliasingNormalCommand(Args & args,CommandReturnObject & result)49414f1b3e8SDimitry Andric bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
495f034231aSEd Maste size_t argc = args.GetArgumentCount();
496f034231aSEd Maste
49714f1b3e8SDimitry Andric if (argc < 2) {
498f3fbd1c0SDimitry Andric result.AppendError("'command alias' requires at least two arguments");
499f034231aSEd Maste return false;
500f034231aSEd Maste }
501f034231aSEd Maste
50214f1b3e8SDimitry Andric // Save these in std::strings since we're going to shift them off.
503cfca06d7SDimitry Andric const std::string alias_command(std::string(args[0].ref()));
504cfca06d7SDimitry Andric const std::string actual_command(std::string(args[1].ref()));
505f034231aSEd Maste
506f034231aSEd Maste args.Shift(); // Shift the alias command word off the argument vector.
507f034231aSEd Maste args.Shift(); // Shift the old command word off the argument vector.
508f034231aSEd Maste
50914f1b3e8SDimitry Andric // Verify that the command is alias'able, and get the appropriate command
51014f1b3e8SDimitry Andric // object.
511f034231aSEd Maste
51214f1b3e8SDimitry Andric if (m_interpreter.CommandExists(alias_command)) {
51314f1b3e8SDimitry Andric result.AppendErrorWithFormat(
51414f1b3e8SDimitry Andric "'%s' is a permanent debugger command and cannot be redefined.\n",
515f034231aSEd Maste alias_command.c_str());
51614f1b3e8SDimitry Andric return false;
517f034231aSEd Maste }
51814f1b3e8SDimitry Andric
519c0981da4SDimitry Andric if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
520c0981da4SDimitry Andric result.AppendErrorWithFormat(
521c0981da4SDimitry Andric "'%s' is user container command and cannot be overwritten.\n"
522c0981da4SDimitry Andric "Delete it first with 'command container delete'",
523c0981da4SDimitry Andric alias_command.c_str());
524c0981da4SDimitry Andric return false;
525c0981da4SDimitry Andric }
526c0981da4SDimitry Andric
52714f1b3e8SDimitry Andric CommandObjectSP command_obj_sp(
52814f1b3e8SDimitry Andric m_interpreter.GetCommandSPExact(actual_command, true));
529f034231aSEd Maste CommandObjectSP subcommand_obj_sp;
530f034231aSEd Maste bool use_subcommand = false;
53114f1b3e8SDimitry Andric if (!command_obj_sp) {
53214f1b3e8SDimitry Andric result.AppendErrorWithFormat("'%s' is not an existing command.\n",
53314f1b3e8SDimitry Andric actual_command.c_str());
53414f1b3e8SDimitry Andric return false;
53514f1b3e8SDimitry Andric }
536f034231aSEd Maste CommandObject *cmd_obj = command_obj_sp.get();
537f3fbd1c0SDimitry Andric CommandObject *sub_cmd_obj = nullptr;
53814f1b3e8SDimitry Andric OptionArgVectorSP option_arg_vector_sp =
53914f1b3e8SDimitry Andric OptionArgVectorSP(new OptionArgVector);
540f034231aSEd Maste
54114f1b3e8SDimitry Andric while (cmd_obj->IsMultiwordObject() && !args.empty()) {
542ead24645SDimitry Andric auto sub_command = args[0].ref();
54314f1b3e8SDimitry Andric assert(!sub_command.empty());
54414f1b3e8SDimitry Andric subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
54514f1b3e8SDimitry Andric if (!subcommand_obj_sp) {
54614f1b3e8SDimitry Andric result.AppendErrorWithFormat(
54714f1b3e8SDimitry Andric "'%s' is not a valid sub-command of '%s'. "
54814f1b3e8SDimitry Andric "Unable to create alias.\n",
54914f1b3e8SDimitry Andric args[0].c_str(), actual_command.c_str());
55014f1b3e8SDimitry Andric return false;
55114f1b3e8SDimitry Andric }
55214f1b3e8SDimitry Andric
553f034231aSEd Maste sub_cmd_obj = subcommand_obj_sp.get();
554f034231aSEd Maste use_subcommand = true;
555f034231aSEd Maste args.Shift(); // Shift the sub_command word off the argument vector.
556f034231aSEd Maste cmd_obj = sub_cmd_obj;
557f034231aSEd Maste }
558f034231aSEd Maste
559f034231aSEd Maste // Verify & handle any options/arguments passed to the alias command
560f034231aSEd Maste
561f3fbd1c0SDimitry Andric std::string args_string;
562f3fbd1c0SDimitry Andric
56314f1b3e8SDimitry Andric if (!args.empty()) {
56414f1b3e8SDimitry Andric CommandObjectSP tmp_sp =
565b60736ecSDimitry Andric m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
566f034231aSEd Maste if (use_subcommand)
567b60736ecSDimitry Andric tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
568f034231aSEd Maste
569f034231aSEd Maste args.GetCommandString(args_string);
570f3fbd1c0SDimitry Andric }
571f034231aSEd Maste
57214f1b3e8SDimitry Andric if (m_interpreter.AliasExists(alias_command) ||
57314f1b3e8SDimitry Andric m_interpreter.UserCommandExists(alias_command)) {
57414f1b3e8SDimitry Andric result.AppendWarningWithFormat(
57514f1b3e8SDimitry Andric "Overwriting existing definition for '%s'.\n", alias_command.c_str());
576f3fbd1c0SDimitry Andric }
577f3fbd1c0SDimitry Andric
57814f1b3e8SDimitry Andric if (CommandAlias *alias = m_interpreter.AddAlias(
57914f1b3e8SDimitry Andric alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
58014f1b3e8SDimitry Andric args_string)) {
581f3fbd1c0SDimitry Andric if (m_command_options.m_help.OptionWasSet())
582f3fbd1c0SDimitry Andric alias->SetHelp(m_command_options.m_help.GetCurrentValue());
583f3fbd1c0SDimitry Andric if (m_command_options.m_long_help.OptionWasSet())
584f3fbd1c0SDimitry Andric alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
585f3fbd1c0SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
58614f1b3e8SDimitry Andric } else {
587f034231aSEd Maste result.AppendError("Unable to create requested alias.\n");
588f034231aSEd Maste return false;
589f034231aSEd Maste }
590f034231aSEd Maste
591f034231aSEd Maste return result.Succeeded();
592f034231aSEd Maste }
593f3fbd1c0SDimitry Andric };
594f034231aSEd Maste
595f034231aSEd Maste #pragma mark CommandObjectCommandsUnalias
596f034231aSEd Maste // CommandObjectCommandsUnalias
597f034231aSEd Maste
59814f1b3e8SDimitry Andric class CommandObjectCommandsUnalias : public CommandObjectParsed {
599f034231aSEd Maste public:
CommandObjectCommandsUnalias(CommandInterpreter & interpreter)600f3fbd1c0SDimitry Andric CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
60114f1b3e8SDimitry Andric : CommandObjectParsed(
60214f1b3e8SDimitry Andric interpreter, "command unalias",
60314f1b3e8SDimitry Andric "Delete one or more custom commands defined by 'command alias'.",
60414f1b3e8SDimitry Andric nullptr) {
605ac9a064cSDimitry Andric AddSimpleArgumentList(eArgTypeAliasName);
606f034231aSEd Maste }
607f034231aSEd Maste
608f3fbd1c0SDimitry Andric ~CommandObjectCommandsUnalias() override = default;
609f034231aSEd Maste
610b60736ecSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)611b60736ecSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
612b60736ecSDimitry Andric OptionElementVector &opt_element_vector) override {
613b60736ecSDimitry Andric if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
614b60736ecSDimitry Andric return;
615b60736ecSDimitry Andric
616b60736ecSDimitry Andric for (const auto &ent : m_interpreter.GetAliases()) {
617b60736ecSDimitry Andric request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
618b60736ecSDimitry Andric }
619b60736ecSDimitry Andric }
620b60736ecSDimitry Andric
621f034231aSEd Maste protected:
DoExecute(Args & args,CommandReturnObject & result)622b1c73532SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
623f034231aSEd Maste CommandObject::CommandMap::iterator pos;
624f034231aSEd Maste CommandObject *cmd_obj;
625f034231aSEd Maste
62614f1b3e8SDimitry Andric if (args.empty()) {
627f034231aSEd Maste result.AppendError("must call 'unalias' with a valid alias");
628b1c73532SDimitry Andric return;
629f034231aSEd Maste }
630f034231aSEd Maste
631ead24645SDimitry Andric auto command_name = args[0].ref();
63214f1b3e8SDimitry Andric cmd_obj = m_interpreter.GetCommandObject(command_name);
63314f1b3e8SDimitry Andric if (!cmd_obj) {
63414f1b3e8SDimitry Andric result.AppendErrorWithFormat(
63514f1b3e8SDimitry Andric "'%s' is not a known command.\nTry 'help' to see a "
63614f1b3e8SDimitry Andric "current list of commands.\n",
63714f1b3e8SDimitry Andric args[0].c_str());
638b1c73532SDimitry Andric return;
63914f1b3e8SDimitry Andric }
64014f1b3e8SDimitry Andric
64114f1b3e8SDimitry Andric if (m_interpreter.CommandExists(command_name)) {
64214f1b3e8SDimitry Andric if (cmd_obj->IsRemovable()) {
64314f1b3e8SDimitry Andric result.AppendErrorWithFormat(
64414f1b3e8SDimitry Andric "'%s' is not an alias, it is a debugger command which can be "
64514f1b3e8SDimitry Andric "removed using the 'command delete' command.\n",
64614f1b3e8SDimitry Andric args[0].c_str());
64714f1b3e8SDimitry Andric } else {
64814f1b3e8SDimitry Andric result.AppendErrorWithFormat(
64914f1b3e8SDimitry Andric "'%s' is a permanent debugger command and cannot be removed.\n",
65014f1b3e8SDimitry Andric args[0].c_str());
65114f1b3e8SDimitry Andric }
652b1c73532SDimitry Andric return;
65314f1b3e8SDimitry Andric }
65414f1b3e8SDimitry Andric
65514f1b3e8SDimitry Andric if (!m_interpreter.RemoveAlias(command_name)) {
65614f1b3e8SDimitry Andric if (m_interpreter.AliasExists(command_name))
65714f1b3e8SDimitry Andric result.AppendErrorWithFormat(
65814f1b3e8SDimitry Andric "Error occurred while attempting to unalias '%s'.\n",
65914f1b3e8SDimitry Andric args[0].c_str());
66014f1b3e8SDimitry Andric else
66114f1b3e8SDimitry Andric result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
66214f1b3e8SDimitry Andric args[0].c_str());
663b1c73532SDimitry Andric return;
66414f1b3e8SDimitry Andric }
66514f1b3e8SDimitry Andric
66614f1b3e8SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
667f034231aSEd Maste }
668f034231aSEd Maste };
669f034231aSEd Maste
670205afe67SEd Maste #pragma mark CommandObjectCommandsDelete
671205afe67SEd Maste // CommandObjectCommandsDelete
672205afe67SEd Maste
67314f1b3e8SDimitry Andric class CommandObjectCommandsDelete : public CommandObjectParsed {
674205afe67SEd Maste public:
CommandObjectCommandsDelete(CommandInterpreter & interpreter)675f3fbd1c0SDimitry Andric CommandObjectCommandsDelete(CommandInterpreter &interpreter)
67614f1b3e8SDimitry Andric : CommandObjectParsed(
67714f1b3e8SDimitry Andric interpreter, "command delete",
67814f1b3e8SDimitry Andric "Delete one or more custom commands defined by 'command regex'.",
67914f1b3e8SDimitry Andric nullptr) {
680ac9a064cSDimitry Andric AddSimpleArgumentList(eArgTypeCommandName);
681205afe67SEd Maste }
682205afe67SEd Maste
683f3fbd1c0SDimitry Andric ~CommandObjectCommandsDelete() override = default;
684205afe67SEd Maste
685b60736ecSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)686b60736ecSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
687b60736ecSDimitry Andric OptionElementVector &opt_element_vector) override {
688b60736ecSDimitry Andric if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
689b60736ecSDimitry Andric return;
690b60736ecSDimitry Andric
691b60736ecSDimitry Andric for (const auto &ent : m_interpreter.GetCommands()) {
692b60736ecSDimitry Andric if (ent.second->IsRemovable())
693b60736ecSDimitry Andric request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
694b60736ecSDimitry Andric }
695b60736ecSDimitry Andric }
696b60736ecSDimitry Andric
697205afe67SEd Maste protected:
DoExecute(Args & args,CommandReturnObject & result)698b1c73532SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
699205afe67SEd Maste CommandObject::CommandMap::iterator pos;
700205afe67SEd Maste
70114f1b3e8SDimitry Andric if (args.empty()) {
70214f1b3e8SDimitry Andric result.AppendErrorWithFormat("must call '%s' with one or more valid user "
70314f1b3e8SDimitry Andric "defined regular expression command names",
70414f1b3e8SDimitry Andric GetCommandName().str().c_str());
705b1c73532SDimitry Andric return;
706205afe67SEd Maste }
70714f1b3e8SDimitry Andric
708ead24645SDimitry Andric auto command_name = args[0].ref();
70914f1b3e8SDimitry Andric if (!m_interpreter.CommandExists(command_name)) {
710f3fbd1c0SDimitry Andric StreamString error_msg_stream;
7115f29bb8aSDimitry Andric const bool generate_upropos = true;
712f3fbd1c0SDimitry Andric const bool generate_type_lookup = false;
71314f1b3e8SDimitry Andric CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
71414f1b3e8SDimitry Andric &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
7155f29bb8aSDimitry Andric generate_upropos, generate_type_lookup);
71614f1b3e8SDimitry Andric result.AppendError(error_msg_stream.GetString());
717b1c73532SDimitry Andric return;
718205afe67SEd Maste }
719205afe67SEd Maste
72014f1b3e8SDimitry Andric if (!m_interpreter.RemoveCommand(command_name)) {
72114f1b3e8SDimitry Andric result.AppendErrorWithFormat(
72214f1b3e8SDimitry Andric "'%s' is a permanent debugger command and cannot be removed.\n",
72314f1b3e8SDimitry Andric args[0].c_str());
724b1c73532SDimitry Andric return;
72514f1b3e8SDimitry Andric }
72614f1b3e8SDimitry Andric
72714f1b3e8SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
728205afe67SEd Maste }
729205afe67SEd Maste };
730205afe67SEd Maste
731f034231aSEd Maste // CommandObjectCommandsAddRegex
73214f1b3e8SDimitry Andric
733ead24645SDimitry Andric #define LLDB_OPTIONS_regex
734ead24645SDimitry Andric #include "CommandOptions.inc"
73514f1b3e8SDimitry Andric
736f034231aSEd Maste #pragma mark CommandObjectCommandsAddRegex
737f034231aSEd Maste
73814f1b3e8SDimitry Andric class CommandObjectCommandsAddRegex : public CommandObjectParsed,
73914f1b3e8SDimitry Andric public IOHandlerDelegateMultiline {
740f034231aSEd Maste public:
CommandObjectCommandsAddRegex(CommandInterpreter & interpreter)741f3fbd1c0SDimitry Andric CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
74214f1b3e8SDimitry Andric : CommandObjectParsed(
743706b4fc4SDimitry Andric interpreter, "command regex",
744706b4fc4SDimitry Andric "Define a custom command in terms of "
74514f1b3e8SDimitry Andric "existing commands by matching "
74614f1b3e8SDimitry Andric "regular expressions.",
747f034231aSEd Maste "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
74814f1b3e8SDimitry Andric IOHandlerDelegateMultiline("",
7496f8fc217SDimitry Andric IOHandlerDelegate::Completion::LLDBCommand) {
75014f1b3e8SDimitry Andric SetHelpLong(
75114f1b3e8SDimitry Andric R"(
75214f1b3e8SDimitry Andric )"
75314f1b3e8SDimitry Andric "This command allows the user to create powerful regular expression commands \
754027f1c96SDimitry Andric with substitutions. The regular expressions and substitutions are specified \
75514f1b3e8SDimitry Andric using the regular expression substitution format of:"
75614f1b3e8SDimitry Andric R"(
757027f1c96SDimitry Andric
758027f1c96SDimitry Andric s/<regex>/<subst>/
759027f1c96SDimitry Andric
76014f1b3e8SDimitry Andric )"
76114f1b3e8SDimitry Andric "<regex> is a regular expression that can use parenthesis to capture regular \
762027f1c96SDimitry Andric expression input and substitute the captured matches in the output using %1 \
76314f1b3e8SDimitry Andric for the first match, %2 for the second, and so on."
76414f1b3e8SDimitry Andric R"(
765027f1c96SDimitry Andric
76614f1b3e8SDimitry Andric )"
76714f1b3e8SDimitry Andric "The regular expressions can all be specified on the command line if more than \
768027f1c96SDimitry Andric one argument is provided. If just the command name is provided on the command \
769027f1c96SDimitry Andric line, then the regular expressions and substitutions can be entered on separate \
77014f1b3e8SDimitry Andric lines, followed by an empty line to terminate the command definition."
77114f1b3e8SDimitry Andric R"(
772027f1c96SDimitry Andric
773027f1c96SDimitry Andric EXAMPLES
774027f1c96SDimitry Andric
77514f1b3e8SDimitry Andric )"
77614f1b3e8SDimitry Andric "The following example will define a regular expression command named 'f' that \
777027f1c96SDimitry Andric will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
77814f1b3e8SDimitry Andric a number follows 'f':"
77914f1b3e8SDimitry Andric R"(
780027f1c96SDimitry Andric
78114f1b3e8SDimitry Andric (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
782ac9a064cSDimitry Andric AddSimpleArgumentList(eArgTypeSEDStylePair, eArgRepeatOptional);
783f034231aSEd Maste }
784f034231aSEd Maste
785f3fbd1c0SDimitry Andric ~CommandObjectCommandsAddRegex() override = default;
786f034231aSEd Maste
787f034231aSEd Maste protected:
IOHandlerActivated(IOHandler & io_handler,bool interactive)7885f29bb8aSDimitry Andric void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
789ead24645SDimitry Andric StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
7905f29bb8aSDimitry Andric if (output_sp && interactive) {
7915f29bb8aSDimitry Andric output_sp->PutCString("Enter one or more sed substitution commands in "
79214f1b3e8SDimitry Andric "the form: 's/<regex>/<subst>/'.\nTerminate the "
79314f1b3e8SDimitry Andric "substitution list with an empty line.\n");
794866dcdacSEd Maste output_sp->Flush();
795866dcdacSEd Maste }
796866dcdacSEd Maste }
797866dcdacSEd Maste
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)79814f1b3e8SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler,
79914f1b3e8SDimitry Andric std::string &data) override {
800866dcdacSEd Maste io_handler.SetIsDone(true);
8015f29bb8aSDimitry Andric if (m_regex_cmd_up) {
802866dcdacSEd Maste StringList lines;
80314f1b3e8SDimitry Andric if (lines.SplitIntoLines(data)) {
804866dcdacSEd Maste bool check_only = false;
805ead24645SDimitry Andric for (const std::string &line : lines) {
806ead24645SDimitry Andric Status error = AppendRegexSubstitution(line, check_only);
80714f1b3e8SDimitry Andric if (error.Fail()) {
8085f29bb8aSDimitry Andric if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
8095f29bb8aSDimitry Andric StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
810866dcdacSEd Maste out_stream->Printf("error: %s\n", error.AsCString());
811866dcdacSEd Maste }
812866dcdacSEd Maste }
813866dcdacSEd Maste }
814866dcdacSEd Maste }
8155f29bb8aSDimitry Andric if (m_regex_cmd_up->HasRegexEntries()) {
8165f29bb8aSDimitry Andric CommandObjectSP cmd_sp(m_regex_cmd_up.release());
817866dcdacSEd Maste m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
818866dcdacSEd Maste }
819866dcdacSEd Maste }
820866dcdacSEd Maste }
821866dcdacSEd Maste
DoExecute(Args & command,CommandReturnObject & result)822b1c73532SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
823f034231aSEd Maste const size_t argc = command.GetArgumentCount();
82414f1b3e8SDimitry Andric if (argc == 0) {
82514f1b3e8SDimitry Andric result.AppendError("usage: 'command regex <command-name> "
82614f1b3e8SDimitry Andric "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
827b1c73532SDimitry Andric return;
828f034231aSEd Maste }
829f034231aSEd Maste
830b76161e4SDimitry Andric Status error;
831ead24645SDimitry Andric auto name = command[0].ref();
832ead24645SDimitry Andric m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
8337fa27ce4SDimitry Andric m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 0,
83414f1b3e8SDimitry Andric true);
83514f1b3e8SDimitry Andric
83614f1b3e8SDimitry Andric if (argc == 1) {
8375f29bb8aSDimitry Andric Debugger &debugger = GetDebugger();
838205afe67SEd Maste bool color_prompt = debugger.GetUseColor();
839866dcdacSEd Maste const bool multiple_lines = true; // Get multiple lines
84014f1b3e8SDimitry Andric IOHandlerSP io_handler_sp(new IOHandlerEditline(
84114f1b3e8SDimitry Andric debugger, IOHandler::Type::Other,
8420cac4ca3SEd Maste "lldb-regex", // Name of input reader for history
84314f1b3e8SDimitry Andric llvm::StringRef("> "), // Prompt
84414f1b3e8SDimitry Andric llvm::StringRef(), // Continuation prompt
84514f1b3e8SDimitry Andric multiple_lines, color_prompt,
8460cac4ca3SEd Maste 0, // Don't show line numbers
847e3b55780SDimitry Andric *this));
848866dcdacSEd Maste
84914f1b3e8SDimitry Andric if (io_handler_sp) {
850cfca06d7SDimitry Andric debugger.RunIOHandlerAsync(io_handler_sp);
851f034231aSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult);
852f034231aSEd Maste }
85314f1b3e8SDimitry Andric } else {
85414f1b3e8SDimitry Andric for (auto &entry : command.entries().drop_front()) {
855866dcdacSEd Maste bool check_only = false;
856ead24645SDimitry Andric error = AppendRegexSubstitution(entry.ref(), check_only);
857f034231aSEd Maste if (error.Fail())
858f034231aSEd Maste break;
859f034231aSEd Maste }
860f034231aSEd Maste
86114f1b3e8SDimitry Andric if (error.Success()) {
862f034231aSEd Maste AddRegexCommandToInterpreter();
863f034231aSEd Maste }
864f034231aSEd Maste }
86514f1b3e8SDimitry Andric if (error.Fail()) {
866f034231aSEd Maste result.AppendError(error.AsCString());
867f034231aSEd Maste }
868f034231aSEd Maste }
869f034231aSEd Maste
AppendRegexSubstitution(const llvm::StringRef & regex_sed,bool check_only)870b76161e4SDimitry Andric Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed,
87114f1b3e8SDimitry Andric bool check_only) {
872b76161e4SDimitry Andric Status error;
873f034231aSEd Maste
8745f29bb8aSDimitry Andric if (!m_regex_cmd_up) {
87514f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
87614f1b3e8SDimitry Andric "invalid regular expression command object for: '%.*s'",
87714f1b3e8SDimitry Andric (int)regex_sed.size(), regex_sed.data());
878f034231aSEd Maste return error;
879f034231aSEd Maste }
880f034231aSEd Maste
881f034231aSEd Maste size_t regex_sed_size = regex_sed.size();
882f034231aSEd Maste
88314f1b3e8SDimitry Andric if (regex_sed_size <= 1) {
88414f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
88514f1b3e8SDimitry Andric "regular expression substitution string is too short: '%.*s'",
88614f1b3e8SDimitry Andric (int)regex_sed.size(), regex_sed.data());
887f034231aSEd Maste return error;
888f034231aSEd Maste }
889f034231aSEd Maste
89014f1b3e8SDimitry Andric if (regex_sed[0] != 's') {
89114f1b3e8SDimitry Andric error.SetErrorStringWithFormat("regular expression substitution string "
89214f1b3e8SDimitry Andric "doesn't start with 's': '%.*s'",
89314f1b3e8SDimitry Andric (int)regex_sed.size(), regex_sed.data());
894f034231aSEd Maste return error;
895f034231aSEd Maste }
896f034231aSEd Maste const size_t first_separator_char_pos = 1;
897f73363f1SDimitry Andric // use the char that follows 's' as the regex separator character so we can
898f73363f1SDimitry Andric // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
899f034231aSEd Maste const char separator_char = regex_sed[first_separator_char_pos];
90014f1b3e8SDimitry Andric const size_t second_separator_char_pos =
90114f1b3e8SDimitry Andric regex_sed.find(separator_char, first_separator_char_pos + 1);
902f034231aSEd Maste
90314f1b3e8SDimitry Andric if (second_separator_char_pos == std::string::npos) {
90414f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
90514f1b3e8SDimitry Andric "missing second '%c' separator char after '%.*s' in '%.*s'",
906f034231aSEd Maste separator_char,
907f034231aSEd Maste (int)(regex_sed.size() - first_separator_char_pos - 1),
908205afe67SEd Maste regex_sed.data() + (first_separator_char_pos + 1),
90914f1b3e8SDimitry Andric (int)regex_sed.size(), regex_sed.data());
910f034231aSEd Maste return error;
911f034231aSEd Maste }
912f034231aSEd Maste
91314f1b3e8SDimitry Andric const size_t third_separator_char_pos =
91414f1b3e8SDimitry Andric regex_sed.find(separator_char, second_separator_char_pos + 1);
915f034231aSEd Maste
91614f1b3e8SDimitry Andric if (third_separator_char_pos == std::string::npos) {
91714f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
91814f1b3e8SDimitry Andric "missing third '%c' separator char after '%.*s' in '%.*s'",
919f034231aSEd Maste separator_char,
920f034231aSEd Maste (int)(regex_sed.size() - second_separator_char_pos - 1),
921205afe67SEd Maste regex_sed.data() + (second_separator_char_pos + 1),
92214f1b3e8SDimitry Andric (int)regex_sed.size(), regex_sed.data());
923f034231aSEd Maste return error;
924f034231aSEd Maste }
925f034231aSEd Maste
92614f1b3e8SDimitry Andric if (third_separator_char_pos != regex_sed_size - 1) {
927f73363f1SDimitry Andric // Make sure that everything that follows the last regex separator char
92814f1b3e8SDimitry Andric if (regex_sed.find_first_not_of("\t\n\v\f\r ",
92914f1b3e8SDimitry Andric third_separator_char_pos + 1) !=
93014f1b3e8SDimitry Andric std::string::npos) {
93114f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
93214f1b3e8SDimitry Andric "extra data found after the '%.*s' regular expression substitution "
93314f1b3e8SDimitry Andric "string: '%.*s'",
93414f1b3e8SDimitry Andric (int)third_separator_char_pos + 1, regex_sed.data(),
935f034231aSEd Maste (int)(regex_sed.size() - third_separator_char_pos - 1),
936f034231aSEd Maste regex_sed.data() + (third_separator_char_pos + 1));
937f034231aSEd Maste return error;
938f034231aSEd Maste }
93914f1b3e8SDimitry Andric } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
94014f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
94114f1b3e8SDimitry Andric "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
94214f1b3e8SDimitry Andric separator_char, separator_char, separator_char, (int)regex_sed.size(),
943f034231aSEd Maste regex_sed.data());
944f034231aSEd Maste return error;
94514f1b3e8SDimitry Andric } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
94614f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
94714f1b3e8SDimitry Andric "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
94814f1b3e8SDimitry Andric separator_char, separator_char, separator_char, (int)regex_sed.size(),
949f034231aSEd Maste regex_sed.data());
950f034231aSEd Maste return error;
951f034231aSEd Maste }
952866dcdacSEd Maste
95314f1b3e8SDimitry Andric if (!check_only) {
954cfca06d7SDimitry Andric std::string regex(std::string(regex_sed.substr(
955cfca06d7SDimitry Andric first_separator_char_pos + 1,
956cfca06d7SDimitry Andric second_separator_char_pos - first_separator_char_pos - 1)));
957cfca06d7SDimitry Andric std::string subst(std::string(regex_sed.substr(
958cfca06d7SDimitry Andric second_separator_char_pos + 1,
959cfca06d7SDimitry Andric third_separator_char_pos - second_separator_char_pos - 1)));
960b60736ecSDimitry Andric m_regex_cmd_up->AddRegexCommand(regex, subst);
961866dcdacSEd Maste }
962f034231aSEd Maste return error;
963f034231aSEd Maste }
964f034231aSEd Maste
AddRegexCommandToInterpreter()96514f1b3e8SDimitry Andric void AddRegexCommandToInterpreter() {
9665f29bb8aSDimitry Andric if (m_regex_cmd_up) {
9675f29bb8aSDimitry Andric if (m_regex_cmd_up->HasRegexEntries()) {
9685f29bb8aSDimitry Andric CommandObjectSP cmd_sp(m_regex_cmd_up.release());
969f034231aSEd Maste m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
970f034231aSEd Maste }
971f034231aSEd Maste }
972f034231aSEd Maste }
973f034231aSEd Maste
974f034231aSEd Maste private:
9755f29bb8aSDimitry Andric std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
976f034231aSEd Maste
97714f1b3e8SDimitry Andric class CommandOptions : public Options {
978f034231aSEd Maste public:
979145449b1SDimitry Andric CommandOptions() = default;
980f034231aSEd Maste
981f3fbd1c0SDimitry Andric ~CommandOptions() override = default;
982f034231aSEd Maste
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)983b76161e4SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
98414f1b3e8SDimitry Andric ExecutionContext *execution_context) override {
985b76161e4SDimitry Andric Status error;
986f034231aSEd Maste const int short_option = m_getopt_table[option_idx].val;
987f034231aSEd Maste
98814f1b3e8SDimitry Andric switch (short_option) {
989f034231aSEd Maste case 'h':
990cfca06d7SDimitry Andric m_help.assign(std::string(option_arg));
991f034231aSEd Maste break;
992f034231aSEd Maste case 's':
993cfca06d7SDimitry Andric m_syntax.assign(std::string(option_arg));
994f034231aSEd Maste break;
995f034231aSEd Maste default:
996ead24645SDimitry Andric llvm_unreachable("Unimplemented option");
997f034231aSEd Maste }
998f034231aSEd Maste
999f034231aSEd Maste return error;
1000f034231aSEd Maste }
1001f034231aSEd Maste
OptionParsingStarting(ExecutionContext * execution_context)100214f1b3e8SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
1003f034231aSEd Maste m_help.clear();
1004f034231aSEd Maste m_syntax.clear();
1005f034231aSEd Maste }
1006f034231aSEd Maste
GetDefinitions()100714f1b3e8SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1008e3b55780SDimitry Andric return llvm::ArrayRef(g_regex_options);
1009f034231aSEd Maste }
1010f034231aSEd Maste
GetHelp()1011cfca06d7SDimitry Andric llvm::StringRef GetHelp() { return m_help; }
1012f3fbd1c0SDimitry Andric
GetSyntax()1013cfca06d7SDimitry Andric llvm::StringRef GetSyntax() { return m_syntax; }
1014f3fbd1c0SDimitry Andric
1015f034231aSEd Maste protected:
1016f3fbd1c0SDimitry Andric // Instance variables to hold the values for command options.
1017f3fbd1c0SDimitry Andric
1018f034231aSEd Maste std::string m_help;
1019f034231aSEd Maste std::string m_syntax;
1020f034231aSEd Maste };
1021f034231aSEd Maste
GetOptions()102214f1b3e8SDimitry Andric Options *GetOptions() override { return &m_options; }
1023f034231aSEd Maste
1024f034231aSEd Maste CommandOptions m_options;
1025f034231aSEd Maste };
1026f034231aSEd Maste
102714f1b3e8SDimitry Andric class CommandObjectPythonFunction : public CommandObjectRaw {
1028f034231aSEd Maste public:
CommandObjectPythonFunction(CommandInterpreter & interpreter,std::string name,std::string funct,std::string help,ScriptedCommandSynchronicity synch,CompletionType completion_type)102914f1b3e8SDimitry Andric CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
103014f1b3e8SDimitry Andric std::string funct, std::string help,
10317fa27ce4SDimitry Andric ScriptedCommandSynchronicity synch,
10327fa27ce4SDimitry Andric CompletionType completion_type)
1033706b4fc4SDimitry Andric : CommandObjectRaw(interpreter, name), m_function_name(funct),
10347fa27ce4SDimitry Andric m_synchro(synch), m_completion_type(completion_type) {
1035205afe67SEd Maste if (!help.empty())
103614f1b3e8SDimitry Andric SetHelp(help);
103714f1b3e8SDimitry Andric else {
1038205afe67SEd Maste StreamString stream;
1039205afe67SEd Maste stream.Printf("For more information run 'help %s'", name.c_str());
104014f1b3e8SDimitry Andric SetHelp(stream.GetString());
1041205afe67SEd Maste }
1042f034231aSEd Maste }
1043f034231aSEd Maste
1044f3fbd1c0SDimitry Andric ~CommandObjectPythonFunction() override = default;
1045f034231aSEd Maste
IsRemovable() const104614f1b3e8SDimitry Andric bool IsRemovable() const override { return true; }
1047f034231aSEd Maste
GetFunctionName()104814f1b3e8SDimitry Andric const std::string &GetFunctionName() { return m_function_name; }
1049f034231aSEd Maste
GetSynchronicity()105014f1b3e8SDimitry Andric ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1051f034231aSEd Maste
GetHelpLong()105214f1b3e8SDimitry Andric llvm::StringRef GetHelpLong() override {
105314f1b3e8SDimitry Andric if (m_fetched_help_long)
105414f1b3e8SDimitry Andric return CommandObjectRaw::GetHelpLong();
105514f1b3e8SDimitry Andric
10565f29bb8aSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
105714f1b3e8SDimitry Andric if (!scripter)
105814f1b3e8SDimitry Andric return CommandObjectRaw::GetHelpLong();
105914f1b3e8SDimitry Andric
1060f034231aSEd Maste std::string docstring;
106114f1b3e8SDimitry Andric m_fetched_help_long =
106214f1b3e8SDimitry Andric scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
1063f034231aSEd Maste if (!docstring.empty())
106414f1b3e8SDimitry Andric SetHelpLong(docstring);
1065f034231aSEd Maste return CommandObjectRaw::GetHelpLong();
1066f034231aSEd Maste }
1067f034231aSEd Maste
10687fa27ce4SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)10697fa27ce4SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
10707fa27ce4SDimitry Andric OptionElementVector &opt_element_vector) override {
10717fa27ce4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
10727fa27ce4SDimitry Andric GetCommandInterpreter(), m_completion_type, request, nullptr);
10737fa27ce4SDimitry Andric }
10747fa27ce4SDimitry Andric
WantsCompletion()10757fa27ce4SDimitry Andric bool WantsCompletion() override { return true; }
10767fa27ce4SDimitry Andric
1077f034231aSEd Maste protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1078b1c73532SDimitry Andric void DoExecute(llvm::StringRef raw_command_line,
107914f1b3e8SDimitry Andric CommandReturnObject &result) override {
10805f29bb8aSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1081f034231aSEd Maste
1082ac9a064cSDimitry Andric m_interpreter.IncreaseCommandUsage(*this);
1083ac9a064cSDimitry Andric
1084b76161e4SDimitry Andric Status error;
1085f034231aSEd Maste
1086f034231aSEd Maste result.SetStatus(eReturnStatusInvalid);
1087f034231aSEd Maste
1088706b4fc4SDimitry Andric if (!scripter || !scripter->RunScriptBasedCommand(
1089706b4fc4SDimitry Andric m_function_name.c_str(), raw_command_line, m_synchro,
1090706b4fc4SDimitry Andric result, error, m_exe_ctx)) {
1091f034231aSEd Maste result.AppendError(error.AsCString());
109214f1b3e8SDimitry Andric } else {
1093f034231aSEd Maste // Don't change the status if the command already set it...
109414f1b3e8SDimitry Andric if (result.GetStatus() == eReturnStatusInvalid) {
109514f1b3e8SDimitry Andric if (result.GetOutputData().empty())
1096f034231aSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult);
1097f034231aSEd Maste else
1098f034231aSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
1099f034231aSEd Maste }
1100f034231aSEd Maste }
1101f034231aSEd Maste }
1102f034231aSEd Maste
1103f3fbd1c0SDimitry Andric private:
1104f3fbd1c0SDimitry Andric std::string m_function_name;
1105f3fbd1c0SDimitry Andric ScriptedCommandSynchronicity m_synchro;
1106145449b1SDimitry Andric bool m_fetched_help_long = false;
11077fa27ce4SDimitry Andric CompletionType m_completion_type = eNoCompletion;
1108f034231aSEd Maste };
1109f034231aSEd Maste
1110ac9a064cSDimitry Andric /// This class implements a "raw" scripted command. lldb does no parsing of the
1111ac9a064cSDimitry Andric /// command line, instead passing the line unaltered (except for backtick
1112ac9a064cSDimitry Andric /// substitution).
1113ac9a064cSDimitry Andric class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
11145e95aa85SEd Maste public:
CommandObjectScriptingObjectRaw(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch,CompletionType completion_type)1115ac9a064cSDimitry Andric CommandObjectScriptingObjectRaw(CommandInterpreter &interpreter,
11165e95aa85SEd Maste std::string name,
11175e95aa85SEd Maste StructuredData::GenericSP cmd_obj_sp,
11187fa27ce4SDimitry Andric ScriptedCommandSynchronicity synch,
11197fa27ce4SDimitry Andric CompletionType completion_type)
1120706b4fc4SDimitry Andric : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1121706b4fc4SDimitry Andric m_synchro(synch), m_fetched_help_short(false),
11227fa27ce4SDimitry Andric m_fetched_help_long(false), m_completion_type(completion_type) {
11235e95aa85SEd Maste StreamString stream;
11245e95aa85SEd Maste stream.Printf("For more information run 'help %s'", name.c_str());
112514f1b3e8SDimitry Andric SetHelp(stream.GetString());
11265f29bb8aSDimitry Andric if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
11275e95aa85SEd Maste GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
11285e95aa85SEd Maste }
11295e95aa85SEd Maste
1130ac9a064cSDimitry Andric ~CommandObjectScriptingObjectRaw() override = default;
11315e95aa85SEd Maste
11327fa27ce4SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)11337fa27ce4SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
11347fa27ce4SDimitry Andric OptionElementVector &opt_element_vector) override {
11357fa27ce4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
11367fa27ce4SDimitry Andric GetCommandInterpreter(), m_completion_type, request, nullptr);
11377fa27ce4SDimitry Andric }
11387fa27ce4SDimitry Andric
WantsCompletion()11397fa27ce4SDimitry Andric bool WantsCompletion() override { return true; }
11407fa27ce4SDimitry Andric
IsRemovable() const114114f1b3e8SDimitry Andric bool IsRemovable() const override { return true; }
11425e95aa85SEd Maste
GetSynchronicity()114314f1b3e8SDimitry Andric ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
11445e95aa85SEd Maste
GetRepeatCommand(Args & args,uint32_t index)1145ac9a064cSDimitry Andric std::optional<std::string> GetRepeatCommand(Args &args,
1146ac9a064cSDimitry Andric uint32_t index) override {
1147ac9a064cSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1148ac9a064cSDimitry Andric if (!scripter)
1149ac9a064cSDimitry Andric return std::nullopt;
1150ac9a064cSDimitry Andric
1151ac9a064cSDimitry Andric return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
1152ac9a064cSDimitry Andric }
1153ac9a064cSDimitry Andric
GetHelp()115414f1b3e8SDimitry Andric llvm::StringRef GetHelp() override {
115514f1b3e8SDimitry Andric if (m_fetched_help_short)
115614f1b3e8SDimitry Andric return CommandObjectRaw::GetHelp();
11575f29bb8aSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
115814f1b3e8SDimitry Andric if (!scripter)
115914f1b3e8SDimitry Andric return CommandObjectRaw::GetHelp();
11605e95aa85SEd Maste std::string docstring;
116114f1b3e8SDimitry Andric m_fetched_help_short =
116214f1b3e8SDimitry Andric scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
11635e95aa85SEd Maste if (!docstring.empty())
116414f1b3e8SDimitry Andric SetHelp(docstring);
116514f1b3e8SDimitry Andric
11665e95aa85SEd Maste return CommandObjectRaw::GetHelp();
11675e95aa85SEd Maste }
11685e95aa85SEd Maste
GetHelpLong()116914f1b3e8SDimitry Andric llvm::StringRef GetHelpLong() override {
117014f1b3e8SDimitry Andric if (m_fetched_help_long)
117114f1b3e8SDimitry Andric return CommandObjectRaw::GetHelpLong();
117214f1b3e8SDimitry Andric
11735f29bb8aSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
117414f1b3e8SDimitry Andric if (!scripter)
117514f1b3e8SDimitry Andric return CommandObjectRaw::GetHelpLong();
117614f1b3e8SDimitry Andric
11775e95aa85SEd Maste std::string docstring;
117814f1b3e8SDimitry Andric m_fetched_help_long =
117914f1b3e8SDimitry Andric scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
11805e95aa85SEd Maste if (!docstring.empty())
118114f1b3e8SDimitry Andric SetHelpLong(docstring);
11825e95aa85SEd Maste return CommandObjectRaw::GetHelpLong();
11835e95aa85SEd Maste }
11845e95aa85SEd Maste
11855e95aa85SEd Maste protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1186b1c73532SDimitry Andric void DoExecute(llvm::StringRef raw_command_line,
118714f1b3e8SDimitry Andric CommandReturnObject &result) override {
11885f29bb8aSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
11895e95aa85SEd Maste
1190b76161e4SDimitry Andric Status error;
11915e95aa85SEd Maste
11925e95aa85SEd Maste result.SetStatus(eReturnStatusInvalid);
11935e95aa85SEd Maste
119414f1b3e8SDimitry Andric if (!scripter ||
119514f1b3e8SDimitry Andric !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
119614f1b3e8SDimitry Andric m_synchro, result, error, m_exe_ctx)) {
11975e95aa85SEd Maste result.AppendError(error.AsCString());
119814f1b3e8SDimitry Andric } else {
11995e95aa85SEd Maste // Don't change the status if the command already set it...
120014f1b3e8SDimitry Andric if (result.GetStatus() == eReturnStatusInvalid) {
120114f1b3e8SDimitry Andric if (result.GetOutputData().empty())
12025e95aa85SEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult);
12035e95aa85SEd Maste else
12045e95aa85SEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
12055e95aa85SEd Maste }
12065e95aa85SEd Maste }
12075e95aa85SEd Maste }
12085e95aa85SEd Maste
1209f3fbd1c0SDimitry Andric private:
1210f3fbd1c0SDimitry Andric StructuredData::GenericSP m_cmd_obj_sp;
1211f3fbd1c0SDimitry Andric ScriptedCommandSynchronicity m_synchro;
1212f3fbd1c0SDimitry Andric bool m_fetched_help_short : 1;
1213f3fbd1c0SDimitry Andric bool m_fetched_help_long : 1;
12147fa27ce4SDimitry Andric CompletionType m_completion_type = eNoCompletion;
12155e95aa85SEd Maste };
12165e95aa85SEd Maste
1217ac9a064cSDimitry Andric
1218ac9a064cSDimitry Andric /// This command implements a lldb parsed scripted command. The command
1219ac9a064cSDimitry Andric /// provides a definition of the options and arguments, and a option value
1220ac9a064cSDimitry Andric /// setting callback, and then the command's execution function gets passed
1221ac9a064cSDimitry Andric /// just the parsed arguments.
1222ac9a064cSDimitry Andric /// Note, implementing a command in Python using these base interfaces is a bit
1223ac9a064cSDimitry Andric /// of a pain, but it is much easier to export this low level interface, and
1224ac9a064cSDimitry Andric /// then make it nicer on the Python side, than to try to do that in a
1225ac9a064cSDimitry Andric /// script language neutral way.
1226ac9a064cSDimitry Andric /// So I've also added a base class in Python that provides a table-driven
1227ac9a064cSDimitry Andric /// way of defining the options and arguments, which automatically fills the
1228ac9a064cSDimitry Andric /// option values, making them available as properties in Python.
1229ac9a064cSDimitry Andric ///
1230ac9a064cSDimitry Andric class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
1231ac9a064cSDimitry Andric private:
1232ac9a064cSDimitry Andric class CommandOptions : public Options {
1233ac9a064cSDimitry Andric public:
CommandOptions(CommandInterpreter & interpreter,StructuredData::GenericSP cmd_obj_sp)1234ac9a064cSDimitry Andric CommandOptions(CommandInterpreter &interpreter,
1235ac9a064cSDimitry Andric StructuredData::GenericSP cmd_obj_sp) : m_interpreter(interpreter),
1236ac9a064cSDimitry Andric m_cmd_obj_sp(cmd_obj_sp) {}
1237ac9a064cSDimitry Andric
1238ac9a064cSDimitry Andric ~CommandOptions() override = default;
1239ac9a064cSDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1240ac9a064cSDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1241ac9a064cSDimitry Andric ExecutionContext *execution_context) override {
1242ac9a064cSDimitry Andric Status error;
1243ac9a064cSDimitry Andric ScriptInterpreter *scripter =
1244ac9a064cSDimitry Andric m_interpreter.GetDebugger().GetScriptInterpreter();
1245ac9a064cSDimitry Andric if (!scripter) {
1246ac9a064cSDimitry Andric error.SetErrorString("No script interpreter for SetOptionValue.");
1247ac9a064cSDimitry Andric return error;
1248ac9a064cSDimitry Andric }
1249ac9a064cSDimitry Andric if (!m_cmd_obj_sp) {
1250ac9a064cSDimitry Andric error.SetErrorString("SetOptionValue called with empty cmd_obj.");
1251ac9a064cSDimitry Andric return error;
1252ac9a064cSDimitry Andric }
1253ac9a064cSDimitry Andric if (!m_options_definition_up) {
1254ac9a064cSDimitry Andric error.SetErrorString("SetOptionValue called before options definitions "
1255ac9a064cSDimitry Andric "were created.");
1256ac9a064cSDimitry Andric return error;
1257ac9a064cSDimitry Andric }
1258ac9a064cSDimitry Andric // Pass the long option, since you aren't actually required to have a
1259ac9a064cSDimitry Andric // short_option, and for those options the index or short option character
1260ac9a064cSDimitry Andric // aren't meaningful on the python side.
1261ac9a064cSDimitry Andric const char * long_option =
1262ac9a064cSDimitry Andric m_options_definition_up.get()[option_idx].long_option;
1263ac9a064cSDimitry Andric bool success = scripter->SetOptionValueForCommandObject(m_cmd_obj_sp,
1264ac9a064cSDimitry Andric execution_context, long_option, option_arg);
1265ac9a064cSDimitry Andric if (!success)
1266ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("Error setting option: {0} to {1}",
1267ac9a064cSDimitry Andric long_option, option_arg);
1268ac9a064cSDimitry Andric return error;
1269ac9a064cSDimitry Andric }
1270ac9a064cSDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)1271ac9a064cSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
1272ac9a064cSDimitry Andric ScriptInterpreter *scripter =
1273ac9a064cSDimitry Andric m_interpreter.GetDebugger().GetScriptInterpreter();
1274ac9a064cSDimitry Andric if (!scripter || !m_cmd_obj_sp)
1275ac9a064cSDimitry Andric return;
1276ac9a064cSDimitry Andric
1277ac9a064cSDimitry Andric scripter->OptionParsingStartedForCommandObject(m_cmd_obj_sp);
1278ac9a064cSDimitry Andric }
1279ac9a064cSDimitry Andric
GetDefinitions()1280ac9a064cSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1281ac9a064cSDimitry Andric if (!m_options_definition_up)
1282ac9a064cSDimitry Andric return {};
1283ac9a064cSDimitry Andric return llvm::ArrayRef(m_options_definition_up.get(), m_num_options);
1284ac9a064cSDimitry Andric }
1285ac9a064cSDimitry Andric
ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,size_t counter,uint32_t & usage_mask)1286ac9a064cSDimitry Andric static Status ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,
1287ac9a064cSDimitry Andric size_t counter, uint32_t &usage_mask) {
1288ac9a064cSDimitry Andric // If the usage entry is not provided, we use LLDB_OPT_SET_ALL.
1289ac9a064cSDimitry Andric // If the usage mask is a UINT, the option belongs to that group.
1290ac9a064cSDimitry Andric // If the usage mask is a vector of UINT's, the option belongs to all the
1291ac9a064cSDimitry Andric // groups listed.
1292ac9a064cSDimitry Andric // If a subelement of the vector is a vector of two ints, then the option
1293ac9a064cSDimitry Andric // belongs to the inclusive range from the first to the second element.
1294ac9a064cSDimitry Andric Status error;
1295ac9a064cSDimitry Andric if (!obj_sp) {
1296ac9a064cSDimitry Andric usage_mask = LLDB_OPT_SET_ALL;
1297ac9a064cSDimitry Andric return error;
1298ac9a064cSDimitry Andric }
1299ac9a064cSDimitry Andric
1300ac9a064cSDimitry Andric usage_mask = 0;
1301ac9a064cSDimitry Andric
1302ac9a064cSDimitry Andric StructuredData::UnsignedInteger *uint_val =
1303ac9a064cSDimitry Andric obj_sp->GetAsUnsignedInteger();
1304ac9a064cSDimitry Andric if (uint_val) {
1305ac9a064cSDimitry Andric // If this is an integer, then this specifies a single group:
1306ac9a064cSDimitry Andric uint32_t value = uint_val->GetValue();
1307ac9a064cSDimitry Andric if (value == 0) {
1308ac9a064cSDimitry Andric error.SetErrorStringWithFormatv(
1309ac9a064cSDimitry Andric "0 is not a valid group for option {0}", counter);
1310ac9a064cSDimitry Andric return error;
1311ac9a064cSDimitry Andric }
1312ac9a064cSDimitry Andric usage_mask = (1 << (value - 1));
1313ac9a064cSDimitry Andric return error;
1314ac9a064cSDimitry Andric }
1315ac9a064cSDimitry Andric // Otherwise it has to be an array:
1316ac9a064cSDimitry Andric StructuredData::Array *array_val = obj_sp->GetAsArray();
1317ac9a064cSDimitry Andric if (!array_val) {
1318ac9a064cSDimitry Andric error.SetErrorStringWithFormatv(
1319ac9a064cSDimitry Andric "required field is not a array for option {0}", counter);
1320ac9a064cSDimitry Andric return error;
1321ac9a064cSDimitry Andric }
1322ac9a064cSDimitry Andric // This is the array ForEach for accumulating a group usage mask from
1323ac9a064cSDimitry Andric // an array of string descriptions of groups.
1324ac9a064cSDimitry Andric auto groups_accumulator
1325ac9a064cSDimitry Andric = [counter, &usage_mask, &error]
1326ac9a064cSDimitry Andric (StructuredData::Object *obj) -> bool {
1327ac9a064cSDimitry Andric StructuredData::UnsignedInteger *int_val = obj->GetAsUnsignedInteger();
1328ac9a064cSDimitry Andric if (int_val) {
1329ac9a064cSDimitry Andric uint32_t value = int_val->GetValue();
1330ac9a064cSDimitry Andric if (value == 0) {
1331ac9a064cSDimitry Andric error.SetErrorStringWithFormatv(
1332ac9a064cSDimitry Andric "0 is not a valid group for element {0}", counter);
1333ac9a064cSDimitry Andric return false;
1334ac9a064cSDimitry Andric }
1335ac9a064cSDimitry Andric usage_mask |= (1 << (value - 1));
1336ac9a064cSDimitry Andric return true;
1337ac9a064cSDimitry Andric }
1338ac9a064cSDimitry Andric StructuredData::Array *arr_val = obj->GetAsArray();
1339ac9a064cSDimitry Andric if (!arr_val) {
1340ac9a064cSDimitry Andric error.SetErrorStringWithFormatv(
1341ac9a064cSDimitry Andric "Group element not an int or array of integers for element {0}",
1342ac9a064cSDimitry Andric counter);
1343ac9a064cSDimitry Andric return false;
1344ac9a064cSDimitry Andric }
1345ac9a064cSDimitry Andric size_t num_range_elem = arr_val->GetSize();
1346ac9a064cSDimitry Andric if (num_range_elem != 2) {
1347ac9a064cSDimitry Andric error.SetErrorStringWithFormatv(
1348ac9a064cSDimitry Andric "Subranges of a group not a start and a stop for element {0}",
1349ac9a064cSDimitry Andric counter);
1350ac9a064cSDimitry Andric return false;
1351ac9a064cSDimitry Andric }
1352ac9a064cSDimitry Andric int_val = arr_val->GetItemAtIndex(0)->GetAsUnsignedInteger();
1353ac9a064cSDimitry Andric if (!int_val) {
1354ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("Start element of a subrange of a "
1355ac9a064cSDimitry Andric "group not unsigned int for element {0}", counter);
1356ac9a064cSDimitry Andric return false;
1357ac9a064cSDimitry Andric }
1358ac9a064cSDimitry Andric uint32_t start = int_val->GetValue();
1359ac9a064cSDimitry Andric int_val = arr_val->GetItemAtIndex(1)->GetAsUnsignedInteger();
1360ac9a064cSDimitry Andric if (!int_val) {
1361ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("End element of a subrange of a group"
1362ac9a064cSDimitry Andric " not unsigned int for element {0}", counter);
1363ac9a064cSDimitry Andric return false;
1364ac9a064cSDimitry Andric }
1365ac9a064cSDimitry Andric uint32_t end = int_val->GetValue();
1366ac9a064cSDimitry Andric if (start == 0 || end == 0 || start > end) {
1367ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("Invalid subrange of a group: {0} - "
1368ac9a064cSDimitry Andric "{1} for element {2}", start, end, counter);
1369ac9a064cSDimitry Andric return false;
1370ac9a064cSDimitry Andric }
1371ac9a064cSDimitry Andric for (uint32_t i = start; i <= end; i++) {
1372ac9a064cSDimitry Andric usage_mask |= (1 << (i - 1));
1373ac9a064cSDimitry Andric }
1374ac9a064cSDimitry Andric return true;
1375ac9a064cSDimitry Andric };
1376ac9a064cSDimitry Andric array_val->ForEach(groups_accumulator);
1377ac9a064cSDimitry Andric return error;
1378ac9a064cSDimitry Andric }
1379ac9a064cSDimitry Andric
1380ac9a064cSDimitry Andric
SetOptionsFromArray(StructuredData::Dictionary & options)1381ac9a064cSDimitry Andric Status SetOptionsFromArray(StructuredData::Dictionary &options) {
1382ac9a064cSDimitry Andric Status error;
1383ac9a064cSDimitry Andric m_num_options = options.GetSize();
1384ac9a064cSDimitry Andric m_options_definition_up.reset(new OptionDefinition[m_num_options]);
1385ac9a064cSDimitry Andric // We need to hand out pointers to contents of these vectors; we reserve
1386ac9a064cSDimitry Andric // as much as we'll need up front so they don't get freed on resize...
1387ac9a064cSDimitry Andric m_usage_container.resize(m_num_options);
1388ac9a064cSDimitry Andric m_enum_storage.resize(m_num_options);
1389ac9a064cSDimitry Andric m_enum_vector.resize(m_num_options);
1390ac9a064cSDimitry Andric
1391ac9a064cSDimitry Andric size_t counter = 0;
1392ac9a064cSDimitry Andric size_t short_opt_counter = 0;
1393ac9a064cSDimitry Andric // This is the Array::ForEach function for adding option elements:
1394ac9a064cSDimitry Andric auto add_element = [this, &error, &counter, &short_opt_counter]
1395ac9a064cSDimitry Andric (llvm::StringRef long_option, StructuredData::Object *object) -> bool {
1396ac9a064cSDimitry Andric StructuredData::Dictionary *opt_dict = object->GetAsDictionary();
1397ac9a064cSDimitry Andric if (!opt_dict) {
1398ac9a064cSDimitry Andric error.SetErrorString("Value in options dictionary is not a dictionary");
1399ac9a064cSDimitry Andric return false;
1400ac9a064cSDimitry Andric }
1401ac9a064cSDimitry Andric OptionDefinition &option_def = m_options_definition_up.get()[counter];
1402ac9a064cSDimitry Andric
1403ac9a064cSDimitry Andric // We aren't exposing the validator yet, set it to null
1404ac9a064cSDimitry Andric option_def.validator = nullptr;
1405ac9a064cSDimitry Andric // We don't require usage masks, so set it to one group by default:
1406ac9a064cSDimitry Andric option_def.usage_mask = 1;
1407ac9a064cSDimitry Andric
1408ac9a064cSDimitry Andric // Now set the fields of the OptionDefinition Array from the dictionary:
1409ac9a064cSDimitry Andric //
1410ac9a064cSDimitry Andric // Note that I don't check for unknown fields in the option dictionaries
1411ac9a064cSDimitry Andric // so a scriptor can add extra elements that are helpful when they go to
1412ac9a064cSDimitry Andric // do "set_option_value"
1413ac9a064cSDimitry Andric
1414ac9a064cSDimitry Andric // Usage Mask:
1415ac9a064cSDimitry Andric StructuredData::ObjectSP obj_sp = opt_dict->GetValueForKey("groups");
1416ac9a064cSDimitry Andric if (obj_sp) {
1417ac9a064cSDimitry Andric error = ParseUsageMaskFromArray(obj_sp, counter,
1418ac9a064cSDimitry Andric option_def.usage_mask);
1419ac9a064cSDimitry Andric if (error.Fail())
1420ac9a064cSDimitry Andric return false;
1421ac9a064cSDimitry Andric }
1422ac9a064cSDimitry Andric
1423ac9a064cSDimitry Andric // Required:
1424ac9a064cSDimitry Andric option_def.required = false;
1425ac9a064cSDimitry Andric obj_sp = opt_dict->GetValueForKey("required");
1426ac9a064cSDimitry Andric if (obj_sp) {
1427ac9a064cSDimitry Andric StructuredData::Boolean *boolean_val = obj_sp->GetAsBoolean();
1428ac9a064cSDimitry Andric if (!boolean_val) {
1429ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("'required' field is not a boolean "
1430ac9a064cSDimitry Andric "for option {0}", counter);
1431ac9a064cSDimitry Andric return false;
1432ac9a064cSDimitry Andric }
1433ac9a064cSDimitry Andric option_def.required = boolean_val->GetValue();
1434ac9a064cSDimitry Andric }
1435ac9a064cSDimitry Andric
1436ac9a064cSDimitry Andric // Short Option:
1437ac9a064cSDimitry Andric int short_option;
1438ac9a064cSDimitry Andric obj_sp = opt_dict->GetValueForKey("short_option");
1439ac9a064cSDimitry Andric if (obj_sp) {
1440ac9a064cSDimitry Andric // The value is a string, so pull the
1441ac9a064cSDimitry Andric llvm::StringRef short_str = obj_sp->GetStringValue();
1442ac9a064cSDimitry Andric if (short_str.empty()) {
1443ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("short_option field empty for "
1444ac9a064cSDimitry Andric "option {0}", counter);
1445ac9a064cSDimitry Andric return false;
1446ac9a064cSDimitry Andric } else if (short_str.size() != 1) {
1447ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("short_option field has extra "
1448ac9a064cSDimitry Andric "characters for option {0}", counter);
1449ac9a064cSDimitry Andric return false;
1450ac9a064cSDimitry Andric }
1451ac9a064cSDimitry Andric short_option = (int) short_str[0];
1452ac9a064cSDimitry Andric } else {
1453ac9a064cSDimitry Andric // If the short option is not provided, then we need a unique value
1454ac9a064cSDimitry Andric // less than the lowest printable ASCII character.
1455ac9a064cSDimitry Andric short_option = short_opt_counter++;
1456ac9a064cSDimitry Andric }
1457ac9a064cSDimitry Andric option_def.short_option = short_option;
1458ac9a064cSDimitry Andric
1459ac9a064cSDimitry Andric // Long Option is the key from the outer dict:
1460ac9a064cSDimitry Andric if (long_option.empty()) {
1461ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("empty long_option for option {0}",
1462ac9a064cSDimitry Andric counter);
1463ac9a064cSDimitry Andric return false;
1464ac9a064cSDimitry Andric }
1465ac9a064cSDimitry Andric auto inserted = g_string_storer.insert(long_option.str());
1466ac9a064cSDimitry Andric option_def.long_option = ((*(inserted.first)).data());
1467ac9a064cSDimitry Andric
1468ac9a064cSDimitry Andric // Value Type:
1469ac9a064cSDimitry Andric obj_sp = opt_dict->GetValueForKey("value_type");
1470ac9a064cSDimitry Andric if (obj_sp) {
1471ac9a064cSDimitry Andric StructuredData::UnsignedInteger *uint_val
1472ac9a064cSDimitry Andric = obj_sp->GetAsUnsignedInteger();
1473ac9a064cSDimitry Andric if (!uint_val) {
1474ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("Value type must be an unsigned "
1475ac9a064cSDimitry Andric "integer");
1476ac9a064cSDimitry Andric return false;
1477ac9a064cSDimitry Andric }
1478ac9a064cSDimitry Andric uint64_t val_type = uint_val->GetValue();
1479ac9a064cSDimitry Andric if (val_type >= eArgTypeLastArg) {
1480ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("Value type {0} beyond the "
1481ac9a064cSDimitry Andric "CommandArgumentType bounds", val_type);
1482ac9a064cSDimitry Andric return false;
1483ac9a064cSDimitry Andric }
1484ac9a064cSDimitry Andric option_def.argument_type = (CommandArgumentType) val_type;
1485ac9a064cSDimitry Andric option_def.option_has_arg = true;
1486ac9a064cSDimitry Andric } else {
1487ac9a064cSDimitry Andric option_def.argument_type = eArgTypeNone;
1488ac9a064cSDimitry Andric option_def.option_has_arg = false;
1489ac9a064cSDimitry Andric }
1490ac9a064cSDimitry Andric
1491ac9a064cSDimitry Andric // Completion Type:
1492ac9a064cSDimitry Andric obj_sp = opt_dict->GetValueForKey("completion_type");
1493ac9a064cSDimitry Andric if (obj_sp) {
1494ac9a064cSDimitry Andric StructuredData::UnsignedInteger *uint_val = obj_sp->GetAsUnsignedInteger();
1495ac9a064cSDimitry Andric if (!uint_val) {
1496ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("Completion type must be an "
1497ac9a064cSDimitry Andric "unsigned integer for option {0}", counter);
1498ac9a064cSDimitry Andric return false;
1499ac9a064cSDimitry Andric }
1500ac9a064cSDimitry Andric uint64_t completion_type = uint_val->GetValue();
1501ac9a064cSDimitry Andric if (completion_type > eCustomCompletion) {
1502ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("Completion type for option {0} "
1503ac9a064cSDimitry Andric "beyond the CompletionType bounds", completion_type);
1504ac9a064cSDimitry Andric return false;
1505ac9a064cSDimitry Andric }
1506ac9a064cSDimitry Andric option_def.completion_type = (CommandArgumentType) completion_type;
1507ac9a064cSDimitry Andric } else
1508ac9a064cSDimitry Andric option_def.completion_type = eNoCompletion;
1509ac9a064cSDimitry Andric
1510ac9a064cSDimitry Andric // Usage Text:
1511ac9a064cSDimitry Andric std::string usage_text;
1512ac9a064cSDimitry Andric obj_sp = opt_dict->GetValueForKey("help");
1513ac9a064cSDimitry Andric if (!obj_sp) {
1514ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("required usage missing from option "
1515ac9a064cSDimitry Andric "{0}", counter);
1516ac9a064cSDimitry Andric return false;
1517ac9a064cSDimitry Andric }
1518ac9a064cSDimitry Andric llvm::StringRef usage_stref;
1519ac9a064cSDimitry Andric usage_stref = obj_sp->GetStringValue();
1520ac9a064cSDimitry Andric if (usage_stref.empty()) {
1521ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("empty usage text for option {0}",
1522ac9a064cSDimitry Andric counter);
1523ac9a064cSDimitry Andric return false;
1524ac9a064cSDimitry Andric }
1525ac9a064cSDimitry Andric m_usage_container[counter] = usage_stref.str().c_str();
1526ac9a064cSDimitry Andric option_def.usage_text = m_usage_container[counter].data();
1527ac9a064cSDimitry Andric
1528ac9a064cSDimitry Andric // Enum Values:
1529ac9a064cSDimitry Andric
1530ac9a064cSDimitry Andric obj_sp = opt_dict->GetValueForKey("enum_values");
1531ac9a064cSDimitry Andric if (obj_sp) {
1532ac9a064cSDimitry Andric StructuredData::Array *array = obj_sp->GetAsArray();
1533ac9a064cSDimitry Andric if (!array) {
1534ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("enum values must be an array for "
1535ac9a064cSDimitry Andric "option {0}", counter);
1536ac9a064cSDimitry Andric return false;
1537ac9a064cSDimitry Andric }
1538ac9a064cSDimitry Andric size_t num_elem = array->GetSize();
1539ac9a064cSDimitry Andric size_t enum_ctr = 0;
1540ac9a064cSDimitry Andric m_enum_storage[counter] = std::vector<EnumValueStorage>(num_elem);
1541ac9a064cSDimitry Andric std::vector<EnumValueStorage> &curr_elem = m_enum_storage[counter];
1542ac9a064cSDimitry Andric
1543ac9a064cSDimitry Andric // This is the Array::ForEach function for adding enum elements:
1544ac9a064cSDimitry Andric // Since there are only two fields to specify the enum, use a simple
1545ac9a064cSDimitry Andric // two element array with value first, usage second.
1546ac9a064cSDimitry Andric // counter is only used for reporting so I pass it by value here.
1547ac9a064cSDimitry Andric auto add_enum = [&enum_ctr, &curr_elem, counter, &error]
1548ac9a064cSDimitry Andric (StructuredData::Object *object) -> bool {
1549ac9a064cSDimitry Andric StructuredData::Array *enum_arr = object->GetAsArray();
1550ac9a064cSDimitry Andric if (!enum_arr) {
1551ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("Enum values for option {0} not "
1552ac9a064cSDimitry Andric "an array", counter);
1553ac9a064cSDimitry Andric return false;
1554ac9a064cSDimitry Andric }
1555ac9a064cSDimitry Andric size_t num_enum_elements = enum_arr->GetSize();
1556ac9a064cSDimitry Andric if (num_enum_elements != 2) {
1557ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("Wrong number of elements: {0} "
1558ac9a064cSDimitry Andric "for enum {1} in option {2}",
1559ac9a064cSDimitry Andric num_enum_elements, enum_ctr, counter);
1560ac9a064cSDimitry Andric return false;
1561ac9a064cSDimitry Andric }
1562ac9a064cSDimitry Andric // Enum Value:
1563ac9a064cSDimitry Andric StructuredData::ObjectSP obj_sp = enum_arr->GetItemAtIndex(0);
1564ac9a064cSDimitry Andric llvm::StringRef val_stref = obj_sp->GetStringValue();
1565ac9a064cSDimitry Andric std::string value_cstr_str = val_stref.str().c_str();
1566ac9a064cSDimitry Andric
1567ac9a064cSDimitry Andric // Enum Usage:
1568ac9a064cSDimitry Andric obj_sp = enum_arr->GetItemAtIndex(1);
1569ac9a064cSDimitry Andric if (!obj_sp) {
1570ac9a064cSDimitry Andric error.SetErrorStringWithFormatv("No usage for enum {0} in option "
1571ac9a064cSDimitry Andric "{1}", enum_ctr, counter);
1572ac9a064cSDimitry Andric return false;
1573ac9a064cSDimitry Andric }
1574ac9a064cSDimitry Andric llvm::StringRef usage_stref = obj_sp->GetStringValue();
1575ac9a064cSDimitry Andric std::string usage_cstr_str = usage_stref.str().c_str();
1576ac9a064cSDimitry Andric curr_elem[enum_ctr] = EnumValueStorage(value_cstr_str,
1577ac9a064cSDimitry Andric usage_cstr_str, enum_ctr);
1578ac9a064cSDimitry Andric
1579ac9a064cSDimitry Andric enum_ctr++;
1580ac9a064cSDimitry Andric return true;
1581ac9a064cSDimitry Andric }; // end of add_enum
1582ac9a064cSDimitry Andric
1583ac9a064cSDimitry Andric array->ForEach(add_enum);
1584ac9a064cSDimitry Andric if (!error.Success())
1585ac9a064cSDimitry Andric return false;
1586ac9a064cSDimitry Andric // We have to have a vector of elements to set in the options, make
1587ac9a064cSDimitry Andric // that here:
1588ac9a064cSDimitry Andric for (auto &elem : curr_elem)
1589ac9a064cSDimitry Andric m_enum_vector[counter].emplace_back(elem.element);
1590ac9a064cSDimitry Andric
1591ac9a064cSDimitry Andric option_def.enum_values = llvm::ArrayRef(m_enum_vector[counter]);
1592ac9a064cSDimitry Andric }
1593ac9a064cSDimitry Andric counter++;
1594ac9a064cSDimitry Andric return true;
1595ac9a064cSDimitry Andric }; // end of add_element
1596ac9a064cSDimitry Andric
1597ac9a064cSDimitry Andric options.ForEach(add_element);
1598ac9a064cSDimitry Andric return error;
1599ac9a064cSDimitry Andric }
1600ac9a064cSDimitry Andric
GetNumOptions()1601ac9a064cSDimitry Andric size_t GetNumOptions() { return m_num_options; }
1602ac9a064cSDimitry Andric
1603ac9a064cSDimitry Andric private:
1604ac9a064cSDimitry Andric struct EnumValueStorage {
EnumValueStorageCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1605ac9a064cSDimitry Andric EnumValueStorage() {
1606ac9a064cSDimitry Andric element.string_value = "value not set";
1607ac9a064cSDimitry Andric element.usage = "usage not set";
1608ac9a064cSDimitry Andric element.value = 0;
1609ac9a064cSDimitry Andric }
1610ac9a064cSDimitry Andric
EnumValueStorageCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1611ac9a064cSDimitry Andric EnumValueStorage(std::string in_str_val, std::string in_usage,
1612ac9a064cSDimitry Andric size_t in_value) : value(std::move(in_str_val)), usage(std::move(in_usage)) {
1613ac9a064cSDimitry Andric SetElement(in_value);
1614ac9a064cSDimitry Andric }
1615ac9a064cSDimitry Andric
EnumValueStorageCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1616ac9a064cSDimitry Andric EnumValueStorage(const EnumValueStorage &in) : value(in.value),
1617ac9a064cSDimitry Andric usage(in.usage) {
1618ac9a064cSDimitry Andric SetElement(in.element.value);
1619ac9a064cSDimitry Andric }
1620ac9a064cSDimitry Andric
operator =CommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1621ac9a064cSDimitry Andric EnumValueStorage &operator=(const EnumValueStorage &in) {
1622ac9a064cSDimitry Andric value = in.value;
1623ac9a064cSDimitry Andric usage = in.usage;
1624ac9a064cSDimitry Andric SetElement(in.element.value);
1625ac9a064cSDimitry Andric return *this;
1626ac9a064cSDimitry Andric }
1627ac9a064cSDimitry Andric
SetElementCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1628ac9a064cSDimitry Andric void SetElement(size_t in_value) {
1629ac9a064cSDimitry Andric element.value = in_value;
1630ac9a064cSDimitry Andric element.string_value = value.data();
1631ac9a064cSDimitry Andric element.usage = usage.data();
1632ac9a064cSDimitry Andric }
1633ac9a064cSDimitry Andric
1634ac9a064cSDimitry Andric std::string value;
1635ac9a064cSDimitry Andric std::string usage;
1636ac9a064cSDimitry Andric OptionEnumValueElement element;
1637ac9a064cSDimitry Andric };
1638ac9a064cSDimitry Andric // We have to provide char * values for the long option, usage and enum
1639ac9a064cSDimitry Andric // values, that's what the option definitions hold.
1640ac9a064cSDimitry Andric // The long option strings are quite likely to be reused in other added
1641ac9a064cSDimitry Andric // commands, so those are stored in a global set: g_string_storer.
1642ac9a064cSDimitry Andric // But the usages are much less likely to be reused, so those are stored in
1643ac9a064cSDimitry Andric // a vector in the command instance. It gets resized to the correct size
1644ac9a064cSDimitry Andric // and then filled with null-terminated strings in the std::string, so the
1645ac9a064cSDimitry Andric // are valid C-strings that won't move around.
1646ac9a064cSDimitry Andric // The enum values and descriptions are treated similarly - these aren't
1647ac9a064cSDimitry Andric // all that common so it's not worth the effort to dedup them.
1648ac9a064cSDimitry Andric size_t m_num_options = 0;
1649ac9a064cSDimitry Andric std::unique_ptr<OptionDefinition> m_options_definition_up;
1650ac9a064cSDimitry Andric std::vector<std::vector<EnumValueStorage>> m_enum_storage;
1651ac9a064cSDimitry Andric std::vector<std::vector<OptionEnumValueElement>> m_enum_vector;
1652ac9a064cSDimitry Andric std::vector<std::string> m_usage_container;
1653ac9a064cSDimitry Andric CommandInterpreter &m_interpreter;
1654ac9a064cSDimitry Andric StructuredData::GenericSP m_cmd_obj_sp;
1655ac9a064cSDimitry Andric static std::unordered_set<std::string> g_string_storer;
1656ac9a064cSDimitry Andric };
1657ac9a064cSDimitry Andric
1658ac9a064cSDimitry Andric public:
Create(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch,CommandReturnObject & result)1659ac9a064cSDimitry Andric static CommandObjectSP Create(CommandInterpreter &interpreter,
1660ac9a064cSDimitry Andric std::string name,
1661ac9a064cSDimitry Andric StructuredData::GenericSP cmd_obj_sp,
1662ac9a064cSDimitry Andric ScriptedCommandSynchronicity synch,
1663ac9a064cSDimitry Andric CommandReturnObject &result) {
1664ac9a064cSDimitry Andric CommandObjectSP new_cmd_sp(new CommandObjectScriptingObjectParsed(
1665ac9a064cSDimitry Andric interpreter, name, cmd_obj_sp, synch));
1666ac9a064cSDimitry Andric
1667ac9a064cSDimitry Andric CommandObjectScriptingObjectParsed *parsed_cmd
1668ac9a064cSDimitry Andric = static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get());
1669ac9a064cSDimitry Andric // Now check all the failure modes, and report if found.
1670ac9a064cSDimitry Andric Status opt_error = parsed_cmd->GetOptionsError();
1671ac9a064cSDimitry Andric Status arg_error = parsed_cmd->GetArgsError();
1672ac9a064cSDimitry Andric
1673ac9a064cSDimitry Andric if (opt_error.Fail())
1674ac9a064cSDimitry Andric result.AppendErrorWithFormat("failed to parse option definitions: %s",
1675ac9a064cSDimitry Andric opt_error.AsCString());
1676ac9a064cSDimitry Andric if (arg_error.Fail())
1677ac9a064cSDimitry Andric result.AppendErrorWithFormat("%sfailed to parse argument definitions: %s",
1678ac9a064cSDimitry Andric opt_error.Fail() ? ", also " : "",
1679ac9a064cSDimitry Andric arg_error.AsCString());
1680ac9a064cSDimitry Andric
1681ac9a064cSDimitry Andric if (!result.Succeeded())
1682ac9a064cSDimitry Andric return {};
1683ac9a064cSDimitry Andric
1684ac9a064cSDimitry Andric return new_cmd_sp;
1685ac9a064cSDimitry Andric }
1686ac9a064cSDimitry Andric
CommandObjectScriptingObjectParsed(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch)1687ac9a064cSDimitry Andric CommandObjectScriptingObjectParsed(CommandInterpreter &interpreter,
1688ac9a064cSDimitry Andric std::string name,
1689ac9a064cSDimitry Andric StructuredData::GenericSP cmd_obj_sp,
1690ac9a064cSDimitry Andric ScriptedCommandSynchronicity synch)
1691ac9a064cSDimitry Andric : CommandObjectParsed(interpreter, name.c_str()),
1692ac9a064cSDimitry Andric m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch),
1693ac9a064cSDimitry Andric m_options(interpreter, cmd_obj_sp), m_fetched_help_short(false),
1694ac9a064cSDimitry Andric m_fetched_help_long(false) {
1695ac9a064cSDimitry Andric StreamString stream;
1696ac9a064cSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1697ac9a064cSDimitry Andric if (!scripter) {
1698ac9a064cSDimitry Andric m_options_error.SetErrorString("No script interpreter");
1699ac9a064cSDimitry Andric return;
1700ac9a064cSDimitry Andric }
1701ac9a064cSDimitry Andric
1702ac9a064cSDimitry Andric // Set the flags:
1703ac9a064cSDimitry Andric GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1704ac9a064cSDimitry Andric
1705ac9a064cSDimitry Andric // Now set up the options definitions from the options:
1706ac9a064cSDimitry Andric StructuredData::ObjectSP options_object_sp
1707ac9a064cSDimitry Andric = scripter->GetOptionsForCommandObject(cmd_obj_sp);
1708ac9a064cSDimitry Andric // It's okay not to have an options dict.
1709ac9a064cSDimitry Andric if (options_object_sp) {
1710ac9a064cSDimitry Andric // The options come as a dictionary of dictionaries. The key of the
1711ac9a064cSDimitry Andric // outer dict is the long option name (since that's required). The
1712ac9a064cSDimitry Andric // value holds all the other option specification bits.
1713ac9a064cSDimitry Andric StructuredData::Dictionary *options_dict
1714ac9a064cSDimitry Andric = options_object_sp->GetAsDictionary();
1715ac9a064cSDimitry Andric // but if it exists, it has to be an array.
1716ac9a064cSDimitry Andric if (options_dict) {
1717ac9a064cSDimitry Andric m_options_error = m_options.SetOptionsFromArray(*(options_dict));
1718ac9a064cSDimitry Andric // If we got an error don't bother with the arguments...
1719ac9a064cSDimitry Andric if (m_options_error.Fail())
1720ac9a064cSDimitry Andric return;
1721ac9a064cSDimitry Andric } else {
1722ac9a064cSDimitry Andric m_options_error.SetErrorString("Options array not an array");
1723ac9a064cSDimitry Andric return;
1724ac9a064cSDimitry Andric }
1725ac9a064cSDimitry Andric }
1726ac9a064cSDimitry Andric // Then fetch the args. Since the arguments can have usage masks you need
1727ac9a064cSDimitry Andric // an array of arrays.
1728ac9a064cSDimitry Andric StructuredData::ObjectSP args_object_sp
1729ac9a064cSDimitry Andric = scripter->GetArgumentsForCommandObject(cmd_obj_sp);
1730ac9a064cSDimitry Andric if (args_object_sp) {
1731ac9a064cSDimitry Andric StructuredData::Array *args_array = args_object_sp->GetAsArray();
1732ac9a064cSDimitry Andric if (!args_array) {
1733ac9a064cSDimitry Andric m_args_error.SetErrorString("Argument specification is not an array");
1734ac9a064cSDimitry Andric return;
1735ac9a064cSDimitry Andric }
1736ac9a064cSDimitry Andric size_t counter = 0;
1737ac9a064cSDimitry Andric
1738ac9a064cSDimitry Andric // This is the Array::ForEach function that handles the
1739ac9a064cSDimitry Andric // CommandArgumentEntry arrays one by one:
1740ac9a064cSDimitry Andric auto arg_array_adder = [this, &counter] (StructuredData::Object *object)
1741ac9a064cSDimitry Andric -> bool {
1742ac9a064cSDimitry Andric // This is the Array::ForEach function to add argument entries:
1743ac9a064cSDimitry Andric CommandArgumentEntry this_entry;
1744ac9a064cSDimitry Andric size_t elem_counter = 0;
1745ac9a064cSDimitry Andric auto args_adder = [this, counter, &elem_counter, &this_entry]
1746ac9a064cSDimitry Andric (StructuredData::Object *object) -> bool {
1747ac9a064cSDimitry Andric // The arguments definition has three fields, the argument type, the
1748ac9a064cSDimitry Andric // repeat and the usage mask.
1749ac9a064cSDimitry Andric CommandArgumentType arg_type = eArgTypeNone;
1750ac9a064cSDimitry Andric ArgumentRepetitionType arg_repetition = eArgRepeatOptional;
1751ac9a064cSDimitry Andric uint32_t arg_opt_set_association;
1752ac9a064cSDimitry Andric
1753ac9a064cSDimitry Andric auto report_error = [this, elem_counter, counter]
1754ac9a064cSDimitry Andric (const char *err_txt) -> bool {
1755ac9a064cSDimitry Andric m_args_error.SetErrorStringWithFormatv("Element {0} of arguments "
1756ac9a064cSDimitry Andric "list element {1}: %s.", elem_counter, counter, err_txt);
1757ac9a064cSDimitry Andric return false;
1758ac9a064cSDimitry Andric };
1759ac9a064cSDimitry Andric
1760ac9a064cSDimitry Andric StructuredData::Dictionary *arg_dict = object->GetAsDictionary();
1761ac9a064cSDimitry Andric if (!arg_dict) {
1762ac9a064cSDimitry Andric report_error("is not a dictionary.");
1763ac9a064cSDimitry Andric return false;
1764ac9a064cSDimitry Andric }
1765ac9a064cSDimitry Andric // Argument Type:
1766ac9a064cSDimitry Andric StructuredData::ObjectSP obj_sp
1767ac9a064cSDimitry Andric = arg_dict->GetValueForKey("arg_type");
1768ac9a064cSDimitry Andric if (obj_sp) {
1769ac9a064cSDimitry Andric StructuredData::UnsignedInteger *uint_val
1770ac9a064cSDimitry Andric = obj_sp->GetAsUnsignedInteger();
1771ac9a064cSDimitry Andric if (!uint_val) {
1772ac9a064cSDimitry Andric report_error("value type must be an unsigned integer");
1773ac9a064cSDimitry Andric return false;
1774ac9a064cSDimitry Andric }
1775ac9a064cSDimitry Andric uint64_t arg_type_int = uint_val->GetValue();
1776ac9a064cSDimitry Andric if (arg_type_int >= eArgTypeLastArg) {
1777ac9a064cSDimitry Andric report_error("value type beyond ArgumentRepetitionType bounds");
1778ac9a064cSDimitry Andric return false;
1779ac9a064cSDimitry Andric }
1780ac9a064cSDimitry Andric arg_type = (CommandArgumentType) arg_type_int;
1781ac9a064cSDimitry Andric }
1782ac9a064cSDimitry Andric // Repeat Value:
1783ac9a064cSDimitry Andric obj_sp = arg_dict->GetValueForKey("repeat");
1784ac9a064cSDimitry Andric std::optional<ArgumentRepetitionType> repeat;
1785ac9a064cSDimitry Andric if (obj_sp) {
1786ac9a064cSDimitry Andric llvm::StringRef repeat_str = obj_sp->GetStringValue();
1787ac9a064cSDimitry Andric if (repeat_str.empty()) {
1788ac9a064cSDimitry Andric report_error("repeat value is empty");
1789ac9a064cSDimitry Andric return false;
1790ac9a064cSDimitry Andric }
1791ac9a064cSDimitry Andric repeat = ArgRepetitionFromString(repeat_str);
1792ac9a064cSDimitry Andric if (!repeat) {
1793ac9a064cSDimitry Andric report_error("invalid repeat value");
1794ac9a064cSDimitry Andric return false;
1795ac9a064cSDimitry Andric }
1796ac9a064cSDimitry Andric arg_repetition = *repeat;
1797ac9a064cSDimitry Andric }
1798ac9a064cSDimitry Andric
1799ac9a064cSDimitry Andric // Usage Mask:
1800ac9a064cSDimitry Andric obj_sp = arg_dict->GetValueForKey("groups");
1801ac9a064cSDimitry Andric m_args_error = CommandOptions::ParseUsageMaskFromArray(obj_sp,
1802ac9a064cSDimitry Andric counter, arg_opt_set_association);
1803ac9a064cSDimitry Andric this_entry.emplace_back(arg_type, arg_repetition,
1804ac9a064cSDimitry Andric arg_opt_set_association);
1805ac9a064cSDimitry Andric elem_counter++;
1806ac9a064cSDimitry Andric return true;
1807ac9a064cSDimitry Andric };
1808ac9a064cSDimitry Andric StructuredData::Array *args_array = object->GetAsArray();
1809ac9a064cSDimitry Andric if (!args_array) {
1810ac9a064cSDimitry Andric m_args_error.SetErrorStringWithFormatv("Argument definition element "
1811ac9a064cSDimitry Andric "{0} is not an array", counter);
1812ac9a064cSDimitry Andric }
1813ac9a064cSDimitry Andric
1814ac9a064cSDimitry Andric args_array->ForEach(args_adder);
1815ac9a064cSDimitry Andric if (m_args_error.Fail())
1816ac9a064cSDimitry Andric return false;
1817ac9a064cSDimitry Andric if (this_entry.empty()) {
1818ac9a064cSDimitry Andric m_args_error.SetErrorStringWithFormatv("Argument definition element "
1819ac9a064cSDimitry Andric "{0} is empty", counter);
1820ac9a064cSDimitry Andric return false;
1821ac9a064cSDimitry Andric }
1822ac9a064cSDimitry Andric m_arguments.push_back(this_entry);
1823ac9a064cSDimitry Andric counter++;
1824ac9a064cSDimitry Andric return true;
1825ac9a064cSDimitry Andric }; // end of arg_array_adder
1826ac9a064cSDimitry Andric // Here we actually parse the args definition:
1827ac9a064cSDimitry Andric args_array->ForEach(arg_array_adder);
1828ac9a064cSDimitry Andric }
1829ac9a064cSDimitry Andric }
1830ac9a064cSDimitry Andric
1831ac9a064cSDimitry Andric ~CommandObjectScriptingObjectParsed() override = default;
1832ac9a064cSDimitry Andric
GetOptionsError()1833ac9a064cSDimitry Andric Status GetOptionsError() { return m_options_error; }
GetArgsError()1834ac9a064cSDimitry Andric Status GetArgsError() { return m_args_error; }
WantsCompletion()1835ac9a064cSDimitry Andric bool WantsCompletion() override { return true; }
1836ac9a064cSDimitry Andric
IsRemovable() const1837ac9a064cSDimitry Andric bool IsRemovable() const override { return true; }
1838ac9a064cSDimitry Andric
GetSynchronicity()1839ac9a064cSDimitry Andric ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1840ac9a064cSDimitry Andric
GetRepeatCommand(Args & args,uint32_t index)1841ac9a064cSDimitry Andric std::optional<std::string> GetRepeatCommand(Args &args,
1842ac9a064cSDimitry Andric uint32_t index) override {
1843ac9a064cSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1844ac9a064cSDimitry Andric if (!scripter)
1845ac9a064cSDimitry Andric return std::nullopt;
1846ac9a064cSDimitry Andric
1847ac9a064cSDimitry Andric return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
1848ac9a064cSDimitry Andric }
1849ac9a064cSDimitry Andric
GetHelp()1850ac9a064cSDimitry Andric llvm::StringRef GetHelp() override {
1851ac9a064cSDimitry Andric if (m_fetched_help_short)
1852ac9a064cSDimitry Andric return CommandObjectParsed::GetHelp();
1853ac9a064cSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1854ac9a064cSDimitry Andric if (!scripter)
1855ac9a064cSDimitry Andric return CommandObjectParsed::GetHelp();
1856ac9a064cSDimitry Andric std::string docstring;
1857ac9a064cSDimitry Andric m_fetched_help_short =
1858ac9a064cSDimitry Andric scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1859ac9a064cSDimitry Andric if (!docstring.empty())
1860ac9a064cSDimitry Andric SetHelp(docstring);
1861ac9a064cSDimitry Andric
1862ac9a064cSDimitry Andric return CommandObjectParsed::GetHelp();
1863ac9a064cSDimitry Andric }
1864ac9a064cSDimitry Andric
GetHelpLong()1865ac9a064cSDimitry Andric llvm::StringRef GetHelpLong() override {
1866ac9a064cSDimitry Andric if (m_fetched_help_long)
1867ac9a064cSDimitry Andric return CommandObjectParsed::GetHelpLong();
1868ac9a064cSDimitry Andric
1869ac9a064cSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1870ac9a064cSDimitry Andric if (!scripter)
1871ac9a064cSDimitry Andric return CommandObjectParsed::GetHelpLong();
1872ac9a064cSDimitry Andric
1873ac9a064cSDimitry Andric std::string docstring;
1874ac9a064cSDimitry Andric m_fetched_help_long =
1875ac9a064cSDimitry Andric scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1876ac9a064cSDimitry Andric if (!docstring.empty())
1877ac9a064cSDimitry Andric SetHelpLong(docstring);
1878ac9a064cSDimitry Andric return CommandObjectParsed::GetHelpLong();
1879ac9a064cSDimitry Andric }
1880ac9a064cSDimitry Andric
GetOptions()1881ac9a064cSDimitry Andric Options *GetOptions() override {
1882ac9a064cSDimitry Andric // CommandObjectParsed requires that a command with no options return
1883ac9a064cSDimitry Andric // nullptr.
1884ac9a064cSDimitry Andric if (m_options.GetNumOptions() == 0)
1885ac9a064cSDimitry Andric return nullptr;
1886ac9a064cSDimitry Andric return &m_options;
1887ac9a064cSDimitry Andric }
1888ac9a064cSDimitry Andric
1889ac9a064cSDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)1890ac9a064cSDimitry Andric void DoExecute(Args &args,
1891ac9a064cSDimitry Andric CommandReturnObject &result) override {
1892ac9a064cSDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1893ac9a064cSDimitry Andric
1894ac9a064cSDimitry Andric Status error;
1895ac9a064cSDimitry Andric
1896ac9a064cSDimitry Andric result.SetStatus(eReturnStatusInvalid);
1897ac9a064cSDimitry Andric
1898ac9a064cSDimitry Andric if (!scripter ||
1899ac9a064cSDimitry Andric !scripter->RunScriptBasedParsedCommand(m_cmd_obj_sp, args,
1900ac9a064cSDimitry Andric m_synchro, result, error, m_exe_ctx)) {
1901ac9a064cSDimitry Andric result.AppendError(error.AsCString());
1902ac9a064cSDimitry Andric } else {
1903ac9a064cSDimitry Andric // Don't change the status if the command already set it...
1904ac9a064cSDimitry Andric if (result.GetStatus() == eReturnStatusInvalid) {
1905ac9a064cSDimitry Andric if (result.GetOutputData().empty())
1906ac9a064cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
1907ac9a064cSDimitry Andric else
1908ac9a064cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
1909ac9a064cSDimitry Andric }
1910ac9a064cSDimitry Andric }
1911ac9a064cSDimitry Andric }
1912ac9a064cSDimitry Andric
1913ac9a064cSDimitry Andric private:
1914ac9a064cSDimitry Andric StructuredData::GenericSP m_cmd_obj_sp;
1915ac9a064cSDimitry Andric ScriptedCommandSynchronicity m_synchro;
1916ac9a064cSDimitry Andric CommandOptions m_options;
1917ac9a064cSDimitry Andric Status m_options_error;
1918ac9a064cSDimitry Andric Status m_args_error;
1919ac9a064cSDimitry Andric bool m_fetched_help_short : 1;
1920ac9a064cSDimitry Andric bool m_fetched_help_long : 1;
1921ac9a064cSDimitry Andric };
1922ac9a064cSDimitry Andric
1923ac9a064cSDimitry Andric std::unordered_set<std::string>
1924ac9a064cSDimitry Andric CommandObjectScriptingObjectParsed::CommandOptions::g_string_storer;
1925ac9a064cSDimitry Andric
1926f034231aSEd Maste // CommandObjectCommandsScriptImport
1927ead24645SDimitry Andric #define LLDB_OPTIONS_script_import
1928ead24645SDimitry Andric #include "CommandOptions.inc"
192914f1b3e8SDimitry Andric
193014f1b3e8SDimitry Andric class CommandObjectCommandsScriptImport : public CommandObjectParsed {
1931f034231aSEd Maste public:
CommandObjectCommandsScriptImport(CommandInterpreter & interpreter)193214f1b3e8SDimitry Andric CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
193314f1b3e8SDimitry Andric : CommandObjectParsed(interpreter, "command script import",
19346f8fc217SDimitry Andric "Import a scripting module in LLDB.", nullptr) {
1935ac9a064cSDimitry Andric AddSimpleArgumentList(eArgTypeFilename, eArgRepeatPlus);
1936f034231aSEd Maste }
1937f034231aSEd Maste
1938f3fbd1c0SDimitry Andric ~CommandObjectCommandsScriptImport() override = default;
1939f034231aSEd Maste
GetOptions()194014f1b3e8SDimitry Andric Options *GetOptions() override { return &m_options; }
1941f034231aSEd Maste
1942f034231aSEd Maste protected:
194314f1b3e8SDimitry Andric class CommandOptions : public Options {
1944f034231aSEd Maste public:
1945145449b1SDimitry Andric CommandOptions() = default;
1946f034231aSEd Maste
1947f3fbd1c0SDimitry Andric ~CommandOptions() override = default;
1948f034231aSEd Maste
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1949b76161e4SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
195014f1b3e8SDimitry Andric ExecutionContext *execution_context) override {
1951b76161e4SDimitry Andric Status error;
1952f034231aSEd Maste const int short_option = m_getopt_table[option_idx].val;
1953f034231aSEd Maste
195414f1b3e8SDimitry Andric switch (short_option) {
1955f034231aSEd Maste case 'r':
1956706b4fc4SDimitry Andric // NO-OP
1957f034231aSEd Maste break;
1958b60736ecSDimitry Andric case 'c':
1959b60736ecSDimitry Andric relative_to_command_file = true;
1960b60736ecSDimitry Andric break;
1961344a3780SDimitry Andric case 's':
1962344a3780SDimitry Andric silent = true;
1963344a3780SDimitry Andric break;
1964f034231aSEd Maste default:
1965ead24645SDimitry Andric llvm_unreachable("Unimplemented option");
1966f034231aSEd Maste }
1967f034231aSEd Maste
1968f034231aSEd Maste return error;
1969f034231aSEd Maste }
1970f034231aSEd Maste
OptionParsingStarting(ExecutionContext * execution_context)197114f1b3e8SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
1972b60736ecSDimitry Andric relative_to_command_file = false;
1973f034231aSEd Maste }
1974f034231aSEd Maste
GetDefinitions()197514f1b3e8SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1976e3b55780SDimitry Andric return llvm::ArrayRef(g_script_import_options);
1977f034231aSEd Maste }
1978b60736ecSDimitry Andric bool relative_to_command_file = false;
1979344a3780SDimitry Andric bool silent = false;
1980f034231aSEd Maste };
1981f034231aSEd Maste
DoExecute(Args & command,CommandReturnObject & result)1982b1c73532SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
198314f1b3e8SDimitry Andric if (command.empty()) {
19845e95aa85SEd Maste result.AppendError("command script import needs one or more arguments");
1985b1c73532SDimitry Andric return;
1986f034231aSEd Maste }
1987f034231aSEd Maste
1988b60736ecSDimitry Andric FileSpec source_dir = {};
1989b60736ecSDimitry Andric if (m_options.relative_to_command_file) {
1990b60736ecSDimitry Andric source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1991b60736ecSDimitry Andric if (!source_dir) {
1992b60736ecSDimitry Andric result.AppendError("command script import -c can only be specified "
1993b60736ecSDimitry Andric "from a command file");
1994b1c73532SDimitry Andric return;
1995b60736ecSDimitry Andric }
1996b60736ecSDimitry Andric }
1997b60736ecSDimitry Andric
199814f1b3e8SDimitry Andric for (auto &entry : command.entries()) {
1999b76161e4SDimitry Andric Status error;
2000f034231aSEd Maste
2001344a3780SDimitry Andric LoadScriptOptions options;
2002344a3780SDimitry Andric options.SetInitSession(true);
2003344a3780SDimitry Andric options.SetSilent(m_options.silent);
2004344a3780SDimitry Andric
200514f1b3e8SDimitry Andric // FIXME: this is necessary because CommandObject::CheckRequirements()
200614f1b3e8SDimitry Andric // assumes that commands won't ever be recursively invoked, but it's
200714f1b3e8SDimitry Andric // actually possible to craft a Python script that does other "command
2008f73363f1SDimitry Andric // script imports" in __lldb_init_module the real fix is to have
2009f73363f1SDimitry Andric // recursive commands possible with a CommandInvocation object separate
2010f73363f1SDimitry Andric // from the CommandObject itself, so that recursive command invocations
2011f73363f1SDimitry Andric // won't stomp on each other (wrt to execution contents, options, and
2012f73363f1SDimitry Andric // more)
2013f034231aSEd Maste m_exe_ctx.Clear();
20145f29bb8aSDimitry Andric if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
2015344a3780SDimitry Andric entry.c_str(), options, error, /*module_sp=*/nullptr,
2016344a3780SDimitry Andric source_dir)) {
2017f034231aSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult);
201814f1b3e8SDimitry Andric } else {
201914f1b3e8SDimitry Andric result.AppendErrorWithFormat("module importing failed: %s",
202014f1b3e8SDimitry Andric error.AsCString());
2021f034231aSEd Maste }
20225e95aa85SEd Maste }
2023f034231aSEd Maste }
2024f034231aSEd Maste
2025f034231aSEd Maste CommandOptions m_options;
2026f034231aSEd Maste };
2027f034231aSEd Maste
2028ead24645SDimitry Andric #define LLDB_OPTIONS_script_add
2029ead24645SDimitry Andric #include "CommandOptions.inc"
203014f1b3e8SDimitry Andric
203114f1b3e8SDimitry Andric class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
203214f1b3e8SDimitry Andric public IOHandlerDelegateMultiline {
2033f034231aSEd Maste public:
CommandObjectCommandsScriptAdd(CommandInterpreter & interpreter)203414f1b3e8SDimitry Andric CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
203514f1b3e8SDimitry Andric : CommandObjectParsed(interpreter, "command script add",
2036f034231aSEd Maste "Add a scripted function as an LLDB command.",
2037c0981da4SDimitry Andric "Add a scripted function as an lldb command. "
2038c0981da4SDimitry Andric "If you provide a single argument, the command "
2039c0981da4SDimitry Andric "will be added at the root level of the command "
2040c0981da4SDimitry Andric "hierarchy. If there are more arguments they "
2041c0981da4SDimitry Andric "must be a path to a user-added container "
2042c0981da4SDimitry Andric "command, and the last element will be the new "
2043c0981da4SDimitry Andric "command name."),
20446f8fc217SDimitry Andric IOHandlerDelegateMultiline("DONE") {
2045ac9a064cSDimitry Andric AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2046f034231aSEd Maste }
2047f034231aSEd Maste
2048f3fbd1c0SDimitry Andric ~CommandObjectCommandsScriptAdd() override = default;
2049f034231aSEd Maste
GetOptions()205014f1b3e8SDimitry Andric Options *GetOptions() override { return &m_options; }
2051f034231aSEd Maste
2052c0981da4SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2053c0981da4SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
2054c0981da4SDimitry Andric OptionElementVector &opt_element_vector) override {
2055c0981da4SDimitry Andric CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
2056c0981da4SDimitry Andric opt_element_vector);
2057c0981da4SDimitry Andric }
2058c0981da4SDimitry Andric
2059f034231aSEd Maste protected:
206014f1b3e8SDimitry Andric class CommandOptions : public Options {
2061f034231aSEd Maste public:
2062145449b1SDimitry Andric CommandOptions() = default;
2063f034231aSEd Maste
2064f3fbd1c0SDimitry Andric ~CommandOptions() override = default;
2065f034231aSEd Maste
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2066b76161e4SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
206714f1b3e8SDimitry Andric ExecutionContext *execution_context) override {
2068b76161e4SDimitry Andric Status error;
2069f034231aSEd Maste const int short_option = m_getopt_table[option_idx].val;
2070f034231aSEd Maste
207114f1b3e8SDimitry Andric switch (short_option) {
2072f034231aSEd Maste case 'f':
207314f1b3e8SDimitry Andric if (!option_arg.empty())
2074cfca06d7SDimitry Andric m_funct_name = std::string(option_arg);
2075205afe67SEd Maste break;
20765e95aa85SEd Maste case 'c':
207714f1b3e8SDimitry Andric if (!option_arg.empty())
2078cfca06d7SDimitry Andric m_class_name = std::string(option_arg);
20795e95aa85SEd Maste break;
2080205afe67SEd Maste case 'h':
208114f1b3e8SDimitry Andric if (!option_arg.empty())
2082cfca06d7SDimitry Andric m_short_help = std::string(option_arg);
2083f034231aSEd Maste break;
2084c0981da4SDimitry Andric case 'o':
2085145449b1SDimitry Andric m_overwrite_lazy = eLazyBoolYes;
2086c0981da4SDimitry Andric break;
2087ac9a064cSDimitry Andric case 'p':
2088ac9a064cSDimitry Andric m_parsed_command = true;
2089ac9a064cSDimitry Andric break;
2090f034231aSEd Maste case 's':
209114f1b3e8SDimitry Andric m_synchronicity =
2092f73363f1SDimitry Andric (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
209314f1b3e8SDimitry Andric option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
2094f034231aSEd Maste if (!error.Success())
209514f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
209614f1b3e8SDimitry Andric "unrecognized value for synchronicity '%s'",
209714f1b3e8SDimitry Andric option_arg.str().c_str());
2098f034231aSEd Maste break;
20997fa27ce4SDimitry Andric case 'C': {
21007fa27ce4SDimitry Andric Status error;
21017fa27ce4SDimitry Andric OptionDefinition definition = GetDefinitions()[option_idx];
21027fa27ce4SDimitry Andric lldb::CompletionType completion_type =
21037fa27ce4SDimitry Andric static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum(
21047fa27ce4SDimitry Andric option_arg, definition.enum_values, eNoCompletion, error));
21057fa27ce4SDimitry Andric if (!error.Success())
21067fa27ce4SDimitry Andric error.SetErrorStringWithFormat(
21077fa27ce4SDimitry Andric "unrecognized value for command completion type '%s'",
21087fa27ce4SDimitry Andric option_arg.str().c_str());
21097fa27ce4SDimitry Andric m_completion_type = completion_type;
21107fa27ce4SDimitry Andric } break;
2111f034231aSEd Maste default:
2112ead24645SDimitry Andric llvm_unreachable("Unimplemented option");
2113f034231aSEd Maste }
2114f034231aSEd Maste
2115f034231aSEd Maste return error;
2116f034231aSEd Maste }
2117f034231aSEd Maste
OptionParsingStarting(ExecutionContext * execution_context)211814f1b3e8SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
21195e95aa85SEd Maste m_class_name.clear();
2120205afe67SEd Maste m_funct_name.clear();
2121205afe67SEd Maste m_short_help.clear();
21227fa27ce4SDimitry Andric m_completion_type = eNoCompletion;
2123145449b1SDimitry Andric m_overwrite_lazy = eLazyBoolCalculate;
2124866dcdacSEd Maste m_synchronicity = eScriptedCommandSynchronicitySynchronous;
2125ac9a064cSDimitry Andric m_parsed_command = false;
2126f034231aSEd Maste }
2127f034231aSEd Maste
GetDefinitions()212814f1b3e8SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2129e3b55780SDimitry Andric return llvm::ArrayRef(g_script_add_options);
2130f034231aSEd Maste }
2131f034231aSEd Maste
2132f034231aSEd Maste // Instance variables to hold the values for command options.
2133f034231aSEd Maste
21345e95aa85SEd Maste std::string m_class_name;
2135f034231aSEd Maste std::string m_funct_name;
2136205afe67SEd Maste std::string m_short_help;
2137145449b1SDimitry Andric LazyBool m_overwrite_lazy = eLazyBoolCalculate;
2138344a3780SDimitry Andric ScriptedCommandSynchronicity m_synchronicity =
2139344a3780SDimitry Andric eScriptedCommandSynchronicitySynchronous;
21407fa27ce4SDimitry Andric CompletionType m_completion_type = eNoCompletion;
2141ac9a064cSDimitry Andric bool m_parsed_command = false;
2142f034231aSEd Maste };
2143f034231aSEd Maste
IOHandlerActivated(IOHandler & io_handler,bool interactive)21445f29bb8aSDimitry Andric void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
2145ead24645SDimitry Andric StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
21465f29bb8aSDimitry Andric if (output_sp && interactive) {
2147866dcdacSEd Maste output_sp->PutCString(g_python_command_instructions);
2148866dcdacSEd Maste output_sp->Flush();
2149f034231aSEd Maste }
2150f034231aSEd Maste }
2151f034231aSEd Maste
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)215214f1b3e8SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler,
215314f1b3e8SDimitry Andric std::string &data) override {
2154ead24645SDimitry Andric StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
2155866dcdacSEd Maste
21565f29bb8aSDimitry Andric ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
215714f1b3e8SDimitry Andric if (interpreter) {
2158866dcdacSEd Maste StringList lines;
2159866dcdacSEd Maste lines.SplitIntoLines(data);
216014f1b3e8SDimitry Andric if (lines.GetSize() > 0) {
2161f034231aSEd Maste std::string funct_name_str;
216214f1b3e8SDimitry Andric if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
216314f1b3e8SDimitry Andric if (funct_name_str.empty()) {
216414f1b3e8SDimitry Andric error_sp->Printf("error: unable to obtain a function name, didn't "
216514f1b3e8SDimitry Andric "add python command.\n");
2166866dcdacSEd Maste error_sp->Flush();
216714f1b3e8SDimitry Andric } else {
2168f034231aSEd Maste // everything should be fine now, let's add this alias
2169f034231aSEd Maste
217014f1b3e8SDimitry Andric CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
217114f1b3e8SDimitry Andric m_interpreter, m_cmd_name, funct_name_str, m_short_help,
21727fa27ce4SDimitry Andric m_synchronicity, m_completion_type));
2173c0981da4SDimitry Andric if (!m_container) {
2174c0981da4SDimitry Andric Status error = m_interpreter.AddUserCommand(
2175c0981da4SDimitry Andric m_cmd_name, command_obj_sp, m_overwrite);
2176c0981da4SDimitry Andric if (error.Fail()) {
2177c0981da4SDimitry Andric error_sp->Printf("error: unable to add selected command: '%s'",
2178c0981da4SDimitry Andric error.AsCString());
2179866dcdacSEd Maste error_sp->Flush();
2180f034231aSEd Maste }
2181c0981da4SDimitry Andric } else {
2182c0981da4SDimitry Andric llvm::Error llvm_error = m_container->LoadUserSubcommand(
2183c0981da4SDimitry Andric m_cmd_name, command_obj_sp, m_overwrite);
2184c0981da4SDimitry Andric if (llvm_error) {
2185c0981da4SDimitry Andric error_sp->Printf("error: unable to add selected command: '%s'",
2186c0981da4SDimitry Andric llvm::toString(std::move(llvm_error)).c_str());
2187c0981da4SDimitry Andric error_sp->Flush();
2188c0981da4SDimitry Andric }
2189c0981da4SDimitry Andric }
2190f034231aSEd Maste }
219114f1b3e8SDimitry Andric } else {
219214f1b3e8SDimitry Andric error_sp->Printf(
2193c0981da4SDimitry Andric "error: unable to create function, didn't add python command\n");
2194866dcdacSEd Maste error_sp->Flush();
2195866dcdacSEd Maste }
219614f1b3e8SDimitry Andric } else {
2197c0981da4SDimitry Andric error_sp->Printf("error: empty function, didn't add python command\n");
2198866dcdacSEd Maste error_sp->Flush();
2199866dcdacSEd Maste }
220014f1b3e8SDimitry Andric } else {
220114f1b3e8SDimitry Andric error_sp->Printf(
2202c0981da4SDimitry Andric "error: script interpreter missing, didn't add python command\n");
2203866dcdacSEd Maste error_sp->Flush();
2204866dcdacSEd Maste }
2205866dcdacSEd Maste
2206866dcdacSEd Maste io_handler.SetIsDone(true);
2207866dcdacSEd Maste }
2208f034231aSEd Maste
DoExecute(Args & command,CommandReturnObject & result)2209b1c73532SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
22105f29bb8aSDimitry Andric if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
221114f1b3e8SDimitry Andric result.AppendError("only scripting language supported for scripted "
221214f1b3e8SDimitry Andric "commands is currently Python");
2213b1c73532SDimitry Andric return;
2214f034231aSEd Maste }
2215f034231aSEd Maste
2216c0981da4SDimitry Andric if (command.GetArgumentCount() == 0) {
2217c0981da4SDimitry Andric result.AppendError("'command script add' requires at least one argument");
2218b1c73532SDimitry Andric return;
2219c0981da4SDimitry Andric }
2220145449b1SDimitry Andric // Store the options in case we get multi-line input, also figure out the
2221145449b1SDimitry Andric // default if not user supplied:
2222145449b1SDimitry Andric switch (m_options.m_overwrite_lazy) {
2223145449b1SDimitry Andric case eLazyBoolCalculate:
2224145449b1SDimitry Andric m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
2225145449b1SDimitry Andric break;
2226145449b1SDimitry Andric case eLazyBoolYes:
2227145449b1SDimitry Andric m_overwrite = true;
2228145449b1SDimitry Andric break;
2229145449b1SDimitry Andric case eLazyBoolNo:
2230145449b1SDimitry Andric m_overwrite = false;
2231145449b1SDimitry Andric }
2232145449b1SDimitry Andric
2233c0981da4SDimitry Andric Status path_error;
2234c0981da4SDimitry Andric m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
2235c0981da4SDimitry Andric command, true, path_error);
2236c0981da4SDimitry Andric
2237c0981da4SDimitry Andric if (path_error.Fail()) {
2238c0981da4SDimitry Andric result.AppendErrorWithFormat("error in command path: %s",
2239c0981da4SDimitry Andric path_error.AsCString());
2240b1c73532SDimitry Andric return;
2241f034231aSEd Maste }
2242f034231aSEd Maste
2243c0981da4SDimitry Andric if (!m_container) {
2244c0981da4SDimitry Andric // This is getting inserted into the root of the interpreter.
2245cfca06d7SDimitry Andric m_cmd_name = std::string(command[0].ref());
2246c0981da4SDimitry Andric } else {
2247c0981da4SDimitry Andric size_t num_args = command.GetArgumentCount();
2248c0981da4SDimitry Andric m_cmd_name = std::string(command[num_args - 1].ref());
2249c0981da4SDimitry Andric }
2250c0981da4SDimitry Andric
2251205afe67SEd Maste m_short_help.assign(m_options.m_short_help);
2252866dcdacSEd Maste m_synchronicity = m_options.m_synchronicity;
22537fa27ce4SDimitry Andric m_completion_type = m_options.m_completion_type;
2254f034231aSEd Maste
2255c0981da4SDimitry Andric // Handle the case where we prompt for the script code first:
2256c0981da4SDimitry Andric if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
2257c0981da4SDimitry Andric m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt
2258706b4fc4SDimitry Andric *this); // IOHandlerDelegate
2259b1c73532SDimitry Andric return;
2260c0981da4SDimitry Andric }
2261c0981da4SDimitry Andric
2262c0981da4SDimitry Andric CommandObjectSP new_cmd_sp;
2263c0981da4SDimitry Andric if (m_options.m_class_name.empty()) {
2264c0981da4SDimitry Andric new_cmd_sp.reset(new CommandObjectPythonFunction(
226514f1b3e8SDimitry Andric m_interpreter, m_cmd_name, m_options.m_funct_name,
22667fa27ce4SDimitry Andric m_options.m_short_help, m_synchronicity, m_completion_type));
226714f1b3e8SDimitry Andric } else {
22685f29bb8aSDimitry Andric ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
226914f1b3e8SDimitry Andric if (!interpreter) {
22705e95aa85SEd Maste result.AppendError("cannot find ScriptInterpreter");
2271b1c73532SDimitry Andric return;
22725e95aa85SEd Maste }
22735e95aa85SEd Maste
227414f1b3e8SDimitry Andric auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
227514f1b3e8SDimitry Andric m_options.m_class_name.c_str());
227614f1b3e8SDimitry Andric if (!cmd_obj_sp) {
22777fa27ce4SDimitry Andric result.AppendErrorWithFormatv("cannot create helper object for: "
22787fa27ce4SDimitry Andric "'{0}'", m_options.m_class_name);
2279b1c73532SDimitry Andric return;
22805e95aa85SEd Maste }
22815e95aa85SEd Maste
2282ac9a064cSDimitry Andric if (m_options.m_parsed_command) {
2283ac9a064cSDimitry Andric new_cmd_sp = CommandObjectScriptingObjectParsed::Create(m_interpreter,
2284ac9a064cSDimitry Andric m_cmd_name, cmd_obj_sp, m_synchronicity, result);
2285ac9a064cSDimitry Andric if (!result.Succeeded())
2286ac9a064cSDimitry Andric return;
2287ac9a064cSDimitry Andric } else
2288ac9a064cSDimitry Andric new_cmd_sp.reset(new CommandObjectScriptingObjectRaw(
22897fa27ce4SDimitry Andric m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity,
22907fa27ce4SDimitry Andric m_completion_type));
22915e95aa85SEd Maste }
2292f034231aSEd Maste
2293c0981da4SDimitry Andric // Assume we're going to succeed...
2294c0981da4SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2295c0981da4SDimitry Andric if (!m_container) {
2296c0981da4SDimitry Andric Status add_error =
2297c0981da4SDimitry Andric m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
2298c0981da4SDimitry Andric if (add_error.Fail())
2299c0981da4SDimitry Andric result.AppendErrorWithFormat("cannot add command: %s",
2300c0981da4SDimitry Andric add_error.AsCString());
2301c0981da4SDimitry Andric } else {
2302c0981da4SDimitry Andric llvm::Error llvm_error =
2303c0981da4SDimitry Andric m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
2304c0981da4SDimitry Andric if (llvm_error)
2305ac9a064cSDimitry Andric result.AppendErrorWithFormat(
2306ac9a064cSDimitry Andric "cannot add command: %s",
2307c0981da4SDimitry Andric llvm::toString(std::move(llvm_error)).c_str());
2308c0981da4SDimitry Andric }
2309f034231aSEd Maste }
2310f034231aSEd Maste
2311f034231aSEd Maste CommandOptions m_options;
2312866dcdacSEd Maste std::string m_cmd_name;
2313c0981da4SDimitry Andric CommandObjectMultiword *m_container = nullptr;
2314205afe67SEd Maste std::string m_short_help;
2315145449b1SDimitry Andric bool m_overwrite = false;
2316145449b1SDimitry Andric ScriptedCommandSynchronicity m_synchronicity =
2317145449b1SDimitry Andric eScriptedCommandSynchronicitySynchronous;
23187fa27ce4SDimitry Andric CompletionType m_completion_type = eNoCompletion;
2319f034231aSEd Maste };
2320f034231aSEd Maste
2321f034231aSEd Maste // CommandObjectCommandsScriptList
2322f034231aSEd Maste
232314f1b3e8SDimitry Andric class CommandObjectCommandsScriptList : public CommandObjectParsed {
2324f034231aSEd Maste public:
CommandObjectCommandsScriptList(CommandInterpreter & interpreter)232514f1b3e8SDimitry Andric CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
232614f1b3e8SDimitry Andric : CommandObjectParsed(interpreter, "command script list",
2327c0981da4SDimitry Andric "List defined top-level scripted commands.",
2328c0981da4SDimitry Andric nullptr) {}
2329f034231aSEd Maste
2330f3fbd1c0SDimitry Andric ~CommandObjectCommandsScriptList() override = default;
2331f034231aSEd Maste
DoExecute(Args & command,CommandReturnObject & result)2332b1c73532SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
233314f1b3e8SDimitry Andric m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
2334f034231aSEd Maste
2335f034231aSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
2336f034231aSEd Maste }
2337f034231aSEd Maste };
2338f034231aSEd Maste
2339f034231aSEd Maste // CommandObjectCommandsScriptClear
2340f034231aSEd Maste
234114f1b3e8SDimitry Andric class CommandObjectCommandsScriptClear : public CommandObjectParsed {
2342f034231aSEd Maste public:
CommandObjectCommandsScriptClear(CommandInterpreter & interpreter)234314f1b3e8SDimitry Andric CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
234414f1b3e8SDimitry Andric : CommandObjectParsed(interpreter, "command script clear",
234514f1b3e8SDimitry Andric "Delete all scripted commands.", nullptr) {}
2346f034231aSEd Maste
2347f3fbd1c0SDimitry Andric ~CommandObjectCommandsScriptClear() override = default;
2348f034231aSEd Maste
2349f034231aSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)2350b1c73532SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
2351f034231aSEd Maste m_interpreter.RemoveAllUser();
2352f034231aSEd Maste
2353f034231aSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
2354f034231aSEd Maste }
2355f034231aSEd Maste };
2356f034231aSEd Maste
2357f034231aSEd Maste // CommandObjectCommandsScriptDelete
2358f034231aSEd Maste
235914f1b3e8SDimitry Andric class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
2360f034231aSEd Maste public:
CommandObjectCommandsScriptDelete(CommandInterpreter & interpreter)236114f1b3e8SDimitry Andric CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
2362c0981da4SDimitry Andric : CommandObjectParsed(
2363c0981da4SDimitry Andric interpreter, "command script delete",
2364c0981da4SDimitry Andric "Delete a scripted command by specifying the path to the command.",
2365c0981da4SDimitry Andric nullptr) {
2366ac9a064cSDimitry Andric AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2367f034231aSEd Maste }
2368f034231aSEd Maste
2369f3fbd1c0SDimitry Andric ~CommandObjectCommandsScriptDelete() override = default;
2370f034231aSEd Maste
2371cfca06d7SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2372cfca06d7SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
2373cfca06d7SDimitry Andric OptionElementVector &opt_element_vector) override {
23747fa27ce4SDimitry Andric lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
23757fa27ce4SDimitry Andric m_interpreter, request, opt_element_vector);
2376cfca06d7SDimitry Andric }
2377cfca06d7SDimitry Andric
2378f034231aSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)2379b1c73532SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
2380f034231aSEd Maste
2381c0981da4SDimitry Andric llvm::StringRef root_cmd = command[0].ref();
2382c0981da4SDimitry Andric size_t num_args = command.GetArgumentCount();
2383c0981da4SDimitry Andric
2384c0981da4SDimitry Andric if (root_cmd.empty()) {
2385c0981da4SDimitry Andric result.AppendErrorWithFormat("empty root command name");
2386b1c73532SDimitry Andric return;
2387c0981da4SDimitry Andric }
2388c0981da4SDimitry Andric if (!m_interpreter.HasUserCommands() &&
2389c0981da4SDimitry Andric !m_interpreter.HasUserMultiwordCommands()) {
2390c0981da4SDimitry Andric result.AppendErrorWithFormat("can only delete user defined commands, "
2391c0981da4SDimitry Andric "but no user defined commands found");
2392b1c73532SDimitry Andric return;
2393f034231aSEd Maste }
2394f034231aSEd Maste
2395c0981da4SDimitry Andric CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
2396c0981da4SDimitry Andric if (!cmd_sp) {
2397c0981da4SDimitry Andric result.AppendErrorWithFormat("command '%s' not found.",
2398c0981da4SDimitry Andric command[0].c_str());
2399b1c73532SDimitry Andric return;
2400c0981da4SDimitry Andric }
2401c0981da4SDimitry Andric if (!cmd_sp->IsUserCommand()) {
2402c0981da4SDimitry Andric result.AppendErrorWithFormat("command '%s' is not a user command.",
2403c0981da4SDimitry Andric command[0].c_str());
2404b1c73532SDimitry Andric return;
2405c0981da4SDimitry Andric }
2406c0981da4SDimitry Andric if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
2407c0981da4SDimitry Andric result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
2408c0981da4SDimitry Andric "Delete with \"command container delete\"",
2409c0981da4SDimitry Andric command[0].c_str());
2410b1c73532SDimitry Andric return;
241114f1b3e8SDimitry Andric }
241214f1b3e8SDimitry Andric
2413c0981da4SDimitry Andric if (command.GetArgumentCount() == 1) {
2414c0981da4SDimitry Andric m_interpreter.RemoveUser(root_cmd);
2415c0981da4SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
2416b1c73532SDimitry Andric return;
2417c0981da4SDimitry Andric }
2418c0981da4SDimitry Andric // We're deleting a command from a multiword command. Verify the command
2419c0981da4SDimitry Andric // path:
2420c0981da4SDimitry Andric Status error;
2421c0981da4SDimitry Andric CommandObjectMultiword *container =
2422c0981da4SDimitry Andric GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2423c0981da4SDimitry Andric error);
2424c0981da4SDimitry Andric if (error.Fail()) {
2425c0981da4SDimitry Andric result.AppendErrorWithFormat("could not resolve command path: %s",
2426c0981da4SDimitry Andric error.AsCString());
2427b1c73532SDimitry Andric return;
2428c0981da4SDimitry Andric }
2429c0981da4SDimitry Andric if (!container) {
2430c0981da4SDimitry Andric // This means that command only had a leaf command, so the container is
2431c0981da4SDimitry Andric // the root. That should have been handled above.
2432c0981da4SDimitry Andric result.AppendErrorWithFormat("could not find a container for '%s'",
2433c0981da4SDimitry Andric command[0].c_str());
2434b1c73532SDimitry Andric return;
2435c0981da4SDimitry Andric }
2436c0981da4SDimitry Andric const char *leaf_cmd = command[num_args - 1].c_str();
2437ac9a064cSDimitry Andric llvm::Error llvm_error =
2438ac9a064cSDimitry Andric container->RemoveUserSubcommand(leaf_cmd,
2439c0981da4SDimitry Andric /* multiword not okay */ false);
2440c0981da4SDimitry Andric if (llvm_error) {
2441ac9a064cSDimitry Andric result.AppendErrorWithFormat(
2442ac9a064cSDimitry Andric "could not delete command '%s': %s", leaf_cmd,
2443c0981da4SDimitry Andric llvm::toString(std::move(llvm_error)).c_str());
2444b1c73532SDimitry Andric return;
2445c0981da4SDimitry Andric }
2446c0981da4SDimitry Andric
2447c0981da4SDimitry Andric Stream &out_stream = result.GetOutputStream();
2448c0981da4SDimitry Andric
2449c0981da4SDimitry Andric out_stream << "Deleted command:";
2450c0981da4SDimitry Andric for (size_t idx = 0; idx < num_args; idx++) {
2451c0981da4SDimitry Andric out_stream << ' ';
2452c0981da4SDimitry Andric out_stream << command[idx].c_str();
2453c0981da4SDimitry Andric }
2454c0981da4SDimitry Andric out_stream << '\n';
2455f034231aSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
2456f034231aSEd Maste }
2457f034231aSEd Maste };
2458f034231aSEd Maste
2459f034231aSEd Maste #pragma mark CommandObjectMultiwordCommandsScript
2460f034231aSEd Maste
2461f034231aSEd Maste // CommandObjectMultiwordCommandsScript
2462f034231aSEd Maste
246314f1b3e8SDimitry Andric class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
2464f034231aSEd Maste public:
CommandObjectMultiwordCommandsScript(CommandInterpreter & interpreter)2465f3fbd1c0SDimitry Andric CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
246614f1b3e8SDimitry Andric : CommandObjectMultiword(
2467706b4fc4SDimitry Andric interpreter, "command script",
2468706b4fc4SDimitry Andric "Commands for managing custom "
246914f1b3e8SDimitry Andric "commands implemented by "
247014f1b3e8SDimitry Andric "interpreter scripts.",
247114f1b3e8SDimitry Andric "command script <subcommand> [<subcommand-options>]") {
247214f1b3e8SDimitry Andric LoadSubCommand("add", CommandObjectSP(
247314f1b3e8SDimitry Andric new CommandObjectCommandsScriptAdd(interpreter)));
247414f1b3e8SDimitry Andric LoadSubCommand(
247514f1b3e8SDimitry Andric "delete",
247614f1b3e8SDimitry Andric CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
247714f1b3e8SDimitry Andric LoadSubCommand(
247814f1b3e8SDimitry Andric "clear",
247914f1b3e8SDimitry Andric CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
248014f1b3e8SDimitry Andric LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
248114f1b3e8SDimitry Andric interpreter)));
248214f1b3e8SDimitry Andric LoadSubCommand(
248314f1b3e8SDimitry Andric "import",
248414f1b3e8SDimitry Andric CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
2485f034231aSEd Maste }
2486f034231aSEd Maste
2487f3fbd1c0SDimitry Andric ~CommandObjectMultiwordCommandsScript() override = default;
2488f034231aSEd Maste };
2489f034231aSEd Maste
2490c0981da4SDimitry Andric #pragma mark CommandObjectCommandContainer
2491c0981da4SDimitry Andric #define LLDB_OPTIONS_container_add
2492c0981da4SDimitry Andric #include "CommandOptions.inc"
2493c0981da4SDimitry Andric
2494c0981da4SDimitry Andric class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
2495c0981da4SDimitry Andric public:
CommandObjectCommandsContainerAdd(CommandInterpreter & interpreter)2496c0981da4SDimitry Andric CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter)
2497c0981da4SDimitry Andric : CommandObjectParsed(
2498c0981da4SDimitry Andric interpreter, "command container add",
2499c0981da4SDimitry Andric "Add a container command to lldb. Adding to built-"
2500c0981da4SDimitry Andric "in container commands is not allowed.",
2501c0981da4SDimitry Andric "command container add [[path1]...] container-name") {
2502ac9a064cSDimitry Andric AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2503c0981da4SDimitry Andric }
2504c0981da4SDimitry Andric
2505c0981da4SDimitry Andric ~CommandObjectCommandsContainerAdd() override = default;
2506c0981da4SDimitry Andric
GetOptions()2507c0981da4SDimitry Andric Options *GetOptions() override { return &m_options; }
2508c0981da4SDimitry Andric
2509c0981da4SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2510c0981da4SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
2511c0981da4SDimitry Andric OptionElementVector &opt_element_vector) override {
25127fa27ce4SDimitry Andric lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
25137fa27ce4SDimitry Andric m_interpreter, request, opt_element_vector);
2514c0981da4SDimitry Andric }
2515c0981da4SDimitry Andric
2516c0981da4SDimitry Andric protected:
2517c0981da4SDimitry Andric class CommandOptions : public Options {
2518c0981da4SDimitry Andric public:
2519145449b1SDimitry Andric CommandOptions() = default;
2520c0981da4SDimitry Andric
2521c0981da4SDimitry Andric ~CommandOptions() override = default;
2522c0981da4SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2523c0981da4SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2524c0981da4SDimitry Andric ExecutionContext *execution_context) override {
2525c0981da4SDimitry Andric Status error;
2526c0981da4SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
2527c0981da4SDimitry Andric
2528c0981da4SDimitry Andric switch (short_option) {
2529c0981da4SDimitry Andric case 'h':
2530c0981da4SDimitry Andric if (!option_arg.empty())
2531c0981da4SDimitry Andric m_short_help = std::string(option_arg);
2532c0981da4SDimitry Andric break;
2533c0981da4SDimitry Andric case 'o':
2534c0981da4SDimitry Andric m_overwrite = true;
2535c0981da4SDimitry Andric break;
2536c0981da4SDimitry Andric case 'H':
2537c0981da4SDimitry Andric if (!option_arg.empty())
2538c0981da4SDimitry Andric m_long_help = std::string(option_arg);
2539c0981da4SDimitry Andric break;
2540c0981da4SDimitry Andric default:
2541c0981da4SDimitry Andric llvm_unreachable("Unimplemented option");
2542c0981da4SDimitry Andric }
2543c0981da4SDimitry Andric
2544c0981da4SDimitry Andric return error;
2545c0981da4SDimitry Andric }
2546c0981da4SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)2547c0981da4SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
2548c0981da4SDimitry Andric m_short_help.clear();
2549c0981da4SDimitry Andric m_long_help.clear();
2550c0981da4SDimitry Andric m_overwrite = false;
2551c0981da4SDimitry Andric }
2552c0981da4SDimitry Andric
GetDefinitions()2553c0981da4SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2554e3b55780SDimitry Andric return llvm::ArrayRef(g_container_add_options);
2555c0981da4SDimitry Andric }
2556c0981da4SDimitry Andric
2557c0981da4SDimitry Andric // Instance variables to hold the values for command options.
2558c0981da4SDimitry Andric
2559c0981da4SDimitry Andric std::string m_short_help;
2560c0981da4SDimitry Andric std::string m_long_help;
2561c0981da4SDimitry Andric bool m_overwrite = false;
2562c0981da4SDimitry Andric };
DoExecute(Args & command,CommandReturnObject & result)2563b1c73532SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
2564c0981da4SDimitry Andric size_t num_args = command.GetArgumentCount();
2565c0981da4SDimitry Andric
2566c0981da4SDimitry Andric if (num_args == 0) {
2567c0981da4SDimitry Andric result.AppendError("no command was specified");
2568b1c73532SDimitry Andric return;
2569c0981da4SDimitry Andric }
2570c0981da4SDimitry Andric
2571c0981da4SDimitry Andric if (num_args == 1) {
2572c0981da4SDimitry Andric // We're adding this as a root command, so use the interpreter.
2573c0981da4SDimitry Andric const char *cmd_name = command.GetArgumentAtIndex(0);
2574c0981da4SDimitry Andric auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
2575c0981da4SDimitry Andric GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
2576c0981da4SDimitry Andric m_options.m_long_help.c_str()));
2577c0981da4SDimitry Andric cmd_sp->GetAsMultiwordCommand()->SetRemovable(true);
2578c0981da4SDimitry Andric Status add_error = GetCommandInterpreter().AddUserCommand(
2579c0981da4SDimitry Andric cmd_name, cmd_sp, m_options.m_overwrite);
2580c0981da4SDimitry Andric if (add_error.Fail()) {
2581c0981da4SDimitry Andric result.AppendErrorWithFormat("error adding command: %s",
2582c0981da4SDimitry Andric add_error.AsCString());
2583b1c73532SDimitry Andric return;
2584c0981da4SDimitry Andric }
2585c0981da4SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2586b1c73532SDimitry Andric return;
2587c0981da4SDimitry Andric }
2588c0981da4SDimitry Andric
2589c0981da4SDimitry Andric // We're adding this to a subcommand, first find the subcommand:
2590c0981da4SDimitry Andric Status path_error;
2591c0981da4SDimitry Andric CommandObjectMultiword *add_to_me =
2592c0981da4SDimitry Andric GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2593c0981da4SDimitry Andric path_error);
2594c0981da4SDimitry Andric
2595c0981da4SDimitry Andric if (!add_to_me) {
2596c0981da4SDimitry Andric result.AppendErrorWithFormat("error adding command: %s",
2597c0981da4SDimitry Andric path_error.AsCString());
2598b1c73532SDimitry Andric return;
2599c0981da4SDimitry Andric }
2600c0981da4SDimitry Andric
2601c0981da4SDimitry Andric const char *cmd_name = command.GetArgumentAtIndex(num_args - 1);
2602c0981da4SDimitry Andric auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
2603c0981da4SDimitry Andric GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
2604c0981da4SDimitry Andric m_options.m_long_help.c_str()));
2605c0981da4SDimitry Andric llvm::Error llvm_error =
2606c0981da4SDimitry Andric add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite);
2607c0981da4SDimitry Andric if (llvm_error) {
2608c0981da4SDimitry Andric result.AppendErrorWithFormat("error adding subcommand: %s",
2609c0981da4SDimitry Andric llvm::toString(std::move(llvm_error)).c_str());
2610b1c73532SDimitry Andric return;
2611c0981da4SDimitry Andric }
2612c0981da4SDimitry Andric
2613c0981da4SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2614c0981da4SDimitry Andric }
2615c0981da4SDimitry Andric
2616c0981da4SDimitry Andric private:
2617c0981da4SDimitry Andric CommandOptions m_options;
2618c0981da4SDimitry Andric };
2619c0981da4SDimitry Andric
2620c0981da4SDimitry Andric #define LLDB_OPTIONS_multiword_delete
2621c0981da4SDimitry Andric #include "CommandOptions.inc"
2622c0981da4SDimitry Andric class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
2623c0981da4SDimitry Andric public:
CommandObjectCommandsContainerDelete(CommandInterpreter & interpreter)2624c0981da4SDimitry Andric CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
2625c0981da4SDimitry Andric : CommandObjectParsed(
2626c0981da4SDimitry Andric interpreter, "command container delete",
2627c0981da4SDimitry Andric "Delete a container command previously added to "
2628c0981da4SDimitry Andric "lldb.",
2629c0981da4SDimitry Andric "command container delete [[path1] ...] container-cmd") {
2630ac9a064cSDimitry Andric AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2631c0981da4SDimitry Andric }
2632c0981da4SDimitry Andric
2633c0981da4SDimitry Andric ~CommandObjectCommandsContainerDelete() override = default;
2634c0981da4SDimitry Andric
2635c0981da4SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2636c0981da4SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
2637c0981da4SDimitry Andric OptionElementVector &opt_element_vector) override {
26387fa27ce4SDimitry Andric lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
26397fa27ce4SDimitry Andric m_interpreter, request, opt_element_vector);
2640c0981da4SDimitry Andric }
2641c0981da4SDimitry Andric
2642c0981da4SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)2643b1c73532SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
2644c0981da4SDimitry Andric size_t num_args = command.GetArgumentCount();
2645c0981da4SDimitry Andric
2646c0981da4SDimitry Andric if (num_args == 0) {
2647c0981da4SDimitry Andric result.AppendError("No command was specified.");
2648b1c73532SDimitry Andric return;
2649c0981da4SDimitry Andric }
2650c0981da4SDimitry Andric
2651c0981da4SDimitry Andric if (num_args == 1) {
2652c0981da4SDimitry Andric // We're removing a root command, so we need to delete it from the
2653c0981da4SDimitry Andric // interpreter.
2654c0981da4SDimitry Andric const char *cmd_name = command.GetArgumentAtIndex(0);
2655c0981da4SDimitry Andric // Let's do a little more work here so we can do better error reporting.
2656c0981da4SDimitry Andric CommandInterpreter &interp = GetCommandInterpreter();
2657c0981da4SDimitry Andric CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2658c0981da4SDimitry Andric if (!cmd_sp) {
2659c0981da4SDimitry Andric result.AppendErrorWithFormat("container command %s doesn't exist.",
2660c0981da4SDimitry Andric cmd_name);
2661b1c73532SDimitry Andric return;
2662c0981da4SDimitry Andric }
2663c0981da4SDimitry Andric if (!cmd_sp->IsUserCommand()) {
2664c0981da4SDimitry Andric result.AppendErrorWithFormat(
2665c0981da4SDimitry Andric "container command %s is not a user command", cmd_name);
2666b1c73532SDimitry Andric return;
2667c0981da4SDimitry Andric }
2668c0981da4SDimitry Andric if (!cmd_sp->GetAsMultiwordCommand()) {
2669c0981da4SDimitry Andric result.AppendErrorWithFormat("command %s is not a container command",
2670c0981da4SDimitry Andric cmd_name);
2671b1c73532SDimitry Andric return;
2672c0981da4SDimitry Andric }
2673c0981da4SDimitry Andric
2674c0981da4SDimitry Andric bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2675c0981da4SDimitry Andric if (!did_remove) {
2676c0981da4SDimitry Andric result.AppendErrorWithFormat("error removing command %s.", cmd_name);
2677b1c73532SDimitry Andric return;
2678c0981da4SDimitry Andric }
2679c0981da4SDimitry Andric
2680c0981da4SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2681b1c73532SDimitry Andric return;
2682c0981da4SDimitry Andric }
2683c0981da4SDimitry Andric
2684c0981da4SDimitry Andric // We're removing a subcommand, first find the subcommand's owner:
2685c0981da4SDimitry Andric Status path_error;
2686c0981da4SDimitry Andric CommandObjectMultiword *container =
2687c0981da4SDimitry Andric GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2688c0981da4SDimitry Andric path_error);
2689c0981da4SDimitry Andric
2690c0981da4SDimitry Andric if (!container) {
2691c0981da4SDimitry Andric result.AppendErrorWithFormat("error removing container command: %s",
2692c0981da4SDimitry Andric path_error.AsCString());
2693b1c73532SDimitry Andric return;
2694c0981da4SDimitry Andric }
2695c0981da4SDimitry Andric const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2696c0981da4SDimitry Andric llvm::Error llvm_error =
2697c0981da4SDimitry Andric container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2698c0981da4SDimitry Andric if (llvm_error) {
2699c0981da4SDimitry Andric result.AppendErrorWithFormat("error removing container command: %s",
2700c0981da4SDimitry Andric llvm::toString(std::move(llvm_error)).c_str());
2701b1c73532SDimitry Andric return;
2702c0981da4SDimitry Andric }
2703c0981da4SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2704c0981da4SDimitry Andric }
2705c0981da4SDimitry Andric };
2706c0981da4SDimitry Andric
2707c0981da4SDimitry Andric class CommandObjectCommandContainer : public CommandObjectMultiword {
2708c0981da4SDimitry Andric public:
CommandObjectCommandContainer(CommandInterpreter & interpreter)2709c0981da4SDimitry Andric CommandObjectCommandContainer(CommandInterpreter &interpreter)
2710c0981da4SDimitry Andric : CommandObjectMultiword(
2711c0981da4SDimitry Andric interpreter, "command container",
2712c0981da4SDimitry Andric "Commands for adding container commands to lldb. "
2713c0981da4SDimitry Andric "Container commands are containers for other commands. You can "
2714145449b1SDimitry Andric "add nested container commands by specifying a command path, "
2715c0981da4SDimitry Andric "but you can't add commands into the built-in command hierarchy.",
2716c0981da4SDimitry Andric "command container <subcommand> [<subcommand-options>]") {
2717c0981da4SDimitry Andric LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2718c0981da4SDimitry Andric interpreter)));
2719c0981da4SDimitry Andric LoadSubCommand(
2720c0981da4SDimitry Andric "delete",
2721c0981da4SDimitry Andric CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2722c0981da4SDimitry Andric }
2723c0981da4SDimitry Andric
2724c0981da4SDimitry Andric ~CommandObjectCommandContainer() override = default;
2725c0981da4SDimitry Andric };
2726c0981da4SDimitry Andric
2727f034231aSEd Maste #pragma mark CommandObjectMultiwordCommands
2728f034231aSEd Maste
2729f034231aSEd Maste // CommandObjectMultiwordCommands
2730f034231aSEd Maste
CommandObjectMultiwordCommands(CommandInterpreter & interpreter)273114f1b3e8SDimitry Andric CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
273214f1b3e8SDimitry Andric CommandInterpreter &interpreter)
273314f1b3e8SDimitry Andric : CommandObjectMultiword(interpreter, "command",
273414f1b3e8SDimitry Andric "Commands for managing custom LLDB commands.",
273514f1b3e8SDimitry Andric "command <subcommand> [<subcommand-options>]") {
273614f1b3e8SDimitry Andric LoadSubCommand("source",
273714f1b3e8SDimitry Andric CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
273814f1b3e8SDimitry Andric LoadSubCommand("alias",
273914f1b3e8SDimitry Andric CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
274014f1b3e8SDimitry Andric LoadSubCommand("unalias", CommandObjectSP(
274114f1b3e8SDimitry Andric new CommandObjectCommandsUnalias(interpreter)));
274214f1b3e8SDimitry Andric LoadSubCommand("delete",
274314f1b3e8SDimitry Andric CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2744c0981da4SDimitry Andric LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2745c0981da4SDimitry Andric interpreter)));
274614f1b3e8SDimitry Andric LoadSubCommand(
274714f1b3e8SDimitry Andric "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
274814f1b3e8SDimitry Andric LoadSubCommand(
274914f1b3e8SDimitry Andric "script",
275014f1b3e8SDimitry Andric CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
2751f034231aSEd Maste }
2752f034231aSEd Maste
2753f3fbd1c0SDimitry Andric CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2754