1 //===-- Args.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 "lldb/lldb-python.h" 11 12 // C Includes 13 #include <getopt.h> 14 #include <cstdlib> 15 // C++ Includes 16 // Other libraries and framework includes 17 // Project includes 18 #include "lldb/Interpreter/Args.h" 19 #include "lldb/Core/Stream.h" 20 #include "lldb/Core/StreamFile.h" 21 #include "lldb/Core/StreamString.h" 22 #include "lldb/DataFormatters/FormatManager.h" 23 #include "lldb/Interpreter/Options.h" 24 #include "lldb/Interpreter/CommandReturnObject.h" 25 #include "lldb/Target/Process.h" 26 //#include "lldb/Target/RegisterContext.h" 27 #include "lldb/Target/StackFrame.h" 28 #include "lldb/Target/Target.h" 29 //#include "lldb/Target/Thread.h" 30 31 using namespace lldb; 32 using namespace lldb_private; 33 34 //---------------------------------------------------------------------- 35 // Args constructor 36 //---------------------------------------------------------------------- 37 Args::Args (const char *command) : 38 m_args(), 39 m_argv(), 40 m_args_quote_char() 41 { 42 if (command) 43 SetCommandString (command); 44 } 45 46 47 Args::Args (const char *command, size_t len) : 48 m_args(), 49 m_argv(), 50 m_args_quote_char() 51 { 52 if (command && len) 53 SetCommandString (command, len); 54 } 55 56 //---------------------------------------------------------------------- 57 // We have to be very careful on the copy constructor of this class 58 // to make sure we copy all of the string values, but we can't copy the 59 // rhs.m_argv into m_argv since it will point to the "const char *" c 60 // strings in rhs.m_args. We need to copy the string list and update our 61 // own m_argv appropriately. 62 //---------------------------------------------------------------------- 63 Args::Args (const Args &rhs) : 64 m_args (rhs.m_args), 65 m_argv (), 66 m_args_quote_char(rhs.m_args_quote_char) 67 { 68 UpdateArgvFromArgs(); 69 } 70 71 //---------------------------------------------------------------------- 72 // We have to be very careful on the copy constructor of this class 73 // to make sure we copy all of the string values, but we can't copy the 74 // rhs.m_argv into m_argv since it will point to the "const char *" c 75 // strings in rhs.m_args. We need to copy the string list and update our 76 // own m_argv appropriately. 77 //---------------------------------------------------------------------- 78 const Args & 79 Args::operator= (const Args &rhs) 80 { 81 // Make sure we aren't assigning to self 82 if (this != &rhs) 83 { 84 m_args = rhs.m_args; 85 m_args_quote_char = rhs.m_args_quote_char; 86 UpdateArgvFromArgs(); 87 } 88 return *this; 89 } 90 91 //---------------------------------------------------------------------- 92 // Destructor 93 //---------------------------------------------------------------------- 94 Args::~Args () 95 { 96 } 97 98 void 99 Args::Dump (Stream *s) 100 { 101 const size_t argc = m_argv.size(); 102 for (size_t i=0; i<argc; ++i) 103 { 104 s->Indent(); 105 const char *arg_cstr = m_argv[i]; 106 if (arg_cstr) 107 s->Printf("argv[%zi]=\"%s\"\n", i, arg_cstr); 108 else 109 s->Printf("argv[%zi]=NULL\n", i); 110 } 111 s->EOL(); 112 } 113 114 bool 115 Args::GetCommandString (std::string &command) const 116 { 117 command.clear(); 118 const size_t argc = GetArgumentCount(); 119 for (size_t i=0; i<argc; ++i) 120 { 121 if (i > 0) 122 command += ' '; 123 command += m_argv[i]; 124 } 125 return argc > 0; 126 } 127 128 bool 129 Args::GetQuotedCommandString (std::string &command) const 130 { 131 command.clear (); 132 const size_t argc = GetArgumentCount(); 133 for (size_t i = 0; i < argc; ++i) 134 { 135 if (i > 0) 136 command.append (1, ' '); 137 char quote_char = GetArgumentQuoteCharAtIndex(i); 138 if (quote_char) 139 { 140 command.append (1, quote_char); 141 command.append (m_argv[i]); 142 command.append (1, quote_char); 143 } 144 else 145 command.append (m_argv[i]); 146 } 147 return argc > 0; 148 } 149 150 void 151 Args::SetCommandString (const char *command, size_t len) 152 { 153 // Use std::string to make sure we get a NULL terminated string we can use 154 // as "command" could point to a string within a large string.... 155 std::string null_terminated_command(command, len); 156 SetCommandString(null_terminated_command.c_str()); 157 } 158 159 void 160 Args::SetCommandString (const char *command) 161 { 162 m_args.clear(); 163 m_argv.clear(); 164 m_args_quote_char.clear(); 165 166 if (command && command[0]) 167 { 168 static const char *k_space_separators = " \t"; 169 static const char *k_space_separators_with_slash_and_quotes = " \t \\'\""; 170 const char *arg_end = NULL; 171 const char *arg_pos; 172 for (arg_pos = command; 173 arg_pos && arg_pos[0]; 174 arg_pos = arg_end) 175 { 176 // Skip any leading space separators 177 const char *arg_start = ::strspn (arg_pos, k_space_separators) + arg_pos; 178 179 // If there were only space separators to the end of the line, then 180 // we're done. 181 if (*arg_start == '\0') 182 break; 183 184 // Arguments can be split into multiple discontiguous pieces, 185 // for example: 186 // "Hello ""World" 187 // this would result in a single argument "Hello World" (without/ 188 // the quotes) since the quotes would be removed and there is 189 // not space between the strings. So we need to keep track of the 190 // current start of each argument piece in "arg_piece_start" 191 const char *arg_piece_start = arg_start; 192 arg_pos = arg_piece_start; 193 194 std::string arg; 195 // Since we can have multiple quotes that form a single command 196 // in a command like: "Hello "world'!' (which will make a single 197 // argument "Hello world!") we remember the first quote character 198 // we encounter and use that for the quote character. 199 char first_quote_char = '\0'; 200 char quote_char = '\0'; 201 bool arg_complete = false; 202 203 do 204 { 205 arg_end = ::strcspn (arg_pos, k_space_separators_with_slash_and_quotes) + arg_pos; 206 207 switch (arg_end[0]) 208 { 209 default: 210 assert (!"Unhandled case statement, we must handle this..."); 211 break; 212 213 case '\0': 214 // End of C string 215 if (arg_piece_start && arg_piece_start[0]) 216 arg.append (arg_piece_start); 217 arg_complete = true; 218 break; 219 220 case '\\': 221 // Backslash character 222 switch (arg_end[1]) 223 { 224 case '\0': 225 arg.append (arg_piece_start); 226 ++arg_end; 227 arg_complete = true; 228 break; 229 230 default: 231 if (quote_char == '\0') 232 { 233 arg.append (arg_piece_start, arg_end - arg_piece_start); 234 if (arg_end[1] != '\0') 235 { 236 arg.append (arg_end + 1, 1); 237 arg_pos = arg_end + 2; 238 arg_piece_start = arg_pos; 239 } 240 } 241 else 242 arg_pos = arg_end + 2; 243 break; 244 } 245 break; 246 247 case '"': 248 case '\'': 249 case '`': 250 // Quote characters 251 if (quote_char) 252 { 253 // We found a quote character while inside a quoted 254 // character argument. If it matches our current quote 255 // character, this ends the effect of the quotes. If it 256 // doesn't we ignore it. 257 if (quote_char == arg_end[0]) 258 { 259 arg.append (arg_piece_start, arg_end - arg_piece_start); 260 // Clear the quote character and let parsing 261 // continue (we need to watch for things like: 262 // "Hello ""World" 263 // "Hello "World 264 // "Hello "'World' 265 // All of which will result in a single argument "Hello World" 266 quote_char = '\0'; // Note that we are no longer inside quotes 267 arg_pos = arg_end + 1; // Skip the quote character 268 arg_piece_start = arg_pos; // Note we are starting from later in the string 269 } 270 else 271 { 272 // different quote, skip it and keep going 273 arg_pos = arg_end + 1; 274 } 275 } 276 else 277 { 278 // We found the start of a quote scope. 279 // Make sure there isn't a string that precedes 280 // the start of a quote scope like: 281 // Hello" World" 282 // If so, then add the "Hello" to the arg 283 if (arg_end > arg_piece_start) 284 arg.append (arg_piece_start, arg_end - arg_piece_start); 285 286 // Enter into a quote scope 287 quote_char = arg_end[0]; 288 289 if (first_quote_char == '\0') 290 first_quote_char = quote_char; 291 292 arg_pos = arg_end; 293 ++arg_pos; // Skip the quote character 294 arg_piece_start = arg_pos; // Note we are starting from later in the string 295 296 // Skip till the next quote character 297 const char *end_quote = ::strchr (arg_piece_start, quote_char); 298 while (end_quote && end_quote[-1] == '\\') 299 { 300 // Don't skip the quote character if it is 301 // preceded by a '\' character 302 end_quote = ::strchr (end_quote + 1, quote_char); 303 } 304 305 if (end_quote) 306 { 307 if (end_quote > arg_piece_start) 308 arg.append (arg_piece_start, end_quote - arg_piece_start); 309 310 // If the next character is a space or the end of 311 // string, this argument is complete... 312 if (end_quote[1] == ' ' || end_quote[1] == '\t' || end_quote[1] == '\0') 313 { 314 arg_complete = true; 315 arg_end = end_quote + 1; 316 } 317 else 318 { 319 arg_pos = end_quote + 1; 320 arg_piece_start = arg_pos; 321 } 322 quote_char = '\0'; 323 } 324 else 325 { 326 // Consume the rest of the string as there was no terminating quote 327 arg.append(arg_piece_start); 328 arg_end = arg_piece_start + strlen(arg_piece_start); 329 arg_complete = true; 330 } 331 } 332 break; 333 334 case ' ': 335 case '\t': 336 if (quote_char) 337 { 338 // We are currently processing a quoted character and found 339 // a space character, skip any spaces and keep trying to find 340 // the end of the argument. 341 arg_pos = ::strspn (arg_end, k_space_separators) + arg_end; 342 } 343 else 344 { 345 // We are not inside any quotes, we just found a space after an 346 // argument 347 if (arg_end > arg_piece_start) 348 arg.append (arg_piece_start, arg_end - arg_piece_start); 349 arg_complete = true; 350 } 351 break; 352 } 353 } while (!arg_complete); 354 355 m_args.push_back(arg); 356 m_args_quote_char.push_back (first_quote_char); 357 } 358 UpdateArgvFromArgs(); 359 } 360 } 361 362 void 363 Args::UpdateArgsAfterOptionParsing() 364 { 365 // Now m_argv might be out of date with m_args, so we need to fix that 366 arg_cstr_collection::const_iterator argv_pos, argv_end = m_argv.end(); 367 arg_sstr_collection::iterator args_pos; 368 arg_quote_char_collection::iterator quotes_pos; 369 370 for (argv_pos = m_argv.begin(), args_pos = m_args.begin(), quotes_pos = m_args_quote_char.begin(); 371 argv_pos != argv_end && args_pos != m_args.end(); 372 ++argv_pos) 373 { 374 const char *argv_cstr = *argv_pos; 375 if (argv_cstr == NULL) 376 break; 377 378 while (args_pos != m_args.end()) 379 { 380 const char *args_cstr = args_pos->c_str(); 381 if (args_cstr == argv_cstr) 382 { 383 // We found the argument that matches the C string in the 384 // vector, so we can now look for the next one 385 ++args_pos; 386 ++quotes_pos; 387 break; 388 } 389 else 390 { 391 quotes_pos = m_args_quote_char.erase (quotes_pos); 392 args_pos = m_args.erase (args_pos); 393 } 394 } 395 } 396 397 if (args_pos != m_args.end()) 398 m_args.erase (args_pos, m_args.end()); 399 400 if (quotes_pos != m_args_quote_char.end()) 401 m_args_quote_char.erase (quotes_pos, m_args_quote_char.end()); 402 } 403 404 void 405 Args::UpdateArgvFromArgs() 406 { 407 m_argv.clear(); 408 arg_sstr_collection::const_iterator pos, end = m_args.end(); 409 for (pos = m_args.begin(); pos != end; ++pos) 410 m_argv.push_back(pos->c_str()); 411 m_argv.push_back(NULL); 412 // Make sure we have enough arg quote chars in the array 413 if (m_args_quote_char.size() < m_args.size()) 414 m_args_quote_char.resize (m_argv.size()); 415 } 416 417 size_t 418 Args::GetArgumentCount() const 419 { 420 if (m_argv.empty()) 421 return 0; 422 return m_argv.size() - 1; 423 } 424 425 const char * 426 Args::GetArgumentAtIndex (size_t idx) const 427 { 428 if (idx < m_argv.size()) 429 return m_argv[idx]; 430 return NULL; 431 } 432 433 char 434 Args::GetArgumentQuoteCharAtIndex (size_t idx) const 435 { 436 if (idx < m_args_quote_char.size()) 437 return m_args_quote_char[idx]; 438 return '\0'; 439 } 440 441 char ** 442 Args::GetArgumentVector() 443 { 444 if (!m_argv.empty()) 445 return (char **)&m_argv[0]; 446 return NULL; 447 } 448 449 const char ** 450 Args::GetConstArgumentVector() const 451 { 452 if (!m_argv.empty()) 453 return (const char **)&m_argv[0]; 454 return NULL; 455 } 456 457 void 458 Args::Shift () 459 { 460 // Don't pop the last NULL terminator from the argv array 461 if (m_argv.size() > 1) 462 { 463 m_argv.erase(m_argv.begin()); 464 m_args.pop_front(); 465 if (!m_args_quote_char.empty()) 466 m_args_quote_char.erase(m_args_quote_char.begin()); 467 } 468 } 469 470 const char * 471 Args::Unshift (const char *arg_cstr, char quote_char) 472 { 473 m_args.push_front(arg_cstr); 474 m_argv.insert(m_argv.begin(), m_args.front().c_str()); 475 m_args_quote_char.insert(m_args_quote_char.begin(), quote_char); 476 return GetArgumentAtIndex (0); 477 } 478 479 void 480 Args::AppendArguments (const Args &rhs) 481 { 482 const size_t rhs_argc = rhs.GetArgumentCount(); 483 for (size_t i=0; i<rhs_argc; ++i) 484 AppendArgument(rhs.GetArgumentAtIndex(i)); 485 } 486 487 void 488 Args::AppendArguments (const char **argv) 489 { 490 if (argv) 491 { 492 for (uint32_t i=0; argv[i]; ++i) 493 AppendArgument(argv[i]); 494 } 495 } 496 497 const char * 498 Args::AppendArgument (const char *arg_cstr, char quote_char) 499 { 500 return InsertArgumentAtIndex (GetArgumentCount(), arg_cstr, quote_char); 501 } 502 503 const char * 504 Args::InsertArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char) 505 { 506 // Since we are using a std::list to hold onto the copied C string and 507 // we don't have direct access to the elements, we have to iterate to 508 // find the value. 509 arg_sstr_collection::iterator pos, end = m_args.end(); 510 size_t i = idx; 511 for (pos = m_args.begin(); i > 0 && pos != end; ++pos) 512 --i; 513 514 pos = m_args.insert(pos, arg_cstr); 515 516 if (idx >= m_args_quote_char.size()) 517 { 518 m_args_quote_char.resize(idx + 1); 519 m_args_quote_char[idx] = quote_char; 520 } 521 else 522 m_args_quote_char.insert(m_args_quote_char.begin() + idx, quote_char); 523 524 UpdateArgvFromArgs(); 525 return GetArgumentAtIndex(idx); 526 } 527 528 const char * 529 Args::ReplaceArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char) 530 { 531 // Since we are using a std::list to hold onto the copied C string and 532 // we don't have direct access to the elements, we have to iterate to 533 // find the value. 534 arg_sstr_collection::iterator pos, end = m_args.end(); 535 size_t i = idx; 536 for (pos = m_args.begin(); i > 0 && pos != end; ++pos) 537 --i; 538 539 if (pos != end) 540 { 541 pos->assign(arg_cstr); 542 assert(idx < m_argv.size() - 1); 543 m_argv[idx] = pos->c_str(); 544 if (idx >= m_args_quote_char.size()) 545 m_args_quote_char.resize(idx + 1); 546 m_args_quote_char[idx] = quote_char; 547 return GetArgumentAtIndex(idx); 548 } 549 return NULL; 550 } 551 552 void 553 Args::DeleteArgumentAtIndex (size_t idx) 554 { 555 // Since we are using a std::list to hold onto the copied C string and 556 // we don't have direct access to the elements, we have to iterate to 557 // find the value. 558 arg_sstr_collection::iterator pos, end = m_args.end(); 559 size_t i = idx; 560 for (pos = m_args.begin(); i > 0 && pos != end; ++pos) 561 --i; 562 563 if (pos != end) 564 { 565 m_args.erase (pos); 566 assert(idx < m_argv.size() - 1); 567 m_argv.erase(m_argv.begin() + idx); 568 if (idx < m_args_quote_char.size()) 569 m_args_quote_char.erase(m_args_quote_char.begin() + idx); 570 } 571 } 572 573 void 574 Args::SetArguments (size_t argc, const char **argv) 575 { 576 // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is 577 // no need to clear it here. 578 m_args.clear(); 579 m_args_quote_char.clear(); 580 581 // First copy each string 582 for (size_t i=0; i<argc; ++i) 583 { 584 m_args.push_back (argv[i]); 585 if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`')) 586 m_args_quote_char.push_back (argv[i][0]); 587 else 588 m_args_quote_char.push_back ('\0'); 589 } 590 591 UpdateArgvFromArgs(); 592 } 593 594 void 595 Args::SetArguments (const char **argv) 596 { 597 // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is 598 // no need to clear it here. 599 m_args.clear(); 600 m_args_quote_char.clear(); 601 602 if (argv) 603 { 604 // First copy each string 605 for (size_t i=0; argv[i]; ++i) 606 { 607 m_args.push_back (argv[i]); 608 if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`')) 609 m_args_quote_char.push_back (argv[i][0]); 610 else 611 m_args_quote_char.push_back ('\0'); 612 } 613 } 614 615 UpdateArgvFromArgs(); 616 } 617 618 619 Error 620 Args::ParseOptions (Options &options) 621 { 622 StreamString sstr; 623 Error error; 624 struct option *long_options = options.GetLongOptions(); 625 if (long_options == NULL) 626 { 627 error.SetErrorStringWithFormat("invalid long options"); 628 return error; 629 } 630 631 for (int i=0; long_options[i].name != NULL; ++i) 632 { 633 if (long_options[i].flag == NULL) 634 { 635 if (isprint8(long_options[i].val)) 636 { 637 sstr << (char)long_options[i].val; 638 switch (long_options[i].has_arg) 639 { 640 default: 641 case no_argument: break; 642 case required_argument: sstr << ':'; break; 643 case optional_argument: sstr << "::"; break; 644 } 645 } 646 } 647 } 648 #ifdef __GLIBC__ 649 optind = 0; 650 #else 651 optreset = 1; 652 optind = 1; 653 #endif 654 int val; 655 while (1) 656 { 657 int long_options_index = -1; 658 val = ::getopt_long_only(GetArgumentCount(), 659 GetArgumentVector(), 660 sstr.GetData(), 661 long_options, 662 &long_options_index); 663 if (val == -1) 664 break; 665 666 // Did we get an error? 667 if (val == '?') 668 { 669 error.SetErrorStringWithFormat("unknown or ambiguous option"); 670 break; 671 } 672 // The option auto-set itself 673 if (val == 0) 674 continue; 675 676 ((Options *) &options)->OptionSeen (val); 677 678 // Lookup the long option index 679 if (long_options_index == -1) 680 { 681 for (int i=0; 682 long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val; 683 ++i) 684 { 685 if (long_options[i].val == val) 686 { 687 long_options_index = i; 688 break; 689 } 690 } 691 } 692 // Call the callback with the option 693 if (long_options_index >= 0) 694 { 695 error = options.SetOptionValue(long_options_index, 696 long_options[long_options_index].has_arg == no_argument ? NULL : optarg); 697 } 698 else 699 { 700 error.SetErrorStringWithFormat("invalid option with value '%i'", val); 701 } 702 if (error.Fail()) 703 break; 704 } 705 706 // Update our ARGV now that get options has consumed all the options 707 m_argv.erase(m_argv.begin(), m_argv.begin() + optind); 708 UpdateArgsAfterOptionParsing (); 709 return error; 710 } 711 712 void 713 Args::Clear () 714 { 715 m_args.clear (); 716 m_argv.clear (); 717 m_args_quote_char.clear(); 718 } 719 720 int32_t 721 Args::StringToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr) 722 { 723 if (s && s[0]) 724 { 725 char *end = NULL; 726 const long sval = ::strtol (s, &end, base); 727 if (*end == '\0') 728 { 729 if (success_ptr) 730 *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN)); 731 return (int32_t)sval; // All characters were used, return the result 732 } 733 } 734 if (success_ptr) *success_ptr = false; 735 return fail_value; 736 } 737 738 uint32_t 739 Args::StringToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr) 740 { 741 if (s && s[0]) 742 { 743 char *end = NULL; 744 const unsigned long uval = ::strtoul (s, &end, base); 745 if (*end == '\0') 746 { 747 if (success_ptr) 748 *success_ptr = (uval <= UINT32_MAX); 749 return (uint32_t)uval; // All characters were used, return the result 750 } 751 } 752 if (success_ptr) *success_ptr = false; 753 return fail_value; 754 } 755 756 757 int64_t 758 Args::StringToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr) 759 { 760 if (s && s[0]) 761 { 762 char *end = NULL; 763 int64_t uval = ::strtoll (s, &end, base); 764 if (*end == '\0') 765 { 766 if (success_ptr) *success_ptr = true; 767 return uval; // All characters were used, return the result 768 } 769 } 770 if (success_ptr) *success_ptr = false; 771 return fail_value; 772 } 773 774 uint64_t 775 Args::StringToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr) 776 { 777 if (s && s[0]) 778 { 779 char *end = NULL; 780 uint64_t uval = ::strtoull (s, &end, base); 781 if (*end == '\0') 782 { 783 if (success_ptr) *success_ptr = true; 784 return uval; // All characters were used, return the result 785 } 786 } 787 if (success_ptr) *success_ptr = false; 788 return fail_value; 789 } 790 791 lldb::addr_t 792 Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::addr_t fail_value, Error *error_ptr) 793 { 794 bool error_set = false; 795 if (s && s[0]) 796 { 797 char *end = NULL; 798 lldb::addr_t addr = ::strtoull (s, &end, 0); 799 if (*end == '\0') 800 { 801 if (error_ptr) 802 error_ptr->Clear(); 803 return addr; // All characters were used, return the result 804 } 805 // Try base 16 with no prefix... 806 addr = ::strtoull (s, &end, 16); 807 if (*end == '\0') 808 { 809 if (error_ptr) 810 error_ptr->Clear(); 811 return addr; // All characters were used, return the result 812 } 813 814 if (exe_ctx) 815 { 816 Target *target = exe_ctx->GetTargetPtr(); 817 if (target) 818 { 819 lldb::ValueObjectSP valobj_sp; 820 EvaluateExpressionOptions options; 821 options.SetCoerceToId(false); 822 options.SetUnwindOnError(true); 823 options.SetKeepInMemory(false); 824 options.SetRunOthers(true); 825 826 ExecutionResults expr_result = target->EvaluateExpression(s, 827 exe_ctx->GetFramePtr(), 828 valobj_sp, 829 options); 830 831 bool success = false; 832 if (expr_result == eExecutionCompleted) 833 { 834 // Get the address to watch. 835 addr = valobj_sp->GetValueAsUnsigned(fail_value, &success); 836 if (success) 837 { 838 if (error_ptr) 839 error_ptr->Clear(); 840 return addr; 841 } 842 else 843 { 844 if (error_ptr) 845 { 846 error_set = true; 847 error_ptr->SetErrorStringWithFormat("address expression \"%s\" resulted in a value whose type can't be converted to an address: %s", s, valobj_sp->GetTypeName().GetCString()); 848 } 849 } 850 851 } 852 else 853 { 854 // Since the compiler can't handle things like "main + 12" we should 855 // try to do this for now. The compliler doesn't like adding offsets 856 // to function pointer types. 857 static RegularExpression g_symbol_plus_offset_regex("^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$"); 858 RegularExpression::Match regex_match(3); 859 if (g_symbol_plus_offset_regex.Execute(s, ®ex_match)) 860 { 861 uint64_t offset = 0; 862 bool add = true; 863 std::string name; 864 std::string str; 865 if (regex_match.GetMatchAtIndex(s, 1, name)) 866 { 867 if (regex_match.GetMatchAtIndex(s, 2, str)) 868 { 869 add = str[0] == '+'; 870 871 if (regex_match.GetMatchAtIndex(s, 3, str)) 872 { 873 offset = Args::StringToUInt64(str.c_str(), 0, 0, &success); 874 875 if (success) 876 { 877 Error error; 878 addr = StringToAddress (exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS, &error); 879 if (addr != LLDB_INVALID_ADDRESS) 880 { 881 if (add) 882 return addr + offset; 883 else 884 return addr - offset; 885 } 886 } 887 } 888 } 889 } 890 } 891 892 if (error_ptr) 893 { 894 error_set = true; 895 error_ptr->SetErrorStringWithFormat("address expression \"%s\" evaluation failed", s); 896 } 897 } 898 } 899 } 900 } 901 if (error_ptr) 902 { 903 if (!error_set) 904 error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", s); 905 } 906 return fail_value; 907 } 908 909 const char * 910 Args::StripSpaces (std::string &s, bool leading, bool trailing, bool return_null_if_empty) 911 { 912 static const char *k_white_space = " \t\v"; 913 if (!s.empty()) 914 { 915 if (leading) 916 { 917 size_t pos = s.find_first_not_of (k_white_space); 918 if (pos == std::string::npos) 919 s.clear(); 920 else if (pos > 0) 921 s.erase(0, pos); 922 } 923 924 if (trailing) 925 { 926 size_t rpos = s.find_last_not_of(k_white_space); 927 if (rpos != std::string::npos && rpos + 1 < s.size()) 928 s.erase(rpos + 1); 929 } 930 } 931 if (return_null_if_empty && s.empty()) 932 return NULL; 933 return s.c_str(); 934 } 935 936 bool 937 Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr) 938 { 939 if (s && s[0]) 940 { 941 if (::strcasecmp (s, "false") == 0 || 942 ::strcasecmp (s, "off") == 0 || 943 ::strcasecmp (s, "no") == 0 || 944 ::strcmp (s, "0") == 0) 945 { 946 if (success_ptr) 947 *success_ptr = true; 948 return false; 949 } 950 else 951 if (::strcasecmp (s, "true") == 0 || 952 ::strcasecmp (s, "on") == 0 || 953 ::strcasecmp (s, "yes") == 0 || 954 ::strcmp (s, "1") == 0) 955 { 956 if (success_ptr) *success_ptr = true; 957 return true; 958 } 959 } 960 if (success_ptr) *success_ptr = false; 961 return fail_value; 962 } 963 964 const char * 965 Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t &update) 966 { 967 major = UINT32_MAX; 968 minor = UINT32_MAX; 969 update = UINT32_MAX; 970 971 if (s && s[0]) 972 { 973 char *pos = NULL; 974 unsigned long uval32 = ::strtoul (s, &pos, 0); 975 if (pos == s) 976 return s; 977 major = uval32; 978 if (*pos == '\0') 979 { 980 return pos; // Decoded major and got end of string 981 } 982 else if (*pos == '.') 983 { 984 const char *minor_cstr = pos + 1; 985 uval32 = ::strtoul (minor_cstr, &pos, 0); 986 if (pos == minor_cstr) 987 return pos; // Didn't get any digits for the minor version... 988 minor = uval32; 989 if (*pos == '.') 990 { 991 const char *update_cstr = pos + 1; 992 uval32 = ::strtoul (update_cstr, &pos, 0); 993 if (pos == update_cstr) 994 return pos; 995 update = uval32; 996 } 997 return pos; 998 } 999 } 1000 return 0; 1001 } 1002 1003 const char * 1004 Args::GetShellSafeArgument (const char *unsafe_arg, std::string &safe_arg) 1005 { 1006 safe_arg.assign (unsafe_arg); 1007 size_t prev_pos = 0; 1008 while (prev_pos < safe_arg.size()) 1009 { 1010 // Escape spaces and quotes 1011 size_t pos = safe_arg.find_first_of(" '\"", prev_pos); 1012 if (pos != std::string::npos) 1013 { 1014 safe_arg.insert (pos, 1, '\\'); 1015 prev_pos = pos + 2; 1016 } 1017 else 1018 break; 1019 } 1020 return safe_arg.c_str(); 1021 } 1022 1023 1024 int64_t 1025 Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error) 1026 { 1027 if (enum_values) 1028 { 1029 if (s && s[0]) 1030 { 1031 for (int i = 0; enum_values[i].string_value != NULL ; i++) 1032 { 1033 if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value) 1034 { 1035 error.Clear(); 1036 return enum_values[i].value; 1037 } 1038 } 1039 } 1040 1041 StreamString strm; 1042 strm.PutCString ("invalid enumeration value, valid values are: "); 1043 for (int i = 0; enum_values[i].string_value != NULL; i++) 1044 { 1045 strm.Printf ("%s\"%s\"", 1046 i > 0 ? ", " : "", 1047 enum_values[i].string_value); 1048 } 1049 error.SetErrorString(strm.GetData()); 1050 } 1051 else 1052 { 1053 error.SetErrorString ("invalid enumeration argument"); 1054 } 1055 return fail_value; 1056 } 1057 1058 ScriptLanguage 1059 Args::StringToScriptLanguage (const char *s, ScriptLanguage fail_value, bool *success_ptr) 1060 { 1061 if (s && s[0]) 1062 { 1063 if ((::strcasecmp (s, "python") == 0) || 1064 (::strcasecmp (s, "default") == 0 && eScriptLanguagePython == eScriptLanguageDefault)) 1065 { 1066 if (success_ptr) *success_ptr = true; 1067 return eScriptLanguagePython; 1068 } 1069 if (::strcasecmp (s, "none")) 1070 { 1071 if (success_ptr) *success_ptr = true; 1072 return eScriptLanguageNone; 1073 } 1074 } 1075 if (success_ptr) *success_ptr = false; 1076 return fail_value; 1077 } 1078 1079 Error 1080 Args::StringToFormat 1081 ( 1082 const char *s, 1083 lldb::Format &format, 1084 size_t *byte_size_ptr 1085 ) 1086 { 1087 format = eFormatInvalid; 1088 Error error; 1089 1090 if (s && s[0]) 1091 { 1092 if (byte_size_ptr) 1093 { 1094 if (isdigit (s[0])) 1095 { 1096 char *format_char = NULL; 1097 unsigned long byte_size = ::strtoul (s, &format_char, 0); 1098 if (byte_size != ULONG_MAX) 1099 *byte_size_ptr = byte_size; 1100 s = format_char; 1101 } 1102 else 1103 *byte_size_ptr = 0; 1104 } 1105 1106 const bool partial_match_ok = true; 1107 if (!FormatManager::GetFormatFromCString (s, partial_match_ok, format)) 1108 { 1109 StreamString error_strm; 1110 error_strm.Printf ("Invalid format character or name '%s'. Valid values are:\n", s); 1111 for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1)) 1112 { 1113 char format_char = FormatManager::GetFormatAsFormatChar(f); 1114 if (format_char) 1115 error_strm.Printf ("'%c' or ", format_char); 1116 1117 error_strm.Printf ("\"%s\"", FormatManager::GetFormatAsCString(f)); 1118 error_strm.EOL(); 1119 } 1120 1121 if (byte_size_ptr) 1122 error_strm.PutCString ("An optional byte size can precede the format character.\n"); 1123 error.SetErrorString(error_strm.GetString().c_str()); 1124 } 1125 1126 if (error.Fail()) 1127 return error; 1128 } 1129 else 1130 { 1131 error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid"); 1132 } 1133 return error; 1134 } 1135 1136 lldb::Encoding 1137 Args::StringToEncoding (const char *s, lldb::Encoding fail_value) 1138 { 1139 if (s && s[0]) 1140 { 1141 if (strcmp(s, "uint") == 0) 1142 return eEncodingUint; 1143 else if (strcmp(s, "sint") == 0) 1144 return eEncodingSint; 1145 else if (strcmp(s, "ieee754") == 0) 1146 return eEncodingIEEE754; 1147 else if (strcmp(s, "vector") == 0) 1148 return eEncodingVector; 1149 } 1150 return fail_value; 1151 } 1152 1153 uint32_t 1154 Args::StringToGenericRegister (const char *s) 1155 { 1156 if (s && s[0]) 1157 { 1158 if (strcmp(s, "pc") == 0) 1159 return LLDB_REGNUM_GENERIC_PC; 1160 else if (strcmp(s, "sp") == 0) 1161 return LLDB_REGNUM_GENERIC_SP; 1162 else if (strcmp(s, "fp") == 0) 1163 return LLDB_REGNUM_GENERIC_FP; 1164 else if (strcmp(s, "ra") == 0) 1165 return LLDB_REGNUM_GENERIC_RA; 1166 else if (strcmp(s, "flags") == 0) 1167 return LLDB_REGNUM_GENERIC_FLAGS; 1168 else if (strncmp(s, "arg", 3) == 0) 1169 { 1170 if (s[3] && s[4] == '\0') 1171 { 1172 switch (s[3]) 1173 { 1174 case '1': return LLDB_REGNUM_GENERIC_ARG1; 1175 case '2': return LLDB_REGNUM_GENERIC_ARG2; 1176 case '3': return LLDB_REGNUM_GENERIC_ARG3; 1177 case '4': return LLDB_REGNUM_GENERIC_ARG4; 1178 case '5': return LLDB_REGNUM_GENERIC_ARG5; 1179 case '6': return LLDB_REGNUM_GENERIC_ARG6; 1180 case '7': return LLDB_REGNUM_GENERIC_ARG7; 1181 case '8': return LLDB_REGNUM_GENERIC_ARG8; 1182 } 1183 } 1184 } 1185 } 1186 return LLDB_INVALID_REGNUM; 1187 } 1188 1189 1190 void 1191 Args::LongestCommonPrefix (std::string &common_prefix) 1192 { 1193 arg_sstr_collection::iterator pos, end = m_args.end(); 1194 pos = m_args.begin(); 1195 if (pos == end) 1196 common_prefix.clear(); 1197 else 1198 common_prefix = (*pos); 1199 1200 for (++pos; pos != end; ++pos) 1201 { 1202 size_t new_size = (*pos).size(); 1203 1204 // First trim common_prefix if it is longer than the current element: 1205 if (common_prefix.size() > new_size) 1206 common_prefix.erase (new_size); 1207 1208 // Then trim it at the first disparity: 1209 1210 for (size_t i = 0; i < common_prefix.size(); i++) 1211 { 1212 if ((*pos)[i] != common_prefix[i]) 1213 { 1214 common_prefix.erase(i); 1215 break; 1216 } 1217 } 1218 1219 // If we've emptied the common prefix, we're done. 1220 if (common_prefix.empty()) 1221 break; 1222 } 1223 } 1224 1225 size_t 1226 Args::FindArgumentIndexForOption (struct option *long_options, int long_options_index) 1227 { 1228 char short_buffer[3]; 1229 char long_buffer[255]; 1230 ::snprintf (short_buffer, sizeof (short_buffer), "-%c", long_options[long_options_index].val); 1231 ::snprintf (long_buffer, sizeof (long_buffer), "--%s", long_options[long_options_index].name); 1232 size_t end = GetArgumentCount (); 1233 size_t idx = 0; 1234 while (idx < end) 1235 { 1236 if ((::strncmp (GetArgumentAtIndex (idx), short_buffer, strlen (short_buffer)) == 0) 1237 || (::strncmp (GetArgumentAtIndex (idx), long_buffer, strlen (long_buffer)) == 0)) 1238 { 1239 return idx; 1240 } 1241 ++idx; 1242 } 1243 1244 return end; 1245 } 1246 1247 bool 1248 Args::IsPositionalArgument (const char *arg) 1249 { 1250 if (arg == NULL) 1251 return false; 1252 1253 bool is_positional = true; 1254 char *cptr = (char *) arg; 1255 1256 if (cptr[0] == '%') 1257 { 1258 ++cptr; 1259 while (isdigit (cptr[0])) 1260 ++cptr; 1261 if (cptr[0] != '\0') 1262 is_positional = false; 1263 } 1264 else 1265 is_positional = false; 1266 1267 return is_positional; 1268 } 1269 1270 void 1271 Args::ParseAliasOptions (Options &options, 1272 CommandReturnObject &result, 1273 OptionArgVector *option_arg_vector, 1274 std::string &raw_input_string) 1275 { 1276 StreamString sstr; 1277 int i; 1278 struct option *long_options = options.GetLongOptions(); 1279 1280 if (long_options == NULL) 1281 { 1282 result.AppendError ("invalid long options"); 1283 result.SetStatus (eReturnStatusFailed); 1284 return; 1285 } 1286 1287 for (i = 0; long_options[i].name != NULL; ++i) 1288 { 1289 if (long_options[i].flag == NULL) 1290 { 1291 sstr << (char) long_options[i].val; 1292 switch (long_options[i].has_arg) 1293 { 1294 default: 1295 case no_argument: 1296 break; 1297 case required_argument: 1298 sstr << ":"; 1299 break; 1300 case optional_argument: 1301 sstr << "::"; 1302 break; 1303 } 1304 } 1305 } 1306 1307 #ifdef __GLIBC__ 1308 optind = 0; 1309 #else 1310 optreset = 1; 1311 optind = 1; 1312 #endif 1313 int val; 1314 while (1) 1315 { 1316 int long_options_index = -1; 1317 val = ::getopt_long_only (GetArgumentCount(), 1318 GetArgumentVector(), 1319 sstr.GetData(), 1320 long_options, 1321 &long_options_index); 1322 1323 if (val == -1) 1324 break; 1325 1326 if (val == '?') 1327 { 1328 result.AppendError ("unknown or ambiguous option"); 1329 result.SetStatus (eReturnStatusFailed); 1330 break; 1331 } 1332 1333 if (val == 0) 1334 continue; 1335 1336 ((Options *) &options)->OptionSeen (val); 1337 1338 // Look up the long option index 1339 if (long_options_index == -1) 1340 { 1341 for (int j = 0; 1342 long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val; 1343 ++j) 1344 { 1345 if (long_options[j].val == val) 1346 { 1347 long_options_index = j; 1348 break; 1349 } 1350 } 1351 } 1352 1353 // See if the option takes an argument, and see if one was supplied. 1354 if (long_options_index >= 0) 1355 { 1356 StreamString option_str; 1357 option_str.Printf ("-%c", val); 1358 1359 switch (long_options[long_options_index].has_arg) 1360 { 1361 case no_argument: 1362 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), 1363 OptionArgValue (no_argument, "<no-argument>"))); 1364 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1365 break; 1366 case required_argument: 1367 if (optarg != NULL) 1368 { 1369 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), 1370 OptionArgValue (required_argument, 1371 std::string (optarg)))); 1372 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1373 } 1374 else 1375 { 1376 result.AppendErrorWithFormat ("Option '%s' is missing argument specifier.\n", 1377 option_str.GetData()); 1378 result.SetStatus (eReturnStatusFailed); 1379 } 1380 break; 1381 case optional_argument: 1382 if (optarg != NULL) 1383 { 1384 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), 1385 OptionArgValue (optional_argument, 1386 std::string (optarg)))); 1387 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1388 } 1389 else 1390 { 1391 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), 1392 OptionArgValue (optional_argument, "<no-argument>"))); 1393 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1394 } 1395 break; 1396 default: 1397 result.AppendErrorWithFormat ("error with options table; invalid value in has_arg field for option '%c'.\n", val); 1398 result.SetStatus (eReturnStatusFailed); 1399 break; 1400 } 1401 } 1402 else 1403 { 1404 result.AppendErrorWithFormat ("Invalid option with value '%c'.\n", val); 1405 result.SetStatus (eReturnStatusFailed); 1406 } 1407 1408 if (long_options_index >= 0) 1409 { 1410 // Find option in the argument list; also see if it was supposed to take an argument and if one was 1411 // supplied. Remove option (and argument, if given) from the argument list. Also remove them from 1412 // the raw_input_string, if one was passed in. 1413 size_t idx = FindArgumentIndexForOption (long_options, long_options_index); 1414 if (idx < GetArgumentCount()) 1415 { 1416 if (raw_input_string.size() > 0) 1417 { 1418 const char *tmp_arg = GetArgumentAtIndex (idx); 1419 size_t pos = raw_input_string.find (tmp_arg); 1420 if (pos != std::string::npos) 1421 raw_input_string.erase (pos, strlen (tmp_arg)); 1422 } 1423 ReplaceArgumentAtIndex (idx, ""); 1424 if ((long_options[long_options_index].has_arg != no_argument) 1425 && (optarg != NULL) 1426 && (idx+1 < GetArgumentCount()) 1427 && (strcmp (optarg, GetArgumentAtIndex(idx+1)) == 0)) 1428 { 1429 if (raw_input_string.size() > 0) 1430 { 1431 const char *tmp_arg = GetArgumentAtIndex (idx+1); 1432 size_t pos = raw_input_string.find (tmp_arg); 1433 if (pos != std::string::npos) 1434 raw_input_string.erase (pos, strlen (tmp_arg)); 1435 } 1436 ReplaceArgumentAtIndex (idx+1, ""); 1437 } 1438 } 1439 } 1440 1441 if (!result.Succeeded()) 1442 break; 1443 } 1444 } 1445 1446 void 1447 Args::ParseArgsForCompletion 1448 ( 1449 Options &options, 1450 OptionElementVector &option_element_vector, 1451 uint32_t cursor_index 1452 ) 1453 { 1454 StreamString sstr; 1455 struct option *long_options = options.GetLongOptions(); 1456 option_element_vector.clear(); 1457 1458 if (long_options == NULL) 1459 { 1460 return; 1461 } 1462 1463 // Leading : tells getopt to return a : for a missing option argument AND 1464 // to suppress error messages. 1465 1466 sstr << ":"; 1467 for (int i = 0; long_options[i].name != NULL; ++i) 1468 { 1469 if (long_options[i].flag == NULL) 1470 { 1471 sstr << (char) long_options[i].val; 1472 switch (long_options[i].has_arg) 1473 { 1474 default: 1475 case no_argument: 1476 break; 1477 case required_argument: 1478 sstr << ":"; 1479 break; 1480 case optional_argument: 1481 sstr << "::"; 1482 break; 1483 } 1484 } 1485 } 1486 1487 #ifdef __GLIBC__ 1488 optind = 0; 1489 #else 1490 optreset = 1; 1491 optind = 1; 1492 #endif 1493 opterr = 0; 1494 1495 int val; 1496 const OptionDefinition *opt_defs = options.GetDefinitions(); 1497 1498 // Fooey... getopt_long_only permutes the GetArgumentVector to move the options to the front. 1499 // So we have to build another Arg and pass that to getopt_long_only so it doesn't 1500 // change the one we have. 1501 1502 std::vector<const char *> dummy_vec (GetArgumentVector(), GetArgumentVector() + GetArgumentCount() + 1); 1503 1504 bool failed_once = false; 1505 uint32_t dash_dash_pos = -1; 1506 1507 while (1) 1508 { 1509 bool missing_argument = false; 1510 int long_options_index = -1; 1511 1512 val = ::getopt_long_only (dummy_vec.size() - 1, 1513 (char *const *) &dummy_vec.front(), 1514 sstr.GetData(), 1515 long_options, 1516 &long_options_index); 1517 1518 if (val == -1) 1519 { 1520 // When we're completing a "--" which is the last option on line, 1521 if (failed_once) 1522 break; 1523 1524 failed_once = true; 1525 1526 // If this is a bare "--" we mark it as such so we can complete it successfully later. 1527 // Handling the "--" is a little tricky, since that may mean end of options or arguments, or the 1528 // user might want to complete options by long name. I make this work by checking whether the 1529 // cursor is in the "--" argument, and if so I assume we're completing the long option, otherwise 1530 // I let it pass to getopt_long_only which will terminate the option parsing. 1531 // Note, in either case we continue parsing the line so we can figure out what other options 1532 // were passed. This will be useful when we come to restricting completions based on what other 1533 // options we've seen on the line. 1534 1535 if (optind < dummy_vec.size() - 1 1536 && (strcmp (dummy_vec[optind-1], "--") == 0)) 1537 { 1538 dash_dash_pos = optind - 1; 1539 if (optind - 1 == cursor_index) 1540 { 1541 option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDoubleDash, optind - 1, 1542 OptionArgElement::eBareDoubleDash)); 1543 continue; 1544 } 1545 else 1546 break; 1547 } 1548 else 1549 break; 1550 } 1551 else if (val == '?') 1552 { 1553 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, optind - 1, 1554 OptionArgElement::eUnrecognizedArg)); 1555 continue; 1556 } 1557 else if (val == 0) 1558 { 1559 continue; 1560 } 1561 else if (val == ':') 1562 { 1563 // This is a missing argument. 1564 val = optopt; 1565 missing_argument = true; 1566 } 1567 1568 ((Options *) &options)->OptionSeen (val); 1569 1570 // Look up the long option index 1571 if (long_options_index == -1) 1572 { 1573 for (int j = 0; 1574 long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val; 1575 ++j) 1576 { 1577 if (long_options[j].val == val) 1578 { 1579 long_options_index = j; 1580 break; 1581 } 1582 } 1583 } 1584 1585 // See if the option takes an argument, and see if one was supplied. 1586 if (long_options_index >= 0) 1587 { 1588 int opt_defs_index = -1; 1589 for (int i = 0; ; i++) 1590 { 1591 if (opt_defs[i].short_option == 0) 1592 break; 1593 else if (opt_defs[i].short_option == val) 1594 { 1595 opt_defs_index = i; 1596 break; 1597 } 1598 } 1599 1600 switch (long_options[long_options_index].has_arg) 1601 { 1602 case no_argument: 1603 option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 1, 0)); 1604 break; 1605 case required_argument: 1606 if (optarg != NULL) 1607 { 1608 int arg_index; 1609 if (missing_argument) 1610 arg_index = -1; 1611 else 1612 arg_index = optind - 1; 1613 1614 option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 2, arg_index)); 1615 } 1616 else 1617 { 1618 option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 1, -1)); 1619 } 1620 break; 1621 case optional_argument: 1622 if (optarg != NULL) 1623 { 1624 option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 2, optind - 1)); 1625 } 1626 else 1627 { 1628 option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 2, optind - 1)); 1629 } 1630 break; 1631 default: 1632 // The options table is messed up. Here we'll just continue 1633 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, optind - 1, 1634 OptionArgElement::eUnrecognizedArg)); 1635 break; 1636 } 1637 } 1638 else 1639 { 1640 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, optind - 1, 1641 OptionArgElement::eUnrecognizedArg)); 1642 } 1643 } 1644 1645 // Finally we have to handle the case where the cursor index points at a single "-". We want to mark that in 1646 // the option_element_vector, but only if it is not after the "--". But it turns out that getopt_long_only just ignores 1647 // an isolated "-". So we have to look it up by hand here. We only care if it is AT the cursor position. 1648 1649 if ((dash_dash_pos == -1 || cursor_index < dash_dash_pos) 1650 && strcmp (GetArgumentAtIndex(cursor_index), "-") == 0) 1651 { 1652 option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDash, cursor_index, 1653 OptionArgElement::eBareDash)); 1654 1655 } 1656 } 1657 1658 void 1659 Args::EncodeEscapeSequences (const char *src, std::string &dst) 1660 { 1661 dst.clear(); 1662 if (src) 1663 { 1664 for (const char *p = src; *p != '\0'; ++p) 1665 { 1666 size_t non_special_chars = ::strcspn (p, "\\"); 1667 if (non_special_chars > 0) 1668 { 1669 dst.append(p, non_special_chars); 1670 p += non_special_chars; 1671 if (*p == '\0') 1672 break; 1673 } 1674 1675 if (*p == '\\') 1676 { 1677 ++p; // skip the slash 1678 switch (*p) 1679 { 1680 case 'a' : dst.append(1, '\a'); break; 1681 case 'b' : dst.append(1, '\b'); break; 1682 case 'f' : dst.append(1, '\f'); break; 1683 case 'n' : dst.append(1, '\n'); break; 1684 case 'r' : dst.append(1, '\r'); break; 1685 case 't' : dst.append(1, '\t'); break; 1686 case 'v' : dst.append(1, '\v'); break; 1687 case '\\': dst.append(1, '\\'); break; 1688 case '\'': dst.append(1, '\''); break; 1689 case '"' : dst.append(1, '"'); break; 1690 case '0' : 1691 // 1 to 3 octal chars 1692 { 1693 // Make a string that can hold onto the initial zero char, 1694 // up to 3 octal digits, and a terminating NULL. 1695 char oct_str[5] = { '\0', '\0', '\0', '\0', '\0' }; 1696 1697 int i; 1698 for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i) 1699 oct_str[i] = p[i]; 1700 1701 // We don't want to consume the last octal character since 1702 // the main for loop will do this for us, so we advance p by 1703 // one less than i (even if i is zero) 1704 p += i - 1; 1705 unsigned long octal_value = ::strtoul (oct_str, NULL, 8); 1706 if (octal_value <= UINT8_MAX) 1707 { 1708 dst.append(1, (char)octal_value); 1709 } 1710 } 1711 break; 1712 1713 case 'x': 1714 // hex number in the format 1715 if (isxdigit(p[1])) 1716 { 1717 ++p; // Skip the 'x' 1718 1719 // Make a string that can hold onto two hex chars plus a 1720 // NULL terminator 1721 char hex_str[3] = { *p, '\0', '\0' }; 1722 if (isxdigit(p[1])) 1723 { 1724 ++p; // Skip the first of the two hex chars 1725 hex_str[1] = *p; 1726 } 1727 1728 unsigned long hex_value = strtoul (hex_str, NULL, 16); 1729 if (hex_value <= UINT8_MAX) 1730 dst.append (1, (char)hex_value); 1731 } 1732 else 1733 { 1734 dst.append(1, 'x'); 1735 } 1736 break; 1737 1738 default: 1739 // Just desensitize any other character by just printing what 1740 // came after the '\' 1741 dst.append(1, *p); 1742 break; 1743 1744 } 1745 } 1746 } 1747 } 1748 } 1749 1750 1751 void 1752 Args::ExpandEscapedCharacters (const char *src, std::string &dst) 1753 { 1754 dst.clear(); 1755 if (src) 1756 { 1757 for (const char *p = src; *p != '\0'; ++p) 1758 { 1759 if (isprint8(*p)) 1760 dst.append(1, *p); 1761 else 1762 { 1763 switch (*p) 1764 { 1765 case '\a': dst.append("\\a"); break; 1766 case '\b': dst.append("\\b"); break; 1767 case '\f': dst.append("\\f"); break; 1768 case '\n': dst.append("\\n"); break; 1769 case '\r': dst.append("\\r"); break; 1770 case '\t': dst.append("\\t"); break; 1771 case '\v': dst.append("\\v"); break; 1772 case '\'': dst.append("\\'"); break; 1773 case '"': dst.append("\\\""); break; 1774 case '\\': dst.append("\\\\"); break; 1775 default: 1776 { 1777 // Just encode as octal 1778 dst.append("\\0"); 1779 char octal_str[32]; 1780 snprintf(octal_str, sizeof(octal_str), "%o", *p); 1781 dst.append(octal_str); 1782 } 1783 break; 1784 } 1785 } 1786 } 1787 } 1788 } 1789 1790