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