15ffd83dbSDimitry Andric //===-- CommandObjectCommands.cpp -----------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "CommandObjectCommands.h" 100b57cec5SDimitry Andric #include "CommandObjectHelp.h" 11e8d8bef9SDimitry Andric #include "CommandObjectRegexCommand.h" 120b57cec5SDimitry Andric #include "lldb/Core/Debugger.h" 130b57cec5SDimitry Andric #include "lldb/Core/IOHandler.h" 140b57cec5SDimitry Andric #include "lldb/Interpreter/CommandHistory.h" 150b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h" 16fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h" 170b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 180b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h" 190b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueBoolean.h" 200b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueString.h" 210b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueUInt64.h" 220b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h" 230b57cec5SDimitry Andric #include "lldb/Interpreter/ScriptInterpreter.h" 240b57cec5SDimitry Andric #include "lldb/Utility/Args.h" 250b57cec5SDimitry Andric #include "lldb/Utility/StringList.h" 26e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h" 27bdd1243dSDimitry Andric #include <optional> 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace lldb; 300b57cec5SDimitry Andric using namespace lldb_private; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric // CommandObjectCommandsSource 330b57cec5SDimitry Andric 349dba64beSDimitry Andric #define LLDB_OPTIONS_source 359dba64beSDimitry Andric #include "CommandOptions.inc" 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric class CommandObjectCommandsSource : public CommandObjectParsed { 380b57cec5SDimitry Andric public: 390b57cec5SDimitry Andric CommandObjectCommandsSource(CommandInterpreter &interpreter) 400b57cec5SDimitry Andric : CommandObjectParsed( 410b57cec5SDimitry Andric interpreter, "command source", 420b57cec5SDimitry Andric "Read and execute LLDB commands from the file <filename>.", 4304eeddc0SDimitry Andric nullptr) { 44*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeFilename); 450b57cec5SDimitry Andric } 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric ~CommandObjectCommandsSource() override = default; 480b57cec5SDimitry Andric 49bdd1243dSDimitry Andric std::optional<std::string> GetRepeatCommand(Args ¤t_command_args, 500b57cec5SDimitry Andric uint32_t index) override { 5181ad6265SDimitry Andric return std::string(""); 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric protected: 570b57cec5SDimitry Andric class CommandOptions : public Options { 580b57cec5SDimitry Andric public: 590b57cec5SDimitry Andric CommandOptions() 6004eeddc0SDimitry Andric : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true), 6104eeddc0SDimitry Andric m_cmd_relative_to_command_file(false) {} 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric ~CommandOptions() override = default; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 660b57cec5SDimitry Andric ExecutionContext *execution_context) override { 670b57cec5SDimitry Andric Status error; 680b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric switch (short_option) { 710b57cec5SDimitry Andric case 'e': 720b57cec5SDimitry Andric error = m_stop_on_error.SetValueFromString(option_arg); 730b57cec5SDimitry Andric break; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric case 'c': 760b57cec5SDimitry Andric error = m_stop_on_continue.SetValueFromString(option_arg); 770b57cec5SDimitry Andric break; 780b57cec5SDimitry Andric 79349cc55cSDimitry Andric case 'C': 80349cc55cSDimitry Andric m_cmd_relative_to_command_file = true; 81349cc55cSDimitry Andric break; 82349cc55cSDimitry Andric 830b57cec5SDimitry Andric case 's': 840b57cec5SDimitry Andric error = m_silent_run.SetValueFromString(option_arg); 850b57cec5SDimitry Andric break; 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric default: 889dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric return error; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 950b57cec5SDimitry Andric m_stop_on_error.Clear(); 960b57cec5SDimitry Andric m_silent_run.Clear(); 970b57cec5SDimitry Andric m_stop_on_continue.Clear(); 98349cc55cSDimitry Andric m_cmd_relative_to_command_file.Clear(); 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 102bdd1243dSDimitry Andric return llvm::ArrayRef(g_source_options); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric // Instance variables to hold the values for command options. 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric OptionValueBoolean m_stop_on_error; 1080b57cec5SDimitry Andric OptionValueBoolean m_silent_run; 1090b57cec5SDimitry Andric OptionValueBoolean m_stop_on_continue; 110349cc55cSDimitry Andric OptionValueBoolean m_cmd_relative_to_command_file; 1110b57cec5SDimitry Andric }; 1120b57cec5SDimitry Andric 1135f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 1140b57cec5SDimitry Andric if (command.GetArgumentCount() != 1) { 1150b57cec5SDimitry Andric result.AppendErrorWithFormat( 1160b57cec5SDimitry Andric "'%s' takes exactly one executable filename argument.\n", 1170b57cec5SDimitry Andric GetCommandName().str().c_str()); 1185f757f3fSDimitry Andric return; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 121349cc55cSDimitry Andric FileSpec source_dir = {}; 122349cc55cSDimitry Andric if (m_options.m_cmd_relative_to_command_file) { 123349cc55cSDimitry Andric source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 124349cc55cSDimitry Andric if (!source_dir) { 125349cc55cSDimitry Andric result.AppendError("command source -C can only be specified " 126349cc55cSDimitry Andric "from a command file"); 127349cc55cSDimitry Andric result.SetStatus(eReturnStatusFailed); 1285f757f3fSDimitry Andric return; 129349cc55cSDimitry Andric } 130349cc55cSDimitry Andric } 131349cc55cSDimitry Andric 1329dba64beSDimitry Andric FileSpec cmd_file(command[0].ref()); 133349cc55cSDimitry Andric if (source_dir) { 134349cc55cSDimitry Andric // Prepend the source_dir to the cmd_file path: 135349cc55cSDimitry Andric if (!cmd_file.IsRelative()) { 136349cc55cSDimitry Andric result.AppendError("command source -C can only be used " 137349cc55cSDimitry Andric "with a relative path."); 138349cc55cSDimitry Andric result.SetStatus(eReturnStatusFailed); 1395f757f3fSDimitry Andric return; 140349cc55cSDimitry Andric } 141349cc55cSDimitry Andric cmd_file.MakeAbsolute(source_dir); 142349cc55cSDimitry Andric } 143349cc55cSDimitry Andric 1440b57cec5SDimitry Andric FileSystem::Instance().Resolve(cmd_file); 1450b57cec5SDimitry Andric 146fe6060f1SDimitry Andric CommandInterpreterRunOptions options; 1470b57cec5SDimitry Andric // If any options were set, then use them 1480b57cec5SDimitry Andric if (m_options.m_stop_on_error.OptionWasSet() || 1490b57cec5SDimitry Andric m_options.m_silent_run.OptionWasSet() || 1500b57cec5SDimitry Andric m_options.m_stop_on_continue.OptionWasSet()) { 1510b57cec5SDimitry Andric if (m_options.m_stop_on_continue.OptionWasSet()) 1520b57cec5SDimitry Andric options.SetStopOnContinue( 1530b57cec5SDimitry Andric m_options.m_stop_on_continue.GetCurrentValue()); 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric if (m_options.m_stop_on_error.OptionWasSet()) 1560b57cec5SDimitry Andric options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue()); 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric // Individual silent setting is override for global command echo settings. 1590b57cec5SDimitry Andric if (m_options.m_silent_run.GetCurrentValue()) { 1600b57cec5SDimitry Andric options.SetSilent(true); 1610b57cec5SDimitry Andric } else { 1620b57cec5SDimitry Andric options.SetPrintResults(true); 1630b57cec5SDimitry Andric options.SetPrintErrors(true); 1640b57cec5SDimitry Andric options.SetEchoCommands(m_interpreter.GetEchoCommands()); 1650b57cec5SDimitry Andric options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands()); 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric } 168fe6060f1SDimitry Andric 169fe6060f1SDimitry Andric m_interpreter.HandleCommandsFromFile(cmd_file, options, result); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric CommandOptions m_options; 1730b57cec5SDimitry Andric }; 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric #pragma mark CommandObjectCommandsAlias 1760b57cec5SDimitry Andric // CommandObjectCommandsAlias 1770b57cec5SDimitry Andric 1789dba64beSDimitry Andric #define LLDB_OPTIONS_alias 1799dba64beSDimitry Andric #include "CommandOptions.inc" 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric static const char *g_python_command_instructions = 1820b57cec5SDimitry Andric "Enter your Python command(s). Type 'DONE' to end.\n" 1830b57cec5SDimitry Andric "You must define a Python function with this signature:\n" 184bdd1243dSDimitry Andric "def my_command_impl(debugger, args, exe_ctx, result, internal_dict):\n"; 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric class CommandObjectCommandsAlias : public CommandObjectRaw { 1870b57cec5SDimitry Andric protected: 1880b57cec5SDimitry Andric class CommandOptions : public OptionGroup { 1890b57cec5SDimitry Andric public: 19081ad6265SDimitry Andric CommandOptions() = default; 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric ~CommandOptions() override = default; 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 195bdd1243dSDimitry Andric return llvm::ArrayRef(g_alias_options); 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, 1990b57cec5SDimitry Andric ExecutionContext *execution_context) override { 2000b57cec5SDimitry Andric Status error; 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option; 2030b57cec5SDimitry Andric std::string option_str(option_value); 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric switch (short_option) { 2060b57cec5SDimitry Andric case 'h': 2070b57cec5SDimitry Andric m_help.SetCurrentValue(option_str); 2080b57cec5SDimitry Andric m_help.SetOptionWasSet(); 2090b57cec5SDimitry Andric break; 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric case 'H': 2120b57cec5SDimitry Andric m_long_help.SetCurrentValue(option_str); 2130b57cec5SDimitry Andric m_long_help.SetOptionWasSet(); 2140b57cec5SDimitry Andric break; 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric default: 2179dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric return error; 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 2240b57cec5SDimitry Andric m_help.Clear(); 2250b57cec5SDimitry Andric m_long_help.Clear(); 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric OptionValueString m_help; 2290b57cec5SDimitry Andric OptionValueString m_long_help; 2300b57cec5SDimitry Andric }; 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric OptionGroupOptions m_option_group; 2330b57cec5SDimitry Andric CommandOptions m_command_options; 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric public: 2360b57cec5SDimitry Andric Options *GetOptions() override { return &m_option_group; } 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric CommandObjectCommandsAlias(CommandInterpreter &interpreter) 2390b57cec5SDimitry Andric : CommandObjectRaw( 2400b57cec5SDimitry Andric interpreter, "command alias", 24104eeddc0SDimitry Andric "Define a custom command in terms of an existing command.") { 2420b57cec5SDimitry Andric m_option_group.Append(&m_command_options); 2430b57cec5SDimitry Andric m_option_group.Finalize(); 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric SetHelpLong( 2460b57cec5SDimitry Andric "'alias' allows the user to create a short-cut or abbreviation for long \ 2470b57cec5SDimitry Andric commands, multi-word commands, and commands that take particular options. \ 2480b57cec5SDimitry Andric Below are some simple examples of how one might use the 'alias' command:" 2490b57cec5SDimitry Andric R"( 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric (lldb) command alias sc script 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric Creates the abbreviation 'sc' for the 'script' command. 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric (lldb) command alias bp breakpoint 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric )" 2580b57cec5SDimitry Andric " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \ 2590b57cec5SDimitry Andric breakpoint commands are two-word commands, the user would still need to \ 2600b57cec5SDimitry Andric enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." 2610b57cec5SDimitry Andric R"( 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric (lldb) command alias bpl breakpoint list 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'. 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric )" 2680b57cec5SDimitry Andric "An alias can include some options for the command, with the values either \ 2690b57cec5SDimitry Andric filled in at the time the alias is created, or specified as positional \ 2700b57cec5SDimitry Andric arguments, to be filled in when the alias is invoked. The following example \ 2710b57cec5SDimitry Andric shows how to create aliases with options:" 2720b57cec5SDimitry Andric R"( 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric (lldb) command alias bfl breakpoint set -f %1 -l %2 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric )" 2770b57cec5SDimitry Andric " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \ 2780b57cec5SDimitry Andric options already part of the alias. So if the user wants to set a breakpoint \ 2790b57cec5SDimitry Andric by file and line without explicitly having to use the -f and -l options, the \ 2800b57cec5SDimitry Andric user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \ 2810b57cec5SDimitry Andric for the actual arguments that will be passed when the alias command is used. \ 2820b57cec5SDimitry Andric The number in the placeholder refers to the position/order the actual value \ 2830b57cec5SDimitry Andric occupies when the alias is used. All the occurrences of '%1' in the alias \ 2840b57cec5SDimitry Andric will be replaced with the first argument, all the occurrences of '%2' in the \ 2850b57cec5SDimitry Andric alias will be replaced with the second argument, and so on. This also allows \ 2860b57cec5SDimitry Andric actual arguments to be used multiple times within an alias (see 'process \ 2870b57cec5SDimitry Andric launch' example below)." 2880b57cec5SDimitry Andric R"( 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric )" 2910b57cec5SDimitry Andric "Note: the positional arguments must substitute as whole words in the resultant \ 2920b57cec5SDimitry Andric command, so you can't at present do something like this to append the file extension \ 2930b57cec5SDimitry Andric \".cpp\":" 2940b57cec5SDimitry Andric R"( 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric )" 2990b57cec5SDimitry Andric "For more complex aliasing, use the \"command regex\" command instead. In the \ 3000b57cec5SDimitry Andric 'bfl' case above, the actual file value will be filled in with the first argument \ 3010b57cec5SDimitry Andric following 'bfl' and the actual line number value will be filled in with the second \ 3020b57cec5SDimitry Andric argument. The user would use this alias as follows:" 3030b57cec5SDimitry Andric R"( 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric (lldb) command alias bfl breakpoint set -f %1 -l %2 3060b57cec5SDimitry Andric (lldb) bfl my-file.c 137 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'. 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric Another example: 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric (lldb) command alias pltty process launch -s -o %1 -e %1 3130b57cec5SDimitry Andric (lldb) pltty /dev/tty0 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0' 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric )" 3180b57cec5SDimitry Andric "If the user always wanted to pass the same value to a particular option, the \ 3190b57cec5SDimitry Andric alias could be defined with that value directly in the alias as a constant, \ 3200b57cec5SDimitry Andric rather than using a positional placeholder:" 3210b57cec5SDimitry Andric R"( 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric (lldb) command alias bl3 breakpoint set -f %1 -l 3 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric Always sets a breakpoint on line 3 of whatever file is indicated.)"); 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric CommandArgumentEntry arg1; 3280b57cec5SDimitry Andric CommandArgumentEntry arg2; 3290b57cec5SDimitry Andric CommandArgumentEntry arg3; 3300b57cec5SDimitry Andric CommandArgumentData alias_arg; 3310b57cec5SDimitry Andric CommandArgumentData cmd_arg; 3320b57cec5SDimitry Andric CommandArgumentData options_arg; 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 3350b57cec5SDimitry Andric alias_arg.arg_type = eArgTypeAliasName; 3360b57cec5SDimitry Andric alias_arg.arg_repetition = eArgRepeatPlain; 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 3390b57cec5SDimitry Andric // argument entry. 3400b57cec5SDimitry Andric arg1.push_back(alias_arg); 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 3430b57cec5SDimitry Andric cmd_arg.arg_type = eArgTypeCommandName; 3440b57cec5SDimitry Andric cmd_arg.arg_repetition = eArgRepeatPlain; 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 3470b57cec5SDimitry Andric // argument entry. 3480b57cec5SDimitry Andric arg2.push_back(cmd_arg); 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 3510b57cec5SDimitry Andric options_arg.arg_type = eArgTypeAliasOptions; 3520b57cec5SDimitry Andric options_arg.arg_repetition = eArgRepeatOptional; 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 3550b57cec5SDimitry Andric // argument entry. 3560b57cec5SDimitry Andric arg3.push_back(options_arg); 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 3590b57cec5SDimitry Andric m_arguments.push_back(arg1); 3600b57cec5SDimitry Andric m_arguments.push_back(arg2); 3610b57cec5SDimitry Andric m_arguments.push_back(arg3); 3620b57cec5SDimitry Andric } 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric ~CommandObjectCommandsAlias() override = default; 3650b57cec5SDimitry Andric 3660b57cec5SDimitry Andric protected: 3675f757f3fSDimitry Andric void DoExecute(llvm::StringRef raw_command_line, 3680b57cec5SDimitry Andric CommandReturnObject &result) override { 3690b57cec5SDimitry Andric if (raw_command_line.empty()) { 3700b57cec5SDimitry Andric result.AppendError("'command alias' requires at least two arguments"); 3715f757f3fSDimitry Andric return; 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext(); 3750b57cec5SDimitry Andric m_option_group.NotifyOptionParsingStarting(&exe_ctx); 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric OptionsWithRaw args_with_suffix(raw_command_line); 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric if (args_with_suffix.HasArgs()) 3800b57cec5SDimitry Andric if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result, 3810b57cec5SDimitry Andric m_option_group, exe_ctx)) 3825f757f3fSDimitry Andric return; 3830b57cec5SDimitry Andric 3845ffd83dbSDimitry Andric llvm::StringRef raw_command_string = args_with_suffix.GetRawPart(); 3850b57cec5SDimitry Andric Args args(raw_command_string); 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric if (args.GetArgumentCount() < 2) { 3880b57cec5SDimitry Andric result.AppendError("'command alias' requires at least two arguments"); 3895f757f3fSDimitry Andric return; 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric // Get the alias command. 3930b57cec5SDimitry Andric 3949dba64beSDimitry Andric auto alias_command = args[0].ref(); 3955f757f3fSDimitry Andric if (alias_command.starts_with("-")) { 3960b57cec5SDimitry Andric result.AppendError("aliases starting with a dash are not supported"); 3970b57cec5SDimitry Andric if (alias_command == "--help" || alias_command == "--long-help") { 3980b57cec5SDimitry Andric result.AppendWarning("if trying to pass options to 'command alias' add " 3990b57cec5SDimitry Andric "a -- at the end of the options"); 4000b57cec5SDimitry Andric } 4015f757f3fSDimitry Andric return; 4020b57cec5SDimitry Andric } 4030b57cec5SDimitry Andric 4040b57cec5SDimitry Andric // Strip the new alias name off 'raw_command_string' (leave it on args, 4050b57cec5SDimitry Andric // which gets passed to 'Execute', which does the stripping itself. 4060b57cec5SDimitry Andric size_t pos = raw_command_string.find(alias_command); 4070b57cec5SDimitry Andric if (pos == 0) { 4080b57cec5SDimitry Andric raw_command_string = raw_command_string.substr(alias_command.size()); 4090b57cec5SDimitry Andric pos = raw_command_string.find_first_not_of(' '); 4100b57cec5SDimitry Andric if ((pos != std::string::npos) && (pos > 0)) 4110b57cec5SDimitry Andric raw_command_string = raw_command_string.substr(pos); 4120b57cec5SDimitry Andric } else { 4130b57cec5SDimitry Andric result.AppendError("Error parsing command string. No alias created."); 4145f757f3fSDimitry Andric return; 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric // Verify that the command is alias-able. 4180b57cec5SDimitry Andric if (m_interpreter.CommandExists(alias_command)) { 4190b57cec5SDimitry Andric result.AppendErrorWithFormat( 4200b57cec5SDimitry Andric "'%s' is a permanent debugger command and cannot be redefined.\n", 4210b57cec5SDimitry Andric args[0].c_str()); 4225f757f3fSDimitry Andric return; 4230b57cec5SDimitry Andric } 4240b57cec5SDimitry Andric 425349cc55cSDimitry Andric if (m_interpreter.UserMultiwordCommandExists(alias_command)) { 426349cc55cSDimitry Andric result.AppendErrorWithFormat( 427349cc55cSDimitry Andric "'%s' is a user container command and cannot be overwritten.\n" 428349cc55cSDimitry Andric "Delete it first with 'command container delete'\n", 429349cc55cSDimitry Andric args[0].c_str()); 4305f757f3fSDimitry Andric return; 431349cc55cSDimitry Andric } 432349cc55cSDimitry Andric 4330b57cec5SDimitry Andric // Get CommandObject that is being aliased. The command name is read from 4340b57cec5SDimitry Andric // the front of raw_command_string. raw_command_string is returned with the 4350b57cec5SDimitry Andric // name of the command object stripped off the front. 4360b57cec5SDimitry Andric llvm::StringRef original_raw_command_string = raw_command_string; 4370b57cec5SDimitry Andric CommandObject *cmd_obj = 4380b57cec5SDimitry Andric m_interpreter.GetCommandObjectForCommand(raw_command_string); 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric if (!cmd_obj) { 4410b57cec5SDimitry Andric result.AppendErrorWithFormat("invalid command given to 'command alias'. " 4420b57cec5SDimitry Andric "'%s' does not begin with a valid command." 4430b57cec5SDimitry Andric " No alias created.", 4440b57cec5SDimitry Andric original_raw_command_string.str().c_str()); 4450b57cec5SDimitry Andric } else if (!cmd_obj->WantsRawCommandString()) { 4460b57cec5SDimitry Andric // Note that args was initialized with the original command, and has not 4470b57cec5SDimitry Andric // been updated to this point. Therefore can we pass it to the version of 4480b57cec5SDimitry Andric // Execute that does not need/expect raw input in the alias. 4495f757f3fSDimitry Andric HandleAliasingNormalCommand(args, result); 4500b57cec5SDimitry Andric } else { 4515f757f3fSDimitry Andric HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj, 4525f757f3fSDimitry Andric result); 4530b57cec5SDimitry Andric } 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric bool HandleAliasingRawCommand(llvm::StringRef alias_command, 4570b57cec5SDimitry Andric llvm::StringRef raw_command_string, 4580b57cec5SDimitry Andric CommandObject &cmd_obj, 4590b57cec5SDimitry Andric CommandReturnObject &result) { 4600b57cec5SDimitry Andric // Verify & handle any options/arguments passed to the alias command 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric OptionArgVectorSP option_arg_vector_sp = 4630b57cec5SDimitry Andric OptionArgVectorSP(new OptionArgVector); 4640b57cec5SDimitry Andric 46504eeddc0SDimitry Andric const bool include_aliases = true; 466bdd1243dSDimitry Andric // Look up the command using command's name first. This is to resolve 467bdd1243dSDimitry Andric // aliases when you are making nested aliases. But if you don't find 468bdd1243dSDimitry Andric // it that way, then it wasn't an alias and we can just use the object 469bdd1243dSDimitry Andric // we were passed in. 470bdd1243dSDimitry Andric CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact( 471bdd1243dSDimitry Andric cmd_obj.GetCommandName(), include_aliases); 472bdd1243dSDimitry Andric if (!cmd_obj_sp) 473bdd1243dSDimitry Andric cmd_obj_sp = cmd_obj.shared_from_this(); 474bdd1243dSDimitry Andric 4750b57cec5SDimitry Andric if (m_interpreter.AliasExists(alias_command) || 4760b57cec5SDimitry Andric m_interpreter.UserCommandExists(alias_command)) { 4770b57cec5SDimitry Andric result.AppendWarningWithFormat( 4780b57cec5SDimitry Andric "Overwriting existing definition for '%s'.\n", 4790b57cec5SDimitry Andric alias_command.str().c_str()); 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric if (CommandAlias *alias = m_interpreter.AddAlias( 4820b57cec5SDimitry Andric alias_command, cmd_obj_sp, raw_command_string)) { 4830b57cec5SDimitry Andric if (m_command_options.m_help.OptionWasSet()) 4840b57cec5SDimitry Andric alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 4850b57cec5SDimitry Andric if (m_command_options.m_long_help.OptionWasSet()) 4860b57cec5SDimitry Andric alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 4870b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 4880b57cec5SDimitry Andric } else { 4890b57cec5SDimitry Andric result.AppendError("Unable to create requested alias.\n"); 4900b57cec5SDimitry Andric } 4910b57cec5SDimitry Andric return result.Succeeded(); 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) { 4950b57cec5SDimitry Andric size_t argc = args.GetArgumentCount(); 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric if (argc < 2) { 4980b57cec5SDimitry Andric result.AppendError("'command alias' requires at least two arguments"); 4990b57cec5SDimitry Andric return false; 5000b57cec5SDimitry Andric } 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric // Save these in std::strings since we're going to shift them off. 5035ffd83dbSDimitry Andric const std::string alias_command(std::string(args[0].ref())); 5045ffd83dbSDimitry Andric const std::string actual_command(std::string(args[1].ref())); 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric args.Shift(); // Shift the alias command word off the argument vector. 5070b57cec5SDimitry Andric args.Shift(); // Shift the old command word off the argument vector. 5080b57cec5SDimitry Andric 5090b57cec5SDimitry Andric // Verify that the command is alias'able, and get the appropriate command 5100b57cec5SDimitry Andric // object. 5110b57cec5SDimitry Andric 5120b57cec5SDimitry Andric if (m_interpreter.CommandExists(alias_command)) { 5130b57cec5SDimitry Andric result.AppendErrorWithFormat( 5140b57cec5SDimitry Andric "'%s' is a permanent debugger command and cannot be redefined.\n", 5150b57cec5SDimitry Andric alias_command.c_str()); 5160b57cec5SDimitry Andric return false; 5170b57cec5SDimitry Andric } 5180b57cec5SDimitry Andric 519349cc55cSDimitry Andric if (m_interpreter.UserMultiwordCommandExists(alias_command)) { 520349cc55cSDimitry Andric result.AppendErrorWithFormat( 521349cc55cSDimitry Andric "'%s' is user container command and cannot be overwritten.\n" 522349cc55cSDimitry Andric "Delete it first with 'command container delete'", 523349cc55cSDimitry Andric alias_command.c_str()); 524349cc55cSDimitry Andric return false; 525349cc55cSDimitry Andric } 526349cc55cSDimitry Andric 5270b57cec5SDimitry Andric CommandObjectSP command_obj_sp( 5280b57cec5SDimitry Andric m_interpreter.GetCommandSPExact(actual_command, true)); 5290b57cec5SDimitry Andric CommandObjectSP subcommand_obj_sp; 5300b57cec5SDimitry Andric bool use_subcommand = false; 5310b57cec5SDimitry Andric if (!command_obj_sp) { 5320b57cec5SDimitry Andric result.AppendErrorWithFormat("'%s' is not an existing command.\n", 5330b57cec5SDimitry Andric actual_command.c_str()); 5340b57cec5SDimitry Andric return false; 5350b57cec5SDimitry Andric } 5360b57cec5SDimitry Andric CommandObject *cmd_obj = command_obj_sp.get(); 5370b57cec5SDimitry Andric CommandObject *sub_cmd_obj = nullptr; 5380b57cec5SDimitry Andric OptionArgVectorSP option_arg_vector_sp = 5390b57cec5SDimitry Andric OptionArgVectorSP(new OptionArgVector); 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric while (cmd_obj->IsMultiwordObject() && !args.empty()) { 5429dba64beSDimitry Andric auto sub_command = args[0].ref(); 5430b57cec5SDimitry Andric assert(!sub_command.empty()); 5440b57cec5SDimitry Andric subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command); 5450b57cec5SDimitry Andric if (!subcommand_obj_sp) { 5460b57cec5SDimitry Andric result.AppendErrorWithFormat( 5470b57cec5SDimitry Andric "'%s' is not a valid sub-command of '%s'. " 5480b57cec5SDimitry Andric "Unable to create alias.\n", 5490b57cec5SDimitry Andric args[0].c_str(), actual_command.c_str()); 5500b57cec5SDimitry Andric return false; 5510b57cec5SDimitry Andric } 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric sub_cmd_obj = subcommand_obj_sp.get(); 5540b57cec5SDimitry Andric use_subcommand = true; 5550b57cec5SDimitry Andric args.Shift(); // Shift the sub_command word off the argument vector. 5560b57cec5SDimitry Andric cmd_obj = sub_cmd_obj; 5570b57cec5SDimitry Andric } 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric // Verify & handle any options/arguments passed to the alias command 5600b57cec5SDimitry Andric 5610b57cec5SDimitry Andric std::string args_string; 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric if (!args.empty()) { 5640b57cec5SDimitry Andric CommandObjectSP tmp_sp = 565e8d8bef9SDimitry Andric m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName()); 5660b57cec5SDimitry Andric if (use_subcommand) 567e8d8bef9SDimitry Andric tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName()); 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric args.GetCommandString(args_string); 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric if (m_interpreter.AliasExists(alias_command) || 5730b57cec5SDimitry Andric m_interpreter.UserCommandExists(alias_command)) { 5740b57cec5SDimitry Andric result.AppendWarningWithFormat( 5750b57cec5SDimitry Andric "Overwriting existing definition for '%s'.\n", alias_command.c_str()); 5760b57cec5SDimitry Andric } 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric if (CommandAlias *alias = m_interpreter.AddAlias( 5790b57cec5SDimitry Andric alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp, 5800b57cec5SDimitry Andric args_string)) { 5810b57cec5SDimitry Andric if (m_command_options.m_help.OptionWasSet()) 5820b57cec5SDimitry Andric alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 5830b57cec5SDimitry Andric if (m_command_options.m_long_help.OptionWasSet()) 5840b57cec5SDimitry Andric alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 5850b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 5860b57cec5SDimitry Andric } else { 5870b57cec5SDimitry Andric result.AppendError("Unable to create requested alias.\n"); 5880b57cec5SDimitry Andric return false; 5890b57cec5SDimitry Andric } 5900b57cec5SDimitry Andric 5910b57cec5SDimitry Andric return result.Succeeded(); 5920b57cec5SDimitry Andric } 5930b57cec5SDimitry Andric }; 5940b57cec5SDimitry Andric 5950b57cec5SDimitry Andric #pragma mark CommandObjectCommandsUnalias 5960b57cec5SDimitry Andric // CommandObjectCommandsUnalias 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric class CommandObjectCommandsUnalias : public CommandObjectParsed { 5990b57cec5SDimitry Andric public: 6000b57cec5SDimitry Andric CommandObjectCommandsUnalias(CommandInterpreter &interpreter) 6010b57cec5SDimitry Andric : CommandObjectParsed( 6020b57cec5SDimitry Andric interpreter, "command unalias", 6030b57cec5SDimitry Andric "Delete one or more custom commands defined by 'command alias'.", 6040b57cec5SDimitry Andric nullptr) { 605*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeAliasName); 6060b57cec5SDimitry Andric } 6070b57cec5SDimitry Andric 6080b57cec5SDimitry Andric ~CommandObjectCommandsUnalias() override = default; 6090b57cec5SDimitry Andric 610e8d8bef9SDimitry Andric void 611e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 612e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override { 613e8d8bef9SDimitry Andric if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 614e8d8bef9SDimitry Andric return; 615e8d8bef9SDimitry Andric 616e8d8bef9SDimitry Andric for (const auto &ent : m_interpreter.GetAliases()) { 617e8d8bef9SDimitry Andric request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 618e8d8bef9SDimitry Andric } 619e8d8bef9SDimitry Andric } 620e8d8bef9SDimitry Andric 6210b57cec5SDimitry Andric protected: 6225f757f3fSDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override { 6230b57cec5SDimitry Andric CommandObject::CommandMap::iterator pos; 6240b57cec5SDimitry Andric CommandObject *cmd_obj; 6250b57cec5SDimitry Andric 6260b57cec5SDimitry Andric if (args.empty()) { 6270b57cec5SDimitry Andric result.AppendError("must call 'unalias' with a valid alias"); 6285f757f3fSDimitry Andric return; 6290b57cec5SDimitry Andric } 6300b57cec5SDimitry Andric 6319dba64beSDimitry Andric auto command_name = args[0].ref(); 6320b57cec5SDimitry Andric cmd_obj = m_interpreter.GetCommandObject(command_name); 6330b57cec5SDimitry Andric if (!cmd_obj) { 6340b57cec5SDimitry Andric result.AppendErrorWithFormat( 6350b57cec5SDimitry Andric "'%s' is not a known command.\nTry 'help' to see a " 6360b57cec5SDimitry Andric "current list of commands.\n", 6370b57cec5SDimitry Andric args[0].c_str()); 6385f757f3fSDimitry Andric return; 6390b57cec5SDimitry Andric } 6400b57cec5SDimitry Andric 6410b57cec5SDimitry Andric if (m_interpreter.CommandExists(command_name)) { 6420b57cec5SDimitry Andric if (cmd_obj->IsRemovable()) { 6430b57cec5SDimitry Andric result.AppendErrorWithFormat( 6440b57cec5SDimitry Andric "'%s' is not an alias, it is a debugger command which can be " 6450b57cec5SDimitry Andric "removed using the 'command delete' command.\n", 6460b57cec5SDimitry Andric args[0].c_str()); 6470b57cec5SDimitry Andric } else { 6480b57cec5SDimitry Andric result.AppendErrorWithFormat( 6490b57cec5SDimitry Andric "'%s' is a permanent debugger command and cannot be removed.\n", 6500b57cec5SDimitry Andric args[0].c_str()); 6510b57cec5SDimitry Andric } 6525f757f3fSDimitry Andric return; 6530b57cec5SDimitry Andric } 6540b57cec5SDimitry Andric 6550b57cec5SDimitry Andric if (!m_interpreter.RemoveAlias(command_name)) { 6560b57cec5SDimitry Andric if (m_interpreter.AliasExists(command_name)) 6570b57cec5SDimitry Andric result.AppendErrorWithFormat( 6580b57cec5SDimitry Andric "Error occurred while attempting to unalias '%s'.\n", 6590b57cec5SDimitry Andric args[0].c_str()); 6600b57cec5SDimitry Andric else 6610b57cec5SDimitry Andric result.AppendErrorWithFormat("'%s' is not an existing alias.\n", 6620b57cec5SDimitry Andric args[0].c_str()); 6635f757f3fSDimitry Andric return; 6640b57cec5SDimitry Andric } 6650b57cec5SDimitry Andric 6660b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 6670b57cec5SDimitry Andric } 6680b57cec5SDimitry Andric }; 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric #pragma mark CommandObjectCommandsDelete 6710b57cec5SDimitry Andric // CommandObjectCommandsDelete 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric class CommandObjectCommandsDelete : public CommandObjectParsed { 6740b57cec5SDimitry Andric public: 6750b57cec5SDimitry Andric CommandObjectCommandsDelete(CommandInterpreter &interpreter) 6760b57cec5SDimitry Andric : CommandObjectParsed( 6770b57cec5SDimitry Andric interpreter, "command delete", 6780b57cec5SDimitry Andric "Delete one or more custom commands defined by 'command regex'.", 6790b57cec5SDimitry Andric nullptr) { 680*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeCommandName); 6810b57cec5SDimitry Andric } 6820b57cec5SDimitry Andric 6830b57cec5SDimitry Andric ~CommandObjectCommandsDelete() override = default; 6840b57cec5SDimitry Andric 685e8d8bef9SDimitry Andric void 686e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 687e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override { 688e8d8bef9SDimitry Andric if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 689e8d8bef9SDimitry Andric return; 690e8d8bef9SDimitry Andric 691e8d8bef9SDimitry Andric for (const auto &ent : m_interpreter.GetCommands()) { 692e8d8bef9SDimitry Andric if (ent.second->IsRemovable()) 693e8d8bef9SDimitry Andric request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 694e8d8bef9SDimitry Andric } 695e8d8bef9SDimitry Andric } 696e8d8bef9SDimitry Andric 6970b57cec5SDimitry Andric protected: 6985f757f3fSDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override { 6990b57cec5SDimitry Andric CommandObject::CommandMap::iterator pos; 7000b57cec5SDimitry Andric 7010b57cec5SDimitry Andric if (args.empty()) { 7020b57cec5SDimitry Andric result.AppendErrorWithFormat("must call '%s' with one or more valid user " 7030b57cec5SDimitry Andric "defined regular expression command names", 7040b57cec5SDimitry Andric GetCommandName().str().c_str()); 7055f757f3fSDimitry Andric return; 7060b57cec5SDimitry Andric } 7070b57cec5SDimitry Andric 7089dba64beSDimitry Andric auto command_name = args[0].ref(); 7090b57cec5SDimitry Andric if (!m_interpreter.CommandExists(command_name)) { 7100b57cec5SDimitry Andric StreamString error_msg_stream; 7110b57cec5SDimitry Andric const bool generate_upropos = true; 7120b57cec5SDimitry Andric const bool generate_type_lookup = false; 7130b57cec5SDimitry Andric CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage( 7140b57cec5SDimitry Andric &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(), 7150b57cec5SDimitry Andric generate_upropos, generate_type_lookup); 7160b57cec5SDimitry Andric result.AppendError(error_msg_stream.GetString()); 7175f757f3fSDimitry Andric return; 7180b57cec5SDimitry Andric } 7190b57cec5SDimitry Andric 7200b57cec5SDimitry Andric if (!m_interpreter.RemoveCommand(command_name)) { 7210b57cec5SDimitry Andric result.AppendErrorWithFormat( 7220b57cec5SDimitry Andric "'%s' is a permanent debugger command and cannot be removed.\n", 7230b57cec5SDimitry Andric args[0].c_str()); 7245f757f3fSDimitry Andric return; 7250b57cec5SDimitry Andric } 7260b57cec5SDimitry Andric 7270b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 7280b57cec5SDimitry Andric } 7290b57cec5SDimitry Andric }; 7300b57cec5SDimitry Andric 7310b57cec5SDimitry Andric // CommandObjectCommandsAddRegex 7320b57cec5SDimitry Andric 7339dba64beSDimitry Andric #define LLDB_OPTIONS_regex 7349dba64beSDimitry Andric #include "CommandOptions.inc" 7350b57cec5SDimitry Andric 7360b57cec5SDimitry Andric #pragma mark CommandObjectCommandsAddRegex 7370b57cec5SDimitry Andric 7380b57cec5SDimitry Andric class CommandObjectCommandsAddRegex : public CommandObjectParsed, 7390b57cec5SDimitry Andric public IOHandlerDelegateMultiline { 7400b57cec5SDimitry Andric public: 7410b57cec5SDimitry Andric CommandObjectCommandsAddRegex(CommandInterpreter &interpreter) 7420b57cec5SDimitry Andric : CommandObjectParsed( 743480093f4SDimitry Andric interpreter, "command regex", 744480093f4SDimitry Andric "Define a custom command in terms of " 7450b57cec5SDimitry Andric "existing commands by matching " 7460b57cec5SDimitry Andric "regular expressions.", 7470b57cec5SDimitry Andric "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 7480b57cec5SDimitry Andric IOHandlerDelegateMultiline("", 74904eeddc0SDimitry Andric IOHandlerDelegate::Completion::LLDBCommand) { 7500b57cec5SDimitry Andric SetHelpLong( 7510b57cec5SDimitry Andric R"( 7520b57cec5SDimitry Andric )" 7530b57cec5SDimitry Andric "This command allows the user to create powerful regular expression commands \ 7540b57cec5SDimitry Andric with substitutions. The regular expressions and substitutions are specified \ 7550b57cec5SDimitry Andric using the regular expression substitution format of:" 7560b57cec5SDimitry Andric R"( 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric s/<regex>/<subst>/ 7590b57cec5SDimitry Andric 7600b57cec5SDimitry Andric )" 7610b57cec5SDimitry Andric "<regex> is a regular expression that can use parenthesis to capture regular \ 7620b57cec5SDimitry Andric expression input and substitute the captured matches in the output using %1 \ 7630b57cec5SDimitry Andric for the first match, %2 for the second, and so on." 7640b57cec5SDimitry Andric R"( 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric )" 7670b57cec5SDimitry Andric "The regular expressions can all be specified on the command line if more than \ 7680b57cec5SDimitry Andric one argument is provided. If just the command name is provided on the command \ 7690b57cec5SDimitry Andric line, then the regular expressions and substitutions can be entered on separate \ 7700b57cec5SDimitry Andric lines, followed by an empty line to terminate the command definition." 7710b57cec5SDimitry Andric R"( 7720b57cec5SDimitry Andric 7730b57cec5SDimitry Andric EXAMPLES 7740b57cec5SDimitry Andric 7750b57cec5SDimitry Andric )" 7760b57cec5SDimitry Andric "The following example will define a regular expression command named 'f' that \ 7770b57cec5SDimitry Andric will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ 7780b57cec5SDimitry Andric a number follows 'f':" 7790b57cec5SDimitry Andric R"( 7800b57cec5SDimitry Andric 7810b57cec5SDimitry Andric (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"); 782*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeSEDStylePair, eArgRepeatOptional); 7830b57cec5SDimitry Andric } 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric ~CommandObjectCommandsAddRegex() override = default; 7860b57cec5SDimitry Andric 7870b57cec5SDimitry Andric protected: 7880b57cec5SDimitry Andric void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 7899dba64beSDimitry Andric StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 7900b57cec5SDimitry Andric if (output_sp && interactive) { 7910b57cec5SDimitry Andric output_sp->PutCString("Enter one or more sed substitution commands in " 7920b57cec5SDimitry Andric "the form: 's/<regex>/<subst>/'.\nTerminate the " 7930b57cec5SDimitry Andric "substitution list with an empty line.\n"); 7940b57cec5SDimitry Andric output_sp->Flush(); 7950b57cec5SDimitry Andric } 7960b57cec5SDimitry Andric } 7970b57cec5SDimitry Andric 7980b57cec5SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler, 7990b57cec5SDimitry Andric std::string &data) override { 8000b57cec5SDimitry Andric io_handler.SetIsDone(true); 8010b57cec5SDimitry Andric if (m_regex_cmd_up) { 8020b57cec5SDimitry Andric StringList lines; 8030b57cec5SDimitry Andric if (lines.SplitIntoLines(data)) { 8040b57cec5SDimitry Andric bool check_only = false; 8059dba64beSDimitry Andric for (const std::string &line : lines) { 8069dba64beSDimitry Andric Status error = AppendRegexSubstitution(line, check_only); 8070b57cec5SDimitry Andric if (error.Fail()) { 8080b57cec5SDimitry Andric if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) { 8090b57cec5SDimitry Andric StreamSP out_stream = GetDebugger().GetAsyncOutputStream(); 8100b57cec5SDimitry Andric out_stream->Printf("error: %s\n", error.AsCString()); 8110b57cec5SDimitry Andric } 8120b57cec5SDimitry Andric } 8130b57cec5SDimitry Andric } 8140b57cec5SDimitry Andric } 8150b57cec5SDimitry Andric if (m_regex_cmd_up->HasRegexEntries()) { 8160b57cec5SDimitry Andric CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 8170b57cec5SDimitry Andric m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 8180b57cec5SDimitry Andric } 8190b57cec5SDimitry Andric } 8200b57cec5SDimitry Andric } 8210b57cec5SDimitry Andric 8225f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 8230b57cec5SDimitry Andric const size_t argc = command.GetArgumentCount(); 8240b57cec5SDimitry Andric if (argc == 0) { 8250b57cec5SDimitry Andric result.AppendError("usage: 'command regex <command-name> " 8260b57cec5SDimitry Andric "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 8275f757f3fSDimitry Andric return; 8280b57cec5SDimitry Andric } 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andric Status error; 8319dba64beSDimitry Andric auto name = command[0].ref(); 8329dba64beSDimitry Andric m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>( 83306c3fb27SDimitry Andric m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 0, 8340b57cec5SDimitry Andric true); 8350b57cec5SDimitry Andric 8360b57cec5SDimitry Andric if (argc == 1) { 8370b57cec5SDimitry Andric Debugger &debugger = GetDebugger(); 8380b57cec5SDimitry Andric bool color_prompt = debugger.GetUseColor(); 8390b57cec5SDimitry Andric const bool multiple_lines = true; // Get multiple lines 8400b57cec5SDimitry Andric IOHandlerSP io_handler_sp(new IOHandlerEditline( 8410b57cec5SDimitry Andric debugger, IOHandler::Type::Other, 8420b57cec5SDimitry Andric "lldb-regex", // Name of input reader for history 8430b57cec5SDimitry Andric llvm::StringRef("> "), // Prompt 8440b57cec5SDimitry Andric llvm::StringRef(), // Continuation prompt 8450b57cec5SDimitry Andric multiple_lines, color_prompt, 8460b57cec5SDimitry Andric 0, // Don't show line numbers 847bdd1243dSDimitry Andric *this)); 8480b57cec5SDimitry Andric 8490b57cec5SDimitry Andric if (io_handler_sp) { 8505ffd83dbSDimitry Andric debugger.RunIOHandlerAsync(io_handler_sp); 8510b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 8520b57cec5SDimitry Andric } 8530b57cec5SDimitry Andric } else { 8540b57cec5SDimitry Andric for (auto &entry : command.entries().drop_front()) { 8550b57cec5SDimitry Andric bool check_only = false; 8569dba64beSDimitry Andric error = AppendRegexSubstitution(entry.ref(), check_only); 8570b57cec5SDimitry Andric if (error.Fail()) 8580b57cec5SDimitry Andric break; 8590b57cec5SDimitry Andric } 8600b57cec5SDimitry Andric 8610b57cec5SDimitry Andric if (error.Success()) { 8620b57cec5SDimitry Andric AddRegexCommandToInterpreter(); 8630b57cec5SDimitry Andric } 8640b57cec5SDimitry Andric } 8650b57cec5SDimitry Andric if (error.Fail()) { 8660b57cec5SDimitry Andric result.AppendError(error.AsCString()); 8670b57cec5SDimitry Andric } 8680b57cec5SDimitry Andric } 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed, 8710b57cec5SDimitry Andric bool check_only) { 8720b57cec5SDimitry Andric Status error; 8730b57cec5SDimitry Andric 8740b57cec5SDimitry Andric if (!m_regex_cmd_up) { 8750b57cec5SDimitry Andric error.SetErrorStringWithFormat( 8760b57cec5SDimitry Andric "invalid regular expression command object for: '%.*s'", 8770b57cec5SDimitry Andric (int)regex_sed.size(), regex_sed.data()); 8780b57cec5SDimitry Andric return error; 8790b57cec5SDimitry Andric } 8800b57cec5SDimitry Andric 8810b57cec5SDimitry Andric size_t regex_sed_size = regex_sed.size(); 8820b57cec5SDimitry Andric 8830b57cec5SDimitry Andric if (regex_sed_size <= 1) { 8840b57cec5SDimitry Andric error.SetErrorStringWithFormat( 8850b57cec5SDimitry Andric "regular expression substitution string is too short: '%.*s'", 8860b57cec5SDimitry Andric (int)regex_sed.size(), regex_sed.data()); 8870b57cec5SDimitry Andric return error; 8880b57cec5SDimitry Andric } 8890b57cec5SDimitry Andric 8900b57cec5SDimitry Andric if (regex_sed[0] != 's') { 8910b57cec5SDimitry Andric error.SetErrorStringWithFormat("regular expression substitution string " 8920b57cec5SDimitry Andric "doesn't start with 's': '%.*s'", 8930b57cec5SDimitry Andric (int)regex_sed.size(), regex_sed.data()); 8940b57cec5SDimitry Andric return error; 8950b57cec5SDimitry Andric } 8960b57cec5SDimitry Andric const size_t first_separator_char_pos = 1; 8970b57cec5SDimitry Andric // use the char that follows 's' as the regex separator character so we can 8980b57cec5SDimitry Andric // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 8990b57cec5SDimitry Andric const char separator_char = regex_sed[first_separator_char_pos]; 9000b57cec5SDimitry Andric const size_t second_separator_char_pos = 9010b57cec5SDimitry Andric regex_sed.find(separator_char, first_separator_char_pos + 1); 9020b57cec5SDimitry Andric 9030b57cec5SDimitry Andric if (second_separator_char_pos == std::string::npos) { 9040b57cec5SDimitry Andric error.SetErrorStringWithFormat( 9050b57cec5SDimitry Andric "missing second '%c' separator char after '%.*s' in '%.*s'", 9060b57cec5SDimitry Andric separator_char, 9070b57cec5SDimitry Andric (int)(regex_sed.size() - first_separator_char_pos - 1), 9080b57cec5SDimitry Andric regex_sed.data() + (first_separator_char_pos + 1), 9090b57cec5SDimitry Andric (int)regex_sed.size(), regex_sed.data()); 9100b57cec5SDimitry Andric return error; 9110b57cec5SDimitry Andric } 9120b57cec5SDimitry Andric 9130b57cec5SDimitry Andric const size_t third_separator_char_pos = 9140b57cec5SDimitry Andric regex_sed.find(separator_char, second_separator_char_pos + 1); 9150b57cec5SDimitry Andric 9160b57cec5SDimitry Andric if (third_separator_char_pos == std::string::npos) { 9170b57cec5SDimitry Andric error.SetErrorStringWithFormat( 9180b57cec5SDimitry Andric "missing third '%c' separator char after '%.*s' in '%.*s'", 9190b57cec5SDimitry Andric separator_char, 9200b57cec5SDimitry Andric (int)(regex_sed.size() - second_separator_char_pos - 1), 9210b57cec5SDimitry Andric regex_sed.data() + (second_separator_char_pos + 1), 9220b57cec5SDimitry Andric (int)regex_sed.size(), regex_sed.data()); 9230b57cec5SDimitry Andric return error; 9240b57cec5SDimitry Andric } 9250b57cec5SDimitry Andric 9260b57cec5SDimitry Andric if (third_separator_char_pos != regex_sed_size - 1) { 9270b57cec5SDimitry Andric // Make sure that everything that follows the last regex separator char 9280b57cec5SDimitry Andric if (regex_sed.find_first_not_of("\t\n\v\f\r ", 9290b57cec5SDimitry Andric third_separator_char_pos + 1) != 9300b57cec5SDimitry Andric std::string::npos) { 9310b57cec5SDimitry Andric error.SetErrorStringWithFormat( 9320b57cec5SDimitry Andric "extra data found after the '%.*s' regular expression substitution " 9330b57cec5SDimitry Andric "string: '%.*s'", 9340b57cec5SDimitry Andric (int)third_separator_char_pos + 1, regex_sed.data(), 9350b57cec5SDimitry Andric (int)(regex_sed.size() - third_separator_char_pos - 1), 9360b57cec5SDimitry Andric regex_sed.data() + (third_separator_char_pos + 1)); 9370b57cec5SDimitry Andric return error; 9380b57cec5SDimitry Andric } 9390b57cec5SDimitry Andric } else if (first_separator_char_pos + 1 == second_separator_char_pos) { 9400b57cec5SDimitry Andric error.SetErrorStringWithFormat( 9410b57cec5SDimitry Andric "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 9420b57cec5SDimitry Andric separator_char, separator_char, separator_char, (int)regex_sed.size(), 9430b57cec5SDimitry Andric regex_sed.data()); 9440b57cec5SDimitry Andric return error; 9450b57cec5SDimitry Andric } else if (second_separator_char_pos + 1 == third_separator_char_pos) { 9460b57cec5SDimitry Andric error.SetErrorStringWithFormat( 9470b57cec5SDimitry Andric "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 9480b57cec5SDimitry Andric separator_char, separator_char, separator_char, (int)regex_sed.size(), 9490b57cec5SDimitry Andric regex_sed.data()); 9500b57cec5SDimitry Andric return error; 9510b57cec5SDimitry Andric } 9520b57cec5SDimitry Andric 9530b57cec5SDimitry Andric if (!check_only) { 9545ffd83dbSDimitry Andric std::string regex(std::string(regex_sed.substr( 9555ffd83dbSDimitry Andric first_separator_char_pos + 1, 9565ffd83dbSDimitry Andric second_separator_char_pos - first_separator_char_pos - 1))); 9575ffd83dbSDimitry Andric std::string subst(std::string(regex_sed.substr( 9585ffd83dbSDimitry Andric second_separator_char_pos + 1, 9595ffd83dbSDimitry Andric third_separator_char_pos - second_separator_char_pos - 1))); 960e8d8bef9SDimitry Andric m_regex_cmd_up->AddRegexCommand(regex, subst); 9610b57cec5SDimitry Andric } 9620b57cec5SDimitry Andric return error; 9630b57cec5SDimitry Andric } 9640b57cec5SDimitry Andric 9650b57cec5SDimitry Andric void AddRegexCommandToInterpreter() { 9660b57cec5SDimitry Andric if (m_regex_cmd_up) { 9670b57cec5SDimitry Andric if (m_regex_cmd_up->HasRegexEntries()) { 9680b57cec5SDimitry Andric CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 9690b57cec5SDimitry Andric m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 9700b57cec5SDimitry Andric } 9710b57cec5SDimitry Andric } 9720b57cec5SDimitry Andric } 9730b57cec5SDimitry Andric 9740b57cec5SDimitry Andric private: 9750b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up; 9760b57cec5SDimitry Andric 9770b57cec5SDimitry Andric class CommandOptions : public Options { 9780b57cec5SDimitry Andric public: 97981ad6265SDimitry Andric CommandOptions() = default; 9800b57cec5SDimitry Andric 9810b57cec5SDimitry Andric ~CommandOptions() override = default; 9820b57cec5SDimitry Andric 9830b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 9840b57cec5SDimitry Andric ExecutionContext *execution_context) override { 9850b57cec5SDimitry Andric Status error; 9860b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 9870b57cec5SDimitry Andric 9880b57cec5SDimitry Andric switch (short_option) { 9890b57cec5SDimitry Andric case 'h': 9905ffd83dbSDimitry Andric m_help.assign(std::string(option_arg)); 9910b57cec5SDimitry Andric break; 9920b57cec5SDimitry Andric case 's': 9935ffd83dbSDimitry Andric m_syntax.assign(std::string(option_arg)); 9940b57cec5SDimitry Andric break; 9950b57cec5SDimitry Andric default: 9969dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 9970b57cec5SDimitry Andric } 9980b57cec5SDimitry Andric 9990b57cec5SDimitry Andric return error; 10000b57cec5SDimitry Andric } 10010b57cec5SDimitry Andric 10020b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 10030b57cec5SDimitry Andric m_help.clear(); 10040b57cec5SDimitry Andric m_syntax.clear(); 10050b57cec5SDimitry Andric } 10060b57cec5SDimitry Andric 10070b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1008bdd1243dSDimitry Andric return llvm::ArrayRef(g_regex_options); 10090b57cec5SDimitry Andric } 10100b57cec5SDimitry Andric 10115ffd83dbSDimitry Andric llvm::StringRef GetHelp() { return m_help; } 10120b57cec5SDimitry Andric 10135ffd83dbSDimitry Andric llvm::StringRef GetSyntax() { return m_syntax; } 10140b57cec5SDimitry Andric 10150b57cec5SDimitry Andric protected: 10160b57cec5SDimitry Andric // Instance variables to hold the values for command options. 10170b57cec5SDimitry Andric 10180b57cec5SDimitry Andric std::string m_help; 10190b57cec5SDimitry Andric std::string m_syntax; 10200b57cec5SDimitry Andric }; 10210b57cec5SDimitry Andric 10220b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 10230b57cec5SDimitry Andric 10240b57cec5SDimitry Andric CommandOptions m_options; 10250b57cec5SDimitry Andric }; 10260b57cec5SDimitry Andric 10270b57cec5SDimitry Andric class CommandObjectPythonFunction : public CommandObjectRaw { 10280b57cec5SDimitry Andric public: 10290b57cec5SDimitry Andric CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, 10300b57cec5SDimitry Andric std::string funct, std::string help, 103106c3fb27SDimitry Andric ScriptedCommandSynchronicity synch, 103206c3fb27SDimitry Andric CompletionType completion_type) 1033480093f4SDimitry Andric : CommandObjectRaw(interpreter, name), m_function_name(funct), 103406c3fb27SDimitry Andric m_synchro(synch), m_completion_type(completion_type) { 10350b57cec5SDimitry Andric if (!help.empty()) 10360b57cec5SDimitry Andric SetHelp(help); 10370b57cec5SDimitry Andric else { 10380b57cec5SDimitry Andric StreamString stream; 10390b57cec5SDimitry Andric stream.Printf("For more information run 'help %s'", name.c_str()); 10400b57cec5SDimitry Andric SetHelp(stream.GetString()); 10410b57cec5SDimitry Andric } 10420b57cec5SDimitry Andric } 10430b57cec5SDimitry Andric 10440b57cec5SDimitry Andric ~CommandObjectPythonFunction() override = default; 10450b57cec5SDimitry Andric 10460b57cec5SDimitry Andric bool IsRemovable() const override { return true; } 10470b57cec5SDimitry Andric 10480b57cec5SDimitry Andric const std::string &GetFunctionName() { return m_function_name; } 10490b57cec5SDimitry Andric 10500b57cec5SDimitry Andric ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 10510b57cec5SDimitry Andric 10520b57cec5SDimitry Andric llvm::StringRef GetHelpLong() override { 10530b57cec5SDimitry Andric if (m_fetched_help_long) 10540b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong(); 10550b57cec5SDimitry Andric 10560b57cec5SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 10570b57cec5SDimitry Andric if (!scripter) 10580b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong(); 10590b57cec5SDimitry Andric 10600b57cec5SDimitry Andric std::string docstring; 10610b57cec5SDimitry Andric m_fetched_help_long = 10620b57cec5SDimitry Andric scripter->GetDocumentationForItem(m_function_name.c_str(), docstring); 10630b57cec5SDimitry Andric if (!docstring.empty()) 10640b57cec5SDimitry Andric SetHelpLong(docstring); 10650b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong(); 10660b57cec5SDimitry Andric } 10670b57cec5SDimitry Andric 106806c3fb27SDimitry Andric void 106906c3fb27SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 107006c3fb27SDimitry Andric OptionElementVector &opt_element_vector) override { 107106c3fb27SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 107206c3fb27SDimitry Andric GetCommandInterpreter(), m_completion_type, request, nullptr); 107306c3fb27SDimitry Andric } 107406c3fb27SDimitry Andric 107506c3fb27SDimitry Andric bool WantsCompletion() override { return true; } 107606c3fb27SDimitry Andric 10770b57cec5SDimitry Andric protected: 10785f757f3fSDimitry Andric void DoExecute(llvm::StringRef raw_command_line, 10790b57cec5SDimitry Andric CommandReturnObject &result) override { 10800b57cec5SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 10810b57cec5SDimitry Andric 1082*0fca6ea1SDimitry Andric m_interpreter.IncreaseCommandUsage(*this); 1083*0fca6ea1SDimitry Andric 10840b57cec5SDimitry Andric Status error; 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric result.SetStatus(eReturnStatusInvalid); 10870b57cec5SDimitry Andric 1088480093f4SDimitry Andric if (!scripter || !scripter->RunScriptBasedCommand( 1089480093f4SDimitry Andric m_function_name.c_str(), raw_command_line, m_synchro, 1090480093f4SDimitry Andric result, error, m_exe_ctx)) { 10910b57cec5SDimitry Andric result.AppendError(error.AsCString()); 10920b57cec5SDimitry Andric } else { 10930b57cec5SDimitry Andric // Don't change the status if the command already set it... 10940b57cec5SDimitry Andric if (result.GetStatus() == eReturnStatusInvalid) { 10950b57cec5SDimitry Andric if (result.GetOutputData().empty()) 10960b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 10970b57cec5SDimitry Andric else 10980b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 10990b57cec5SDimitry Andric } 11000b57cec5SDimitry Andric } 11010b57cec5SDimitry Andric } 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric private: 11040b57cec5SDimitry Andric std::string m_function_name; 11050b57cec5SDimitry Andric ScriptedCommandSynchronicity m_synchro; 110681ad6265SDimitry Andric bool m_fetched_help_long = false; 110706c3fb27SDimitry Andric CompletionType m_completion_type = eNoCompletion; 11080b57cec5SDimitry Andric }; 11090b57cec5SDimitry Andric 1110*0fca6ea1SDimitry Andric /// This class implements a "raw" scripted command. lldb does no parsing of the 1111*0fca6ea1SDimitry Andric /// command line, instead passing the line unaltered (except for backtick 1112*0fca6ea1SDimitry Andric /// substitution). 1113*0fca6ea1SDimitry Andric class CommandObjectScriptingObjectRaw : public CommandObjectRaw { 11140b57cec5SDimitry Andric public: 1115*0fca6ea1SDimitry Andric CommandObjectScriptingObjectRaw(CommandInterpreter &interpreter, 11160b57cec5SDimitry Andric std::string name, 11170b57cec5SDimitry Andric StructuredData::GenericSP cmd_obj_sp, 111806c3fb27SDimitry Andric ScriptedCommandSynchronicity synch, 111906c3fb27SDimitry Andric CompletionType completion_type) 1120480093f4SDimitry Andric : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp), 1121480093f4SDimitry Andric m_synchro(synch), m_fetched_help_short(false), 112206c3fb27SDimitry Andric m_fetched_help_long(false), m_completion_type(completion_type) { 11230b57cec5SDimitry Andric StreamString stream; 11240b57cec5SDimitry Andric stream.Printf("For more information run 'help %s'", name.c_str()); 11250b57cec5SDimitry Andric SetHelp(stream.GetString()); 11260b57cec5SDimitry Andric if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter()) 11270b57cec5SDimitry Andric GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 11280b57cec5SDimitry Andric } 11290b57cec5SDimitry Andric 1130*0fca6ea1SDimitry Andric ~CommandObjectScriptingObjectRaw() override = default; 11310b57cec5SDimitry Andric 113206c3fb27SDimitry Andric void 113306c3fb27SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 113406c3fb27SDimitry Andric OptionElementVector &opt_element_vector) override { 113506c3fb27SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 113606c3fb27SDimitry Andric GetCommandInterpreter(), m_completion_type, request, nullptr); 113706c3fb27SDimitry Andric } 113806c3fb27SDimitry Andric 113906c3fb27SDimitry Andric bool WantsCompletion() override { return true; } 114006c3fb27SDimitry Andric 11410b57cec5SDimitry Andric bool IsRemovable() const override { return true; } 11420b57cec5SDimitry Andric 11430b57cec5SDimitry Andric ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 11440b57cec5SDimitry Andric 1145*0fca6ea1SDimitry Andric std::optional<std::string> GetRepeatCommand(Args &args, 1146*0fca6ea1SDimitry Andric uint32_t index) override { 1147*0fca6ea1SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1148*0fca6ea1SDimitry Andric if (!scripter) 1149*0fca6ea1SDimitry Andric return std::nullopt; 1150*0fca6ea1SDimitry Andric 1151*0fca6ea1SDimitry Andric return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args); 1152*0fca6ea1SDimitry Andric } 1153*0fca6ea1SDimitry Andric 11540b57cec5SDimitry Andric llvm::StringRef GetHelp() override { 11550b57cec5SDimitry Andric if (m_fetched_help_short) 11560b57cec5SDimitry Andric return CommandObjectRaw::GetHelp(); 11570b57cec5SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 11580b57cec5SDimitry Andric if (!scripter) 11590b57cec5SDimitry Andric return CommandObjectRaw::GetHelp(); 11600b57cec5SDimitry Andric std::string docstring; 11610b57cec5SDimitry Andric m_fetched_help_short = 11620b57cec5SDimitry Andric scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 11630b57cec5SDimitry Andric if (!docstring.empty()) 11640b57cec5SDimitry Andric SetHelp(docstring); 11650b57cec5SDimitry Andric 11660b57cec5SDimitry Andric return CommandObjectRaw::GetHelp(); 11670b57cec5SDimitry Andric } 11680b57cec5SDimitry Andric 11690b57cec5SDimitry Andric llvm::StringRef GetHelpLong() override { 11700b57cec5SDimitry Andric if (m_fetched_help_long) 11710b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong(); 11720b57cec5SDimitry Andric 11730b57cec5SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 11740b57cec5SDimitry Andric if (!scripter) 11750b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong(); 11760b57cec5SDimitry Andric 11770b57cec5SDimitry Andric std::string docstring; 11780b57cec5SDimitry Andric m_fetched_help_long = 11790b57cec5SDimitry Andric scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 11800b57cec5SDimitry Andric if (!docstring.empty()) 11810b57cec5SDimitry Andric SetHelpLong(docstring); 11820b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong(); 11830b57cec5SDimitry Andric } 11840b57cec5SDimitry Andric 11850b57cec5SDimitry Andric protected: 11865f757f3fSDimitry Andric void DoExecute(llvm::StringRef raw_command_line, 11870b57cec5SDimitry Andric CommandReturnObject &result) override { 11880b57cec5SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 11890b57cec5SDimitry Andric 11900b57cec5SDimitry Andric Status error; 11910b57cec5SDimitry Andric 11920b57cec5SDimitry Andric result.SetStatus(eReturnStatusInvalid); 11930b57cec5SDimitry Andric 11940b57cec5SDimitry Andric if (!scripter || 11950b57cec5SDimitry Andric !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 11960b57cec5SDimitry Andric m_synchro, result, error, m_exe_ctx)) { 11970b57cec5SDimitry Andric result.AppendError(error.AsCString()); 11980b57cec5SDimitry Andric } else { 11990b57cec5SDimitry Andric // Don't change the status if the command already set it... 12000b57cec5SDimitry Andric if (result.GetStatus() == eReturnStatusInvalid) { 12010b57cec5SDimitry Andric if (result.GetOutputData().empty()) 12020b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 12030b57cec5SDimitry Andric else 12040b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 12050b57cec5SDimitry Andric } 12060b57cec5SDimitry Andric } 12070b57cec5SDimitry Andric } 12080b57cec5SDimitry Andric 12090b57cec5SDimitry Andric private: 12100b57cec5SDimitry Andric StructuredData::GenericSP m_cmd_obj_sp; 12110b57cec5SDimitry Andric ScriptedCommandSynchronicity m_synchro; 12120b57cec5SDimitry Andric bool m_fetched_help_short : 1; 12130b57cec5SDimitry Andric bool m_fetched_help_long : 1; 121406c3fb27SDimitry Andric CompletionType m_completion_type = eNoCompletion; 12150b57cec5SDimitry Andric }; 12160b57cec5SDimitry Andric 1217*0fca6ea1SDimitry Andric 1218*0fca6ea1SDimitry Andric /// This command implements a lldb parsed scripted command. The command 1219*0fca6ea1SDimitry Andric /// provides a definition of the options and arguments, and a option value 1220*0fca6ea1SDimitry Andric /// setting callback, and then the command's execution function gets passed 1221*0fca6ea1SDimitry Andric /// just the parsed arguments. 1222*0fca6ea1SDimitry Andric /// Note, implementing a command in Python using these base interfaces is a bit 1223*0fca6ea1SDimitry Andric /// of a pain, but it is much easier to export this low level interface, and 1224*0fca6ea1SDimitry Andric /// then make it nicer on the Python side, than to try to do that in a 1225*0fca6ea1SDimitry Andric /// script language neutral way. 1226*0fca6ea1SDimitry Andric /// So I've also added a base class in Python that provides a table-driven 1227*0fca6ea1SDimitry Andric /// way of defining the options and arguments, which automatically fills the 1228*0fca6ea1SDimitry Andric /// option values, making them available as properties in Python. 1229*0fca6ea1SDimitry Andric /// 1230*0fca6ea1SDimitry Andric class CommandObjectScriptingObjectParsed : public CommandObjectParsed { 1231*0fca6ea1SDimitry Andric private: 1232*0fca6ea1SDimitry Andric class CommandOptions : public Options { 1233*0fca6ea1SDimitry Andric public: 1234*0fca6ea1SDimitry Andric CommandOptions(CommandInterpreter &interpreter, 1235*0fca6ea1SDimitry Andric StructuredData::GenericSP cmd_obj_sp) : m_interpreter(interpreter), 1236*0fca6ea1SDimitry Andric m_cmd_obj_sp(cmd_obj_sp) {} 1237*0fca6ea1SDimitry Andric 1238*0fca6ea1SDimitry Andric ~CommandOptions() override = default; 1239*0fca6ea1SDimitry Andric 1240*0fca6ea1SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1241*0fca6ea1SDimitry Andric ExecutionContext *execution_context) override { 1242*0fca6ea1SDimitry Andric Status error; 1243*0fca6ea1SDimitry Andric ScriptInterpreter *scripter = 1244*0fca6ea1SDimitry Andric m_interpreter.GetDebugger().GetScriptInterpreter(); 1245*0fca6ea1SDimitry Andric if (!scripter) { 1246*0fca6ea1SDimitry Andric error.SetErrorString("No script interpreter for SetOptionValue."); 1247*0fca6ea1SDimitry Andric return error; 1248*0fca6ea1SDimitry Andric } 1249*0fca6ea1SDimitry Andric if (!m_cmd_obj_sp) { 1250*0fca6ea1SDimitry Andric error.SetErrorString("SetOptionValue called with empty cmd_obj."); 1251*0fca6ea1SDimitry Andric return error; 1252*0fca6ea1SDimitry Andric } 1253*0fca6ea1SDimitry Andric if (!m_options_definition_up) { 1254*0fca6ea1SDimitry Andric error.SetErrorString("SetOptionValue called before options definitions " 1255*0fca6ea1SDimitry Andric "were created."); 1256*0fca6ea1SDimitry Andric return error; 1257*0fca6ea1SDimitry Andric } 1258*0fca6ea1SDimitry Andric // Pass the long option, since you aren't actually required to have a 1259*0fca6ea1SDimitry Andric // short_option, and for those options the index or short option character 1260*0fca6ea1SDimitry Andric // aren't meaningful on the python side. 1261*0fca6ea1SDimitry Andric const char * long_option = 1262*0fca6ea1SDimitry Andric m_options_definition_up.get()[option_idx].long_option; 1263*0fca6ea1SDimitry Andric bool success = scripter->SetOptionValueForCommandObject(m_cmd_obj_sp, 1264*0fca6ea1SDimitry Andric execution_context, long_option, option_arg); 1265*0fca6ea1SDimitry Andric if (!success) 1266*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("Error setting option: {0} to {1}", 1267*0fca6ea1SDimitry Andric long_option, option_arg); 1268*0fca6ea1SDimitry Andric return error; 1269*0fca6ea1SDimitry Andric } 1270*0fca6ea1SDimitry Andric 1271*0fca6ea1SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 1272*0fca6ea1SDimitry Andric ScriptInterpreter *scripter = 1273*0fca6ea1SDimitry Andric m_interpreter.GetDebugger().GetScriptInterpreter(); 1274*0fca6ea1SDimitry Andric if (!scripter || !m_cmd_obj_sp) 1275*0fca6ea1SDimitry Andric return; 1276*0fca6ea1SDimitry Andric 1277*0fca6ea1SDimitry Andric scripter->OptionParsingStartedForCommandObject(m_cmd_obj_sp); 1278*0fca6ea1SDimitry Andric } 1279*0fca6ea1SDimitry Andric 1280*0fca6ea1SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1281*0fca6ea1SDimitry Andric if (!m_options_definition_up) 1282*0fca6ea1SDimitry Andric return {}; 1283*0fca6ea1SDimitry Andric return llvm::ArrayRef(m_options_definition_up.get(), m_num_options); 1284*0fca6ea1SDimitry Andric } 1285*0fca6ea1SDimitry Andric 1286*0fca6ea1SDimitry Andric static Status ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp, 1287*0fca6ea1SDimitry Andric size_t counter, uint32_t &usage_mask) { 1288*0fca6ea1SDimitry Andric // If the usage entry is not provided, we use LLDB_OPT_SET_ALL. 1289*0fca6ea1SDimitry Andric // If the usage mask is a UINT, the option belongs to that group. 1290*0fca6ea1SDimitry Andric // If the usage mask is a vector of UINT's, the option belongs to all the 1291*0fca6ea1SDimitry Andric // groups listed. 1292*0fca6ea1SDimitry Andric // If a subelement of the vector is a vector of two ints, then the option 1293*0fca6ea1SDimitry Andric // belongs to the inclusive range from the first to the second element. 1294*0fca6ea1SDimitry Andric Status error; 1295*0fca6ea1SDimitry Andric if (!obj_sp) { 1296*0fca6ea1SDimitry Andric usage_mask = LLDB_OPT_SET_ALL; 1297*0fca6ea1SDimitry Andric return error; 1298*0fca6ea1SDimitry Andric } 1299*0fca6ea1SDimitry Andric 1300*0fca6ea1SDimitry Andric usage_mask = 0; 1301*0fca6ea1SDimitry Andric 1302*0fca6ea1SDimitry Andric StructuredData::UnsignedInteger *uint_val = 1303*0fca6ea1SDimitry Andric obj_sp->GetAsUnsignedInteger(); 1304*0fca6ea1SDimitry Andric if (uint_val) { 1305*0fca6ea1SDimitry Andric // If this is an integer, then this specifies a single group: 1306*0fca6ea1SDimitry Andric uint32_t value = uint_val->GetValue(); 1307*0fca6ea1SDimitry Andric if (value == 0) { 1308*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv( 1309*0fca6ea1SDimitry Andric "0 is not a valid group for option {0}", counter); 1310*0fca6ea1SDimitry Andric return error; 1311*0fca6ea1SDimitry Andric } 1312*0fca6ea1SDimitry Andric usage_mask = (1 << (value - 1)); 1313*0fca6ea1SDimitry Andric return error; 1314*0fca6ea1SDimitry Andric } 1315*0fca6ea1SDimitry Andric // Otherwise it has to be an array: 1316*0fca6ea1SDimitry Andric StructuredData::Array *array_val = obj_sp->GetAsArray(); 1317*0fca6ea1SDimitry Andric if (!array_val) { 1318*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv( 1319*0fca6ea1SDimitry Andric "required field is not a array for option {0}", counter); 1320*0fca6ea1SDimitry Andric return error; 1321*0fca6ea1SDimitry Andric } 1322*0fca6ea1SDimitry Andric // This is the array ForEach for accumulating a group usage mask from 1323*0fca6ea1SDimitry Andric // an array of string descriptions of groups. 1324*0fca6ea1SDimitry Andric auto groups_accumulator 1325*0fca6ea1SDimitry Andric = [counter, &usage_mask, &error] 1326*0fca6ea1SDimitry Andric (StructuredData::Object *obj) -> bool { 1327*0fca6ea1SDimitry Andric StructuredData::UnsignedInteger *int_val = obj->GetAsUnsignedInteger(); 1328*0fca6ea1SDimitry Andric if (int_val) { 1329*0fca6ea1SDimitry Andric uint32_t value = int_val->GetValue(); 1330*0fca6ea1SDimitry Andric if (value == 0) { 1331*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv( 1332*0fca6ea1SDimitry Andric "0 is not a valid group for element {0}", counter); 1333*0fca6ea1SDimitry Andric return false; 1334*0fca6ea1SDimitry Andric } 1335*0fca6ea1SDimitry Andric usage_mask |= (1 << (value - 1)); 1336*0fca6ea1SDimitry Andric return true; 1337*0fca6ea1SDimitry Andric } 1338*0fca6ea1SDimitry Andric StructuredData::Array *arr_val = obj->GetAsArray(); 1339*0fca6ea1SDimitry Andric if (!arr_val) { 1340*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv( 1341*0fca6ea1SDimitry Andric "Group element not an int or array of integers for element {0}", 1342*0fca6ea1SDimitry Andric counter); 1343*0fca6ea1SDimitry Andric return false; 1344*0fca6ea1SDimitry Andric } 1345*0fca6ea1SDimitry Andric size_t num_range_elem = arr_val->GetSize(); 1346*0fca6ea1SDimitry Andric if (num_range_elem != 2) { 1347*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv( 1348*0fca6ea1SDimitry Andric "Subranges of a group not a start and a stop for element {0}", 1349*0fca6ea1SDimitry Andric counter); 1350*0fca6ea1SDimitry Andric return false; 1351*0fca6ea1SDimitry Andric } 1352*0fca6ea1SDimitry Andric int_val = arr_val->GetItemAtIndex(0)->GetAsUnsignedInteger(); 1353*0fca6ea1SDimitry Andric if (!int_val) { 1354*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("Start element of a subrange of a " 1355*0fca6ea1SDimitry Andric "group not unsigned int for element {0}", counter); 1356*0fca6ea1SDimitry Andric return false; 1357*0fca6ea1SDimitry Andric } 1358*0fca6ea1SDimitry Andric uint32_t start = int_val->GetValue(); 1359*0fca6ea1SDimitry Andric int_val = arr_val->GetItemAtIndex(1)->GetAsUnsignedInteger(); 1360*0fca6ea1SDimitry Andric if (!int_val) { 1361*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("End element of a subrange of a group" 1362*0fca6ea1SDimitry Andric " not unsigned int for element {0}", counter); 1363*0fca6ea1SDimitry Andric return false; 1364*0fca6ea1SDimitry Andric } 1365*0fca6ea1SDimitry Andric uint32_t end = int_val->GetValue(); 1366*0fca6ea1SDimitry Andric if (start == 0 || end == 0 || start > end) { 1367*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("Invalid subrange of a group: {0} - " 1368*0fca6ea1SDimitry Andric "{1} for element {2}", start, end, counter); 1369*0fca6ea1SDimitry Andric return false; 1370*0fca6ea1SDimitry Andric } 1371*0fca6ea1SDimitry Andric for (uint32_t i = start; i <= end; i++) { 1372*0fca6ea1SDimitry Andric usage_mask |= (1 << (i - 1)); 1373*0fca6ea1SDimitry Andric } 1374*0fca6ea1SDimitry Andric return true; 1375*0fca6ea1SDimitry Andric }; 1376*0fca6ea1SDimitry Andric array_val->ForEach(groups_accumulator); 1377*0fca6ea1SDimitry Andric return error; 1378*0fca6ea1SDimitry Andric } 1379*0fca6ea1SDimitry Andric 1380*0fca6ea1SDimitry Andric 1381*0fca6ea1SDimitry Andric Status SetOptionsFromArray(StructuredData::Dictionary &options) { 1382*0fca6ea1SDimitry Andric Status error; 1383*0fca6ea1SDimitry Andric m_num_options = options.GetSize(); 1384*0fca6ea1SDimitry Andric m_options_definition_up.reset(new OptionDefinition[m_num_options]); 1385*0fca6ea1SDimitry Andric // We need to hand out pointers to contents of these vectors; we reserve 1386*0fca6ea1SDimitry Andric // as much as we'll need up front so they don't get freed on resize... 1387*0fca6ea1SDimitry Andric m_usage_container.resize(m_num_options); 1388*0fca6ea1SDimitry Andric m_enum_storage.resize(m_num_options); 1389*0fca6ea1SDimitry Andric m_enum_vector.resize(m_num_options); 1390*0fca6ea1SDimitry Andric 1391*0fca6ea1SDimitry Andric size_t counter = 0; 1392*0fca6ea1SDimitry Andric size_t short_opt_counter = 0; 1393*0fca6ea1SDimitry Andric // This is the Array::ForEach function for adding option elements: 1394*0fca6ea1SDimitry Andric auto add_element = [this, &error, &counter, &short_opt_counter] 1395*0fca6ea1SDimitry Andric (llvm::StringRef long_option, StructuredData::Object *object) -> bool { 1396*0fca6ea1SDimitry Andric StructuredData::Dictionary *opt_dict = object->GetAsDictionary(); 1397*0fca6ea1SDimitry Andric if (!opt_dict) { 1398*0fca6ea1SDimitry Andric error.SetErrorString("Value in options dictionary is not a dictionary"); 1399*0fca6ea1SDimitry Andric return false; 1400*0fca6ea1SDimitry Andric } 1401*0fca6ea1SDimitry Andric OptionDefinition &option_def = m_options_definition_up.get()[counter]; 1402*0fca6ea1SDimitry Andric 1403*0fca6ea1SDimitry Andric // We aren't exposing the validator yet, set it to null 1404*0fca6ea1SDimitry Andric option_def.validator = nullptr; 1405*0fca6ea1SDimitry Andric // We don't require usage masks, so set it to one group by default: 1406*0fca6ea1SDimitry Andric option_def.usage_mask = 1; 1407*0fca6ea1SDimitry Andric 1408*0fca6ea1SDimitry Andric // Now set the fields of the OptionDefinition Array from the dictionary: 1409*0fca6ea1SDimitry Andric // 1410*0fca6ea1SDimitry Andric // Note that I don't check for unknown fields in the option dictionaries 1411*0fca6ea1SDimitry Andric // so a scriptor can add extra elements that are helpful when they go to 1412*0fca6ea1SDimitry Andric // do "set_option_value" 1413*0fca6ea1SDimitry Andric 1414*0fca6ea1SDimitry Andric // Usage Mask: 1415*0fca6ea1SDimitry Andric StructuredData::ObjectSP obj_sp = opt_dict->GetValueForKey("groups"); 1416*0fca6ea1SDimitry Andric if (obj_sp) { 1417*0fca6ea1SDimitry Andric error = ParseUsageMaskFromArray(obj_sp, counter, 1418*0fca6ea1SDimitry Andric option_def.usage_mask); 1419*0fca6ea1SDimitry Andric if (error.Fail()) 1420*0fca6ea1SDimitry Andric return false; 1421*0fca6ea1SDimitry Andric } 1422*0fca6ea1SDimitry Andric 1423*0fca6ea1SDimitry Andric // Required: 1424*0fca6ea1SDimitry Andric option_def.required = false; 1425*0fca6ea1SDimitry Andric obj_sp = opt_dict->GetValueForKey("required"); 1426*0fca6ea1SDimitry Andric if (obj_sp) { 1427*0fca6ea1SDimitry Andric StructuredData::Boolean *boolean_val = obj_sp->GetAsBoolean(); 1428*0fca6ea1SDimitry Andric if (!boolean_val) { 1429*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("'required' field is not a boolean " 1430*0fca6ea1SDimitry Andric "for option {0}", counter); 1431*0fca6ea1SDimitry Andric return false; 1432*0fca6ea1SDimitry Andric } 1433*0fca6ea1SDimitry Andric option_def.required = boolean_val->GetValue(); 1434*0fca6ea1SDimitry Andric } 1435*0fca6ea1SDimitry Andric 1436*0fca6ea1SDimitry Andric // Short Option: 1437*0fca6ea1SDimitry Andric int short_option; 1438*0fca6ea1SDimitry Andric obj_sp = opt_dict->GetValueForKey("short_option"); 1439*0fca6ea1SDimitry Andric if (obj_sp) { 1440*0fca6ea1SDimitry Andric // The value is a string, so pull the 1441*0fca6ea1SDimitry Andric llvm::StringRef short_str = obj_sp->GetStringValue(); 1442*0fca6ea1SDimitry Andric if (short_str.empty()) { 1443*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("short_option field empty for " 1444*0fca6ea1SDimitry Andric "option {0}", counter); 1445*0fca6ea1SDimitry Andric return false; 1446*0fca6ea1SDimitry Andric } else if (short_str.size() != 1) { 1447*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("short_option field has extra " 1448*0fca6ea1SDimitry Andric "characters for option {0}", counter); 1449*0fca6ea1SDimitry Andric return false; 1450*0fca6ea1SDimitry Andric } 1451*0fca6ea1SDimitry Andric short_option = (int) short_str[0]; 1452*0fca6ea1SDimitry Andric } else { 1453*0fca6ea1SDimitry Andric // If the short option is not provided, then we need a unique value 1454*0fca6ea1SDimitry Andric // less than the lowest printable ASCII character. 1455*0fca6ea1SDimitry Andric short_option = short_opt_counter++; 1456*0fca6ea1SDimitry Andric } 1457*0fca6ea1SDimitry Andric option_def.short_option = short_option; 1458*0fca6ea1SDimitry Andric 1459*0fca6ea1SDimitry Andric // Long Option is the key from the outer dict: 1460*0fca6ea1SDimitry Andric if (long_option.empty()) { 1461*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("empty long_option for option {0}", 1462*0fca6ea1SDimitry Andric counter); 1463*0fca6ea1SDimitry Andric return false; 1464*0fca6ea1SDimitry Andric } 1465*0fca6ea1SDimitry Andric auto inserted = g_string_storer.insert(long_option.str()); 1466*0fca6ea1SDimitry Andric option_def.long_option = ((*(inserted.first)).data()); 1467*0fca6ea1SDimitry Andric 1468*0fca6ea1SDimitry Andric // Value Type: 1469*0fca6ea1SDimitry Andric obj_sp = opt_dict->GetValueForKey("value_type"); 1470*0fca6ea1SDimitry Andric if (obj_sp) { 1471*0fca6ea1SDimitry Andric StructuredData::UnsignedInteger *uint_val 1472*0fca6ea1SDimitry Andric = obj_sp->GetAsUnsignedInteger(); 1473*0fca6ea1SDimitry Andric if (!uint_val) { 1474*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("Value type must be an unsigned " 1475*0fca6ea1SDimitry Andric "integer"); 1476*0fca6ea1SDimitry Andric return false; 1477*0fca6ea1SDimitry Andric } 1478*0fca6ea1SDimitry Andric uint64_t val_type = uint_val->GetValue(); 1479*0fca6ea1SDimitry Andric if (val_type >= eArgTypeLastArg) { 1480*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("Value type {0} beyond the " 1481*0fca6ea1SDimitry Andric "CommandArgumentType bounds", val_type); 1482*0fca6ea1SDimitry Andric return false; 1483*0fca6ea1SDimitry Andric } 1484*0fca6ea1SDimitry Andric option_def.argument_type = (CommandArgumentType) val_type; 1485*0fca6ea1SDimitry Andric option_def.option_has_arg = true; 1486*0fca6ea1SDimitry Andric } else { 1487*0fca6ea1SDimitry Andric option_def.argument_type = eArgTypeNone; 1488*0fca6ea1SDimitry Andric option_def.option_has_arg = false; 1489*0fca6ea1SDimitry Andric } 1490*0fca6ea1SDimitry Andric 1491*0fca6ea1SDimitry Andric // Completion Type: 1492*0fca6ea1SDimitry Andric obj_sp = opt_dict->GetValueForKey("completion_type"); 1493*0fca6ea1SDimitry Andric if (obj_sp) { 1494*0fca6ea1SDimitry Andric StructuredData::UnsignedInteger *uint_val = obj_sp->GetAsUnsignedInteger(); 1495*0fca6ea1SDimitry Andric if (!uint_val) { 1496*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("Completion type must be an " 1497*0fca6ea1SDimitry Andric "unsigned integer for option {0}", counter); 1498*0fca6ea1SDimitry Andric return false; 1499*0fca6ea1SDimitry Andric } 1500*0fca6ea1SDimitry Andric uint64_t completion_type = uint_val->GetValue(); 1501*0fca6ea1SDimitry Andric if (completion_type > eCustomCompletion) { 1502*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("Completion type for option {0} " 1503*0fca6ea1SDimitry Andric "beyond the CompletionType bounds", completion_type); 1504*0fca6ea1SDimitry Andric return false; 1505*0fca6ea1SDimitry Andric } 1506*0fca6ea1SDimitry Andric option_def.completion_type = (CommandArgumentType) completion_type; 1507*0fca6ea1SDimitry Andric } else 1508*0fca6ea1SDimitry Andric option_def.completion_type = eNoCompletion; 1509*0fca6ea1SDimitry Andric 1510*0fca6ea1SDimitry Andric // Usage Text: 1511*0fca6ea1SDimitry Andric std::string usage_text; 1512*0fca6ea1SDimitry Andric obj_sp = opt_dict->GetValueForKey("help"); 1513*0fca6ea1SDimitry Andric if (!obj_sp) { 1514*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("required usage missing from option " 1515*0fca6ea1SDimitry Andric "{0}", counter); 1516*0fca6ea1SDimitry Andric return false; 1517*0fca6ea1SDimitry Andric } 1518*0fca6ea1SDimitry Andric llvm::StringRef usage_stref; 1519*0fca6ea1SDimitry Andric usage_stref = obj_sp->GetStringValue(); 1520*0fca6ea1SDimitry Andric if (usage_stref.empty()) { 1521*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("empty usage text for option {0}", 1522*0fca6ea1SDimitry Andric counter); 1523*0fca6ea1SDimitry Andric return false; 1524*0fca6ea1SDimitry Andric } 1525*0fca6ea1SDimitry Andric m_usage_container[counter] = usage_stref.str().c_str(); 1526*0fca6ea1SDimitry Andric option_def.usage_text = m_usage_container[counter].data(); 1527*0fca6ea1SDimitry Andric 1528*0fca6ea1SDimitry Andric // Enum Values: 1529*0fca6ea1SDimitry Andric 1530*0fca6ea1SDimitry Andric obj_sp = opt_dict->GetValueForKey("enum_values"); 1531*0fca6ea1SDimitry Andric if (obj_sp) { 1532*0fca6ea1SDimitry Andric StructuredData::Array *array = obj_sp->GetAsArray(); 1533*0fca6ea1SDimitry Andric if (!array) { 1534*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("enum values must be an array for " 1535*0fca6ea1SDimitry Andric "option {0}", counter); 1536*0fca6ea1SDimitry Andric return false; 1537*0fca6ea1SDimitry Andric } 1538*0fca6ea1SDimitry Andric size_t num_elem = array->GetSize(); 1539*0fca6ea1SDimitry Andric size_t enum_ctr = 0; 1540*0fca6ea1SDimitry Andric m_enum_storage[counter] = std::vector<EnumValueStorage>(num_elem); 1541*0fca6ea1SDimitry Andric std::vector<EnumValueStorage> &curr_elem = m_enum_storage[counter]; 1542*0fca6ea1SDimitry Andric 1543*0fca6ea1SDimitry Andric // This is the Array::ForEach function for adding enum elements: 1544*0fca6ea1SDimitry Andric // Since there are only two fields to specify the enum, use a simple 1545*0fca6ea1SDimitry Andric // two element array with value first, usage second. 1546*0fca6ea1SDimitry Andric // counter is only used for reporting so I pass it by value here. 1547*0fca6ea1SDimitry Andric auto add_enum = [&enum_ctr, &curr_elem, counter, &error] 1548*0fca6ea1SDimitry Andric (StructuredData::Object *object) -> bool { 1549*0fca6ea1SDimitry Andric StructuredData::Array *enum_arr = object->GetAsArray(); 1550*0fca6ea1SDimitry Andric if (!enum_arr) { 1551*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("Enum values for option {0} not " 1552*0fca6ea1SDimitry Andric "an array", counter); 1553*0fca6ea1SDimitry Andric return false; 1554*0fca6ea1SDimitry Andric } 1555*0fca6ea1SDimitry Andric size_t num_enum_elements = enum_arr->GetSize(); 1556*0fca6ea1SDimitry Andric if (num_enum_elements != 2) { 1557*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("Wrong number of elements: {0} " 1558*0fca6ea1SDimitry Andric "for enum {1} in option {2}", 1559*0fca6ea1SDimitry Andric num_enum_elements, enum_ctr, counter); 1560*0fca6ea1SDimitry Andric return false; 1561*0fca6ea1SDimitry Andric } 1562*0fca6ea1SDimitry Andric // Enum Value: 1563*0fca6ea1SDimitry Andric StructuredData::ObjectSP obj_sp = enum_arr->GetItemAtIndex(0); 1564*0fca6ea1SDimitry Andric llvm::StringRef val_stref = obj_sp->GetStringValue(); 1565*0fca6ea1SDimitry Andric std::string value_cstr_str = val_stref.str().c_str(); 1566*0fca6ea1SDimitry Andric 1567*0fca6ea1SDimitry Andric // Enum Usage: 1568*0fca6ea1SDimitry Andric obj_sp = enum_arr->GetItemAtIndex(1); 1569*0fca6ea1SDimitry Andric if (!obj_sp) { 1570*0fca6ea1SDimitry Andric error.SetErrorStringWithFormatv("No usage for enum {0} in option " 1571*0fca6ea1SDimitry Andric "{1}", enum_ctr, counter); 1572*0fca6ea1SDimitry Andric return false; 1573*0fca6ea1SDimitry Andric } 1574*0fca6ea1SDimitry Andric llvm::StringRef usage_stref = obj_sp->GetStringValue(); 1575*0fca6ea1SDimitry Andric std::string usage_cstr_str = usage_stref.str().c_str(); 1576*0fca6ea1SDimitry Andric curr_elem[enum_ctr] = EnumValueStorage(value_cstr_str, 1577*0fca6ea1SDimitry Andric usage_cstr_str, enum_ctr); 1578*0fca6ea1SDimitry Andric 1579*0fca6ea1SDimitry Andric enum_ctr++; 1580*0fca6ea1SDimitry Andric return true; 1581*0fca6ea1SDimitry Andric }; // end of add_enum 1582*0fca6ea1SDimitry Andric 1583*0fca6ea1SDimitry Andric array->ForEach(add_enum); 1584*0fca6ea1SDimitry Andric if (!error.Success()) 1585*0fca6ea1SDimitry Andric return false; 1586*0fca6ea1SDimitry Andric // We have to have a vector of elements to set in the options, make 1587*0fca6ea1SDimitry Andric // that here: 1588*0fca6ea1SDimitry Andric for (auto &elem : curr_elem) 1589*0fca6ea1SDimitry Andric m_enum_vector[counter].emplace_back(elem.element); 1590*0fca6ea1SDimitry Andric 1591*0fca6ea1SDimitry Andric option_def.enum_values = llvm::ArrayRef(m_enum_vector[counter]); 1592*0fca6ea1SDimitry Andric } 1593*0fca6ea1SDimitry Andric counter++; 1594*0fca6ea1SDimitry Andric return true; 1595*0fca6ea1SDimitry Andric }; // end of add_element 1596*0fca6ea1SDimitry Andric 1597*0fca6ea1SDimitry Andric options.ForEach(add_element); 1598*0fca6ea1SDimitry Andric return error; 1599*0fca6ea1SDimitry Andric } 1600*0fca6ea1SDimitry Andric 1601*0fca6ea1SDimitry Andric size_t GetNumOptions() { return m_num_options; } 1602*0fca6ea1SDimitry Andric 1603*0fca6ea1SDimitry Andric private: 1604*0fca6ea1SDimitry Andric struct EnumValueStorage { 1605*0fca6ea1SDimitry Andric EnumValueStorage() { 1606*0fca6ea1SDimitry Andric element.string_value = "value not set"; 1607*0fca6ea1SDimitry Andric element.usage = "usage not set"; 1608*0fca6ea1SDimitry Andric element.value = 0; 1609*0fca6ea1SDimitry Andric } 1610*0fca6ea1SDimitry Andric 1611*0fca6ea1SDimitry Andric EnumValueStorage(std::string in_str_val, std::string in_usage, 1612*0fca6ea1SDimitry Andric size_t in_value) : value(std::move(in_str_val)), usage(std::move(in_usage)) { 1613*0fca6ea1SDimitry Andric SetElement(in_value); 1614*0fca6ea1SDimitry Andric } 1615*0fca6ea1SDimitry Andric 1616*0fca6ea1SDimitry Andric EnumValueStorage(const EnumValueStorage &in) : value(in.value), 1617*0fca6ea1SDimitry Andric usage(in.usage) { 1618*0fca6ea1SDimitry Andric SetElement(in.element.value); 1619*0fca6ea1SDimitry Andric } 1620*0fca6ea1SDimitry Andric 1621*0fca6ea1SDimitry Andric EnumValueStorage &operator=(const EnumValueStorage &in) { 1622*0fca6ea1SDimitry Andric value = in.value; 1623*0fca6ea1SDimitry Andric usage = in.usage; 1624*0fca6ea1SDimitry Andric SetElement(in.element.value); 1625*0fca6ea1SDimitry Andric return *this; 1626*0fca6ea1SDimitry Andric } 1627*0fca6ea1SDimitry Andric 1628*0fca6ea1SDimitry Andric void SetElement(size_t in_value) { 1629*0fca6ea1SDimitry Andric element.value = in_value; 1630*0fca6ea1SDimitry Andric element.string_value = value.data(); 1631*0fca6ea1SDimitry Andric element.usage = usage.data(); 1632*0fca6ea1SDimitry Andric } 1633*0fca6ea1SDimitry Andric 1634*0fca6ea1SDimitry Andric std::string value; 1635*0fca6ea1SDimitry Andric std::string usage; 1636*0fca6ea1SDimitry Andric OptionEnumValueElement element; 1637*0fca6ea1SDimitry Andric }; 1638*0fca6ea1SDimitry Andric // We have to provide char * values for the long option, usage and enum 1639*0fca6ea1SDimitry Andric // values, that's what the option definitions hold. 1640*0fca6ea1SDimitry Andric // The long option strings are quite likely to be reused in other added 1641*0fca6ea1SDimitry Andric // commands, so those are stored in a global set: g_string_storer. 1642*0fca6ea1SDimitry Andric // But the usages are much less likely to be reused, so those are stored in 1643*0fca6ea1SDimitry Andric // a vector in the command instance. It gets resized to the correct size 1644*0fca6ea1SDimitry Andric // and then filled with null-terminated strings in the std::string, so the 1645*0fca6ea1SDimitry Andric // are valid C-strings that won't move around. 1646*0fca6ea1SDimitry Andric // The enum values and descriptions are treated similarly - these aren't 1647*0fca6ea1SDimitry Andric // all that common so it's not worth the effort to dedup them. 1648*0fca6ea1SDimitry Andric size_t m_num_options = 0; 1649*0fca6ea1SDimitry Andric std::unique_ptr<OptionDefinition> m_options_definition_up; 1650*0fca6ea1SDimitry Andric std::vector<std::vector<EnumValueStorage>> m_enum_storage; 1651*0fca6ea1SDimitry Andric std::vector<std::vector<OptionEnumValueElement>> m_enum_vector; 1652*0fca6ea1SDimitry Andric std::vector<std::string> m_usage_container; 1653*0fca6ea1SDimitry Andric CommandInterpreter &m_interpreter; 1654*0fca6ea1SDimitry Andric StructuredData::GenericSP m_cmd_obj_sp; 1655*0fca6ea1SDimitry Andric static std::unordered_set<std::string> g_string_storer; 1656*0fca6ea1SDimitry Andric }; 1657*0fca6ea1SDimitry Andric 1658*0fca6ea1SDimitry Andric public: 1659*0fca6ea1SDimitry Andric static CommandObjectSP Create(CommandInterpreter &interpreter, 1660*0fca6ea1SDimitry Andric std::string name, 1661*0fca6ea1SDimitry Andric StructuredData::GenericSP cmd_obj_sp, 1662*0fca6ea1SDimitry Andric ScriptedCommandSynchronicity synch, 1663*0fca6ea1SDimitry Andric CommandReturnObject &result) { 1664*0fca6ea1SDimitry Andric CommandObjectSP new_cmd_sp(new CommandObjectScriptingObjectParsed( 1665*0fca6ea1SDimitry Andric interpreter, name, cmd_obj_sp, synch)); 1666*0fca6ea1SDimitry Andric 1667*0fca6ea1SDimitry Andric CommandObjectScriptingObjectParsed *parsed_cmd 1668*0fca6ea1SDimitry Andric = static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get()); 1669*0fca6ea1SDimitry Andric // Now check all the failure modes, and report if found. 1670*0fca6ea1SDimitry Andric Status opt_error = parsed_cmd->GetOptionsError(); 1671*0fca6ea1SDimitry Andric Status arg_error = parsed_cmd->GetArgsError(); 1672*0fca6ea1SDimitry Andric 1673*0fca6ea1SDimitry Andric if (opt_error.Fail()) 1674*0fca6ea1SDimitry Andric result.AppendErrorWithFormat("failed to parse option definitions: %s", 1675*0fca6ea1SDimitry Andric opt_error.AsCString()); 1676*0fca6ea1SDimitry Andric if (arg_error.Fail()) 1677*0fca6ea1SDimitry Andric result.AppendErrorWithFormat("%sfailed to parse argument definitions: %s", 1678*0fca6ea1SDimitry Andric opt_error.Fail() ? ", also " : "", 1679*0fca6ea1SDimitry Andric arg_error.AsCString()); 1680*0fca6ea1SDimitry Andric 1681*0fca6ea1SDimitry Andric if (!result.Succeeded()) 1682*0fca6ea1SDimitry Andric return {}; 1683*0fca6ea1SDimitry Andric 1684*0fca6ea1SDimitry Andric return new_cmd_sp; 1685*0fca6ea1SDimitry Andric } 1686*0fca6ea1SDimitry Andric 1687*0fca6ea1SDimitry Andric CommandObjectScriptingObjectParsed(CommandInterpreter &interpreter, 1688*0fca6ea1SDimitry Andric std::string name, 1689*0fca6ea1SDimitry Andric StructuredData::GenericSP cmd_obj_sp, 1690*0fca6ea1SDimitry Andric ScriptedCommandSynchronicity synch) 1691*0fca6ea1SDimitry Andric : CommandObjectParsed(interpreter, name.c_str()), 1692*0fca6ea1SDimitry Andric m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), 1693*0fca6ea1SDimitry Andric m_options(interpreter, cmd_obj_sp), m_fetched_help_short(false), 1694*0fca6ea1SDimitry Andric m_fetched_help_long(false) { 1695*0fca6ea1SDimitry Andric StreamString stream; 1696*0fca6ea1SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1697*0fca6ea1SDimitry Andric if (!scripter) { 1698*0fca6ea1SDimitry Andric m_options_error.SetErrorString("No script interpreter"); 1699*0fca6ea1SDimitry Andric return; 1700*0fca6ea1SDimitry Andric } 1701*0fca6ea1SDimitry Andric 1702*0fca6ea1SDimitry Andric // Set the flags: 1703*0fca6ea1SDimitry Andric GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1704*0fca6ea1SDimitry Andric 1705*0fca6ea1SDimitry Andric // Now set up the options definitions from the options: 1706*0fca6ea1SDimitry Andric StructuredData::ObjectSP options_object_sp 1707*0fca6ea1SDimitry Andric = scripter->GetOptionsForCommandObject(cmd_obj_sp); 1708*0fca6ea1SDimitry Andric // It's okay not to have an options dict. 1709*0fca6ea1SDimitry Andric if (options_object_sp) { 1710*0fca6ea1SDimitry Andric // The options come as a dictionary of dictionaries. The key of the 1711*0fca6ea1SDimitry Andric // outer dict is the long option name (since that's required). The 1712*0fca6ea1SDimitry Andric // value holds all the other option specification bits. 1713*0fca6ea1SDimitry Andric StructuredData::Dictionary *options_dict 1714*0fca6ea1SDimitry Andric = options_object_sp->GetAsDictionary(); 1715*0fca6ea1SDimitry Andric // but if it exists, it has to be an array. 1716*0fca6ea1SDimitry Andric if (options_dict) { 1717*0fca6ea1SDimitry Andric m_options_error = m_options.SetOptionsFromArray(*(options_dict)); 1718*0fca6ea1SDimitry Andric // If we got an error don't bother with the arguments... 1719*0fca6ea1SDimitry Andric if (m_options_error.Fail()) 1720*0fca6ea1SDimitry Andric return; 1721*0fca6ea1SDimitry Andric } else { 1722*0fca6ea1SDimitry Andric m_options_error.SetErrorString("Options array not an array"); 1723*0fca6ea1SDimitry Andric return; 1724*0fca6ea1SDimitry Andric } 1725*0fca6ea1SDimitry Andric } 1726*0fca6ea1SDimitry Andric // Then fetch the args. Since the arguments can have usage masks you need 1727*0fca6ea1SDimitry Andric // an array of arrays. 1728*0fca6ea1SDimitry Andric StructuredData::ObjectSP args_object_sp 1729*0fca6ea1SDimitry Andric = scripter->GetArgumentsForCommandObject(cmd_obj_sp); 1730*0fca6ea1SDimitry Andric if (args_object_sp) { 1731*0fca6ea1SDimitry Andric StructuredData::Array *args_array = args_object_sp->GetAsArray(); 1732*0fca6ea1SDimitry Andric if (!args_array) { 1733*0fca6ea1SDimitry Andric m_args_error.SetErrorString("Argument specification is not an array"); 1734*0fca6ea1SDimitry Andric return; 1735*0fca6ea1SDimitry Andric } 1736*0fca6ea1SDimitry Andric size_t counter = 0; 1737*0fca6ea1SDimitry Andric 1738*0fca6ea1SDimitry Andric // This is the Array::ForEach function that handles the 1739*0fca6ea1SDimitry Andric // CommandArgumentEntry arrays one by one: 1740*0fca6ea1SDimitry Andric auto arg_array_adder = [this, &counter] (StructuredData::Object *object) 1741*0fca6ea1SDimitry Andric -> bool { 1742*0fca6ea1SDimitry Andric // This is the Array::ForEach function to add argument entries: 1743*0fca6ea1SDimitry Andric CommandArgumentEntry this_entry; 1744*0fca6ea1SDimitry Andric size_t elem_counter = 0; 1745*0fca6ea1SDimitry Andric auto args_adder = [this, counter, &elem_counter, &this_entry] 1746*0fca6ea1SDimitry Andric (StructuredData::Object *object) -> bool { 1747*0fca6ea1SDimitry Andric // The arguments definition has three fields, the argument type, the 1748*0fca6ea1SDimitry Andric // repeat and the usage mask. 1749*0fca6ea1SDimitry Andric CommandArgumentType arg_type = eArgTypeNone; 1750*0fca6ea1SDimitry Andric ArgumentRepetitionType arg_repetition = eArgRepeatOptional; 1751*0fca6ea1SDimitry Andric uint32_t arg_opt_set_association; 1752*0fca6ea1SDimitry Andric 1753*0fca6ea1SDimitry Andric auto report_error = [this, elem_counter, counter] 1754*0fca6ea1SDimitry Andric (const char *err_txt) -> bool { 1755*0fca6ea1SDimitry Andric m_args_error.SetErrorStringWithFormatv("Element {0} of arguments " 1756*0fca6ea1SDimitry Andric "list element {1}: %s.", elem_counter, counter, err_txt); 1757*0fca6ea1SDimitry Andric return false; 1758*0fca6ea1SDimitry Andric }; 1759*0fca6ea1SDimitry Andric 1760*0fca6ea1SDimitry Andric StructuredData::Dictionary *arg_dict = object->GetAsDictionary(); 1761*0fca6ea1SDimitry Andric if (!arg_dict) { 1762*0fca6ea1SDimitry Andric report_error("is not a dictionary."); 1763*0fca6ea1SDimitry Andric return false; 1764*0fca6ea1SDimitry Andric } 1765*0fca6ea1SDimitry Andric // Argument Type: 1766*0fca6ea1SDimitry Andric StructuredData::ObjectSP obj_sp 1767*0fca6ea1SDimitry Andric = arg_dict->GetValueForKey("arg_type"); 1768*0fca6ea1SDimitry Andric if (obj_sp) { 1769*0fca6ea1SDimitry Andric StructuredData::UnsignedInteger *uint_val 1770*0fca6ea1SDimitry Andric = obj_sp->GetAsUnsignedInteger(); 1771*0fca6ea1SDimitry Andric if (!uint_val) { 1772*0fca6ea1SDimitry Andric report_error("value type must be an unsigned integer"); 1773*0fca6ea1SDimitry Andric return false; 1774*0fca6ea1SDimitry Andric } 1775*0fca6ea1SDimitry Andric uint64_t arg_type_int = uint_val->GetValue(); 1776*0fca6ea1SDimitry Andric if (arg_type_int >= eArgTypeLastArg) { 1777*0fca6ea1SDimitry Andric report_error("value type beyond ArgumentRepetitionType bounds"); 1778*0fca6ea1SDimitry Andric return false; 1779*0fca6ea1SDimitry Andric } 1780*0fca6ea1SDimitry Andric arg_type = (CommandArgumentType) arg_type_int; 1781*0fca6ea1SDimitry Andric } 1782*0fca6ea1SDimitry Andric // Repeat Value: 1783*0fca6ea1SDimitry Andric obj_sp = arg_dict->GetValueForKey("repeat"); 1784*0fca6ea1SDimitry Andric std::optional<ArgumentRepetitionType> repeat; 1785*0fca6ea1SDimitry Andric if (obj_sp) { 1786*0fca6ea1SDimitry Andric llvm::StringRef repeat_str = obj_sp->GetStringValue(); 1787*0fca6ea1SDimitry Andric if (repeat_str.empty()) { 1788*0fca6ea1SDimitry Andric report_error("repeat value is empty"); 1789*0fca6ea1SDimitry Andric return false; 1790*0fca6ea1SDimitry Andric } 1791*0fca6ea1SDimitry Andric repeat = ArgRepetitionFromString(repeat_str); 1792*0fca6ea1SDimitry Andric if (!repeat) { 1793*0fca6ea1SDimitry Andric report_error("invalid repeat value"); 1794*0fca6ea1SDimitry Andric return false; 1795*0fca6ea1SDimitry Andric } 1796*0fca6ea1SDimitry Andric arg_repetition = *repeat; 1797*0fca6ea1SDimitry Andric } 1798*0fca6ea1SDimitry Andric 1799*0fca6ea1SDimitry Andric // Usage Mask: 1800*0fca6ea1SDimitry Andric obj_sp = arg_dict->GetValueForKey("groups"); 1801*0fca6ea1SDimitry Andric m_args_error = CommandOptions::ParseUsageMaskFromArray(obj_sp, 1802*0fca6ea1SDimitry Andric counter, arg_opt_set_association); 1803*0fca6ea1SDimitry Andric this_entry.emplace_back(arg_type, arg_repetition, 1804*0fca6ea1SDimitry Andric arg_opt_set_association); 1805*0fca6ea1SDimitry Andric elem_counter++; 1806*0fca6ea1SDimitry Andric return true; 1807*0fca6ea1SDimitry Andric }; 1808*0fca6ea1SDimitry Andric StructuredData::Array *args_array = object->GetAsArray(); 1809*0fca6ea1SDimitry Andric if (!args_array) { 1810*0fca6ea1SDimitry Andric m_args_error.SetErrorStringWithFormatv("Argument definition element " 1811*0fca6ea1SDimitry Andric "{0} is not an array", counter); 1812*0fca6ea1SDimitry Andric } 1813*0fca6ea1SDimitry Andric 1814*0fca6ea1SDimitry Andric args_array->ForEach(args_adder); 1815*0fca6ea1SDimitry Andric if (m_args_error.Fail()) 1816*0fca6ea1SDimitry Andric return false; 1817*0fca6ea1SDimitry Andric if (this_entry.empty()) { 1818*0fca6ea1SDimitry Andric m_args_error.SetErrorStringWithFormatv("Argument definition element " 1819*0fca6ea1SDimitry Andric "{0} is empty", counter); 1820*0fca6ea1SDimitry Andric return false; 1821*0fca6ea1SDimitry Andric } 1822*0fca6ea1SDimitry Andric m_arguments.push_back(this_entry); 1823*0fca6ea1SDimitry Andric counter++; 1824*0fca6ea1SDimitry Andric return true; 1825*0fca6ea1SDimitry Andric }; // end of arg_array_adder 1826*0fca6ea1SDimitry Andric // Here we actually parse the args definition: 1827*0fca6ea1SDimitry Andric args_array->ForEach(arg_array_adder); 1828*0fca6ea1SDimitry Andric } 1829*0fca6ea1SDimitry Andric } 1830*0fca6ea1SDimitry Andric 1831*0fca6ea1SDimitry Andric ~CommandObjectScriptingObjectParsed() override = default; 1832*0fca6ea1SDimitry Andric 1833*0fca6ea1SDimitry Andric Status GetOptionsError() { return m_options_error; } 1834*0fca6ea1SDimitry Andric Status GetArgsError() { return m_args_error; } 1835*0fca6ea1SDimitry Andric bool WantsCompletion() override { return true; } 1836*0fca6ea1SDimitry Andric 1837*0fca6ea1SDimitry Andric bool IsRemovable() const override { return true; } 1838*0fca6ea1SDimitry Andric 1839*0fca6ea1SDimitry Andric ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1840*0fca6ea1SDimitry Andric 1841*0fca6ea1SDimitry Andric std::optional<std::string> GetRepeatCommand(Args &args, 1842*0fca6ea1SDimitry Andric uint32_t index) override { 1843*0fca6ea1SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1844*0fca6ea1SDimitry Andric if (!scripter) 1845*0fca6ea1SDimitry Andric return std::nullopt; 1846*0fca6ea1SDimitry Andric 1847*0fca6ea1SDimitry Andric return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args); 1848*0fca6ea1SDimitry Andric } 1849*0fca6ea1SDimitry Andric 1850*0fca6ea1SDimitry Andric llvm::StringRef GetHelp() override { 1851*0fca6ea1SDimitry Andric if (m_fetched_help_short) 1852*0fca6ea1SDimitry Andric return CommandObjectParsed::GetHelp(); 1853*0fca6ea1SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1854*0fca6ea1SDimitry Andric if (!scripter) 1855*0fca6ea1SDimitry Andric return CommandObjectParsed::GetHelp(); 1856*0fca6ea1SDimitry Andric std::string docstring; 1857*0fca6ea1SDimitry Andric m_fetched_help_short = 1858*0fca6ea1SDimitry Andric scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1859*0fca6ea1SDimitry Andric if (!docstring.empty()) 1860*0fca6ea1SDimitry Andric SetHelp(docstring); 1861*0fca6ea1SDimitry Andric 1862*0fca6ea1SDimitry Andric return CommandObjectParsed::GetHelp(); 1863*0fca6ea1SDimitry Andric } 1864*0fca6ea1SDimitry Andric 1865*0fca6ea1SDimitry Andric llvm::StringRef GetHelpLong() override { 1866*0fca6ea1SDimitry Andric if (m_fetched_help_long) 1867*0fca6ea1SDimitry Andric return CommandObjectParsed::GetHelpLong(); 1868*0fca6ea1SDimitry Andric 1869*0fca6ea1SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1870*0fca6ea1SDimitry Andric if (!scripter) 1871*0fca6ea1SDimitry Andric return CommandObjectParsed::GetHelpLong(); 1872*0fca6ea1SDimitry Andric 1873*0fca6ea1SDimitry Andric std::string docstring; 1874*0fca6ea1SDimitry Andric m_fetched_help_long = 1875*0fca6ea1SDimitry Andric scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1876*0fca6ea1SDimitry Andric if (!docstring.empty()) 1877*0fca6ea1SDimitry Andric SetHelpLong(docstring); 1878*0fca6ea1SDimitry Andric return CommandObjectParsed::GetHelpLong(); 1879*0fca6ea1SDimitry Andric } 1880*0fca6ea1SDimitry Andric 1881*0fca6ea1SDimitry Andric Options *GetOptions() override { 1882*0fca6ea1SDimitry Andric // CommandObjectParsed requires that a command with no options return 1883*0fca6ea1SDimitry Andric // nullptr. 1884*0fca6ea1SDimitry Andric if (m_options.GetNumOptions() == 0) 1885*0fca6ea1SDimitry Andric return nullptr; 1886*0fca6ea1SDimitry Andric return &m_options; 1887*0fca6ea1SDimitry Andric } 1888*0fca6ea1SDimitry Andric 1889*0fca6ea1SDimitry Andric protected: 1890*0fca6ea1SDimitry Andric void DoExecute(Args &args, 1891*0fca6ea1SDimitry Andric CommandReturnObject &result) override { 1892*0fca6ea1SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1893*0fca6ea1SDimitry Andric 1894*0fca6ea1SDimitry Andric Status error; 1895*0fca6ea1SDimitry Andric 1896*0fca6ea1SDimitry Andric result.SetStatus(eReturnStatusInvalid); 1897*0fca6ea1SDimitry Andric 1898*0fca6ea1SDimitry Andric if (!scripter || 1899*0fca6ea1SDimitry Andric !scripter->RunScriptBasedParsedCommand(m_cmd_obj_sp, args, 1900*0fca6ea1SDimitry Andric m_synchro, result, error, m_exe_ctx)) { 1901*0fca6ea1SDimitry Andric result.AppendError(error.AsCString()); 1902*0fca6ea1SDimitry Andric } else { 1903*0fca6ea1SDimitry Andric // Don't change the status if the command already set it... 1904*0fca6ea1SDimitry Andric if (result.GetStatus() == eReturnStatusInvalid) { 1905*0fca6ea1SDimitry Andric if (result.GetOutputData().empty()) 1906*0fca6ea1SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 1907*0fca6ea1SDimitry Andric else 1908*0fca6ea1SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 1909*0fca6ea1SDimitry Andric } 1910*0fca6ea1SDimitry Andric } 1911*0fca6ea1SDimitry Andric } 1912*0fca6ea1SDimitry Andric 1913*0fca6ea1SDimitry Andric private: 1914*0fca6ea1SDimitry Andric StructuredData::GenericSP m_cmd_obj_sp; 1915*0fca6ea1SDimitry Andric ScriptedCommandSynchronicity m_synchro; 1916*0fca6ea1SDimitry Andric CommandOptions m_options; 1917*0fca6ea1SDimitry Andric Status m_options_error; 1918*0fca6ea1SDimitry Andric Status m_args_error; 1919*0fca6ea1SDimitry Andric bool m_fetched_help_short : 1; 1920*0fca6ea1SDimitry Andric bool m_fetched_help_long : 1; 1921*0fca6ea1SDimitry Andric }; 1922*0fca6ea1SDimitry Andric 1923*0fca6ea1SDimitry Andric std::unordered_set<std::string> 1924*0fca6ea1SDimitry Andric CommandObjectScriptingObjectParsed::CommandOptions::g_string_storer; 1925*0fca6ea1SDimitry Andric 19260b57cec5SDimitry Andric // CommandObjectCommandsScriptImport 19279dba64beSDimitry Andric #define LLDB_OPTIONS_script_import 19289dba64beSDimitry Andric #include "CommandOptions.inc" 19290b57cec5SDimitry Andric 19300b57cec5SDimitry Andric class CommandObjectCommandsScriptImport : public CommandObjectParsed { 19310b57cec5SDimitry Andric public: 19320b57cec5SDimitry Andric CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 19330b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "command script import", 193404eeddc0SDimitry Andric "Import a scripting module in LLDB.", nullptr) { 1935*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeFilename, eArgRepeatPlus); 19360b57cec5SDimitry Andric } 19370b57cec5SDimitry Andric 19380b57cec5SDimitry Andric ~CommandObjectCommandsScriptImport() override = default; 19390b57cec5SDimitry Andric 19400b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 19410b57cec5SDimitry Andric 19420b57cec5SDimitry Andric protected: 19430b57cec5SDimitry Andric class CommandOptions : public Options { 19440b57cec5SDimitry Andric public: 194581ad6265SDimitry Andric CommandOptions() = default; 19460b57cec5SDimitry Andric 19470b57cec5SDimitry Andric ~CommandOptions() override = default; 19480b57cec5SDimitry Andric 19490b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 19500b57cec5SDimitry Andric ExecutionContext *execution_context) override { 19510b57cec5SDimitry Andric Status error; 19520b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 19530b57cec5SDimitry Andric 19540b57cec5SDimitry Andric switch (short_option) { 19550b57cec5SDimitry Andric case 'r': 1956480093f4SDimitry Andric // NO-OP 19570b57cec5SDimitry Andric break; 1958e8d8bef9SDimitry Andric case 'c': 1959e8d8bef9SDimitry Andric relative_to_command_file = true; 1960e8d8bef9SDimitry Andric break; 1961fe6060f1SDimitry Andric case 's': 1962fe6060f1SDimitry Andric silent = true; 1963fe6060f1SDimitry Andric break; 19640b57cec5SDimitry Andric default: 19659dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 19660b57cec5SDimitry Andric } 19670b57cec5SDimitry Andric 19680b57cec5SDimitry Andric return error; 19690b57cec5SDimitry Andric } 19700b57cec5SDimitry Andric 19710b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 1972e8d8bef9SDimitry Andric relative_to_command_file = false; 19730b57cec5SDimitry Andric } 19740b57cec5SDimitry Andric 19750b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1976bdd1243dSDimitry Andric return llvm::ArrayRef(g_script_import_options); 19770b57cec5SDimitry Andric } 1978e8d8bef9SDimitry Andric bool relative_to_command_file = false; 1979fe6060f1SDimitry Andric bool silent = false; 19800b57cec5SDimitry Andric }; 19810b57cec5SDimitry Andric 19825f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 19830b57cec5SDimitry Andric if (command.empty()) { 19840b57cec5SDimitry Andric result.AppendError("command script import needs one or more arguments"); 19855f757f3fSDimitry Andric return; 19860b57cec5SDimitry Andric } 19870b57cec5SDimitry Andric 1988e8d8bef9SDimitry Andric FileSpec source_dir = {}; 1989e8d8bef9SDimitry Andric if (m_options.relative_to_command_file) { 1990e8d8bef9SDimitry Andric source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 1991e8d8bef9SDimitry Andric if (!source_dir) { 1992e8d8bef9SDimitry Andric result.AppendError("command script import -c can only be specified " 1993e8d8bef9SDimitry Andric "from a command file"); 19945f757f3fSDimitry Andric return; 1995e8d8bef9SDimitry Andric } 1996e8d8bef9SDimitry Andric } 1997e8d8bef9SDimitry Andric 19980b57cec5SDimitry Andric for (auto &entry : command.entries()) { 19990b57cec5SDimitry Andric Status error; 20000b57cec5SDimitry Andric 2001fe6060f1SDimitry Andric LoadScriptOptions options; 2002fe6060f1SDimitry Andric options.SetInitSession(true); 2003fe6060f1SDimitry Andric options.SetSilent(m_options.silent); 2004fe6060f1SDimitry Andric 20050b57cec5SDimitry Andric // FIXME: this is necessary because CommandObject::CheckRequirements() 20060b57cec5SDimitry Andric // assumes that commands won't ever be recursively invoked, but it's 20070b57cec5SDimitry Andric // actually possible to craft a Python script that does other "command 20080b57cec5SDimitry Andric // script imports" in __lldb_init_module the real fix is to have 20090b57cec5SDimitry Andric // recursive commands possible with a CommandInvocation object separate 20100b57cec5SDimitry Andric // from the CommandObject itself, so that recursive command invocations 20110b57cec5SDimitry Andric // won't stomp on each other (wrt to execution contents, options, and 20120b57cec5SDimitry Andric // more) 20130b57cec5SDimitry Andric m_exe_ctx.Clear(); 20140b57cec5SDimitry Andric if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 2015fe6060f1SDimitry Andric entry.c_str(), options, error, /*module_sp=*/nullptr, 2016fe6060f1SDimitry Andric source_dir)) { 20170b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 20180b57cec5SDimitry Andric } else { 20190b57cec5SDimitry Andric result.AppendErrorWithFormat("module importing failed: %s", 20200b57cec5SDimitry Andric error.AsCString()); 20210b57cec5SDimitry Andric } 20220b57cec5SDimitry Andric } 20230b57cec5SDimitry Andric } 20240b57cec5SDimitry Andric 20250b57cec5SDimitry Andric CommandOptions m_options; 20260b57cec5SDimitry Andric }; 20270b57cec5SDimitry Andric 20289dba64beSDimitry Andric #define LLDB_OPTIONS_script_add 20299dba64beSDimitry Andric #include "CommandOptions.inc" 20300b57cec5SDimitry Andric 20310b57cec5SDimitry Andric class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 20320b57cec5SDimitry Andric public IOHandlerDelegateMultiline { 20330b57cec5SDimitry Andric public: 20340b57cec5SDimitry Andric CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 20350b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "command script add", 20360b57cec5SDimitry Andric "Add a scripted function as an LLDB command.", 2037349cc55cSDimitry Andric "Add a scripted function as an lldb command. " 2038349cc55cSDimitry Andric "If you provide a single argument, the command " 2039349cc55cSDimitry Andric "will be added at the root level of the command " 2040349cc55cSDimitry Andric "hierarchy. If there are more arguments they " 2041349cc55cSDimitry Andric "must be a path to a user-added container " 2042349cc55cSDimitry Andric "command, and the last element will be the new " 2043349cc55cSDimitry Andric "command name."), 204404eeddc0SDimitry Andric IOHandlerDelegateMultiline("DONE") { 2045*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); 20460b57cec5SDimitry Andric } 20470b57cec5SDimitry Andric 20480b57cec5SDimitry Andric ~CommandObjectCommandsScriptAdd() override = default; 20490b57cec5SDimitry Andric 20500b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 20510b57cec5SDimitry Andric 2052349cc55cSDimitry Andric void 2053349cc55cSDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 2054349cc55cSDimitry Andric OptionElementVector &opt_element_vector) override { 2055349cc55cSDimitry Andric CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request, 2056349cc55cSDimitry Andric opt_element_vector); 2057349cc55cSDimitry Andric } 2058349cc55cSDimitry Andric 20590b57cec5SDimitry Andric protected: 20600b57cec5SDimitry Andric class CommandOptions : public Options { 20610b57cec5SDimitry Andric public: 206281ad6265SDimitry Andric CommandOptions() = default; 20630b57cec5SDimitry Andric 20640b57cec5SDimitry Andric ~CommandOptions() override = default; 20650b57cec5SDimitry Andric 20660b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 20670b57cec5SDimitry Andric ExecutionContext *execution_context) override { 20680b57cec5SDimitry Andric Status error; 20690b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 20700b57cec5SDimitry Andric 20710b57cec5SDimitry Andric switch (short_option) { 20720b57cec5SDimitry Andric case 'f': 20730b57cec5SDimitry Andric if (!option_arg.empty()) 20745ffd83dbSDimitry Andric m_funct_name = std::string(option_arg); 20750b57cec5SDimitry Andric break; 20760b57cec5SDimitry Andric case 'c': 20770b57cec5SDimitry Andric if (!option_arg.empty()) 20785ffd83dbSDimitry Andric m_class_name = std::string(option_arg); 20790b57cec5SDimitry Andric break; 20800b57cec5SDimitry Andric case 'h': 20810b57cec5SDimitry Andric if (!option_arg.empty()) 20825ffd83dbSDimitry Andric m_short_help = std::string(option_arg); 20830b57cec5SDimitry Andric break; 2084349cc55cSDimitry Andric case 'o': 208581ad6265SDimitry Andric m_overwrite_lazy = eLazyBoolYes; 2086349cc55cSDimitry Andric break; 2087*0fca6ea1SDimitry Andric case 'p': 2088*0fca6ea1SDimitry Andric m_parsed_command = true; 2089*0fca6ea1SDimitry Andric break; 20900b57cec5SDimitry Andric case 's': 20910b57cec5SDimitry Andric m_synchronicity = 20920b57cec5SDimitry Andric (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 20930b57cec5SDimitry Andric option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 20940b57cec5SDimitry Andric if (!error.Success()) 20950b57cec5SDimitry Andric error.SetErrorStringWithFormat( 20960b57cec5SDimitry Andric "unrecognized value for synchronicity '%s'", 20970b57cec5SDimitry Andric option_arg.str().c_str()); 20980b57cec5SDimitry Andric break; 209906c3fb27SDimitry Andric case 'C': { 210006c3fb27SDimitry Andric Status error; 210106c3fb27SDimitry Andric OptionDefinition definition = GetDefinitions()[option_idx]; 210206c3fb27SDimitry Andric lldb::CompletionType completion_type = 210306c3fb27SDimitry Andric static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum( 210406c3fb27SDimitry Andric option_arg, definition.enum_values, eNoCompletion, error)); 210506c3fb27SDimitry Andric if (!error.Success()) 210606c3fb27SDimitry Andric error.SetErrorStringWithFormat( 210706c3fb27SDimitry Andric "unrecognized value for command completion type '%s'", 210806c3fb27SDimitry Andric option_arg.str().c_str()); 210906c3fb27SDimitry Andric m_completion_type = completion_type; 211006c3fb27SDimitry Andric } break; 21110b57cec5SDimitry Andric default: 21129dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 21130b57cec5SDimitry Andric } 21140b57cec5SDimitry Andric 21150b57cec5SDimitry Andric return error; 21160b57cec5SDimitry Andric } 21170b57cec5SDimitry Andric 21180b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 21190b57cec5SDimitry Andric m_class_name.clear(); 21200b57cec5SDimitry Andric m_funct_name.clear(); 21210b57cec5SDimitry Andric m_short_help.clear(); 212206c3fb27SDimitry Andric m_completion_type = eNoCompletion; 212381ad6265SDimitry Andric m_overwrite_lazy = eLazyBoolCalculate; 21240b57cec5SDimitry Andric m_synchronicity = eScriptedCommandSynchronicitySynchronous; 2125*0fca6ea1SDimitry Andric m_parsed_command = false; 21260b57cec5SDimitry Andric } 21270b57cec5SDimitry Andric 21280b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2129bdd1243dSDimitry Andric return llvm::ArrayRef(g_script_add_options); 21300b57cec5SDimitry Andric } 21310b57cec5SDimitry Andric 21320b57cec5SDimitry Andric // Instance variables to hold the values for command options. 21330b57cec5SDimitry Andric 21340b57cec5SDimitry Andric std::string m_class_name; 21350b57cec5SDimitry Andric std::string m_funct_name; 21360b57cec5SDimitry Andric std::string m_short_help; 213781ad6265SDimitry Andric LazyBool m_overwrite_lazy = eLazyBoolCalculate; 2138fe6060f1SDimitry Andric ScriptedCommandSynchronicity m_synchronicity = 2139fe6060f1SDimitry Andric eScriptedCommandSynchronicitySynchronous; 214006c3fb27SDimitry Andric CompletionType m_completion_type = eNoCompletion; 2141*0fca6ea1SDimitry Andric bool m_parsed_command = false; 21420b57cec5SDimitry Andric }; 21430b57cec5SDimitry Andric 21440b57cec5SDimitry Andric void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 21459dba64beSDimitry Andric StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 21460b57cec5SDimitry Andric if (output_sp && interactive) { 21470b57cec5SDimitry Andric output_sp->PutCString(g_python_command_instructions); 21480b57cec5SDimitry Andric output_sp->Flush(); 21490b57cec5SDimitry Andric } 21500b57cec5SDimitry Andric } 21510b57cec5SDimitry Andric 21520b57cec5SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler, 21530b57cec5SDimitry Andric std::string &data) override { 21549dba64beSDimitry Andric StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); 21550b57cec5SDimitry Andric 21560b57cec5SDimitry Andric ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 21570b57cec5SDimitry Andric if (interpreter) { 21580b57cec5SDimitry Andric StringList lines; 21590b57cec5SDimitry Andric lines.SplitIntoLines(data); 21600b57cec5SDimitry Andric if (lines.GetSize() > 0) { 21610b57cec5SDimitry Andric std::string funct_name_str; 21620b57cec5SDimitry Andric if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 21630b57cec5SDimitry Andric if (funct_name_str.empty()) { 21640b57cec5SDimitry Andric error_sp->Printf("error: unable to obtain a function name, didn't " 21650b57cec5SDimitry Andric "add python command.\n"); 21660b57cec5SDimitry Andric error_sp->Flush(); 21670b57cec5SDimitry Andric } else { 21680b57cec5SDimitry Andric // everything should be fine now, let's add this alias 21690b57cec5SDimitry Andric 21700b57cec5SDimitry Andric CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 21710b57cec5SDimitry Andric m_interpreter, m_cmd_name, funct_name_str, m_short_help, 217206c3fb27SDimitry Andric m_synchronicity, m_completion_type)); 2173349cc55cSDimitry Andric if (!m_container) { 2174349cc55cSDimitry Andric Status error = m_interpreter.AddUserCommand( 2175349cc55cSDimitry Andric m_cmd_name, command_obj_sp, m_overwrite); 2176349cc55cSDimitry Andric if (error.Fail()) { 2177349cc55cSDimitry Andric error_sp->Printf("error: unable to add selected command: '%s'", 2178349cc55cSDimitry Andric error.AsCString()); 21790b57cec5SDimitry Andric error_sp->Flush(); 21800b57cec5SDimitry Andric } 2181349cc55cSDimitry Andric } else { 2182349cc55cSDimitry Andric llvm::Error llvm_error = m_container->LoadUserSubcommand( 2183349cc55cSDimitry Andric m_cmd_name, command_obj_sp, m_overwrite); 2184349cc55cSDimitry Andric if (llvm_error) { 2185349cc55cSDimitry Andric error_sp->Printf("error: unable to add selected command: '%s'", 2186349cc55cSDimitry Andric llvm::toString(std::move(llvm_error)).c_str()); 2187349cc55cSDimitry Andric error_sp->Flush(); 2188349cc55cSDimitry Andric } 2189349cc55cSDimitry Andric } 21900b57cec5SDimitry Andric } 21910b57cec5SDimitry Andric } else { 21920b57cec5SDimitry Andric error_sp->Printf( 2193349cc55cSDimitry Andric "error: unable to create function, didn't add python command\n"); 21940b57cec5SDimitry Andric error_sp->Flush(); 21950b57cec5SDimitry Andric } 21960b57cec5SDimitry Andric } else { 2197349cc55cSDimitry Andric error_sp->Printf("error: empty function, didn't add python command\n"); 21980b57cec5SDimitry Andric error_sp->Flush(); 21990b57cec5SDimitry Andric } 22000b57cec5SDimitry Andric } else { 22010b57cec5SDimitry Andric error_sp->Printf( 2202349cc55cSDimitry Andric "error: script interpreter missing, didn't add python command\n"); 22030b57cec5SDimitry Andric error_sp->Flush(); 22040b57cec5SDimitry Andric } 22050b57cec5SDimitry Andric 22060b57cec5SDimitry Andric io_handler.SetIsDone(true); 22070b57cec5SDimitry Andric } 22080b57cec5SDimitry Andric 22095f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 22100b57cec5SDimitry Andric if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 22110b57cec5SDimitry Andric result.AppendError("only scripting language supported for scripted " 22120b57cec5SDimitry Andric "commands is currently Python"); 22135f757f3fSDimitry Andric return; 22140b57cec5SDimitry Andric } 22150b57cec5SDimitry Andric 2216349cc55cSDimitry Andric if (command.GetArgumentCount() == 0) { 2217349cc55cSDimitry Andric result.AppendError("'command script add' requires at least one argument"); 22185f757f3fSDimitry Andric return; 2219349cc55cSDimitry Andric } 222081ad6265SDimitry Andric // Store the options in case we get multi-line input, also figure out the 222181ad6265SDimitry Andric // default if not user supplied: 222281ad6265SDimitry Andric switch (m_options.m_overwrite_lazy) { 222381ad6265SDimitry Andric case eLazyBoolCalculate: 222481ad6265SDimitry Andric m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite(); 222581ad6265SDimitry Andric break; 222681ad6265SDimitry Andric case eLazyBoolYes: 222781ad6265SDimitry Andric m_overwrite = true; 222881ad6265SDimitry Andric break; 222981ad6265SDimitry Andric case eLazyBoolNo: 223081ad6265SDimitry Andric m_overwrite = false; 223181ad6265SDimitry Andric } 223281ad6265SDimitry Andric 2233349cc55cSDimitry Andric Status path_error; 2234349cc55cSDimitry Andric m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath( 2235349cc55cSDimitry Andric command, true, path_error); 2236349cc55cSDimitry Andric 2237349cc55cSDimitry Andric if (path_error.Fail()) { 2238349cc55cSDimitry Andric result.AppendErrorWithFormat("error in command path: %s", 2239349cc55cSDimitry Andric path_error.AsCString()); 22405f757f3fSDimitry Andric return; 22410b57cec5SDimitry Andric } 22420b57cec5SDimitry Andric 2243349cc55cSDimitry Andric if (!m_container) { 2244349cc55cSDimitry Andric // This is getting inserted into the root of the interpreter. 22455ffd83dbSDimitry Andric m_cmd_name = std::string(command[0].ref()); 2246349cc55cSDimitry Andric } else { 2247349cc55cSDimitry Andric size_t num_args = command.GetArgumentCount(); 2248349cc55cSDimitry Andric m_cmd_name = std::string(command[num_args - 1].ref()); 2249349cc55cSDimitry Andric } 2250349cc55cSDimitry Andric 22510b57cec5SDimitry Andric m_short_help.assign(m_options.m_short_help); 22520b57cec5SDimitry Andric m_synchronicity = m_options.m_synchronicity; 225306c3fb27SDimitry Andric m_completion_type = m_options.m_completion_type; 22540b57cec5SDimitry Andric 2255349cc55cSDimitry Andric // Handle the case where we prompt for the script code first: 2256349cc55cSDimitry Andric if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) { 2257349cc55cSDimitry Andric m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt 2258480093f4SDimitry Andric *this); // IOHandlerDelegate 22595f757f3fSDimitry Andric return; 2260349cc55cSDimitry Andric } 2261349cc55cSDimitry Andric 2262349cc55cSDimitry Andric CommandObjectSP new_cmd_sp; 2263349cc55cSDimitry Andric if (m_options.m_class_name.empty()) { 2264349cc55cSDimitry Andric new_cmd_sp.reset(new CommandObjectPythonFunction( 22650b57cec5SDimitry Andric m_interpreter, m_cmd_name, m_options.m_funct_name, 226606c3fb27SDimitry Andric m_options.m_short_help, m_synchronicity, m_completion_type)); 22670b57cec5SDimitry Andric } else { 22680b57cec5SDimitry Andric ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 22690b57cec5SDimitry Andric if (!interpreter) { 22700b57cec5SDimitry Andric result.AppendError("cannot find ScriptInterpreter"); 22715f757f3fSDimitry Andric return; 22720b57cec5SDimitry Andric } 22730b57cec5SDimitry Andric 22740b57cec5SDimitry Andric auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 22750b57cec5SDimitry Andric m_options.m_class_name.c_str()); 22760b57cec5SDimitry Andric if (!cmd_obj_sp) { 227706c3fb27SDimitry Andric result.AppendErrorWithFormatv("cannot create helper object for: " 227806c3fb27SDimitry Andric "'{0}'", m_options.m_class_name); 22795f757f3fSDimitry Andric return; 22800b57cec5SDimitry Andric } 22810b57cec5SDimitry Andric 2282*0fca6ea1SDimitry Andric if (m_options.m_parsed_command) { 2283*0fca6ea1SDimitry Andric new_cmd_sp = CommandObjectScriptingObjectParsed::Create(m_interpreter, 2284*0fca6ea1SDimitry Andric m_cmd_name, cmd_obj_sp, m_synchronicity, result); 2285*0fca6ea1SDimitry Andric if (!result.Succeeded()) 2286*0fca6ea1SDimitry Andric return; 2287*0fca6ea1SDimitry Andric } else 2288*0fca6ea1SDimitry Andric new_cmd_sp.reset(new CommandObjectScriptingObjectRaw( 228906c3fb27SDimitry Andric m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity, 229006c3fb27SDimitry Andric m_completion_type)); 22910b57cec5SDimitry Andric } 22920b57cec5SDimitry Andric 2293349cc55cSDimitry Andric // Assume we're going to succeed... 2294349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 2295349cc55cSDimitry Andric if (!m_container) { 2296349cc55cSDimitry Andric Status add_error = 2297349cc55cSDimitry Andric m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite); 2298349cc55cSDimitry Andric if (add_error.Fail()) 2299349cc55cSDimitry Andric result.AppendErrorWithFormat("cannot add command: %s", 2300349cc55cSDimitry Andric add_error.AsCString()); 2301349cc55cSDimitry Andric } else { 2302349cc55cSDimitry Andric llvm::Error llvm_error = 2303349cc55cSDimitry Andric m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite); 2304349cc55cSDimitry Andric if (llvm_error) 2305*0fca6ea1SDimitry Andric result.AppendErrorWithFormat( 2306*0fca6ea1SDimitry Andric "cannot add command: %s", 2307349cc55cSDimitry Andric llvm::toString(std::move(llvm_error)).c_str()); 2308349cc55cSDimitry Andric } 23090b57cec5SDimitry Andric } 23100b57cec5SDimitry Andric 23110b57cec5SDimitry Andric CommandOptions m_options; 23120b57cec5SDimitry Andric std::string m_cmd_name; 2313349cc55cSDimitry Andric CommandObjectMultiword *m_container = nullptr; 23140b57cec5SDimitry Andric std::string m_short_help; 231581ad6265SDimitry Andric bool m_overwrite = false; 231681ad6265SDimitry Andric ScriptedCommandSynchronicity m_synchronicity = 231781ad6265SDimitry Andric eScriptedCommandSynchronicitySynchronous; 231806c3fb27SDimitry Andric CompletionType m_completion_type = eNoCompletion; 23190b57cec5SDimitry Andric }; 23200b57cec5SDimitry Andric 23210b57cec5SDimitry Andric // CommandObjectCommandsScriptList 23220b57cec5SDimitry Andric 23230b57cec5SDimitry Andric class CommandObjectCommandsScriptList : public CommandObjectParsed { 23240b57cec5SDimitry Andric public: 23250b57cec5SDimitry Andric CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 23260b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "command script list", 2327349cc55cSDimitry Andric "List defined top-level scripted commands.", 2328349cc55cSDimitry Andric nullptr) {} 23290b57cec5SDimitry Andric 23300b57cec5SDimitry Andric ~CommandObjectCommandsScriptList() override = default; 23310b57cec5SDimitry Andric 23325f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 23330b57cec5SDimitry Andric m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 23340b57cec5SDimitry Andric 23350b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 23360b57cec5SDimitry Andric } 23370b57cec5SDimitry Andric }; 23380b57cec5SDimitry Andric 23390b57cec5SDimitry Andric // CommandObjectCommandsScriptClear 23400b57cec5SDimitry Andric 23410b57cec5SDimitry Andric class CommandObjectCommandsScriptClear : public CommandObjectParsed { 23420b57cec5SDimitry Andric public: 23430b57cec5SDimitry Andric CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 23440b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "command script clear", 23450b57cec5SDimitry Andric "Delete all scripted commands.", nullptr) {} 23460b57cec5SDimitry Andric 23470b57cec5SDimitry Andric ~CommandObjectCommandsScriptClear() override = default; 23480b57cec5SDimitry Andric 23490b57cec5SDimitry Andric protected: 23505f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 23510b57cec5SDimitry Andric m_interpreter.RemoveAllUser(); 23520b57cec5SDimitry Andric 23530b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 23540b57cec5SDimitry Andric } 23550b57cec5SDimitry Andric }; 23560b57cec5SDimitry Andric 23570b57cec5SDimitry Andric // CommandObjectCommandsScriptDelete 23580b57cec5SDimitry Andric 23590b57cec5SDimitry Andric class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 23600b57cec5SDimitry Andric public: 23610b57cec5SDimitry Andric CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 2362349cc55cSDimitry Andric : CommandObjectParsed( 2363349cc55cSDimitry Andric interpreter, "command script delete", 2364349cc55cSDimitry Andric "Delete a scripted command by specifying the path to the command.", 2365349cc55cSDimitry Andric nullptr) { 2366*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); 23670b57cec5SDimitry Andric } 23680b57cec5SDimitry Andric 23690b57cec5SDimitry Andric ~CommandObjectCommandsScriptDelete() override = default; 23700b57cec5SDimitry Andric 23715ffd83dbSDimitry Andric void 23725ffd83dbSDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 23735ffd83dbSDimitry Andric OptionElementVector &opt_element_vector) override { 237406c3fb27SDimitry Andric lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 237506c3fb27SDimitry Andric m_interpreter, request, opt_element_vector); 23765ffd83dbSDimitry Andric } 23775ffd83dbSDimitry Andric 23780b57cec5SDimitry Andric protected: 23795f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 23800b57cec5SDimitry Andric 2381349cc55cSDimitry Andric llvm::StringRef root_cmd = command[0].ref(); 2382349cc55cSDimitry Andric size_t num_args = command.GetArgumentCount(); 2383349cc55cSDimitry Andric 2384349cc55cSDimitry Andric if (root_cmd.empty()) { 2385349cc55cSDimitry Andric result.AppendErrorWithFormat("empty root command name"); 23865f757f3fSDimitry Andric return; 2387349cc55cSDimitry Andric } 2388349cc55cSDimitry Andric if (!m_interpreter.HasUserCommands() && 2389349cc55cSDimitry Andric !m_interpreter.HasUserMultiwordCommands()) { 2390349cc55cSDimitry Andric result.AppendErrorWithFormat("can only delete user defined commands, " 2391349cc55cSDimitry Andric "but no user defined commands found"); 23925f757f3fSDimitry Andric return; 23930b57cec5SDimitry Andric } 23940b57cec5SDimitry Andric 2395349cc55cSDimitry Andric CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd); 2396349cc55cSDimitry Andric if (!cmd_sp) { 2397349cc55cSDimitry Andric result.AppendErrorWithFormat("command '%s' not found.", 2398349cc55cSDimitry Andric command[0].c_str()); 23995f757f3fSDimitry Andric return; 2400349cc55cSDimitry Andric } 2401349cc55cSDimitry Andric if (!cmd_sp->IsUserCommand()) { 2402349cc55cSDimitry Andric result.AppendErrorWithFormat("command '%s' is not a user command.", 2403349cc55cSDimitry Andric command[0].c_str()); 24045f757f3fSDimitry Andric return; 2405349cc55cSDimitry Andric } 2406349cc55cSDimitry Andric if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) { 2407349cc55cSDimitry Andric result.AppendErrorWithFormat("command '%s' is a multi-word command.\n " 2408349cc55cSDimitry Andric "Delete with \"command container delete\"", 2409349cc55cSDimitry Andric command[0].c_str()); 24105f757f3fSDimitry Andric return; 24110b57cec5SDimitry Andric } 24120b57cec5SDimitry Andric 2413349cc55cSDimitry Andric if (command.GetArgumentCount() == 1) { 2414349cc55cSDimitry Andric m_interpreter.RemoveUser(root_cmd); 2415349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 24165f757f3fSDimitry Andric return; 2417349cc55cSDimitry Andric } 2418349cc55cSDimitry Andric // We're deleting a command from a multiword command. Verify the command 2419349cc55cSDimitry Andric // path: 2420349cc55cSDimitry Andric Status error; 2421349cc55cSDimitry Andric CommandObjectMultiword *container = 2422349cc55cSDimitry Andric GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2423349cc55cSDimitry Andric error); 2424349cc55cSDimitry Andric if (error.Fail()) { 2425349cc55cSDimitry Andric result.AppendErrorWithFormat("could not resolve command path: %s", 2426349cc55cSDimitry Andric error.AsCString()); 24275f757f3fSDimitry Andric return; 2428349cc55cSDimitry Andric } 2429349cc55cSDimitry Andric if (!container) { 2430349cc55cSDimitry Andric // This means that command only had a leaf command, so the container is 2431349cc55cSDimitry Andric // the root. That should have been handled above. 2432349cc55cSDimitry Andric result.AppendErrorWithFormat("could not find a container for '%s'", 2433349cc55cSDimitry Andric command[0].c_str()); 24345f757f3fSDimitry Andric return; 2435349cc55cSDimitry Andric } 2436349cc55cSDimitry Andric const char *leaf_cmd = command[num_args - 1].c_str(); 2437*0fca6ea1SDimitry Andric llvm::Error llvm_error = 2438*0fca6ea1SDimitry Andric container->RemoveUserSubcommand(leaf_cmd, 2439349cc55cSDimitry Andric /* multiword not okay */ false); 2440349cc55cSDimitry Andric if (llvm_error) { 2441*0fca6ea1SDimitry Andric result.AppendErrorWithFormat( 2442*0fca6ea1SDimitry Andric "could not delete command '%s': %s", leaf_cmd, 2443349cc55cSDimitry Andric llvm::toString(std::move(llvm_error)).c_str()); 24445f757f3fSDimitry Andric return; 2445349cc55cSDimitry Andric } 2446349cc55cSDimitry Andric 2447349cc55cSDimitry Andric Stream &out_stream = result.GetOutputStream(); 2448349cc55cSDimitry Andric 2449349cc55cSDimitry Andric out_stream << "Deleted command:"; 2450349cc55cSDimitry Andric for (size_t idx = 0; idx < num_args; idx++) { 2451349cc55cSDimitry Andric out_stream << ' '; 2452349cc55cSDimitry Andric out_stream << command[idx].c_str(); 2453349cc55cSDimitry Andric } 2454349cc55cSDimitry Andric out_stream << '\n'; 24550b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 24560b57cec5SDimitry Andric } 24570b57cec5SDimitry Andric }; 24580b57cec5SDimitry Andric 24590b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordCommandsScript 24600b57cec5SDimitry Andric 24610b57cec5SDimitry Andric // CommandObjectMultiwordCommandsScript 24620b57cec5SDimitry Andric 24630b57cec5SDimitry Andric class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 24640b57cec5SDimitry Andric public: 24650b57cec5SDimitry Andric CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 24660b57cec5SDimitry Andric : CommandObjectMultiword( 2467480093f4SDimitry Andric interpreter, "command script", 2468480093f4SDimitry Andric "Commands for managing custom " 24690b57cec5SDimitry Andric "commands implemented by " 24700b57cec5SDimitry Andric "interpreter scripts.", 24710b57cec5SDimitry Andric "command script <subcommand> [<subcommand-options>]") { 24720b57cec5SDimitry Andric LoadSubCommand("add", CommandObjectSP( 24730b57cec5SDimitry Andric new CommandObjectCommandsScriptAdd(interpreter))); 24740b57cec5SDimitry Andric LoadSubCommand( 24750b57cec5SDimitry Andric "delete", 24760b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 24770b57cec5SDimitry Andric LoadSubCommand( 24780b57cec5SDimitry Andric "clear", 24790b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 24800b57cec5SDimitry Andric LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 24810b57cec5SDimitry Andric interpreter))); 24820b57cec5SDimitry Andric LoadSubCommand( 24830b57cec5SDimitry Andric "import", 24840b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 24850b57cec5SDimitry Andric } 24860b57cec5SDimitry Andric 24870b57cec5SDimitry Andric ~CommandObjectMultiwordCommandsScript() override = default; 24880b57cec5SDimitry Andric }; 24890b57cec5SDimitry Andric 2490349cc55cSDimitry Andric #pragma mark CommandObjectCommandContainer 2491349cc55cSDimitry Andric #define LLDB_OPTIONS_container_add 2492349cc55cSDimitry Andric #include "CommandOptions.inc" 2493349cc55cSDimitry Andric 2494349cc55cSDimitry Andric class CommandObjectCommandsContainerAdd : public CommandObjectParsed { 2495349cc55cSDimitry Andric public: 2496349cc55cSDimitry Andric CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter) 2497349cc55cSDimitry Andric : CommandObjectParsed( 2498349cc55cSDimitry Andric interpreter, "command container add", 2499349cc55cSDimitry Andric "Add a container command to lldb. Adding to built-" 2500349cc55cSDimitry Andric "in container commands is not allowed.", 2501349cc55cSDimitry Andric "command container add [[path1]...] container-name") { 2502*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); 2503349cc55cSDimitry Andric } 2504349cc55cSDimitry Andric 2505349cc55cSDimitry Andric ~CommandObjectCommandsContainerAdd() override = default; 2506349cc55cSDimitry Andric 2507349cc55cSDimitry Andric Options *GetOptions() override { return &m_options; } 2508349cc55cSDimitry Andric 2509349cc55cSDimitry Andric void 2510349cc55cSDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 2511349cc55cSDimitry Andric OptionElementVector &opt_element_vector) override { 251206c3fb27SDimitry Andric lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 251306c3fb27SDimitry Andric m_interpreter, request, opt_element_vector); 2514349cc55cSDimitry Andric } 2515349cc55cSDimitry Andric 2516349cc55cSDimitry Andric protected: 2517349cc55cSDimitry Andric class CommandOptions : public Options { 2518349cc55cSDimitry Andric public: 251981ad6265SDimitry Andric CommandOptions() = default; 2520349cc55cSDimitry Andric 2521349cc55cSDimitry Andric ~CommandOptions() override = default; 2522349cc55cSDimitry Andric 2523349cc55cSDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2524349cc55cSDimitry Andric ExecutionContext *execution_context) override { 2525349cc55cSDimitry Andric Status error; 2526349cc55cSDimitry Andric const int short_option = m_getopt_table[option_idx].val; 2527349cc55cSDimitry Andric 2528349cc55cSDimitry Andric switch (short_option) { 2529349cc55cSDimitry Andric case 'h': 2530349cc55cSDimitry Andric if (!option_arg.empty()) 2531349cc55cSDimitry Andric m_short_help = std::string(option_arg); 2532349cc55cSDimitry Andric break; 2533349cc55cSDimitry Andric case 'o': 2534349cc55cSDimitry Andric m_overwrite = true; 2535349cc55cSDimitry Andric break; 2536349cc55cSDimitry Andric case 'H': 2537349cc55cSDimitry Andric if (!option_arg.empty()) 2538349cc55cSDimitry Andric m_long_help = std::string(option_arg); 2539349cc55cSDimitry Andric break; 2540349cc55cSDimitry Andric default: 2541349cc55cSDimitry Andric llvm_unreachable("Unimplemented option"); 2542349cc55cSDimitry Andric } 2543349cc55cSDimitry Andric 2544349cc55cSDimitry Andric return error; 2545349cc55cSDimitry Andric } 2546349cc55cSDimitry Andric 2547349cc55cSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 2548349cc55cSDimitry Andric m_short_help.clear(); 2549349cc55cSDimitry Andric m_long_help.clear(); 2550349cc55cSDimitry Andric m_overwrite = false; 2551349cc55cSDimitry Andric } 2552349cc55cSDimitry Andric 2553349cc55cSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2554bdd1243dSDimitry Andric return llvm::ArrayRef(g_container_add_options); 2555349cc55cSDimitry Andric } 2556349cc55cSDimitry Andric 2557349cc55cSDimitry Andric // Instance variables to hold the values for command options. 2558349cc55cSDimitry Andric 2559349cc55cSDimitry Andric std::string m_short_help; 2560349cc55cSDimitry Andric std::string m_long_help; 2561349cc55cSDimitry Andric bool m_overwrite = false; 2562349cc55cSDimitry Andric }; 25635f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 2564349cc55cSDimitry Andric size_t num_args = command.GetArgumentCount(); 2565349cc55cSDimitry Andric 2566349cc55cSDimitry Andric if (num_args == 0) { 2567349cc55cSDimitry Andric result.AppendError("no command was specified"); 25685f757f3fSDimitry Andric return; 2569349cc55cSDimitry Andric } 2570349cc55cSDimitry Andric 2571349cc55cSDimitry Andric if (num_args == 1) { 2572349cc55cSDimitry Andric // We're adding this as a root command, so use the interpreter. 2573349cc55cSDimitry Andric const char *cmd_name = command.GetArgumentAtIndex(0); 2574349cc55cSDimitry Andric auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 2575349cc55cSDimitry Andric GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 2576349cc55cSDimitry Andric m_options.m_long_help.c_str())); 2577349cc55cSDimitry Andric cmd_sp->GetAsMultiwordCommand()->SetRemovable(true); 2578349cc55cSDimitry Andric Status add_error = GetCommandInterpreter().AddUserCommand( 2579349cc55cSDimitry Andric cmd_name, cmd_sp, m_options.m_overwrite); 2580349cc55cSDimitry Andric if (add_error.Fail()) { 2581349cc55cSDimitry Andric result.AppendErrorWithFormat("error adding command: %s", 2582349cc55cSDimitry Andric add_error.AsCString()); 25835f757f3fSDimitry Andric return; 2584349cc55cSDimitry Andric } 2585349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 25865f757f3fSDimitry Andric return; 2587349cc55cSDimitry Andric } 2588349cc55cSDimitry Andric 2589349cc55cSDimitry Andric // We're adding this to a subcommand, first find the subcommand: 2590349cc55cSDimitry Andric Status path_error; 2591349cc55cSDimitry Andric CommandObjectMultiword *add_to_me = 2592349cc55cSDimitry Andric GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2593349cc55cSDimitry Andric path_error); 2594349cc55cSDimitry Andric 2595349cc55cSDimitry Andric if (!add_to_me) { 2596349cc55cSDimitry Andric result.AppendErrorWithFormat("error adding command: %s", 2597349cc55cSDimitry Andric path_error.AsCString()); 25985f757f3fSDimitry Andric return; 2599349cc55cSDimitry Andric } 2600349cc55cSDimitry Andric 2601349cc55cSDimitry Andric const char *cmd_name = command.GetArgumentAtIndex(num_args - 1); 2602349cc55cSDimitry Andric auto cmd_sp = CommandObjectSP(new CommandObjectMultiword( 2603349cc55cSDimitry Andric GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(), 2604349cc55cSDimitry Andric m_options.m_long_help.c_str())); 2605349cc55cSDimitry Andric llvm::Error llvm_error = 2606349cc55cSDimitry Andric add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite); 2607349cc55cSDimitry Andric if (llvm_error) { 2608349cc55cSDimitry Andric result.AppendErrorWithFormat("error adding subcommand: %s", 2609349cc55cSDimitry Andric llvm::toString(std::move(llvm_error)).c_str()); 26105f757f3fSDimitry Andric return; 2611349cc55cSDimitry Andric } 2612349cc55cSDimitry Andric 2613349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 2614349cc55cSDimitry Andric } 2615349cc55cSDimitry Andric 2616349cc55cSDimitry Andric private: 2617349cc55cSDimitry Andric CommandOptions m_options; 2618349cc55cSDimitry Andric }; 2619349cc55cSDimitry Andric 2620349cc55cSDimitry Andric #define LLDB_OPTIONS_multiword_delete 2621349cc55cSDimitry Andric #include "CommandOptions.inc" 2622349cc55cSDimitry Andric class CommandObjectCommandsContainerDelete : public CommandObjectParsed { 2623349cc55cSDimitry Andric public: 2624349cc55cSDimitry Andric CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter) 2625349cc55cSDimitry Andric : CommandObjectParsed( 2626349cc55cSDimitry Andric interpreter, "command container delete", 2627349cc55cSDimitry Andric "Delete a container command previously added to " 2628349cc55cSDimitry Andric "lldb.", 2629349cc55cSDimitry Andric "command container delete [[path1] ...] container-cmd") { 2630*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); 2631349cc55cSDimitry Andric } 2632349cc55cSDimitry Andric 2633349cc55cSDimitry Andric ~CommandObjectCommandsContainerDelete() override = default; 2634349cc55cSDimitry Andric 2635349cc55cSDimitry Andric void 2636349cc55cSDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 2637349cc55cSDimitry Andric OptionElementVector &opt_element_vector) override { 263806c3fb27SDimitry Andric lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs( 263906c3fb27SDimitry Andric m_interpreter, request, opt_element_vector); 2640349cc55cSDimitry Andric } 2641349cc55cSDimitry Andric 2642349cc55cSDimitry Andric protected: 26435f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 2644349cc55cSDimitry Andric size_t num_args = command.GetArgumentCount(); 2645349cc55cSDimitry Andric 2646349cc55cSDimitry Andric if (num_args == 0) { 2647349cc55cSDimitry Andric result.AppendError("No command was specified."); 26485f757f3fSDimitry Andric return; 2649349cc55cSDimitry Andric } 2650349cc55cSDimitry Andric 2651349cc55cSDimitry Andric if (num_args == 1) { 2652349cc55cSDimitry Andric // We're removing a root command, so we need to delete it from the 2653349cc55cSDimitry Andric // interpreter. 2654349cc55cSDimitry Andric const char *cmd_name = command.GetArgumentAtIndex(0); 2655349cc55cSDimitry Andric // Let's do a little more work here so we can do better error reporting. 2656349cc55cSDimitry Andric CommandInterpreter &interp = GetCommandInterpreter(); 2657349cc55cSDimitry Andric CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name); 2658349cc55cSDimitry Andric if (!cmd_sp) { 2659349cc55cSDimitry Andric result.AppendErrorWithFormat("container command %s doesn't exist.", 2660349cc55cSDimitry Andric cmd_name); 26615f757f3fSDimitry Andric return; 2662349cc55cSDimitry Andric } 2663349cc55cSDimitry Andric if (!cmd_sp->IsUserCommand()) { 2664349cc55cSDimitry Andric result.AppendErrorWithFormat( 2665349cc55cSDimitry Andric "container command %s is not a user command", cmd_name); 26665f757f3fSDimitry Andric return; 2667349cc55cSDimitry Andric } 2668349cc55cSDimitry Andric if (!cmd_sp->GetAsMultiwordCommand()) { 2669349cc55cSDimitry Andric result.AppendErrorWithFormat("command %s is not a container command", 2670349cc55cSDimitry Andric cmd_name); 26715f757f3fSDimitry Andric return; 2672349cc55cSDimitry Andric } 2673349cc55cSDimitry Andric 2674349cc55cSDimitry Andric bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name); 2675349cc55cSDimitry Andric if (!did_remove) { 2676349cc55cSDimitry Andric result.AppendErrorWithFormat("error removing command %s.", cmd_name); 26775f757f3fSDimitry Andric return; 2678349cc55cSDimitry Andric } 2679349cc55cSDimitry Andric 2680349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 26815f757f3fSDimitry Andric return; 2682349cc55cSDimitry Andric } 2683349cc55cSDimitry Andric 2684349cc55cSDimitry Andric // We're removing a subcommand, first find the subcommand's owner: 2685349cc55cSDimitry Andric Status path_error; 2686349cc55cSDimitry Andric CommandObjectMultiword *container = 2687349cc55cSDimitry Andric GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true, 2688349cc55cSDimitry Andric path_error); 2689349cc55cSDimitry Andric 2690349cc55cSDimitry Andric if (!container) { 2691349cc55cSDimitry Andric result.AppendErrorWithFormat("error removing container command: %s", 2692349cc55cSDimitry Andric path_error.AsCString()); 26935f757f3fSDimitry Andric return; 2694349cc55cSDimitry Andric } 2695349cc55cSDimitry Andric const char *leaf = command.GetArgumentAtIndex(num_args - 1); 2696349cc55cSDimitry Andric llvm::Error llvm_error = 2697349cc55cSDimitry Andric container->RemoveUserSubcommand(leaf, /* multiword okay */ true); 2698349cc55cSDimitry Andric if (llvm_error) { 2699349cc55cSDimitry Andric result.AppendErrorWithFormat("error removing container command: %s", 2700349cc55cSDimitry Andric llvm::toString(std::move(llvm_error)).c_str()); 27015f757f3fSDimitry Andric return; 2702349cc55cSDimitry Andric } 2703349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 2704349cc55cSDimitry Andric } 2705349cc55cSDimitry Andric }; 2706349cc55cSDimitry Andric 2707349cc55cSDimitry Andric class CommandObjectCommandContainer : public CommandObjectMultiword { 2708349cc55cSDimitry Andric public: 2709349cc55cSDimitry Andric CommandObjectCommandContainer(CommandInterpreter &interpreter) 2710349cc55cSDimitry Andric : CommandObjectMultiword( 2711349cc55cSDimitry Andric interpreter, "command container", 2712349cc55cSDimitry Andric "Commands for adding container commands to lldb. " 2713349cc55cSDimitry Andric "Container commands are containers for other commands. You can " 271481ad6265SDimitry Andric "add nested container commands by specifying a command path, " 2715349cc55cSDimitry Andric "but you can't add commands into the built-in command hierarchy.", 2716349cc55cSDimitry Andric "command container <subcommand> [<subcommand-options>]") { 2717349cc55cSDimitry Andric LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd( 2718349cc55cSDimitry Andric interpreter))); 2719349cc55cSDimitry Andric LoadSubCommand( 2720349cc55cSDimitry Andric "delete", 2721349cc55cSDimitry Andric CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter))); 2722349cc55cSDimitry Andric } 2723349cc55cSDimitry Andric 2724349cc55cSDimitry Andric ~CommandObjectCommandContainer() override = default; 2725349cc55cSDimitry Andric }; 2726349cc55cSDimitry Andric 27270b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordCommands 27280b57cec5SDimitry Andric 27290b57cec5SDimitry Andric // CommandObjectMultiwordCommands 27300b57cec5SDimitry Andric 27310b57cec5SDimitry Andric CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 27320b57cec5SDimitry Andric CommandInterpreter &interpreter) 27330b57cec5SDimitry Andric : CommandObjectMultiword(interpreter, "command", 27340b57cec5SDimitry Andric "Commands for managing custom LLDB commands.", 27350b57cec5SDimitry Andric "command <subcommand> [<subcommand-options>]") { 27360b57cec5SDimitry Andric LoadSubCommand("source", 27370b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 27380b57cec5SDimitry Andric LoadSubCommand("alias", 27390b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 27400b57cec5SDimitry Andric LoadSubCommand("unalias", CommandObjectSP( 27410b57cec5SDimitry Andric new CommandObjectCommandsUnalias(interpreter))); 27420b57cec5SDimitry Andric LoadSubCommand("delete", 27430b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 2744349cc55cSDimitry Andric LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer( 2745349cc55cSDimitry Andric interpreter))); 27460b57cec5SDimitry Andric LoadSubCommand( 27470b57cec5SDimitry Andric "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 27480b57cec5SDimitry Andric LoadSubCommand( 27490b57cec5SDimitry Andric "script", 27500b57cec5SDimitry Andric CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 27510b57cec5SDimitry Andric } 27520b57cec5SDimitry Andric 27530b57cec5SDimitry Andric CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 2754