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