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 CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj.GetCommandName(), false); 625 626 if (!CommandInterpreter::CommandAlias::ProcessAliasOptionsArgs (cmd_obj_sp, raw_command_string.c_str(), option_arg_vector_sp)) 627 { 628 result.AppendError ("Unable to create requested alias.\n"); 629 result.SetStatus (eReturnStatusFailed); 630 return false; 631 } 632 633 // Create the alias 634 if (m_interpreter.AliasExists (alias_command.c_str()) 635 || m_interpreter.UserCommandExists (alias_command.c_str())) 636 { 637 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 638 alias_command.c_str()); 639 } 640 641 if (cmd_obj_sp) 642 { 643 m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp, option_arg_vector_sp); 644 result.SetStatus (eReturnStatusSuccessFinishNoResult); 645 } 646 else 647 { 648 result.AppendError ("Unable to create requested alias.\n"); 649 result.SetStatus (eReturnStatusFailed); 650 } 651 return result.Succeeded (); 652 } 653 654 bool 655 HandleAliasingNormalCommand (Args& args, CommandReturnObject &result) 656 { 657 size_t argc = args.GetArgumentCount(); 658 659 if (argc < 2) 660 { 661 result.AppendError ("'alias' requires at least two arguments"); 662 result.SetStatus (eReturnStatusFailed); 663 return false; 664 } 665 666 const std::string alias_command = args.GetArgumentAtIndex(0); 667 const std::string actual_command = args.GetArgumentAtIndex(1); 668 669 args.Shift(); // Shift the alias command word off the argument vector. 670 args.Shift(); // Shift the old command word off the argument vector. 671 672 // Verify that the command is alias'able, and get the appropriate command object. 673 674 if (m_interpreter.CommandExists (alias_command.c_str())) 675 { 676 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", 677 alias_command.c_str()); 678 result.SetStatus (eReturnStatusFailed); 679 } 680 else 681 { 682 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true)); 683 CommandObjectSP subcommand_obj_sp; 684 bool use_subcommand = false; 685 if (command_obj_sp) 686 { 687 CommandObject *cmd_obj = command_obj_sp.get(); 688 CommandObject *sub_cmd_obj = nullptr; 689 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); 690 691 while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0) 692 { 693 if (argc >= 3) 694 { 695 const std::string sub_command = args.GetArgumentAtIndex(0); 696 assert (sub_command.length() != 0); 697 subcommand_obj_sp = cmd_obj->GetSubcommandSP (sub_command.c_str()); 698 if (subcommand_obj_sp) 699 { 700 sub_cmd_obj = subcommand_obj_sp.get(); 701 use_subcommand = true; 702 args.Shift(); // Shift the sub_command word off the argument vector. 703 cmd_obj = sub_cmd_obj; 704 } 705 else 706 { 707 result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'. " 708 "Unable to create alias.\n", 709 sub_command.c_str(), actual_command.c_str()); 710 result.SetStatus (eReturnStatusFailed); 711 return false; 712 } 713 } 714 } 715 716 // Verify & handle any options/arguments passed to the alias command 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 std::string args_string; 725 args.GetCommandString (args_string); 726 727 if (!CommandInterpreter::CommandAlias::ProcessAliasOptionsArgs (tmp_sp, args_string.c_str(), option_arg_vector_sp)) 728 { 729 result.AppendError ("Unable to create requested alias.\n"); 730 result.SetStatus (eReturnStatusFailed); 731 return false; 732 } 733 } 734 735 // Create the alias. 736 737 if (m_interpreter.AliasExists (alias_command.c_str()) 738 || m_interpreter.UserCommandExists (alias_command.c_str())) 739 { 740 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 741 alias_command.c_str()); 742 } 743 744 if (use_subcommand) 745 m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp, option_arg_vector_sp); 746 else 747 m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp, option_arg_vector_sp); 748 result.SetStatus (eReturnStatusSuccessFinishNoResult); 749 } 750 else 751 { 752 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str()); 753 result.SetStatus (eReturnStatusFailed); 754 return false; 755 } 756 } 757 758 return result.Succeeded(); 759 } 760 }; 761 762 #pragma mark CommandObjectCommandsUnalias 763 //------------------------------------------------------------------------- 764 // CommandObjectCommandsUnalias 765 //------------------------------------------------------------------------- 766 767 class CommandObjectCommandsUnalias : public CommandObjectParsed 768 { 769 public: 770 CommandObjectCommandsUnalias (CommandInterpreter &interpreter) : 771 CommandObjectParsed(interpreter, 772 "command unalias", 773 "Allow the user to remove/delete a user-defined command abbreviation.", 774 nullptr) 775 { 776 CommandArgumentEntry arg; 777 CommandArgumentData alias_arg; 778 779 // Define the first (and only) variant of this arg. 780 alias_arg.arg_type = eArgTypeAliasName; 781 alias_arg.arg_repetition = eArgRepeatPlain; 782 783 // There is only one variant this argument could be; put it into the argument entry. 784 arg.push_back (alias_arg); 785 786 // Push the data for the first argument into the m_arguments vector. 787 m_arguments.push_back (arg); 788 } 789 790 ~CommandObjectCommandsUnalias() override = default; 791 792 protected: 793 bool 794 DoExecute (Args& args, CommandReturnObject &result) override 795 { 796 CommandObject::CommandMap::iterator pos; 797 CommandObject *cmd_obj; 798 799 if (args.GetArgumentCount() != 0) 800 { 801 const char *command_name = args.GetArgumentAtIndex(0); 802 cmd_obj = m_interpreter.GetCommandObject(command_name); 803 if (cmd_obj) 804 { 805 if (m_interpreter.CommandExists (command_name)) 806 { 807 if (cmd_obj->IsRemovable()) 808 { 809 result.AppendErrorWithFormat ("'%s' is not an alias, it is a debugger command which can be removed using the 'command delete' command.\n", 810 command_name); 811 } 812 else 813 { 814 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", 815 command_name); 816 } 817 result.SetStatus (eReturnStatusFailed); 818 } 819 else 820 { 821 if (!m_interpreter.RemoveAlias(command_name)) 822 { 823 if (m_interpreter.AliasExists (command_name)) 824 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n", 825 command_name); 826 else 827 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name); 828 result.SetStatus (eReturnStatusFailed); 829 } 830 else 831 result.SetStatus (eReturnStatusSuccessFinishNoResult); 832 } 833 } 834 else 835 { 836 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a " 837 "current list of commands.\n", 838 command_name); 839 result.SetStatus (eReturnStatusFailed); 840 } 841 } 842 else 843 { 844 result.AppendError ("must call 'unalias' with a valid alias"); 845 result.SetStatus (eReturnStatusFailed); 846 } 847 848 return result.Succeeded(); 849 } 850 }; 851 852 #pragma mark CommandObjectCommandsDelete 853 //------------------------------------------------------------------------- 854 // CommandObjectCommandsDelete 855 //------------------------------------------------------------------------- 856 857 class CommandObjectCommandsDelete : public CommandObjectParsed 858 { 859 public: 860 CommandObjectCommandsDelete (CommandInterpreter &interpreter) : 861 CommandObjectParsed(interpreter, 862 "command delete", 863 "Allow the user to delete user-defined regular expression, python or multi-word commands.", 864 nullptr) 865 { 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 argument entry. 874 arg.push_back (alias_arg); 875 876 // Push the data for the first argument into the m_arguments vector. 877 m_arguments.push_back (arg); 878 } 879 880 ~CommandObjectCommandsDelete() override = default; 881 882 protected: 883 bool 884 DoExecute (Args& args, CommandReturnObject &result) override 885 { 886 CommandObject::CommandMap::iterator pos; 887 888 if (args.GetArgumentCount() != 0) 889 { 890 const char *command_name = args.GetArgumentAtIndex(0); 891 if (m_interpreter.CommandExists (command_name)) 892 { 893 if (m_interpreter.RemoveCommand (command_name)) 894 { 895 result.SetStatus (eReturnStatusSuccessFinishNoResult); 896 } 897 else 898 { 899 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", 900 command_name); 901 result.SetStatus (eReturnStatusFailed); 902 } 903 } 904 else 905 { 906 StreamString error_msg_stream; 907 const bool generate_apropos = true; 908 const bool generate_type_lookup = false; 909 CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(&error_msg_stream, 910 command_name, 911 nullptr, 912 nullptr, 913 generate_apropos, 914 generate_type_lookup); 915 result.AppendErrorWithFormat ("%s", error_msg_stream.GetData()); 916 result.SetStatus (eReturnStatusFailed); 917 } 918 } 919 else 920 { 921 result.AppendErrorWithFormat ("must call '%s' with one or more valid user defined regular expression, python or multi-word command names", GetCommandName ()); 922 result.SetStatus (eReturnStatusFailed); 923 } 924 925 return result.Succeeded(); 926 } 927 }; 928 929 //------------------------------------------------------------------------- 930 // CommandObjectCommandsAddRegex 931 //------------------------------------------------------------------------- 932 #pragma mark CommandObjectCommandsAddRegex 933 934 class CommandObjectCommandsAddRegex : 935 public CommandObjectParsed, 936 public IOHandlerDelegateMultiline 937 { 938 public: 939 CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) : 940 CommandObjectParsed (interpreter, 941 "command regex", 942 "Allow the user to create a regular expression command.", 943 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 944 IOHandlerDelegateMultiline ("", IOHandlerDelegate::Completion::LLDBCommand), 945 m_options (interpreter) 946 { 947 SetHelpLong(R"( 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:" R"( 951 952 s/<regex>/<subst>/ 953 954 )" "<regex> is a regular expression that can use parenthesis to capture regular \ 955 expression input and substitute the captured matches in the output using %1 \ 956 for the first match, %2 for the second, and so on." R"( 957 958 )" "The regular expressions can all be specified on the command line if more than \ 959 one argument is provided. If just the command name is provided on the command \ 960 line, then the regular expressions and substitutions can be entered on separate \ 961 lines, followed by an empty line to terminate the command definition." R"( 962 963 EXAMPLES 964 965 )" "The following example will define a regular expression command named 'f' that \ 966 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ 967 a number follows 'f':" R"( 968 969 (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')" 970 ); 971 } 972 973 ~CommandObjectCommandsAddRegex() override = default; 974 975 protected: 976 void 977 IOHandlerActivated (IOHandler &io_handler) override 978 { 979 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 980 if (output_sp) 981 { 982 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"); 983 output_sp->Flush(); 984 } 985 } 986 987 void 988 IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override 989 { 990 io_handler.SetIsDone(true); 991 if (m_regex_cmd_ap) 992 { 993 StringList lines; 994 if (lines.SplitIntoLines (data)) 995 { 996 const size_t num_lines = lines.GetSize(); 997 bool check_only = false; 998 for (size_t i=0; i<num_lines; ++i) 999 { 1000 llvm::StringRef bytes_strref (lines[i]); 1001 Error error = AppendRegexSubstitution (bytes_strref, check_only); 1002 if (error.Fail()) 1003 { 1004 if (!m_interpreter.GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) 1005 { 1006 StreamSP out_stream = m_interpreter.GetDebugger().GetAsyncOutputStream(); 1007 out_stream->Printf("error: %s\n", error.AsCString()); 1008 } 1009 } 1010 } 1011 } 1012 if (m_regex_cmd_ap->HasRegexEntries()) 1013 { 1014 CommandObjectSP cmd_sp (m_regex_cmd_ap.release()); 1015 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 1016 } 1017 } 1018 } 1019 1020 bool 1021 DoExecute (Args& command, CommandReturnObject &result) override 1022 { 1023 const size_t argc = command.GetArgumentCount(); 1024 if (argc == 0) 1025 { 1026 result.AppendError ("usage: 'command regex <command-name> [s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 1027 result.SetStatus (eReturnStatusFailed); 1028 } 1029 else 1030 { 1031 Error error; 1032 const char *name = command.GetArgumentAtIndex(0); 1033 m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter, 1034 name, 1035 m_options.GetHelp (), 1036 m_options.GetSyntax (), 1037 10, 1038 0, 1039 true)); 1040 1041 if (argc == 1) 1042 { 1043 Debugger &debugger = m_interpreter.GetDebugger(); 1044 bool color_prompt = debugger.GetUseColor(); 1045 const bool multiple_lines = true; // Get multiple lines 1046 IOHandlerSP io_handler_sp(new IOHandlerEditline(debugger, 1047 IOHandler::Type::Other, 1048 "lldb-regex", // Name of input reader for history 1049 "> ", // Prompt 1050 nullptr, // Continuation prompt 1051 multiple_lines, 1052 color_prompt, 1053 0, // Don't show line numbers 1054 *this)); 1055 1056 if (io_handler_sp) 1057 { 1058 debugger.PushIOHandler(io_handler_sp); 1059 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1060 } 1061 } 1062 else 1063 { 1064 for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx) 1065 { 1066 llvm::StringRef arg_strref (command.GetArgumentAtIndex(arg_idx)); 1067 bool check_only = false; 1068 error = AppendRegexSubstitution (arg_strref, check_only); 1069 if (error.Fail()) 1070 break; 1071 } 1072 1073 if (error.Success()) 1074 { 1075 AddRegexCommandToInterpreter(); 1076 } 1077 } 1078 if (error.Fail()) 1079 { 1080 result.AppendError (error.AsCString()); 1081 result.SetStatus (eReturnStatusFailed); 1082 } 1083 } 1084 1085 return result.Succeeded(); 1086 } 1087 1088 Error 1089 AppendRegexSubstitution (const llvm::StringRef ®ex_sed, bool check_only) 1090 { 1091 Error error; 1092 1093 if (!m_regex_cmd_ap) 1094 { 1095 error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'", 1096 (int)regex_sed.size(), 1097 regex_sed.data()); 1098 return error; 1099 } 1100 1101 size_t regex_sed_size = regex_sed.size(); 1102 1103 if (regex_sed_size <= 1) 1104 { 1105 error.SetErrorStringWithFormat("regular expression substitution string is too short: '%.*s'", 1106 (int)regex_sed.size(), 1107 regex_sed.data()); 1108 return error; 1109 } 1110 1111 if (regex_sed[0] != 's') 1112 { 1113 error.SetErrorStringWithFormat("regular expression substitution string doesn't start with 's': '%.*s'", 1114 (int)regex_sed.size(), 1115 regex_sed.data()); 1116 return error; 1117 } 1118 const size_t first_separator_char_pos = 1; 1119 // use the char that follows 's' as the regex separator character 1120 // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 1121 const char separator_char = regex_sed[first_separator_char_pos]; 1122 const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1); 1123 1124 if (second_separator_char_pos == std::string::npos) 1125 { 1126 error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s' in '%.*s'", 1127 separator_char, 1128 (int)(regex_sed.size() - first_separator_char_pos - 1), 1129 regex_sed.data() + (first_separator_char_pos + 1), 1130 (int)regex_sed.size(), 1131 regex_sed.data()); 1132 return error; 1133 } 1134 1135 const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1); 1136 1137 if (third_separator_char_pos == std::string::npos) 1138 { 1139 error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s' in '%.*s'", 1140 separator_char, 1141 (int)(regex_sed.size() - second_separator_char_pos - 1), 1142 regex_sed.data() + (second_separator_char_pos + 1), 1143 (int)regex_sed.size(), 1144 regex_sed.data()); 1145 return error; 1146 } 1147 1148 if (third_separator_char_pos != regex_sed_size - 1) 1149 { 1150 // Make sure that everything that follows the last regex 1151 // separator char 1152 if (regex_sed.find_first_not_of("\t\n\v\f\r ", third_separator_char_pos + 1) != std::string::npos) 1153 { 1154 error.SetErrorStringWithFormat("extra data found after the '%.*s' regular expression substitution string: '%.*s'", 1155 (int)third_separator_char_pos + 1, 1156 regex_sed.data(), 1157 (int)(regex_sed.size() - third_separator_char_pos - 1), 1158 regex_sed.data() + (third_separator_char_pos + 1)); 1159 return error; 1160 } 1161 } 1162 else if (first_separator_char_pos + 1 == second_separator_char_pos) 1163 { 1164 error.SetErrorStringWithFormat("<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 1165 separator_char, 1166 separator_char, 1167 separator_char, 1168 (int)regex_sed.size(), 1169 regex_sed.data()); 1170 return error; 1171 } 1172 else if (second_separator_char_pos + 1 == third_separator_char_pos) 1173 { 1174 error.SetErrorStringWithFormat("<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 1175 separator_char, 1176 separator_char, 1177 separator_char, 1178 (int)regex_sed.size(), 1179 regex_sed.data()); 1180 return error; 1181 } 1182 1183 if (!check_only) 1184 { 1185 std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1)); 1186 std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1)); 1187 m_regex_cmd_ap->AddRegexCommand (regex.c_str(), 1188 subst.c_str()); 1189 } 1190 return error; 1191 } 1192 1193 void 1194 AddRegexCommandToInterpreter() 1195 { 1196 if (m_regex_cmd_ap) 1197 { 1198 if (m_regex_cmd_ap->HasRegexEntries()) 1199 { 1200 CommandObjectSP cmd_sp (m_regex_cmd_ap.release()); 1201 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 1202 } 1203 } 1204 } 1205 1206 private: 1207 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_ap; 1208 1209 class CommandOptions : public Options 1210 { 1211 public: 1212 CommandOptions (CommandInterpreter &interpreter) : 1213 Options (interpreter) 1214 { 1215 } 1216 1217 ~CommandOptions() override = default; 1218 1219 Error 1220 SetOptionValue (uint32_t option_idx, const char *option_arg) override 1221 { 1222 Error error; 1223 const int short_option = m_getopt_table[option_idx].val; 1224 1225 switch (short_option) 1226 { 1227 case 'h': 1228 m_help.assign (option_arg); 1229 break; 1230 case 's': 1231 m_syntax.assign (option_arg); 1232 break; 1233 default: 1234 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 1235 break; 1236 } 1237 1238 return error; 1239 } 1240 1241 void 1242 OptionParsingStarting () override 1243 { 1244 m_help.clear(); 1245 m_syntax.clear(); 1246 } 1247 1248 const OptionDefinition* 1249 GetDefinitions () override 1250 { 1251 return g_option_table; 1252 } 1253 1254 // Options table: Required for subclasses of Options. 1255 1256 static OptionDefinition g_option_table[]; 1257 1258 const char * 1259 GetHelp() 1260 { 1261 return (m_help.empty() ? nullptr : m_help.c_str()); 1262 } 1263 1264 const char * 1265 GetSyntax () 1266 { 1267 return (m_syntax.empty() ? nullptr : m_syntax.c_str()); 1268 } 1269 1270 protected: 1271 // Instance variables to hold the values for command options. 1272 1273 std::string m_help; 1274 std::string m_syntax; 1275 }; 1276 1277 Options * 1278 GetOptions () override 1279 { 1280 return &m_options; 1281 } 1282 1283 CommandOptions m_options; 1284 }; 1285 1286 OptionDefinition 1287 CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] = 1288 { 1289 { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "The help text to display for this command."}, 1290 { LLDB_OPT_SET_1, false, "syntax", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."}, 1291 { 0 , false, nullptr , 0 , 0 , nullptr, nullptr, 0, eArgTypeNone, nullptr } 1292 }; 1293 1294 class CommandObjectPythonFunction : public CommandObjectRaw 1295 { 1296 public: 1297 CommandObjectPythonFunction (CommandInterpreter &interpreter, 1298 std::string name, 1299 std::string funct, 1300 std::string help, 1301 ScriptedCommandSynchronicity synch) : 1302 CommandObjectRaw(interpreter, 1303 name.c_str(), 1304 nullptr, 1305 nullptr), 1306 m_function_name(funct), 1307 m_synchro(synch), 1308 m_fetched_help_long(false) 1309 { 1310 if (!help.empty()) 1311 SetHelp(help.c_str()); 1312 else 1313 { 1314 StreamString stream; 1315 stream.Printf("For more information run 'help %s'",name.c_str()); 1316 SetHelp(stream.GetData()); 1317 } 1318 } 1319 1320 ~CommandObjectPythonFunction() override = default; 1321 1322 bool 1323 IsRemovable () const override 1324 { 1325 return true; 1326 } 1327 1328 const std::string& 1329 GetFunctionName () 1330 { 1331 return m_function_name; 1332 } 1333 1334 ScriptedCommandSynchronicity 1335 GetSynchronicity () 1336 { 1337 return m_synchro; 1338 } 1339 1340 const char * 1341 GetHelpLong () override 1342 { 1343 if (!m_fetched_help_long) 1344 { 1345 ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); 1346 if (scripter) 1347 { 1348 std::string docstring; 1349 m_fetched_help_long = scripter->GetDocumentationForItem(m_function_name.c_str(),docstring); 1350 if (!docstring.empty()) 1351 SetHelpLong(docstring); 1352 } 1353 } 1354 return CommandObjectRaw::GetHelpLong(); 1355 } 1356 1357 protected: 1358 bool 1359 DoExecute (const char *raw_command_line, CommandReturnObject &result) override 1360 { 1361 ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); 1362 1363 Error error; 1364 1365 result.SetStatus(eReturnStatusInvalid); 1366 1367 if (!scripter || !scripter->RunScriptBasedCommand(m_function_name.c_str(), 1368 raw_command_line, 1369 m_synchro, 1370 result, 1371 error, 1372 m_exe_ctx)) 1373 { 1374 result.AppendError(error.AsCString()); 1375 result.SetStatus(eReturnStatusFailed); 1376 } 1377 else 1378 { 1379 // Don't change the status if the command already set it... 1380 if (result.GetStatus() == eReturnStatusInvalid) 1381 { 1382 if (result.GetOutputData() == nullptr || result.GetOutputData()[0] == '\0') 1383 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1384 else 1385 result.SetStatus(eReturnStatusSuccessFinishResult); 1386 } 1387 } 1388 1389 return result.Succeeded(); 1390 } 1391 1392 private: 1393 std::string m_function_name; 1394 ScriptedCommandSynchronicity m_synchro; 1395 bool m_fetched_help_long; 1396 }; 1397 1398 class CommandObjectScriptingObject : public CommandObjectRaw 1399 { 1400 public: 1401 CommandObjectScriptingObject (CommandInterpreter &interpreter, 1402 std::string name, 1403 StructuredData::GenericSP cmd_obj_sp, 1404 ScriptedCommandSynchronicity synch) : 1405 CommandObjectRaw(interpreter, 1406 name.c_str(), 1407 nullptr, 1408 nullptr), 1409 m_cmd_obj_sp(cmd_obj_sp), 1410 m_synchro(synch), 1411 m_fetched_help_short(false), 1412 m_fetched_help_long(false) 1413 { 1414 StreamString stream; 1415 stream.Printf("For more information run 'help %s'",name.c_str()); 1416 SetHelp(stream.GetData()); 1417 if (ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter()) 1418 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1419 } 1420 1421 ~CommandObjectScriptingObject() override = default; 1422 1423 bool 1424 IsRemovable () const override 1425 { 1426 return true; 1427 } 1428 1429 StructuredData::GenericSP 1430 GetImplementingObject () 1431 { 1432 return m_cmd_obj_sp; 1433 } 1434 1435 ScriptedCommandSynchronicity 1436 GetSynchronicity () 1437 { 1438 return m_synchro; 1439 } 1440 1441 const char * 1442 GetHelp () override 1443 { 1444 if (!m_fetched_help_short) 1445 { 1446 ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); 1447 if (scripter) 1448 { 1449 std::string docstring; 1450 m_fetched_help_short = scripter->GetShortHelpForCommandObject(m_cmd_obj_sp,docstring); 1451 if (!docstring.empty()) 1452 SetHelp(docstring); 1453 } 1454 } 1455 return CommandObjectRaw::GetHelp(); 1456 } 1457 1458 const char * 1459 GetHelpLong () override 1460 { 1461 if (!m_fetched_help_long) 1462 { 1463 ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); 1464 if (scripter) 1465 { 1466 std::string docstring; 1467 m_fetched_help_long = scripter->GetLongHelpForCommandObject(m_cmd_obj_sp,docstring); 1468 if (!docstring.empty()) 1469 SetHelpLong(docstring); 1470 } 1471 } 1472 return CommandObjectRaw::GetHelpLong(); 1473 } 1474 1475 protected: 1476 bool 1477 DoExecute (const char *raw_command_line, CommandReturnObject &result) override 1478 { 1479 ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); 1480 1481 Error error; 1482 1483 result.SetStatus(eReturnStatusInvalid); 1484 1485 if (!scripter || !scripter->RunScriptBasedCommand(m_cmd_obj_sp, 1486 raw_command_line, 1487 m_synchro, 1488 result, 1489 error, 1490 m_exe_ctx)) 1491 { 1492 result.AppendError(error.AsCString()); 1493 result.SetStatus(eReturnStatusFailed); 1494 } 1495 else 1496 { 1497 // Don't change the status if the command already set it... 1498 if (result.GetStatus() == eReturnStatusInvalid) 1499 { 1500 if (result.GetOutputData() == nullptr || result.GetOutputData()[0] == '\0') 1501 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1502 else 1503 result.SetStatus(eReturnStatusSuccessFinishResult); 1504 } 1505 } 1506 1507 return result.Succeeded(); 1508 } 1509 1510 private: 1511 StructuredData::GenericSP m_cmd_obj_sp; 1512 ScriptedCommandSynchronicity m_synchro; 1513 bool m_fetched_help_short: 1; 1514 bool m_fetched_help_long: 1; 1515 }; 1516 1517 //------------------------------------------------------------------------- 1518 // CommandObjectCommandsScriptImport 1519 //------------------------------------------------------------------------- 1520 1521 class CommandObjectCommandsScriptImport : public CommandObjectParsed 1522 { 1523 public: 1524 CommandObjectCommandsScriptImport (CommandInterpreter &interpreter) : 1525 CommandObjectParsed(interpreter, 1526 "command script import", 1527 "Import a scripting module in LLDB.", 1528 nullptr), 1529 m_options(interpreter) 1530 { 1531 CommandArgumentEntry arg1; 1532 CommandArgumentData cmd_arg; 1533 1534 // Define the first (and only) variant of this arg. 1535 cmd_arg.arg_type = eArgTypeFilename; 1536 cmd_arg.arg_repetition = eArgRepeatPlus; 1537 1538 // There is only one variant this argument could be; put it into the argument entry. 1539 arg1.push_back (cmd_arg); 1540 1541 // Push the data for the first argument into the m_arguments vector. 1542 m_arguments.push_back (arg1); 1543 } 1544 1545 ~CommandObjectCommandsScriptImport() override = default; 1546 1547 int 1548 HandleArgumentCompletion (Args &input, 1549 int &cursor_index, 1550 int &cursor_char_position, 1551 OptionElementVector &opt_element_vector, 1552 int match_start_point, 1553 int max_return_elements, 1554 bool &word_complete, 1555 StringList &matches) override 1556 { 1557 std::string completion_str (input.GetArgumentAtIndex(cursor_index)); 1558 completion_str.erase (cursor_char_position); 1559 1560 CommandCompletions::InvokeCommonCompletionCallbacks(m_interpreter, 1561 CommandCompletions::eDiskFileCompletion, 1562 completion_str.c_str(), 1563 match_start_point, 1564 max_return_elements, 1565 nullptr, 1566 word_complete, 1567 matches); 1568 return matches.GetSize(); 1569 } 1570 1571 Options * 1572 GetOptions () override 1573 { 1574 return &m_options; 1575 } 1576 1577 protected: 1578 class CommandOptions : public Options 1579 { 1580 public: 1581 CommandOptions (CommandInterpreter &interpreter) : 1582 Options (interpreter) 1583 { 1584 } 1585 1586 ~CommandOptions() override = default; 1587 1588 Error 1589 SetOptionValue (uint32_t option_idx, const char *option_arg) override 1590 { 1591 Error error; 1592 const int short_option = m_getopt_table[option_idx].val; 1593 1594 switch (short_option) 1595 { 1596 case 'r': 1597 m_allow_reload = true; 1598 break; 1599 default: 1600 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 1601 break; 1602 } 1603 1604 return error; 1605 } 1606 1607 void 1608 OptionParsingStarting () override 1609 { 1610 m_allow_reload = true; 1611 } 1612 1613 const OptionDefinition* 1614 GetDefinitions () override 1615 { 1616 return g_option_table; 1617 } 1618 1619 // Options table: Required for subclasses of Options. 1620 1621 static OptionDefinition g_option_table[]; 1622 1623 // Instance variables to hold the values for command options. 1624 1625 bool m_allow_reload; 1626 }; 1627 1628 bool 1629 DoExecute (Args& command, CommandReturnObject &result) override 1630 { 1631 if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) 1632 { 1633 result.AppendError ("only scripting language supported for module importing is currently Python"); 1634 result.SetStatus (eReturnStatusFailed); 1635 return false; 1636 } 1637 1638 size_t argc = command.GetArgumentCount(); 1639 if (0 == argc) 1640 { 1641 result.AppendError("command script import needs one or more arguments"); 1642 result.SetStatus (eReturnStatusFailed); 1643 return false; 1644 } 1645 1646 for (size_t i = 0; 1647 i < argc; 1648 i++) 1649 { 1650 std::string path = command.GetArgumentAtIndex(i); 1651 Error error; 1652 1653 const bool init_session = true; 1654 // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that 1655 // commands won't ever be recursively invoked, but it's actually possible to craft 1656 // a Python script that does other "command script imports" in __lldb_init_module 1657 // the real fix is to have recursive commands possible with a CommandInvocation object 1658 // separate from the CommandObject itself, so that recursive command invocations 1659 // won't stomp on each other (wrt to execution contents, options, and more) 1660 m_exe_ctx.Clear(); 1661 if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(), 1662 m_options.m_allow_reload, 1663 init_session, 1664 error)) 1665 { 1666 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1667 } 1668 else 1669 { 1670 result.AppendErrorWithFormat("module importing failed: %s", error.AsCString()); 1671 result.SetStatus (eReturnStatusFailed); 1672 } 1673 } 1674 1675 return result.Succeeded(); 1676 } 1677 1678 CommandOptions m_options; 1679 }; 1680 1681 OptionDefinition 1682 CommandObjectCommandsScriptImport::CommandOptions::g_option_table[] = 1683 { 1684 { 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."}, 1685 { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } 1686 }; 1687 1688 //------------------------------------------------------------------------- 1689 // CommandObjectCommandsScriptAdd 1690 //------------------------------------------------------------------------- 1691 1692 class CommandObjectCommandsScriptAdd : 1693 public CommandObjectParsed, 1694 public IOHandlerDelegateMultiline 1695 { 1696 public: 1697 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) : 1698 CommandObjectParsed(interpreter, 1699 "command script add", 1700 "Add a scripted function as an LLDB command.", 1701 nullptr), 1702 IOHandlerDelegateMultiline ("DONE"), 1703 m_options (interpreter) 1704 { 1705 CommandArgumentEntry arg1; 1706 CommandArgumentData cmd_arg; 1707 1708 // Define the first (and only) variant of this arg. 1709 cmd_arg.arg_type = eArgTypeCommandName; 1710 cmd_arg.arg_repetition = eArgRepeatPlain; 1711 1712 // There is only one variant this argument could be; put it into the argument entry. 1713 arg1.push_back (cmd_arg); 1714 1715 // Push the data for the first argument into the m_arguments vector. 1716 m_arguments.push_back (arg1); 1717 } 1718 1719 ~CommandObjectCommandsScriptAdd() override = default; 1720 1721 Options * 1722 GetOptions () override 1723 { 1724 return &m_options; 1725 } 1726 1727 protected: 1728 class CommandOptions : public Options 1729 { 1730 public: 1731 CommandOptions (CommandInterpreter &interpreter) : 1732 Options (interpreter), 1733 m_class_name(), 1734 m_funct_name(), 1735 m_short_help(), 1736 m_synchronicity(eScriptedCommandSynchronicitySynchronous) 1737 { 1738 } 1739 1740 ~CommandOptions() override = default; 1741 1742 Error 1743 SetOptionValue (uint32_t option_idx, const char *option_arg) override 1744 { 1745 Error error; 1746 const int short_option = m_getopt_table[option_idx].val; 1747 1748 switch (short_option) 1749 { 1750 case 'f': 1751 if (option_arg) 1752 m_funct_name.assign(option_arg); 1753 break; 1754 case 'c': 1755 if (option_arg) 1756 m_class_name.assign(option_arg); 1757 break; 1758 case 'h': 1759 if (option_arg) 1760 m_short_help.assign(option_arg); 1761 break; 1762 case 's': 1763 m_synchronicity = (ScriptedCommandSynchronicity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); 1764 if (!error.Success()) 1765 error.SetErrorStringWithFormat ("unrecognized value for synchronicity '%s'", option_arg); 1766 break; 1767 default: 1768 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 1769 break; 1770 } 1771 1772 return error; 1773 } 1774 1775 void 1776 OptionParsingStarting () override 1777 { 1778 m_class_name.clear(); 1779 m_funct_name.clear(); 1780 m_short_help.clear(); 1781 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1782 } 1783 1784 const OptionDefinition* 1785 GetDefinitions () override 1786 { 1787 return g_option_table; 1788 } 1789 1790 // Options table: Required for subclasses of Options. 1791 1792 static OptionDefinition g_option_table[]; 1793 1794 // Instance variables to hold the values for command options. 1795 1796 std::string m_class_name; 1797 std::string m_funct_name; 1798 std::string m_short_help; 1799 ScriptedCommandSynchronicity m_synchronicity; 1800 }; 1801 1802 void 1803 IOHandlerActivated (IOHandler &io_handler) override 1804 { 1805 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 1806 if (output_sp) 1807 { 1808 output_sp->PutCString(g_python_command_instructions); 1809 output_sp->Flush(); 1810 } 1811 } 1812 1813 1814 void 1815 IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override 1816 { 1817 StreamFileSP error_sp = io_handler.GetErrorStreamFile(); 1818 1819 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); 1820 if (interpreter) 1821 { 1822 1823 StringList lines; 1824 lines.SplitIntoLines(data); 1825 if (lines.GetSize() > 0) 1826 { 1827 std::string funct_name_str; 1828 if (interpreter->GenerateScriptAliasFunction (lines, funct_name_str)) 1829 { 1830 if (funct_name_str.empty()) 1831 { 1832 error_sp->Printf ("error: unable to obtain a function name, didn't add python command.\n"); 1833 error_sp->Flush(); 1834 } 1835 else 1836 { 1837 // everything should be fine now, let's add this alias 1838 1839 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction (m_interpreter, 1840 m_cmd_name, 1841 funct_name_str.c_str(), 1842 m_short_help, 1843 m_synchronicity)); 1844 1845 if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, true)) 1846 { 1847 error_sp->Printf ("error: unable to add selected command, didn't add python command.\n"); 1848 error_sp->Flush(); 1849 } 1850 } 1851 } 1852 else 1853 { 1854 error_sp->Printf ("error: unable to create function, didn't add python command.\n"); 1855 error_sp->Flush(); 1856 } 1857 } 1858 else 1859 { 1860 error_sp->Printf ("error: empty function, didn't add python command.\n"); 1861 error_sp->Flush(); 1862 } 1863 } 1864 else 1865 { 1866 error_sp->Printf ("error: script interpreter missing, didn't add python command.\n"); 1867 error_sp->Flush(); 1868 } 1869 1870 io_handler.SetIsDone(true); 1871 } 1872 1873 protected: 1874 bool 1875 DoExecute (Args& command, CommandReturnObject &result) override 1876 { 1877 if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) 1878 { 1879 result.AppendError ("only scripting language supported for scripted commands is currently Python"); 1880 result.SetStatus (eReturnStatusFailed); 1881 return false; 1882 } 1883 1884 size_t argc = command.GetArgumentCount(); 1885 1886 if (argc != 1) 1887 { 1888 result.AppendError ("'command script add' requires one argument"); 1889 result.SetStatus (eReturnStatusFailed); 1890 return false; 1891 } 1892 1893 // Store the options in case we get multi-line input 1894 m_cmd_name = command.GetArgumentAtIndex(0); 1895 m_short_help.assign(m_options.m_short_help); 1896 m_synchronicity = m_options.m_synchronicity; 1897 1898 if (m_options.m_class_name.empty()) 1899 { 1900 if (m_options.m_funct_name.empty()) 1901 { 1902 m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt 1903 *this, // IOHandlerDelegate 1904 true, // Run IOHandler in async mode 1905 nullptr); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions 1906 } 1907 else 1908 { 1909 CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter, 1910 m_cmd_name, 1911 m_options.m_funct_name, 1912 m_options.m_short_help, 1913 m_synchronicity)); 1914 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) 1915 { 1916 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1917 } 1918 else 1919 { 1920 result.AppendError("cannot add command"); 1921 result.SetStatus (eReturnStatusFailed); 1922 } 1923 } 1924 } 1925 else 1926 { 1927 ScriptInterpreter *interpreter = GetCommandInterpreter().GetScriptInterpreter(); 1928 if (!interpreter) 1929 { 1930 result.AppendError("cannot find ScriptInterpreter"); 1931 result.SetStatus(eReturnStatusFailed); 1932 return false; 1933 } 1934 1935 auto cmd_obj_sp = interpreter->CreateScriptCommandObject(m_options.m_class_name.c_str()); 1936 if (!cmd_obj_sp) 1937 { 1938 result.AppendError("cannot create helper object"); 1939 result.SetStatus(eReturnStatusFailed); 1940 return false; 1941 } 1942 1943 CommandObjectSP new_cmd(new CommandObjectScriptingObject(m_interpreter, 1944 m_cmd_name, 1945 cmd_obj_sp, 1946 m_synchronicity)); 1947 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) 1948 { 1949 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1950 } 1951 else 1952 { 1953 result.AppendError("cannot add command"); 1954 result.SetStatus (eReturnStatusFailed); 1955 } 1956 } 1957 1958 return result.Succeeded(); 1959 } 1960 1961 CommandOptions m_options; 1962 std::string m_cmd_name; 1963 std::string m_short_help; 1964 ScriptedCommandSynchronicity m_synchronicity; 1965 }; 1966 1967 static OptionEnumValueElement g_script_synchro_type[] = 1968 { 1969 { eScriptedCommandSynchronicitySynchronous, "synchronous", "Run synchronous"}, 1970 { eScriptedCommandSynchronicityAsynchronous, "asynchronous", "Run asynchronous"}, 1971 { eScriptedCommandSynchronicityCurrentValue, "current", "Do not alter current setting"}, 1972 { 0, nullptr, nullptr } 1973 }; 1974 1975 OptionDefinition 1976 CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] = 1977 { 1978 { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name."}, 1979 { LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name."}, 1980 { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "The help text to display for this command."}, 1981 { 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."}, 1982 { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } 1983 }; 1984 1985 //------------------------------------------------------------------------- 1986 // CommandObjectCommandsScriptList 1987 //------------------------------------------------------------------------- 1988 1989 class CommandObjectCommandsScriptList : public CommandObjectParsed 1990 { 1991 public: 1992 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) : 1993 CommandObjectParsed(interpreter, 1994 "command script list", 1995 "List defined scripted commands.", 1996 nullptr) 1997 { 1998 } 1999 2000 ~CommandObjectCommandsScriptList() override = default; 2001 2002 bool 2003 DoExecute (Args& command, CommandReturnObject &result) override 2004 { 2005 m_interpreter.GetHelp(result, 2006 CommandInterpreter::eCommandTypesUserDef); 2007 2008 result.SetStatus (eReturnStatusSuccessFinishResult); 2009 2010 return true; 2011 } 2012 }; 2013 2014 //------------------------------------------------------------------------- 2015 // CommandObjectCommandsScriptClear 2016 //------------------------------------------------------------------------- 2017 2018 class CommandObjectCommandsScriptClear : public CommandObjectParsed 2019 { 2020 public: 2021 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) : 2022 CommandObjectParsed(interpreter, 2023 "command script clear", 2024 "Delete all scripted commands.", 2025 nullptr) 2026 { 2027 } 2028 2029 ~CommandObjectCommandsScriptClear() override = default; 2030 2031 protected: 2032 bool 2033 DoExecute (Args& command, CommandReturnObject &result) override 2034 { 2035 m_interpreter.RemoveAllUser(); 2036 2037 result.SetStatus (eReturnStatusSuccessFinishResult); 2038 2039 return true; 2040 } 2041 }; 2042 2043 //------------------------------------------------------------------------- 2044 // CommandObjectCommandsScriptDelete 2045 //------------------------------------------------------------------------- 2046 2047 class CommandObjectCommandsScriptDelete : public CommandObjectParsed 2048 { 2049 public: 2050 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) : 2051 CommandObjectParsed(interpreter, 2052 "command script delete", 2053 "Delete a scripted command.", 2054 nullptr) 2055 { 2056 CommandArgumentEntry arg1; 2057 CommandArgumentData cmd_arg; 2058 2059 // Define the first (and only) variant of this arg. 2060 cmd_arg.arg_type = eArgTypeCommandName; 2061 cmd_arg.arg_repetition = eArgRepeatPlain; 2062 2063 // There is only one variant this argument could be; put it into the argument entry. 2064 arg1.push_back (cmd_arg); 2065 2066 // Push the data for the first argument into the m_arguments vector. 2067 m_arguments.push_back (arg1); 2068 } 2069 2070 ~CommandObjectCommandsScriptDelete() override = default; 2071 2072 protected: 2073 bool 2074 DoExecute (Args& command, CommandReturnObject &result) override 2075 { 2076 2077 size_t argc = command.GetArgumentCount(); 2078 2079 if (argc != 1) 2080 { 2081 result.AppendError ("'command script delete' requires one argument"); 2082 result.SetStatus (eReturnStatusFailed); 2083 return false; 2084 } 2085 2086 const char* cmd_name = command.GetArgumentAtIndex(0); 2087 2088 if (cmd_name && *cmd_name && m_interpreter.HasUserCommands() && m_interpreter.UserCommandExists(cmd_name)) 2089 { 2090 m_interpreter.RemoveUser(cmd_name); 2091 result.SetStatus (eReturnStatusSuccessFinishResult); 2092 } 2093 else 2094 { 2095 result.AppendErrorWithFormat ("command %s not found", cmd_name); 2096 result.SetStatus (eReturnStatusFailed); 2097 } 2098 2099 return result.Succeeded(); 2100 } 2101 }; 2102 2103 #pragma mark CommandObjectMultiwordCommandsScript 2104 2105 //------------------------------------------------------------------------- 2106 // CommandObjectMultiwordCommandsScript 2107 //------------------------------------------------------------------------- 2108 2109 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword 2110 { 2111 public: 2112 CommandObjectMultiwordCommandsScript (CommandInterpreter &interpreter) : 2113 CommandObjectMultiword (interpreter, 2114 "command script", 2115 "A set of commands for managing or customizing script commands.", 2116 "command script <subcommand> [<subcommand-options>]") 2117 { 2118 LoadSubCommand ("add", CommandObjectSP (new CommandObjectCommandsScriptAdd (interpreter))); 2119 LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsScriptDelete (interpreter))); 2120 LoadSubCommand ("clear", CommandObjectSP (new CommandObjectCommandsScriptClear (interpreter))); 2121 LoadSubCommand ("list", CommandObjectSP (new CommandObjectCommandsScriptList (interpreter))); 2122 LoadSubCommand ("import", CommandObjectSP (new CommandObjectCommandsScriptImport (interpreter))); 2123 } 2124 2125 ~CommandObjectMultiwordCommandsScript() override = default; 2126 }; 2127 2128 #pragma mark CommandObjectMultiwordCommands 2129 2130 //------------------------------------------------------------------------- 2131 // CommandObjectMultiwordCommands 2132 //------------------------------------------------------------------------- 2133 2134 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) : 2135 CommandObjectMultiword (interpreter, 2136 "command", 2137 "A set of commands for managing or customizing the debugger commands.", 2138 "command <subcommand> [<subcommand-options>]") 2139 { 2140 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter))); 2141 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter))); 2142 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter))); 2143 LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsDelete (interpreter))); 2144 LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter))); 2145 LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter))); 2146 LoadSubCommand ("script", CommandObjectSP (new CommandObjectMultiwordCommandsScript (interpreter))); 2147 } 2148 2149 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 2150