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 #include "CommandObjectCommands.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 #include "llvm/ADT/StringRef.h" 16 17 // Project includes 18 #include "lldb/Core/Debugger.h" 19 #include "lldb/Core/InputReader.h" 20 #include "lldb/Interpreter/Args.h" 21 #include "lldb/Interpreter/CommandInterpreter.h" 22 #include "lldb/Interpreter/CommandObjectRegexCommand.h" 23 #include "lldb/Interpreter/CommandReturnObject.h" 24 #include "lldb/Interpreter/Options.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 //------------------------------------------------------------------------- 30 // CommandObjectCommandsSource 31 //------------------------------------------------------------------------- 32 33 class CommandObjectCommandsSource : public CommandObject 34 { 35 private: 36 37 class CommandOptions : public Options 38 { 39 public: 40 41 CommandOptions (CommandInterpreter &interpreter) : 42 Options (interpreter) 43 { 44 } 45 46 virtual 47 ~CommandOptions (){} 48 49 virtual Error 50 SetOptionValue (uint32_t option_idx, const char *option_arg) 51 { 52 Error error; 53 char short_option = (char) m_getopt_table[option_idx].val; 54 bool success; 55 56 switch (short_option) 57 { 58 case 'e': 59 m_stop_on_error = Args::StringToBoolean(option_arg, true, &success); 60 if (!success) 61 error.SetErrorStringWithFormat("Invalid value for stop-on-error: %s.\n", option_arg); 62 break; 63 case 'c': 64 m_stop_on_continue = Args::StringToBoolean(option_arg, true, &success); 65 if (!success) 66 error.SetErrorStringWithFormat("Invalid value for stop-on-continue: %s.\n", option_arg); 67 break; 68 default: 69 error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); 70 break; 71 } 72 73 return error; 74 } 75 76 void 77 OptionParsingStarting () 78 { 79 m_stop_on_error = true; 80 m_stop_on_continue = true; 81 } 82 83 const OptionDefinition* 84 GetDefinitions () 85 { 86 return g_option_table; 87 } 88 89 // Options table: Required for subclasses of Options. 90 91 static OptionDefinition g_option_table[]; 92 93 // Instance variables to hold the values for command options. 94 95 bool m_stop_on_error; 96 bool m_stop_on_continue; 97 }; 98 99 CommandOptions m_options; 100 101 virtual Options * 102 GetOptions () 103 { 104 return &m_options; 105 } 106 107 public: 108 CommandObjectCommandsSource(CommandInterpreter &interpreter) : 109 CommandObject (interpreter, 110 "command source", 111 "Read in debugger commands from the file <filename> and execute them.", 112 NULL), 113 m_options (interpreter) 114 { 115 CommandArgumentEntry arg; 116 CommandArgumentData file_arg; 117 118 // Define the first (and only) variant of this arg. 119 file_arg.arg_type = eArgTypeFilename; 120 file_arg.arg_repetition = eArgRepeatPlain; 121 122 // There is only one variant this argument could be; put it into the argument entry. 123 arg.push_back (file_arg); 124 125 // Push the data for the first argument into the m_arguments vector. 126 m_arguments.push_back (arg); 127 } 128 129 ~CommandObjectCommandsSource () 130 { 131 } 132 133 bool 134 Execute 135 ( 136 Args& args, 137 CommandReturnObject &result 138 ) 139 { 140 const int argc = args.GetArgumentCount(); 141 if (argc == 1) 142 { 143 const char *filename = args.GetArgumentAtIndex(0); 144 145 result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename); 146 147 FileSpec cmd_file (filename, true); 148 ExecutionContext *exe_ctx = NULL; // Just use the default context. 149 bool echo_commands = true; 150 bool print_results = true; 151 152 m_interpreter.HandleCommandsFromFile (cmd_file, 153 exe_ctx, 154 m_options.m_stop_on_continue, 155 m_options.m_stop_on_error, 156 echo_commands, 157 print_results, 158 result); 159 } 160 else 161 { 162 result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName()); 163 result.SetStatus (eReturnStatusFailed); 164 } 165 return result.Succeeded(); 166 167 } 168 }; 169 170 OptionDefinition 171 CommandObjectCommandsSource::CommandOptions::g_option_table[] = 172 { 173 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on error."}, 174 { LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on continue."}, 175 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 176 }; 177 178 #pragma mark CommandObjectCommandsAlias 179 //------------------------------------------------------------------------- 180 // CommandObjectCommandsAlias 181 //------------------------------------------------------------------------- 182 183 class CommandObjectCommandsAlias : public CommandObject 184 { 185 public: 186 CommandObjectCommandsAlias (CommandInterpreter &interpreter) : 187 CommandObject (interpreter, 188 "command alias", 189 "Allow users to define their own debugger command abbreviations.", 190 NULL) 191 { 192 SetHelpLong( 193 "'alias' allows the user to create a short-cut or abbreviation for long \n\ 194 commands, multi-word commands, and commands that take particular options. \n\ 195 Below are some simple examples of how one might use the 'alias' command: \n\ 196 \n 'commands alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\ 197 // command. \n\ 198 'commands alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\ 199 // command. Since breakpoint commands are two-word \n\ 200 // commands, the user will still need to enter the \n\ 201 // second word after 'bp', e.g. 'bp enable' or \n\ 202 // 'bp delete'. \n\ 203 'commands alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\ 204 // two-word command 'breakpoint list'. \n\ 205 \nAn alias can include some options for the command, with the values either \n\ 206 filled in at the time the alias is created, or specified as positional \n\ 207 arguments, to be filled in when the alias is invoked. The following example \n\ 208 shows how to create aliases with options: \n\ 209 \n\ 210 'commands alias bfl breakpoint set -f %1 -l %2' \n\ 211 \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\ 212 options already part of the alias. So if the user wants to set a breakpoint \n\ 213 by file and line without explicitly having to use the -f and -l options, the \n\ 214 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\ 215 for the actual arguments that will be passed when the alias command is used. \n\ 216 The number in the placeholder refers to the position/order the actual value \n\ 217 occupies when the alias is used. So all the occurrences of '%1' in the alias \n\ 218 will be replaced with the first argument, all the occurrences of '%2' in the \n\ 219 alias will be replaced with the second argument, and so on. This also allows \n\ 220 actual arguments to be used multiple times within an alias (see 'process \n\ 221 launch' example below). So in the 'bfl' case, the actual file value will be \n\ 222 filled in with the first argument following 'bfl' and the actual line number \n\ 223 value will be filled in with the second argument. The user would use this \n\ 224 alias as follows: \n\ 225 \n (lldb) commands alias bfl breakpoint set -f %1 -l %2 \n\ 226 <... some time later ...> \n\ 227 (lldb) bfl my-file.c 137 \n\ 228 \nThis would be the same as if the user had entered \n\ 229 'breakpoint set -f my-file.c -l 137'. \n\ 230 \nAnother example: \n\ 231 \n (lldb) commands alias pltty process launch -s -o %1 -e %1 \n\ 232 (lldb) pltty /dev/tty0 \n\ 233 // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\ 234 \nIf the user always wanted to pass the same value to a particular option, the \n\ 235 alias could be defined with that value directly in the alias as a constant, \n\ 236 rather than using a positional placeholder: \n\ 237 \n commands alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\ 238 // 3 of whatever file is indicated. \n"); 239 240 CommandArgumentEntry arg1; 241 CommandArgumentEntry arg2; 242 CommandArgumentEntry arg3; 243 CommandArgumentData alias_arg; 244 CommandArgumentData cmd_arg; 245 CommandArgumentData options_arg; 246 247 // Define the first (and only) variant of this arg. 248 alias_arg.arg_type = eArgTypeAliasName; 249 alias_arg.arg_repetition = eArgRepeatPlain; 250 251 // There is only one variant this argument could be; put it into the argument entry. 252 arg1.push_back (alias_arg); 253 254 // Define the first (and only) variant of this arg. 255 cmd_arg.arg_type = eArgTypeCommandName; 256 cmd_arg.arg_repetition = eArgRepeatPlain; 257 258 // There is only one variant this argument could be; put it into the argument entry. 259 arg2.push_back (cmd_arg); 260 261 // Define the first (and only) variant of this arg. 262 options_arg.arg_type = eArgTypeAliasOptions; 263 options_arg.arg_repetition = eArgRepeatOptional; 264 265 // There is only one variant this argument could be; put it into the argument entry. 266 arg3.push_back (options_arg); 267 268 // Push the data for the first argument into the m_arguments vector. 269 m_arguments.push_back (arg1); 270 m_arguments.push_back (arg2); 271 m_arguments.push_back (arg3); 272 } 273 274 ~CommandObjectCommandsAlias () 275 { 276 } 277 278 bool 279 WantsRawCommandString () 280 { 281 return true; 282 } 283 284 bool 285 ExecuteRawCommandString (const char *raw_command_line, CommandReturnObject &result) 286 { 287 Args args (raw_command_line); 288 std::string raw_command_string (raw_command_line); 289 290 size_t argc = args.GetArgumentCount(); 291 292 if (argc < 2) 293 { 294 result.AppendError ("'alias' requires at least two arguments"); 295 result.SetStatus (eReturnStatusFailed); 296 return false; 297 } 298 299 // Get the alias command. 300 301 const std::string alias_command = args.GetArgumentAtIndex (0); 302 303 // Strip the new alias name off 'raw_command_string' (leave it on args, which gets passed to 'Execute', which 304 // does the stripping itself. 305 size_t pos = raw_command_string.find (alias_command); 306 if (pos == 0) 307 { 308 raw_command_string = raw_command_string.substr (alias_command.size()); 309 pos = raw_command_string.find_first_not_of (' '); 310 if ((pos != std::string::npos) && (pos > 0)) 311 raw_command_string = raw_command_string.substr (pos); 312 } 313 else 314 { 315 result.AppendError ("Error parsing command string. No alias created."); 316 result.SetStatus (eReturnStatusFailed); 317 return false; 318 } 319 320 321 // Verify that the command is alias-able. 322 if (m_interpreter.CommandExists (alias_command.c_str())) 323 { 324 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", 325 alias_command.c_str()); 326 result.SetStatus (eReturnStatusFailed); 327 return false; 328 } 329 330 // Get CommandObject that is being aliased. The command name is read from the front of raw_command_string. 331 // raw_command_string is returned with the name of the command object stripped off the front. 332 CommandObject *cmd_obj = m_interpreter.GetCommandObjectForCommand (raw_command_string); 333 334 if (!cmd_obj) 335 { 336 result.AppendErrorWithFormat ("Invalid command given to 'alias'. '%s' does not begin with a valid command." 337 " No alias created.", raw_command_string.c_str()); 338 result.SetStatus (eReturnStatusFailed); 339 return false; 340 } 341 else if (!cmd_obj->WantsRawCommandString ()) 342 { 343 // Note that args was initialized with the original command, and has not been updated to this point. 344 // Therefore can we pass it to the version of Execute that does not need/expect raw input in the alias. 345 return Execute (args, result); 346 } 347 else 348 { 349 // Verify & handle any options/arguments passed to the alias command 350 351 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); 352 OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 353 354 // Check to see if there's anything left in the input command string. 355 if (raw_command_string.size() > 0) 356 { 357 358 // Check to see if the command being aliased can take any command options. 359 Options *options = cmd_obj->GetOptions(); 360 if (options) 361 { 362 // See if any options were specified as part of the alias; if so, handle them appropriately 363 options->NotifyOptionParsingStarting (); 364 Args tmp_args (raw_command_string.c_str()); 365 args.Unshift ("dummy_arg"); 366 args.ParseAliasOptions (*options, result, option_arg_vector, raw_command_string); 367 args.Shift (); 368 if (result.Succeeded()) 369 options->VerifyPartialOptions (result); 370 if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted) 371 { 372 result.AppendError ("Unable to create requested alias.\n"); 373 return false; 374 } 375 } 376 // Anything remaining must be plain raw input. Push it in as a single raw input argument. 377 if (raw_command_string.size() > 0) 378 option_arg_vector->push_back (OptionArgPair ("<argument>", 379 OptionArgValue (-1, 380 raw_command_string))); 381 } 382 383 // Create the alias 384 if (m_interpreter.AliasExists (alias_command.c_str()) 385 || m_interpreter.UserCommandExists (alias_command.c_str())) 386 { 387 OptionArgVectorSP temp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str())); 388 if (temp_option_arg_sp.get()) 389 { 390 if (option_arg_vector->size() == 0) 391 m_interpreter.RemoveAliasOptions (alias_command.c_str()); 392 } 393 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 394 alias_command.c_str()); 395 } 396 397 CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false); 398 if (cmd_obj_sp) 399 { 400 m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp); 401 if (option_arg_vector->size() > 0) 402 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); 403 result.SetStatus (eReturnStatusSuccessFinishNoResult); 404 } 405 else 406 { 407 result.AppendError ("Unable to create requested alias.\n"); 408 result.SetStatus (eReturnStatusFailed); 409 } 410 } 411 return result.Succeeded(); 412 } 413 414 bool 415 Execute 416 ( 417 Args& args, 418 CommandReturnObject &result 419 ) 420 { 421 size_t argc = args.GetArgumentCount(); 422 423 if (argc < 2) 424 { 425 result.AppendError ("'alias' requires at least two arguments"); 426 result.SetStatus (eReturnStatusFailed); 427 return false; 428 } 429 430 const std::string alias_command = args.GetArgumentAtIndex(0); 431 const std::string actual_command = args.GetArgumentAtIndex(1); 432 433 args.Shift(); // Shift the alias command word off the argument vector. 434 args.Shift(); // Shift the old command word off the argument vector. 435 436 // Verify that the command is alias'able, and get the appropriate command object. 437 438 if (m_interpreter.CommandExists (alias_command.c_str())) 439 { 440 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", 441 alias_command.c_str()); 442 result.SetStatus (eReturnStatusFailed); 443 } 444 else 445 { 446 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true)); 447 CommandObjectSP subcommand_obj_sp; 448 bool use_subcommand = false; 449 if (command_obj_sp.get()) 450 { 451 CommandObject *cmd_obj = command_obj_sp.get(); 452 CommandObject *sub_cmd_obj = NULL; 453 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); 454 OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 455 456 while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0) 457 { 458 if (argc >= 3) 459 { 460 const std::string sub_command = args.GetArgumentAtIndex(0); 461 assert (sub_command.length() != 0); 462 subcommand_obj_sp = 463 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str())); 464 if (subcommand_obj_sp.get()) 465 { 466 sub_cmd_obj = subcommand_obj_sp.get(); 467 use_subcommand = true; 468 args.Shift(); // Shift the sub_command word off the argument vector. 469 cmd_obj = sub_cmd_obj; 470 } 471 else 472 { 473 result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'. " 474 "Unable to create alias.\n", 475 sub_command.c_str(), actual_command.c_str()); 476 result.SetStatus (eReturnStatusFailed); 477 return false; 478 } 479 } 480 } 481 482 // Verify & handle any options/arguments passed to the alias command 483 484 if (args.GetArgumentCount () > 0) 485 { 486 if ((!use_subcommand && (cmd_obj->GetOptions() != NULL)) 487 || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL))) 488 { 489 Options *options; 490 if (use_subcommand) 491 options = sub_cmd_obj->GetOptions(); 492 else 493 options = cmd_obj->GetOptions(); 494 options->NotifyOptionParsingStarting (); 495 std::string empty_string; 496 args.Unshift ("dummy_arg"); 497 args.ParseAliasOptions (*options, result, option_arg_vector, empty_string); 498 args.Shift (); 499 if (result.Succeeded()) 500 options->VerifyPartialOptions (result); 501 if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted) 502 { 503 result.AppendError ("Unable to create requested command alias.\n"); 504 return false; 505 } 506 } 507 508 // Anything remaining in args must be a plain argument. 509 510 argc = args.GetArgumentCount(); 511 for (size_t i = 0; i < argc; ++i) 512 if (strcmp (args.GetArgumentAtIndex (i), "") != 0) 513 option_arg_vector->push_back 514 (OptionArgPair ("<argument>", 515 OptionArgValue (-1, 516 std::string (args.GetArgumentAtIndex (i))))); 517 } 518 519 // Create the alias. 520 521 if (m_interpreter.AliasExists (alias_command.c_str()) 522 || m_interpreter.UserCommandExists (alias_command.c_str())) 523 { 524 OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str())); 525 if (tmp_option_arg_sp.get()) 526 { 527 if (option_arg_vector->size() == 0) 528 m_interpreter.RemoveAliasOptions (alias_command.c_str()); 529 } 530 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 531 alias_command.c_str()); 532 } 533 534 if (use_subcommand) 535 m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp); 536 else 537 m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp); 538 if (option_arg_vector->size() > 0) 539 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); 540 result.SetStatus (eReturnStatusSuccessFinishNoResult); 541 } 542 else 543 { 544 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str()); 545 result.SetStatus (eReturnStatusFailed); 546 return false; 547 } 548 } 549 550 return result.Succeeded(); 551 } 552 }; 553 554 #pragma mark CommandObjectCommandsUnalias 555 //------------------------------------------------------------------------- 556 // CommandObjectCommandsUnalias 557 //------------------------------------------------------------------------- 558 559 class CommandObjectCommandsUnalias : public CommandObject 560 { 561 public: 562 CommandObjectCommandsUnalias (CommandInterpreter &interpreter) : 563 CommandObject (interpreter, 564 "command unalias", 565 "Allow the user to remove/delete a user-defined command abbreviation.", 566 NULL) 567 { 568 CommandArgumentEntry arg; 569 CommandArgumentData alias_arg; 570 571 // Define the first (and only) variant of this arg. 572 alias_arg.arg_type = eArgTypeAliasName; 573 alias_arg.arg_repetition = eArgRepeatPlain; 574 575 // There is only one variant this argument could be; put it into the argument entry. 576 arg.push_back (alias_arg); 577 578 // Push the data for the first argument into the m_arguments vector. 579 m_arguments.push_back (arg); 580 } 581 582 ~CommandObjectCommandsUnalias() 583 { 584 } 585 586 587 bool 588 Execute 589 ( 590 Args& args, 591 CommandReturnObject &result 592 ) 593 { 594 CommandObject::CommandMap::iterator pos; 595 CommandObject *cmd_obj; 596 597 if (args.GetArgumentCount() != 0) 598 { 599 const char *command_name = args.GetArgumentAtIndex(0); 600 cmd_obj = m_interpreter.GetCommandObject(command_name); 601 if (cmd_obj) 602 { 603 if (m_interpreter.CommandExists (command_name)) 604 { 605 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", 606 command_name); 607 result.SetStatus (eReturnStatusFailed); 608 } 609 else 610 { 611 612 if (m_interpreter.RemoveAlias (command_name) == false) 613 { 614 if (m_interpreter.AliasExists (command_name)) 615 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n", 616 command_name); 617 else 618 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name); 619 result.SetStatus (eReturnStatusFailed); 620 } 621 else 622 result.SetStatus (eReturnStatusSuccessFinishNoResult); 623 } 624 } 625 else 626 { 627 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a " 628 "current list of commands.\n", 629 command_name); 630 result.SetStatus (eReturnStatusFailed); 631 } 632 } 633 else 634 { 635 result.AppendError ("must call 'unalias' with a valid alias"); 636 result.SetStatus (eReturnStatusFailed); 637 } 638 639 return result.Succeeded(); 640 } 641 }; 642 643 #pragma mark CommandObjectCommandsAddRegex 644 //------------------------------------------------------------------------- 645 // CommandObjectCommandsAddRegex 646 //------------------------------------------------------------------------- 647 648 class CommandObjectCommandsAddRegex : public CommandObject 649 { 650 public: 651 CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) : 652 CommandObject (interpreter, 653 "command regex", 654 "Allow the user to create a regular expression command.", 655 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 656 m_options (interpreter) 657 { 658 SetHelpLong( 659 "This command allows the user to create powerful regular expression commands\n" 660 "with substitutions. The regular expressions and substitutions are specified\n" 661 "using the regular exression substitution format of:\n" 662 "\n" 663 " s/<regex>/<subst>/\n" 664 "\n" 665 "<regex> is a regular expression that can use parenthesis to capture regular\n" 666 "expression input and substitute the captured matches in the output using %1\n" 667 "for the first match, %2 for the second, and so on.\n" 668 "\n" 669 "The regular expressions can all be specified on the command line if more than\n" 670 "one argument is provided. If just the command name is provided on the command\n" 671 "line, then the regular expressions and substitutions can be entered on separate\n" 672 " lines, followed by an empty line to terminate the command definition.\n" 673 "\n" 674 "EXAMPLES\n" 675 "\n" 676 "The following example with define a regular expression command named 'f' that\n" 677 "will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if\n" 678 "a number follows 'f':\n" 679 "(lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/'\n" 680 ); 681 } 682 683 ~CommandObjectCommandsAddRegex() 684 { 685 } 686 687 688 bool 689 Execute (Args& args, CommandReturnObject &result) 690 { 691 const size_t argc = args.GetArgumentCount(); 692 if (argc == 0) 693 { 694 result.AppendError ("usage: 'commands regex <command-name> [s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 695 result.SetStatus (eReturnStatusFailed); 696 } 697 else 698 { 699 Error error; 700 const char *name = args.GetArgumentAtIndex(0); 701 m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter, 702 name, 703 m_options.GetHelp (), 704 m_options.GetSyntax (), 705 10)); 706 707 if (argc == 1) 708 { 709 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 710 if (reader_sp) 711 { 712 error =reader_sp->Initialize (CommandObjectCommandsAddRegex::InputReaderCallback, 713 this, // baton 714 eInputReaderGranularityLine, // token size, to pass to callback function 715 NULL, // end token 716 "> ", // prompt 717 true); // echo input 718 if (error.Success()) 719 { 720 m_interpreter.GetDebugger().PushInputReader (reader_sp); 721 result.SetStatus (eReturnStatusSuccessFinishNoResult); 722 return true; 723 } 724 } 725 } 726 else 727 { 728 for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx) 729 { 730 llvm::StringRef arg_strref (args.GetArgumentAtIndex(arg_idx)); 731 error = AppendRegexSubstitution (arg_strref); 732 if (error.Fail()) 733 break; 734 } 735 736 if (error.Success()) 737 { 738 AddRegexCommandToInterpreter(); 739 } 740 } 741 if (error.Fail()) 742 { 743 result.AppendError (error.AsCString()); 744 result.SetStatus (eReturnStatusFailed); 745 } 746 } 747 748 return result.Succeeded(); 749 } 750 751 Error 752 AppendRegexSubstitution (const llvm::StringRef ®ex_sed) 753 { 754 Error error; 755 756 if (m_regex_cmd_ap.get() == NULL) 757 { 758 error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'", 759 (int)regex_sed.size(), 760 regex_sed.data()); 761 return error; 762 } 763 764 size_t regex_sed_size = regex_sed.size(); 765 766 if (regex_sed_size <= 1) 767 { 768 error.SetErrorStringWithFormat("regular expression substitution string is too short: '%.*s'", 769 (int)regex_sed.size(), 770 regex_sed.data()); 771 return error; 772 } 773 774 if (regex_sed[0] != 's') 775 { 776 error.SetErrorStringWithFormat("regular expression substitution string doesn't start with 's': '%.*s'", 777 (int)regex_sed.size(), 778 regex_sed.data()); 779 return error; 780 } 781 const size_t first_separator_char_pos = 1; 782 // use the char that follows 's' as the regex separator character 783 // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 784 const char separator_char = regex_sed[first_separator_char_pos]; 785 const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1); 786 787 if (second_separator_char_pos == std::string::npos) 788 { 789 error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s'", 790 separator_char, 791 (int)(regex_sed.size() - first_separator_char_pos - 1), 792 regex_sed.data() + (first_separator_char_pos + 1)); 793 return error; 794 } 795 796 const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1); 797 798 if (third_separator_char_pos == std::string::npos) 799 { 800 error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s'", 801 separator_char, 802 (int)(regex_sed.size() - second_separator_char_pos - 1), 803 regex_sed.data() + (second_separator_char_pos + 1)); 804 return error; 805 } 806 807 if (third_separator_char_pos != regex_sed_size - 1) 808 { 809 // Make sure that everything that follows the last regex 810 // separator char 811 if (regex_sed.find_first_not_of("\t\n\v\f\r ", third_separator_char_pos + 1) != std::string::npos) 812 { 813 error.SetErrorStringWithFormat("extra data found after the '%.*s' regular expression substitution string: '%.*s'", 814 (int)third_separator_char_pos + 1, 815 regex_sed.data(), 816 (int)(regex_sed.size() - third_separator_char_pos - 1), 817 regex_sed.data() + (third_separator_char_pos + 1)); 818 return error; 819 } 820 821 } 822 else if (first_separator_char_pos + 1 == second_separator_char_pos) 823 { 824 error.SetErrorStringWithFormat("<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 825 separator_char, 826 separator_char, 827 separator_char, 828 (int)regex_sed.size(), 829 regex_sed.data()); 830 return error; 831 } 832 else if (second_separator_char_pos + 1 == third_separator_char_pos) 833 { 834 error.SetErrorStringWithFormat("<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 835 separator_char, 836 separator_char, 837 separator_char, 838 (int)regex_sed.size(), 839 regex_sed.data()); 840 return error; 841 } 842 std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1)); 843 std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1)); 844 m_regex_cmd_ap->AddRegexCommand (regex.c_str(), 845 subst.c_str()); 846 return error; 847 } 848 849 void 850 AddRegexCommandToInterpreter() 851 { 852 if (m_regex_cmd_ap.get()) 853 { 854 if (m_regex_cmd_ap->HasRegexEntries()) 855 { 856 CommandObjectSP cmd_sp (m_regex_cmd_ap.release()); 857 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 858 } 859 } 860 } 861 862 void 863 InputReaderDidCancel() 864 { 865 m_regex_cmd_ap.reset(); 866 } 867 868 static size_t 869 InputReaderCallback (void *baton, 870 InputReader &reader, 871 lldb::InputReaderAction notification, 872 const char *bytes, 873 size_t bytes_len); 874 private: 875 std::auto_ptr<CommandObjectRegexCommand> m_regex_cmd_ap; 876 877 class CommandOptions : public Options 878 { 879 public: 880 881 CommandOptions (CommandInterpreter &interpreter) : 882 Options (interpreter) 883 { 884 } 885 886 virtual 887 ~CommandOptions (){} 888 889 virtual Error 890 SetOptionValue (uint32_t option_idx, const char *option_arg) 891 { 892 Error error; 893 char short_option = (char) m_getopt_table[option_idx].val; 894 895 switch (short_option) 896 { 897 case 'h': 898 m_help.assign (option_arg); 899 break; 900 case 's': 901 m_syntax.assign (option_arg); 902 break; 903 904 default: 905 error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); 906 break; 907 } 908 909 return error; 910 } 911 912 void 913 OptionParsingStarting () 914 { 915 m_help.clear(); 916 m_syntax.clear(); 917 } 918 919 const OptionDefinition* 920 GetDefinitions () 921 { 922 return g_option_table; 923 } 924 925 // Options table: Required for subclasses of Options. 926 927 static OptionDefinition g_option_table[]; 928 929 const char * 930 GetHelp () 931 { 932 if (m_help.empty()) 933 return NULL; 934 return m_help.c_str(); 935 } 936 const char * 937 GetSyntax () 938 { 939 if (m_syntax.empty()) 940 return NULL; 941 return m_syntax.c_str(); 942 } 943 // Instance variables to hold the values for command options. 944 protected: 945 std::string m_help; 946 std::string m_syntax; 947 }; 948 949 CommandOptions m_options; 950 951 virtual Options * 952 GetOptions () 953 { 954 return &m_options; 955 } 956 957 }; 958 959 size_t 960 CommandObjectCommandsAddRegex::InputReaderCallback (void *baton, 961 InputReader &reader, 962 lldb::InputReaderAction notification, 963 const char *bytes, 964 size_t bytes_len) 965 { 966 CommandObjectCommandsAddRegex *add_regex_cmd = (CommandObjectCommandsAddRegex *) baton; 967 968 switch (notification) 969 { 970 case eInputReaderActivate: 971 reader.GetDebugger().GetOutputStream().Printf("%s\n", "Enter regular expressions in the form 's/<regex>/<subst>/' and terminate with an empty line:"); 972 break; 973 case eInputReaderReactivate: 974 break; 975 976 case eInputReaderDeactivate: 977 break; 978 979 case eInputReaderAsynchronousOutputWritten: 980 break; 981 982 case eInputReaderGotToken: 983 while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n')) 984 --bytes_len; 985 if (bytes_len == 0) 986 reader.SetIsDone(true); 987 else if (bytes) 988 { 989 llvm::StringRef bytes_strref (bytes, bytes_len); 990 Error error (add_regex_cmd->AppendRegexSubstitution (bytes_strref)); 991 if (error.Fail()) 992 { 993 reader.GetDebugger().GetOutputStream().Printf("error: %s\n", error.AsCString()); 994 add_regex_cmd->InputReaderDidCancel (); 995 reader.SetIsDone (true); 996 } 997 } 998 break; 999 1000 case eInputReaderInterrupt: 1001 reader.SetIsDone (true); 1002 reader.GetDebugger().GetOutputStream().PutCString("Regular expression command creations was cancelled.\n"); 1003 add_regex_cmd->InputReaderDidCancel (); 1004 break; 1005 1006 case eInputReaderEndOfFile: 1007 reader.SetIsDone (true); 1008 break; 1009 1010 case eInputReaderDone: 1011 add_regex_cmd->AddRegexCommandToInterpreter(); 1012 break; 1013 } 1014 1015 return bytes_len; 1016 } 1017 1018 1019 OptionDefinition 1020 CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] = 1021 { 1022 { LLDB_OPT_SET_1, false, "help" , 'h', required_argument, NULL, 0, eArgTypeNone, "The help text to display for this command."}, 1023 { LLDB_OPT_SET_1, false, "syntax", 's', required_argument, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."}, 1024 { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL } 1025 }; 1026 1027 1028 #pragma mark CommandObjectMultiwordCommands 1029 1030 //------------------------------------------------------------------------- 1031 // CommandObjectMultiwordCommands 1032 //------------------------------------------------------------------------- 1033 1034 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) : 1035 CommandObjectMultiword (interpreter, 1036 "command", 1037 "A set of commands for managing or customizing the debugger commands.", 1038 "command <subcommand> [<subcommand-options>]") 1039 { 1040 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter))); 1041 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter))); 1042 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter))); 1043 LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter))); 1044 } 1045 1046 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands () 1047 { 1048 } 1049 1050