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 OptionDefinition g_history_options[] = { 42 // clang-format off 43 { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "How many history commands to print." }, 44 { LLDB_OPT_SET_1, false, "start-index", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)." }, 45 { LLDB_OPT_SET_1, false, "end-index", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands." }, 46 { LLDB_OPT_SET_2, false, "clear", 'C', OptionParser::eNoArgument, nullptr, 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 OptionDefinition g_source_options[] = { 201 // clang-format off 202 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on error." }, 203 { LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on continue." }, 204 { LLDB_OPT_SET_ALL, false, "silent-run", 's', OptionParser::eRequiredArgument, nullptr, 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 auto completion_str = request.GetParsedLine()[request.GetCursorIndex()].ref; 242 completion_str = completion_str.take_front(request.GetCursorCharPosition()); 243 244 bool word_complete = request.GetWordComplete(); 245 CommandCompletions::InvokeCommonCompletionCallbacks( 246 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 247 completion_str, request.GetMatchStartPoint(), 248 request.GetMaxReturnElements(), nullptr, word_complete, 249 request.GetMatches()); 250 request.SetWordComplete(word_complete); 251 return request.GetMatches().GetSize(); 252 } 253 254 Options *GetOptions() override { return &m_options; } 255 256 protected: 257 class CommandOptions : public Options { 258 public: 259 CommandOptions() 260 : Options(), m_stop_on_error(true), m_silent_run(false), 261 m_stop_on_continue(true) {} 262 263 ~CommandOptions() override = default; 264 265 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 266 ExecutionContext *execution_context) override { 267 Status error; 268 const int short_option = m_getopt_table[option_idx].val; 269 270 switch (short_option) { 271 case 'e': 272 error = m_stop_on_error.SetValueFromString(option_arg); 273 break; 274 275 case 'c': 276 error = m_stop_on_continue.SetValueFromString(option_arg); 277 break; 278 279 case 's': 280 error = m_silent_run.SetValueFromString(option_arg); 281 break; 282 283 default: 284 error.SetErrorStringWithFormat("unrecognized option '%c'", 285 short_option); 286 break; 287 } 288 289 return error; 290 } 291 292 void OptionParsingStarting(ExecutionContext *execution_context) override { 293 m_stop_on_error.Clear(); 294 m_silent_run.Clear(); 295 m_stop_on_continue.Clear(); 296 } 297 298 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 299 return llvm::makeArrayRef(g_source_options); 300 } 301 302 // Instance variables to hold the values for command options. 303 304 OptionValueBoolean m_stop_on_error; 305 OptionValueBoolean m_silent_run; 306 OptionValueBoolean m_stop_on_continue; 307 }; 308 309 bool DoExecute(Args &command, CommandReturnObject &result) override { 310 if (command.GetArgumentCount() != 1) { 311 result.AppendErrorWithFormat( 312 "'%s' takes exactly one executable filename argument.\n", 313 GetCommandName().str().c_str()); 314 result.SetStatus(eReturnStatusFailed); 315 return false; 316 } 317 318 FileSpec cmd_file(command[0].ref, true); 319 ExecutionContext *exe_ctx = nullptr; // Just use the default context. 320 321 // If any options were set, then use them 322 if (m_options.m_stop_on_error.OptionWasSet() || 323 m_options.m_silent_run.OptionWasSet() || 324 m_options.m_stop_on_continue.OptionWasSet()) { 325 // Use user set settings 326 CommandInterpreterRunOptions options; 327 options.SetStopOnContinue(m_options.m_stop_on_continue.GetCurrentValue()); 328 options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue()); 329 options.SetEchoCommands(!m_options.m_silent_run.GetCurrentValue()); 330 options.SetPrintResults(!m_options.m_silent_run.GetCurrentValue()); 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 OptionDefinition g_alias_options[] = { 351 // clang-format off 352 { LLDB_OPT_SET_ALL, false, "help", 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Help text for this command" }, 353 { LLDB_OPT_SET_ALL, false, "long-help", 'H', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Long help text for this command" }, 354 // clang-format on 355 }; 356 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 OptionDefinition g_regex_options[] = { 925 // clang-format off 926 { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "The help text to display for this command." }, 927 { LLDB_OPT_SET_1, false, "syntax", 's', OptionParser::eRequiredArgument, nullptr, 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 OptionDefinition g_script_import_options[] = { 1405 // clang-format off 1406 { LLDB_OPT_SET_1, false, "allow-reload", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not." }, 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 llvm::StringRef completion_str = 1437 request.GetParsedLine()[request.GetCursorIndex()].ref; 1438 completion_str = completion_str.take_front(request.GetCursorCharPosition()); 1439 1440 bool word_complete = request.GetWordComplete(); 1441 CommandCompletions::InvokeCommonCompletionCallbacks( 1442 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1443 completion_str, request.GetMatchStartPoint(), 1444 request.GetMaxReturnElements(), nullptr, word_complete, 1445 request.GetMatches()); 1446 request.SetWordComplete(word_complete); 1447 return request.GetMatches().GetSize(); 1448 } 1449 1450 Options *GetOptions() override { return &m_options; } 1451 1452 protected: 1453 class CommandOptions : public Options { 1454 public: 1455 CommandOptions() : Options() {} 1456 1457 ~CommandOptions() override = default; 1458 1459 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1460 ExecutionContext *execution_context) override { 1461 Status error; 1462 const int short_option = m_getopt_table[option_idx].val; 1463 1464 switch (short_option) { 1465 case 'r': 1466 m_allow_reload = true; 1467 break; 1468 default: 1469 error.SetErrorStringWithFormat("unrecognized option '%c'", 1470 short_option); 1471 break; 1472 } 1473 1474 return error; 1475 } 1476 1477 void OptionParsingStarting(ExecutionContext *execution_context) override { 1478 m_allow_reload = true; 1479 } 1480 1481 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1482 return llvm::makeArrayRef(g_script_import_options); 1483 } 1484 1485 // Instance variables to hold the values for command options. 1486 1487 bool m_allow_reload; 1488 }; 1489 1490 bool DoExecute(Args &command, CommandReturnObject &result) override { 1491 if (m_interpreter.GetDebugger().GetScriptLanguage() != 1492 lldb::eScriptLanguagePython) { 1493 result.AppendError("only scripting language supported for module " 1494 "importing is currently Python"); 1495 result.SetStatus(eReturnStatusFailed); 1496 return false; 1497 } 1498 1499 if (command.empty()) { 1500 result.AppendError("command script import needs one or more arguments"); 1501 result.SetStatus(eReturnStatusFailed); 1502 return false; 1503 } 1504 1505 for (auto &entry : command.entries()) { 1506 Status error; 1507 1508 const bool init_session = true; 1509 // FIXME: this is necessary because CommandObject::CheckRequirements() 1510 // assumes that commands won't ever be recursively invoked, but it's 1511 // actually possible to craft a Python script that does other "command 1512 // script imports" in __lldb_init_module the real fix is to have 1513 // recursive commands possible with a CommandInvocation object separate 1514 // from the CommandObject itself, so that recursive command invocations 1515 // won't stomp on each other (wrt to execution contents, options, and 1516 // more) 1517 m_exe_ctx.Clear(); 1518 if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule( 1519 entry.c_str(), m_options.m_allow_reload, init_session, error)) { 1520 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1521 } else { 1522 result.AppendErrorWithFormat("module importing failed: %s", 1523 error.AsCString()); 1524 result.SetStatus(eReturnStatusFailed); 1525 } 1526 } 1527 1528 return result.Succeeded(); 1529 } 1530 1531 CommandOptions m_options; 1532 }; 1533 1534 //------------------------------------------------------------------------- 1535 // CommandObjectCommandsScriptAdd 1536 //------------------------------------------------------------------------- 1537 1538 static OptionEnumValueElement g_script_synchro_type[] = { 1539 {eScriptedCommandSynchronicitySynchronous, "synchronous", 1540 "Run synchronous"}, 1541 {eScriptedCommandSynchronicityAsynchronous, "asynchronous", 1542 "Run asynchronous"}, 1543 {eScriptedCommandSynchronicityCurrentValue, "current", 1544 "Do not alter current setting"}, 1545 {0, nullptr, nullptr}}; 1546 1547 static OptionDefinition g_script_add_options[] = { 1548 // clang-format off 1549 { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name." }, 1550 { LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name." }, 1551 { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "The help text to display for this command." }, 1552 { LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, nullptr, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system." }, 1553 // clang-format on 1554 }; 1555 1556 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1557 public IOHandlerDelegateMultiline { 1558 public: 1559 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1560 : CommandObjectParsed(interpreter, "command script add", 1561 "Add a scripted function as an LLDB command.", 1562 nullptr), 1563 IOHandlerDelegateMultiline("DONE"), m_options() { 1564 CommandArgumentEntry arg1; 1565 CommandArgumentData cmd_arg; 1566 1567 // Define the first (and only) variant of this arg. 1568 cmd_arg.arg_type = eArgTypeCommandName; 1569 cmd_arg.arg_repetition = eArgRepeatPlain; 1570 1571 // There is only one variant this argument could be; put it into the 1572 // argument entry. 1573 arg1.push_back(cmd_arg); 1574 1575 // Push the data for the first argument into the m_arguments vector. 1576 m_arguments.push_back(arg1); 1577 } 1578 1579 ~CommandObjectCommandsScriptAdd() override = default; 1580 1581 Options *GetOptions() override { return &m_options; } 1582 1583 protected: 1584 class CommandOptions : public Options { 1585 public: 1586 CommandOptions() 1587 : Options(), m_class_name(), m_funct_name(), m_short_help(), 1588 m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} 1589 1590 ~CommandOptions() override = default; 1591 1592 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1593 ExecutionContext *execution_context) override { 1594 Status error; 1595 const int short_option = m_getopt_table[option_idx].val; 1596 1597 switch (short_option) { 1598 case 'f': 1599 if (!option_arg.empty()) 1600 m_funct_name = option_arg; 1601 break; 1602 case 'c': 1603 if (!option_arg.empty()) 1604 m_class_name = option_arg; 1605 break; 1606 case 'h': 1607 if (!option_arg.empty()) 1608 m_short_help = option_arg; 1609 break; 1610 case 's': 1611 m_synchronicity = 1612 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1613 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1614 if (!error.Success()) 1615 error.SetErrorStringWithFormat( 1616 "unrecognized value for synchronicity '%s'", 1617 option_arg.str().c_str()); 1618 break; 1619 default: 1620 error.SetErrorStringWithFormat("unrecognized option '%c'", 1621 short_option); 1622 break; 1623 } 1624 1625 return error; 1626 } 1627 1628 void OptionParsingStarting(ExecutionContext *execution_context) override { 1629 m_class_name.clear(); 1630 m_funct_name.clear(); 1631 m_short_help.clear(); 1632 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1633 } 1634 1635 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1636 return llvm::makeArrayRef(g_script_add_options); 1637 } 1638 1639 // Instance variables to hold the values for command options. 1640 1641 std::string m_class_name; 1642 std::string m_funct_name; 1643 std::string m_short_help; 1644 ScriptedCommandSynchronicity m_synchronicity; 1645 }; 1646 1647 void IOHandlerActivated(IOHandler &io_handler) override { 1648 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 1649 if (output_sp) { 1650 output_sp->PutCString(g_python_command_instructions); 1651 output_sp->Flush(); 1652 } 1653 } 1654 1655 void IOHandlerInputComplete(IOHandler &io_handler, 1656 std::string &data) override { 1657 StreamFileSP error_sp = io_handler.GetErrorStreamFile(); 1658 1659 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); 1660 if (interpreter) { 1661 1662 StringList lines; 1663 lines.SplitIntoLines(data); 1664 if (lines.GetSize() > 0) { 1665 std::string funct_name_str; 1666 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1667 if (funct_name_str.empty()) { 1668 error_sp->Printf("error: unable to obtain a function name, didn't " 1669 "add python command.\n"); 1670 error_sp->Flush(); 1671 } else { 1672 // everything should be fine now, let's add this alias 1673 1674 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1675 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1676 m_synchronicity)); 1677 1678 if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, 1679 true)) { 1680 error_sp->Printf("error: unable to add selected command, didn't " 1681 "add python command.\n"); 1682 error_sp->Flush(); 1683 } 1684 } 1685 } else { 1686 error_sp->Printf( 1687 "error: unable to create function, didn't add python command.\n"); 1688 error_sp->Flush(); 1689 } 1690 } else { 1691 error_sp->Printf("error: empty function, didn't add python command.\n"); 1692 error_sp->Flush(); 1693 } 1694 } else { 1695 error_sp->Printf( 1696 "error: script interpreter missing, didn't add python command.\n"); 1697 error_sp->Flush(); 1698 } 1699 1700 io_handler.SetIsDone(true); 1701 } 1702 1703 protected: 1704 bool DoExecute(Args &command, CommandReturnObject &result) override { 1705 if (m_interpreter.GetDebugger().GetScriptLanguage() != 1706 lldb::eScriptLanguagePython) { 1707 result.AppendError("only scripting language supported for scripted " 1708 "commands is currently Python"); 1709 result.SetStatus(eReturnStatusFailed); 1710 return false; 1711 } 1712 1713 if (command.GetArgumentCount() != 1) { 1714 result.AppendError("'command script add' requires one argument"); 1715 result.SetStatus(eReturnStatusFailed); 1716 return false; 1717 } 1718 1719 // Store the options in case we get multi-line input 1720 m_cmd_name = command[0].ref; 1721 m_short_help.assign(m_options.m_short_help); 1722 m_synchronicity = m_options.m_synchronicity; 1723 1724 if (m_options.m_class_name.empty()) { 1725 if (m_options.m_funct_name.empty()) { 1726 m_interpreter.GetPythonCommandsFromIOHandler( 1727 " ", // Prompt 1728 *this, // IOHandlerDelegate 1729 true, // Run IOHandler in async mode 1730 nullptr); // Baton for the "io_handler" that will be passed back 1731 // into our IOHandlerDelegate functions 1732 } else { 1733 CommandObjectSP new_cmd(new CommandObjectPythonFunction( 1734 m_interpreter, m_cmd_name, m_options.m_funct_name, 1735 m_options.m_short_help, m_synchronicity)); 1736 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1737 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1738 } else { 1739 result.AppendError("cannot add command"); 1740 result.SetStatus(eReturnStatusFailed); 1741 } 1742 } 1743 } else { 1744 ScriptInterpreter *interpreter = 1745 GetCommandInterpreter().GetScriptInterpreter(); 1746 if (!interpreter) { 1747 result.AppendError("cannot find ScriptInterpreter"); 1748 result.SetStatus(eReturnStatusFailed); 1749 return false; 1750 } 1751 1752 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1753 m_options.m_class_name.c_str()); 1754 if (!cmd_obj_sp) { 1755 result.AppendError("cannot create helper object"); 1756 result.SetStatus(eReturnStatusFailed); 1757 return false; 1758 } 1759 1760 CommandObjectSP new_cmd(new CommandObjectScriptingObject( 1761 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1762 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1763 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1764 } else { 1765 result.AppendError("cannot add command"); 1766 result.SetStatus(eReturnStatusFailed); 1767 } 1768 } 1769 1770 return result.Succeeded(); 1771 } 1772 1773 CommandOptions m_options; 1774 std::string m_cmd_name; 1775 std::string m_short_help; 1776 ScriptedCommandSynchronicity m_synchronicity; 1777 }; 1778 1779 //------------------------------------------------------------------------- 1780 // CommandObjectCommandsScriptList 1781 //------------------------------------------------------------------------- 1782 1783 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1784 public: 1785 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1786 : CommandObjectParsed(interpreter, "command script list", 1787 "List defined scripted commands.", nullptr) {} 1788 1789 ~CommandObjectCommandsScriptList() override = default; 1790 1791 bool DoExecute(Args &command, CommandReturnObject &result) override { 1792 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1793 1794 result.SetStatus(eReturnStatusSuccessFinishResult); 1795 1796 return true; 1797 } 1798 }; 1799 1800 //------------------------------------------------------------------------- 1801 // CommandObjectCommandsScriptClear 1802 //------------------------------------------------------------------------- 1803 1804 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1805 public: 1806 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1807 : CommandObjectParsed(interpreter, "command script clear", 1808 "Delete all scripted commands.", nullptr) {} 1809 1810 ~CommandObjectCommandsScriptClear() override = default; 1811 1812 protected: 1813 bool DoExecute(Args &command, CommandReturnObject &result) override { 1814 m_interpreter.RemoveAllUser(); 1815 1816 result.SetStatus(eReturnStatusSuccessFinishResult); 1817 1818 return true; 1819 } 1820 }; 1821 1822 //------------------------------------------------------------------------- 1823 // CommandObjectCommandsScriptDelete 1824 //------------------------------------------------------------------------- 1825 1826 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1827 public: 1828 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1829 : CommandObjectParsed(interpreter, "command script delete", 1830 "Delete a scripted command.", nullptr) { 1831 CommandArgumentEntry arg1; 1832 CommandArgumentData cmd_arg; 1833 1834 // Define the first (and only) variant of this arg. 1835 cmd_arg.arg_type = eArgTypeCommandName; 1836 cmd_arg.arg_repetition = eArgRepeatPlain; 1837 1838 // There is only one variant this argument could be; put it into the 1839 // argument entry. 1840 arg1.push_back(cmd_arg); 1841 1842 // Push the data for the first argument into the m_arguments vector. 1843 m_arguments.push_back(arg1); 1844 } 1845 1846 ~CommandObjectCommandsScriptDelete() override = default; 1847 1848 protected: 1849 bool DoExecute(Args &command, CommandReturnObject &result) override { 1850 1851 if (command.GetArgumentCount() != 1) { 1852 result.AppendError("'command script delete' requires one argument"); 1853 result.SetStatus(eReturnStatusFailed); 1854 return false; 1855 } 1856 1857 auto cmd_name = command[0].ref; 1858 1859 if (cmd_name.empty() || !m_interpreter.HasUserCommands() || 1860 !m_interpreter.UserCommandExists(cmd_name)) { 1861 result.AppendErrorWithFormat("command %s not found", command[0].c_str()); 1862 result.SetStatus(eReturnStatusFailed); 1863 return false; 1864 } 1865 1866 m_interpreter.RemoveUser(cmd_name); 1867 result.SetStatus(eReturnStatusSuccessFinishResult); 1868 return true; 1869 } 1870 }; 1871 1872 #pragma mark CommandObjectMultiwordCommandsScript 1873 1874 //------------------------------------------------------------------------- 1875 // CommandObjectMultiwordCommandsScript 1876 //------------------------------------------------------------------------- 1877 1878 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1879 public: 1880 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1881 : CommandObjectMultiword( 1882 interpreter, "command script", "Commands for managing custom " 1883 "commands implemented by " 1884 "interpreter scripts.", 1885 "command script <subcommand> [<subcommand-options>]") { 1886 LoadSubCommand("add", CommandObjectSP( 1887 new CommandObjectCommandsScriptAdd(interpreter))); 1888 LoadSubCommand( 1889 "delete", 1890 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1891 LoadSubCommand( 1892 "clear", 1893 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1894 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1895 interpreter))); 1896 LoadSubCommand( 1897 "import", 1898 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1899 } 1900 1901 ~CommandObjectMultiwordCommandsScript() override = default; 1902 }; 1903 1904 #pragma mark CommandObjectMultiwordCommands 1905 1906 //------------------------------------------------------------------------- 1907 // CommandObjectMultiwordCommands 1908 //------------------------------------------------------------------------- 1909 1910 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 1911 CommandInterpreter &interpreter) 1912 : CommandObjectMultiword(interpreter, "command", 1913 "Commands for managing custom LLDB commands.", 1914 "command <subcommand> [<subcommand-options>]") { 1915 LoadSubCommand("source", 1916 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 1917 LoadSubCommand("alias", 1918 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 1919 LoadSubCommand("unalias", CommandObjectSP( 1920 new CommandObjectCommandsUnalias(interpreter))); 1921 LoadSubCommand("delete", 1922 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 1923 LoadSubCommand( 1924 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 1925 LoadSubCommand("history", CommandObjectSP( 1926 new CommandObjectCommandsHistory(interpreter))); 1927 LoadSubCommand( 1928 "script", 1929 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 1930 } 1931 1932 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 1933