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