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 CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false); 355 356 if (!m_interpreter.ProcessAliasOptionsArgs (cmd_obj_sp, raw_command_string.c_str(), option_arg_vector_sp)) 357 { 358 result.AppendError ("Unable to create requested alias.\n"); 359 result.SetStatus (eReturnStatusFailed); 360 return false; 361 } 362 363 // Create the alias 364 if (m_interpreter.AliasExists (alias_command.c_str()) 365 || m_interpreter.UserCommandExists (alias_command.c_str())) 366 { 367 OptionArgVectorSP temp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str())); 368 if (temp_option_arg_sp.get()) 369 { 370 if (option_arg_vector->size() == 0) 371 m_interpreter.RemoveAliasOptions (alias_command.c_str()); 372 } 373 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 374 alias_command.c_str()); 375 } 376 377 if (cmd_obj_sp) 378 { 379 m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp); 380 if (option_arg_vector->size() > 0) 381 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); 382 result.SetStatus (eReturnStatusSuccessFinishNoResult); 383 } 384 else 385 { 386 result.AppendError ("Unable to create requested alias.\n"); 387 result.SetStatus (eReturnStatusFailed); 388 } 389 } 390 return result.Succeeded(); 391 } 392 393 bool 394 Execute 395 ( 396 Args& args, 397 CommandReturnObject &result 398 ) 399 { 400 size_t argc = args.GetArgumentCount(); 401 402 if (argc < 2) 403 { 404 result.AppendError ("'alias' requires at least two arguments"); 405 result.SetStatus (eReturnStatusFailed); 406 return false; 407 } 408 409 const std::string alias_command = args.GetArgumentAtIndex(0); 410 const std::string actual_command = args.GetArgumentAtIndex(1); 411 412 args.Shift(); // Shift the alias command word off the argument vector. 413 args.Shift(); // Shift the old command word off the argument vector. 414 415 // Verify that the command is alias'able, and get the appropriate command object. 416 417 if (m_interpreter.CommandExists (alias_command.c_str())) 418 { 419 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", 420 alias_command.c_str()); 421 result.SetStatus (eReturnStatusFailed); 422 } 423 else 424 { 425 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true)); 426 CommandObjectSP subcommand_obj_sp; 427 bool use_subcommand = false; 428 if (command_obj_sp.get()) 429 { 430 CommandObject *cmd_obj = command_obj_sp.get(); 431 CommandObject *sub_cmd_obj = NULL; 432 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); 433 OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 434 435 while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0) 436 { 437 if (argc >= 3) 438 { 439 const std::string sub_command = args.GetArgumentAtIndex(0); 440 assert (sub_command.length() != 0); 441 subcommand_obj_sp = 442 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str())); 443 if (subcommand_obj_sp.get()) 444 { 445 sub_cmd_obj = subcommand_obj_sp.get(); 446 use_subcommand = true; 447 args.Shift(); // Shift the sub_command word off the argument vector. 448 cmd_obj = sub_cmd_obj; 449 } 450 else 451 { 452 result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'. " 453 "Unable to create alias.\n", 454 sub_command.c_str(), actual_command.c_str()); 455 result.SetStatus (eReturnStatusFailed); 456 return false; 457 } 458 } 459 } 460 461 // Verify & handle any options/arguments passed to the alias command 462 463 if (args.GetArgumentCount () > 0) 464 { 465 CommandObjectSP tmp_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false); 466 if (use_subcommand) 467 tmp_sp = m_interpreter.GetCommandSPExact (sub_cmd_obj->GetCommandName(), false); 468 469 std::string args_string; 470 args.GetCommandString (args_string); 471 472 if (!m_interpreter.ProcessAliasOptionsArgs (tmp_sp, args_string.c_str(), option_arg_vector_sp)) 473 { 474 result.AppendError ("Unable to create requested alias.\n"); 475 result.SetStatus (eReturnStatusFailed); 476 return false; 477 } 478 } 479 480 // Create the alias. 481 482 if (m_interpreter.AliasExists (alias_command.c_str()) 483 || m_interpreter.UserCommandExists (alias_command.c_str())) 484 { 485 OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str())); 486 if (tmp_option_arg_sp.get()) 487 { 488 if (option_arg_vector->size() == 0) 489 m_interpreter.RemoveAliasOptions (alias_command.c_str()); 490 } 491 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 492 alias_command.c_str()); 493 } 494 495 if (use_subcommand) 496 m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp); 497 else 498 m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp); 499 if (option_arg_vector->size() > 0) 500 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); 501 result.SetStatus (eReturnStatusSuccessFinishNoResult); 502 } 503 else 504 { 505 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str()); 506 result.SetStatus (eReturnStatusFailed); 507 return false; 508 } 509 } 510 511 return result.Succeeded(); 512 } 513 }; 514 515 #pragma mark CommandObjectCommandsUnalias 516 //------------------------------------------------------------------------- 517 // CommandObjectCommandsUnalias 518 //------------------------------------------------------------------------- 519 520 class CommandObjectCommandsUnalias : public CommandObject 521 { 522 public: 523 CommandObjectCommandsUnalias (CommandInterpreter &interpreter) : 524 CommandObject (interpreter, 525 "command unalias", 526 "Allow the user to remove/delete a user-defined command abbreviation.", 527 NULL) 528 { 529 CommandArgumentEntry arg; 530 CommandArgumentData alias_arg; 531 532 // Define the first (and only) variant of this arg. 533 alias_arg.arg_type = eArgTypeAliasName; 534 alias_arg.arg_repetition = eArgRepeatPlain; 535 536 // There is only one variant this argument could be; put it into the argument entry. 537 arg.push_back (alias_arg); 538 539 // Push the data for the first argument into the m_arguments vector. 540 m_arguments.push_back (arg); 541 } 542 543 ~CommandObjectCommandsUnalias() 544 { 545 } 546 547 548 bool 549 Execute 550 ( 551 Args& args, 552 CommandReturnObject &result 553 ) 554 { 555 CommandObject::CommandMap::iterator pos; 556 CommandObject *cmd_obj; 557 558 if (args.GetArgumentCount() != 0) 559 { 560 const char *command_name = args.GetArgumentAtIndex(0); 561 cmd_obj = m_interpreter.GetCommandObject(command_name); 562 if (cmd_obj) 563 { 564 if (m_interpreter.CommandExists (command_name)) 565 { 566 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", 567 command_name); 568 result.SetStatus (eReturnStatusFailed); 569 } 570 else 571 { 572 573 if (m_interpreter.RemoveAlias (command_name) == false) 574 { 575 if (m_interpreter.AliasExists (command_name)) 576 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n", 577 command_name); 578 else 579 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name); 580 result.SetStatus (eReturnStatusFailed); 581 } 582 else 583 result.SetStatus (eReturnStatusSuccessFinishNoResult); 584 } 585 } 586 else 587 { 588 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a " 589 "current list of commands.\n", 590 command_name); 591 result.SetStatus (eReturnStatusFailed); 592 } 593 } 594 else 595 { 596 result.AppendError ("must call 'unalias' with a valid alias"); 597 result.SetStatus (eReturnStatusFailed); 598 } 599 600 return result.Succeeded(); 601 } 602 }; 603 604 #pragma mark CommandObjectCommandsAddRegex 605 //------------------------------------------------------------------------- 606 // CommandObjectCommandsAddRegex 607 //------------------------------------------------------------------------- 608 609 class CommandObjectCommandsAddRegex : public CommandObject 610 { 611 public: 612 CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) : 613 CommandObject (interpreter, 614 "command regex", 615 "Allow the user to create a regular expression command.", 616 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 617 m_options (interpreter) 618 { 619 SetHelpLong( 620 "This command allows the user to create powerful regular expression commands\n" 621 "with substitutions. The regular expressions and substitutions are specified\n" 622 "using the regular exression substitution format of:\n" 623 "\n" 624 " s/<regex>/<subst>/\n" 625 "\n" 626 "<regex> is a regular expression that can use parenthesis to capture regular\n" 627 "expression input and substitute the captured matches in the output using %1\n" 628 "for the first match, %2 for the second, and so on.\n" 629 "\n" 630 "The regular expressions can all be specified on the command line if more than\n" 631 "one argument is provided. If just the command name is provided on the command\n" 632 "line, then the regular expressions and substitutions can be entered on separate\n" 633 " lines, followed by an empty line to terminate the command definition.\n" 634 "\n" 635 "EXAMPLES\n" 636 "\n" 637 "The following example with define a regular expression command named 'f' that\n" 638 "will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if\n" 639 "a number follows 'f':\n" 640 "(lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/'\n" 641 ); 642 } 643 644 ~CommandObjectCommandsAddRegex() 645 { 646 } 647 648 649 bool 650 Execute (Args& args, CommandReturnObject &result) 651 { 652 const size_t argc = args.GetArgumentCount(); 653 if (argc == 0) 654 { 655 result.AppendError ("usage: 'commands regex <command-name> [s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 656 result.SetStatus (eReturnStatusFailed); 657 } 658 else 659 { 660 Error error; 661 const char *name = args.GetArgumentAtIndex(0); 662 m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter, 663 name, 664 m_options.GetHelp (), 665 m_options.GetSyntax (), 666 10)); 667 668 if (argc == 1) 669 { 670 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 671 if (reader_sp) 672 { 673 error =reader_sp->Initialize (CommandObjectCommandsAddRegex::InputReaderCallback, 674 this, // baton 675 eInputReaderGranularityLine, // token size, to pass to callback function 676 NULL, // end token 677 "> ", // prompt 678 true); // echo input 679 if (error.Success()) 680 { 681 m_interpreter.GetDebugger().PushInputReader (reader_sp); 682 result.SetStatus (eReturnStatusSuccessFinishNoResult); 683 return true; 684 } 685 } 686 } 687 else 688 { 689 for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx) 690 { 691 llvm::StringRef arg_strref (args.GetArgumentAtIndex(arg_idx)); 692 error = AppendRegexSubstitution (arg_strref); 693 if (error.Fail()) 694 break; 695 } 696 697 if (error.Success()) 698 { 699 AddRegexCommandToInterpreter(); 700 } 701 } 702 if (error.Fail()) 703 { 704 result.AppendError (error.AsCString()); 705 result.SetStatus (eReturnStatusFailed); 706 } 707 } 708 709 return result.Succeeded(); 710 } 711 712 Error 713 AppendRegexSubstitution (const llvm::StringRef ®ex_sed) 714 { 715 Error error; 716 717 if (m_regex_cmd_ap.get() == NULL) 718 { 719 error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'", 720 (int)regex_sed.size(), 721 regex_sed.data()); 722 return error; 723 } 724 725 size_t regex_sed_size = regex_sed.size(); 726 727 if (regex_sed_size <= 1) 728 { 729 error.SetErrorStringWithFormat("regular expression substitution string is too short: '%.*s'", 730 (int)regex_sed.size(), 731 regex_sed.data()); 732 return error; 733 } 734 735 if (regex_sed[0] != 's') 736 { 737 error.SetErrorStringWithFormat("regular expression substitution string doesn't start with 's': '%.*s'", 738 (int)regex_sed.size(), 739 regex_sed.data()); 740 return error; 741 } 742 const size_t first_separator_char_pos = 1; 743 // use the char that follows 's' as the regex separator character 744 // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 745 const char separator_char = regex_sed[first_separator_char_pos]; 746 const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1); 747 748 if (second_separator_char_pos == std::string::npos) 749 { 750 error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s'", 751 separator_char, 752 (int)(regex_sed.size() - first_separator_char_pos - 1), 753 regex_sed.data() + (first_separator_char_pos + 1)); 754 return error; 755 } 756 757 const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1); 758 759 if (third_separator_char_pos == std::string::npos) 760 { 761 error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s'", 762 separator_char, 763 (int)(regex_sed.size() - second_separator_char_pos - 1), 764 regex_sed.data() + (second_separator_char_pos + 1)); 765 return error; 766 } 767 768 if (third_separator_char_pos != regex_sed_size - 1) 769 { 770 // Make sure that everything that follows the last regex 771 // separator char 772 if (regex_sed.find_first_not_of("\t\n\v\f\r ", third_separator_char_pos + 1) != std::string::npos) 773 { 774 error.SetErrorStringWithFormat("extra data found after the '%.*s' regular expression substitution string: '%.*s'", 775 (int)third_separator_char_pos + 1, 776 regex_sed.data(), 777 (int)(regex_sed.size() - third_separator_char_pos - 1), 778 regex_sed.data() + (third_separator_char_pos + 1)); 779 return error; 780 } 781 782 } 783 else if (first_separator_char_pos + 1 == second_separator_char_pos) 784 { 785 error.SetErrorStringWithFormat("<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 786 separator_char, 787 separator_char, 788 separator_char, 789 (int)regex_sed.size(), 790 regex_sed.data()); 791 return error; 792 } 793 else if (second_separator_char_pos + 1 == third_separator_char_pos) 794 { 795 error.SetErrorStringWithFormat("<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 796 separator_char, 797 separator_char, 798 separator_char, 799 (int)regex_sed.size(), 800 regex_sed.data()); 801 return error; 802 } 803 std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1)); 804 std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1)); 805 m_regex_cmd_ap->AddRegexCommand (regex.c_str(), 806 subst.c_str()); 807 return error; 808 } 809 810 void 811 AddRegexCommandToInterpreter() 812 { 813 if (m_regex_cmd_ap.get()) 814 { 815 if (m_regex_cmd_ap->HasRegexEntries()) 816 { 817 CommandObjectSP cmd_sp (m_regex_cmd_ap.release()); 818 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 819 } 820 } 821 } 822 823 void 824 InputReaderDidCancel() 825 { 826 m_regex_cmd_ap.reset(); 827 } 828 829 static size_t 830 InputReaderCallback (void *baton, 831 InputReader &reader, 832 lldb::InputReaderAction notification, 833 const char *bytes, 834 size_t bytes_len); 835 private: 836 std::auto_ptr<CommandObjectRegexCommand> m_regex_cmd_ap; 837 838 class CommandOptions : public Options 839 { 840 public: 841 842 CommandOptions (CommandInterpreter &interpreter) : 843 Options (interpreter) 844 { 845 } 846 847 virtual 848 ~CommandOptions (){} 849 850 virtual Error 851 SetOptionValue (uint32_t option_idx, const char *option_arg) 852 { 853 Error error; 854 char short_option = (char) m_getopt_table[option_idx].val; 855 856 switch (short_option) 857 { 858 case 'h': 859 m_help.assign (option_arg); 860 break; 861 case 's': 862 m_syntax.assign (option_arg); 863 break; 864 865 default: 866 error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); 867 break; 868 } 869 870 return error; 871 } 872 873 void 874 OptionParsingStarting () 875 { 876 m_help.clear(); 877 m_syntax.clear(); 878 } 879 880 const OptionDefinition* 881 GetDefinitions () 882 { 883 return g_option_table; 884 } 885 886 // Options table: Required for subclasses of Options. 887 888 static OptionDefinition g_option_table[]; 889 890 const char * 891 GetHelp () 892 { 893 if (m_help.empty()) 894 return NULL; 895 return m_help.c_str(); 896 } 897 const char * 898 GetSyntax () 899 { 900 if (m_syntax.empty()) 901 return NULL; 902 return m_syntax.c_str(); 903 } 904 // Instance variables to hold the values for command options. 905 protected: 906 std::string m_help; 907 std::string m_syntax; 908 }; 909 910 CommandOptions m_options; 911 912 virtual Options * 913 GetOptions () 914 { 915 return &m_options; 916 } 917 918 }; 919 920 size_t 921 CommandObjectCommandsAddRegex::InputReaderCallback (void *baton, 922 InputReader &reader, 923 lldb::InputReaderAction notification, 924 const char *bytes, 925 size_t bytes_len) 926 { 927 CommandObjectCommandsAddRegex *add_regex_cmd = (CommandObjectCommandsAddRegex *) baton; 928 929 switch (notification) 930 { 931 case eInputReaderActivate: 932 reader.GetDebugger().GetOutputStream().Printf("%s\n", "Enter regular expressions in the form 's/<regex>/<subst>/' and terminate with an empty line:"); 933 break; 934 case eInputReaderReactivate: 935 break; 936 937 case eInputReaderDeactivate: 938 break; 939 940 case eInputReaderAsynchronousOutputWritten: 941 break; 942 943 case eInputReaderGotToken: 944 while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n')) 945 --bytes_len; 946 if (bytes_len == 0) 947 reader.SetIsDone(true); 948 else if (bytes) 949 { 950 llvm::StringRef bytes_strref (bytes, bytes_len); 951 Error error (add_regex_cmd->AppendRegexSubstitution (bytes_strref)); 952 if (error.Fail()) 953 { 954 reader.GetDebugger().GetOutputStream().Printf("error: %s\n", error.AsCString()); 955 add_regex_cmd->InputReaderDidCancel (); 956 reader.SetIsDone (true); 957 } 958 } 959 break; 960 961 case eInputReaderInterrupt: 962 reader.SetIsDone (true); 963 reader.GetDebugger().GetOutputStream().PutCString("Regular expression command creations was cancelled.\n"); 964 add_regex_cmd->InputReaderDidCancel (); 965 break; 966 967 case eInputReaderEndOfFile: 968 reader.SetIsDone (true); 969 break; 970 971 case eInputReaderDone: 972 add_regex_cmd->AddRegexCommandToInterpreter(); 973 break; 974 } 975 976 return bytes_len; 977 } 978 979 980 OptionDefinition 981 CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] = 982 { 983 { LLDB_OPT_SET_1, false, "help" , 'h', required_argument, NULL, 0, eArgTypeNone, "The help text to display for this command."}, 984 { LLDB_OPT_SET_1, false, "syntax", 's', required_argument, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."}, 985 { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL } 986 }; 987 988 989 #pragma mark CommandObjectMultiwordCommands 990 991 //------------------------------------------------------------------------- 992 // CommandObjectMultiwordCommands 993 //------------------------------------------------------------------------- 994 995 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) : 996 CommandObjectMultiword (interpreter, 997 "command", 998 "A set of commands for managing or customizing the debugger commands.", 999 "command <subcommand> [<subcommand-options>]") 1000 { 1001 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter))); 1002 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter))); 1003 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter))); 1004 LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter))); 1005 } 1006 1007 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands () 1008 { 1009 } 1010 1011