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