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