| 1 |
// Copyright (c) 2005, Google Inc. |
// Copyright (c) 2010, Google Inc. |
| 2 |
// All rights reserved. |
// All rights reserved. |
| 3 |
// |
// |
| 4 |
// Redistribution and use in source and binary forms, with or without |
// Redistribution and use in source and binary forms, with or without |
| 29 |
// |
// |
| 30 |
// Author: Sanjay Ghemawat |
// Author: Sanjay Ghemawat |
| 31 |
|
|
| 32 |
|
#ifdef HAVE_CONFIG_H |
| 33 |
|
#include "config.h" |
| 34 |
|
#endif |
| 35 |
|
|
| 36 |
#include <stdlib.h> |
#include <stdlib.h> |
| 37 |
#include <stdio.h> |
#include <stdio.h> |
| 38 |
#include <ctype.h> |
#include <ctype.h> |
| 41 |
#include <errno.h> |
#include <errno.h> |
| 42 |
#include <string> |
#include <string> |
| 43 |
#include <algorithm> |
#include <algorithm> |
| 44 |
#include "config.h" |
|
| 45 |
// We need this to compile the proper dll on windows/msys. This is copied |
#include "pcrecpp_internal.h" |
|
// from pcre_internal.h. It would probably be better just to include that. |
|
|
#define PCRE_DEFINITION /* Win32 __declspec(export) trigger for .dll */ |
|
| 46 |
#include "pcre.h" |
#include "pcre.h" |
|
#include "pcre_stringpiece.h" |
|
| 47 |
#include "pcrecpp.h" |
#include "pcrecpp.h" |
| 48 |
|
#include "pcre_stringpiece.h" |
| 49 |
|
|
| 50 |
|
|
| 51 |
namespace pcrecpp { |
namespace pcrecpp { |
| 55 |
static const int kVecSize = (1 + kMaxArgs) * 3; // results + PCRE workspace |
static const int kVecSize = (1 + kMaxArgs) * 3; // results + PCRE workspace |
| 56 |
|
|
| 57 |
// Special object that stands-in for no argument |
// Special object that stands-in for no argument |
| 58 |
Arg no_arg((void*)NULL); |
Arg RE::no_arg((void*)NULL); |
| 59 |
|
|
| 60 |
|
// This is for ABI compatibility with old versions of pcre (pre-7.6), |
| 61 |
|
// which defined a global no_arg variable instead of putting it in the |
| 62 |
|
// RE class. This works on GCC >= 3, at least. It definitely works |
| 63 |
|
// for ELF, but may not for other object formats (Mach-O, for |
| 64 |
|
// instance, does not support aliases.) We could probably have a more |
| 65 |
|
// inclusive test if we ever needed it. (Note that not only the |
| 66 |
|
// __attribute__ syntax, but also __USER_LABEL_PREFIX__, are |
| 67 |
|
// gnu-specific.) |
| 68 |
|
#if defined(__GNUC__) && __GNUC__ >= 3 && defined(__ELF__) |
| 69 |
|
# define ULP_AS_STRING(x) ULP_AS_STRING_INTERNAL(x) |
| 70 |
|
# define ULP_AS_STRING_INTERNAL(x) #x |
| 71 |
|
# define USER_LABEL_PREFIX_STR ULP_AS_STRING(__USER_LABEL_PREFIX__) |
| 72 |
|
extern Arg no_arg |
| 73 |
|
__attribute__((alias(USER_LABEL_PREFIX_STR "_ZN7pcrecpp2RE6no_argE"))); |
| 74 |
|
#endif |
| 75 |
|
|
| 76 |
// If a regular expression has no error, its error_ field points here |
// If a regular expression has no error, its error_ field points here |
| 77 |
static const string empty_string; |
static const string empty_string; |
| 92 |
|
|
| 93 |
re_partial_ = Compile(UNANCHORED); |
re_partial_ = Compile(UNANCHORED); |
| 94 |
if (re_partial_ != NULL) { |
if (re_partial_ != NULL) { |
| 95 |
// Check for complicated patterns. The following change is |
re_full_ = Compile(ANCHOR_BOTH); |
|
// conservative in that it may treat some "simple" patterns |
|
|
// as "complex" (e.g., if the vertical bar is in a character |
|
|
// class or is escaped). But it seems good enough. |
|
|
if (strchr(pat.c_str(), '|') == NULL) { |
|
|
// Simple pattern: we can use position-based checks to perform |
|
|
// fully anchored matches |
|
|
re_full_ = re_partial_; |
|
|
} else { |
|
|
// We need a special pattern for anchored matches |
|
|
re_full_ = Compile(ANCHOR_BOTH); |
|
|
} |
|
| 96 |
} |
} |
| 97 |
} |
} |
| 98 |
|
|
| 99 |
void RE::Cleanup() { |
void RE::Cleanup() { |
| 100 |
if (re_full_ != NULL && re_full_ != re_partial_) (*pcre_free)(re_full_); |
if (re_full_ != NULL) (*pcre_free)(re_full_); |
| 101 |
if (re_partial_ != NULL) (*pcre_free)(re_partial_); |
if (re_partial_ != NULL) (*pcre_free)(re_partial_); |
| 102 |
if (error_ != &empty_string) delete error_; |
if (error_ != &empty_string) delete error_; |
| 103 |
} |
} |
| 104 |
|
|
| 105 |
|
|
| 331 |
bool RE::Replace(const StringPiece& rewrite, |
bool RE::Replace(const StringPiece& rewrite, |
| 332 |
string *str) const { |
string *str) const { |
| 333 |
int vec[kVecSize]; |
int vec[kVecSize]; |
| 334 |
int matches = TryMatch(*str, 0, UNANCHORED, vec, kVecSize); |
int matches = TryMatch(*str, 0, UNANCHORED, true, vec, kVecSize); |
| 335 |
if (matches == 0) |
if (matches == 0) |
| 336 |
return false; |
return false; |
| 337 |
|
|
| 347 |
|
|
| 348 |
// Returns PCRE_NEWLINE_CRLF, PCRE_NEWLINE_CR, or PCRE_NEWLINE_LF. |
// Returns PCRE_NEWLINE_CRLF, PCRE_NEWLINE_CR, or PCRE_NEWLINE_LF. |
| 349 |
// Note that PCRE_NEWLINE_CRLF is defined to be P_N_CR | P_N_LF. |
// Note that PCRE_NEWLINE_CRLF is defined to be P_N_CR | P_N_LF. |
| 350 |
|
// Modified by PH to add PCRE_NEWLINE_ANY and PCRE_NEWLINE_ANYCRLF. |
| 351 |
|
|
| 352 |
static int NewlineMode(int pcre_options) { |
static int NewlineMode(int pcre_options) { |
| 353 |
// TODO: if we can make it threadsafe, cache this var |
// TODO: if we can make it threadsafe, cache this var |
| 354 |
int newline_mode = 0; |
int newline_mode = 0; |
| 355 |
/* if (newline_mode) return newline_mode; */ // do this once it's cached |
/* if (newline_mode) return newline_mode; */ // do this once it's cached |
| 356 |
if (pcre_options & (PCRE_NEWLINE_CRLF|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF)) { |
if (pcre_options & (PCRE_NEWLINE_CRLF|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF| |
| 357 |
|
PCRE_NEWLINE_ANY|PCRE_NEWLINE_ANYCRLF)) { |
| 358 |
newline_mode = (pcre_options & |
newline_mode = (pcre_options & |
| 359 |
(PCRE_NEWLINE_CRLF|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF)); |
(PCRE_NEWLINE_CRLF|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF| |
| 360 |
|
PCRE_NEWLINE_ANY|PCRE_NEWLINE_ANYCRLF)); |
| 361 |
} else { |
} else { |
| 362 |
int newline; |
int newline; |
| 363 |
pcre_config(PCRE_CONFIG_NEWLINE, &newline); |
pcre_config(PCRE_CONFIG_NEWLINE, &newline); |
| 367 |
newline_mode = PCRE_NEWLINE_CR; |
newline_mode = PCRE_NEWLINE_CR; |
| 368 |
else if (newline == 3338) |
else if (newline == 3338) |
| 369 |
newline_mode = PCRE_NEWLINE_CRLF; |
newline_mode = PCRE_NEWLINE_CRLF; |
| 370 |
|
else if (newline == -1) |
| 371 |
|
newline_mode = PCRE_NEWLINE_ANY; |
| 372 |
|
else if (newline == -2) |
| 373 |
|
newline_mode = PCRE_NEWLINE_ANYCRLF; |
| 374 |
else |
else |
| 375 |
assert("" == "Unexpected return value from pcre_config(NEWLINE)"); |
assert(NULL == "Unexpected return value from pcre_config(NEWLINE)"); |
| 376 |
} |
} |
| 377 |
return newline_mode; |
return newline_mode; |
| 378 |
} |
} |
| 384 |
string out; |
string out; |
| 385 |
int start = 0; |
int start = 0; |
| 386 |
int lastend = -1; |
int lastend = -1; |
| 387 |
|
bool last_match_was_empty_string = false; |
| 388 |
|
|
| 389 |
for (; start <= static_cast<int>(str->length()); count++) { |
while (start <= static_cast<int>(str->length())) { |
| 390 |
int matches = TryMatch(*str, start, UNANCHORED, vec, kVecSize); |
// If the previous match was for the empty string, we shouldn't |
| 391 |
if (matches <= 0) |
// just match again: we'll match in the same way and get an |
| 392 |
break; |
// infinite loop. Instead, we do the match in a special way: |
| 393 |
int matchstart = vec[0], matchend = vec[1]; |
// anchored -- to force another try at the same position -- |
| 394 |
assert(matchstart >= start); |
// and with a flag saying that this time, ignore empty matches. |
| 395 |
assert(matchend >= matchstart); |
// If this special match returns, that means there's a non-empty |
| 396 |
if (matchstart == matchend && matchstart == lastend) { |
// match at this position as well, and we can continue. If not, |
| 397 |
// advance one character if we matched an empty string at the same |
// we do what perl does, and just advance by one. |
| 398 |
// place as the last match occurred |
// Notice that perl prints '@@@' for this; |
| 399 |
matchend = start + 1; |
// perl -le '$_ = "aa"; s/b*|aa/@/g; print' |
| 400 |
// If the current char is CR and we're in CRLF mode, skip LF too. |
int matches; |
| 401 |
// Note it's better to call pcre_fullinfo() than to examine |
if (last_match_was_empty_string) { |
| 402 |
// all_options(), since options_ could have changed bewteen |
matches = TryMatch(*str, start, ANCHOR_START, false, vec, kVecSize); |
| 403 |
// compile-time and now, but this is simpler and safe enough. |
if (matches <= 0) { |
| 404 |
if (start+1 < static_cast<int>(str->length()) && |
int matchend = start + 1; // advance one character. |
| 405 |
(*str)[start] == '\r' && (*str)[start+1] == '\n' && |
// If the current char is CR and we're in CRLF mode, skip LF too. |
| 406 |
NewlineMode(options_.all_options()) == PCRE_NEWLINE_CRLF) { |
// Note it's better to call pcre_fullinfo() than to examine |
| 407 |
matchend++; |
// all_options(), since options_ could have changed bewteen |
| 408 |
} |
// compile-time and now, but this is simpler and safe enough. |
| 409 |
// We also need to advance more than one char if we're in utf8 mode. |
// Modified by PH to add ANY and ANYCRLF. |
| 410 |
#ifdef SUPPORT_UTF8 |
if (matchend < static_cast<int>(str->length()) && |
| 411 |
if (options_.utf8()) { |
(*str)[start] == '\r' && (*str)[matchend] == '\n' && |
| 412 |
while (matchend < static_cast<int>(str->length()) && |
(NewlineMode(options_.all_options()) == PCRE_NEWLINE_CRLF || |
| 413 |
((*str)[matchend] & 0xc0) == 0x80) |
NewlineMode(options_.all_options()) == PCRE_NEWLINE_ANY || |
| 414 |
|
NewlineMode(options_.all_options()) == PCRE_NEWLINE_ANYCRLF)) { |
| 415 |
matchend++; |
matchend++; |
| 416 |
} |
} |
| 417 |
|
// We also need to advance more than one char if we're in utf8 mode. |
| 418 |
|
#ifdef SUPPORT_UTF8 |
| 419 |
|
if (options_.utf8()) { |
| 420 |
|
while (matchend < static_cast<int>(str->length()) && |
| 421 |
|
((*str)[matchend] & 0xc0) == 0x80) |
| 422 |
|
matchend++; |
| 423 |
|
} |
| 424 |
#endif |
#endif |
| 425 |
if (matchend <= static_cast<int>(str->length())) |
if (start < static_cast<int>(str->length())) |
| 426 |
out.append(*str, start, matchend - start); |
out.append(*str, start, matchend - start); |
| 427 |
start = matchend; |
start = matchend; |
| 428 |
|
last_match_was_empty_string = false; |
| 429 |
|
continue; |
| 430 |
|
} |
| 431 |
} else { |
} else { |
| 432 |
out.append(*str, start, matchstart - start); |
matches = TryMatch(*str, start, UNANCHORED, true, vec, kVecSize); |
| 433 |
Rewrite(&out, rewrite, *str, vec, matches); |
if (matches <= 0) |
| 434 |
start = matchend; |
break; |
|
lastend = matchend; |
|
|
count++; |
|
| 435 |
} |
} |
| 436 |
|
int matchstart = vec[0], matchend = vec[1]; |
| 437 |
|
assert(matchstart >= start); |
| 438 |
|
assert(matchend >= matchstart); |
| 439 |
|
out.append(*str, start, matchstart - start); |
| 440 |
|
Rewrite(&out, rewrite, *str, vec, matches); |
| 441 |
|
start = matchend; |
| 442 |
|
lastend = matchend; |
| 443 |
|
count++; |
| 444 |
|
last_match_was_empty_string = (matchstart == matchend); |
| 445 |
} |
} |
| 446 |
|
|
| 447 |
if (count == 0) |
if (count == 0) |
| 457 |
const StringPiece& text, |
const StringPiece& text, |
| 458 |
string *out) const { |
string *out) const { |
| 459 |
int vec[kVecSize]; |
int vec[kVecSize]; |
| 460 |
int matches = TryMatch(text, 0, UNANCHORED, vec, kVecSize); |
int matches = TryMatch(text, 0, UNANCHORED, true, vec, kVecSize); |
| 461 |
if (matches == 0) |
if (matches == 0) |
| 462 |
return false; |
return false; |
| 463 |
out->erase(); |
out->erase(); |
| 472 |
// Note that it's legal to escape a character even if it has no |
// Note that it's legal to escape a character even if it has no |
| 473 |
// special meaning in a regular expression -- so this function does |
// special meaning in a regular expression -- so this function does |
| 474 |
// that. (This also makes it identical to the perl function of the |
// that. (This also makes it identical to the perl function of the |
| 475 |
// same name; see `perldoc -f quotemeta`.) |
// same name; see `perldoc -f quotemeta`.) The one exception is |
| 476 |
|
// escaping NUL: rather than doing backslash + NUL, like perl does, |
| 477 |
|
// we do '\0', because pcre itself doesn't take embedded NUL chars. |
| 478 |
for (int ii = 0; ii < unquoted.size(); ++ii) { |
for (int ii = 0; ii < unquoted.size(); ++ii) { |
| 479 |
// Note that using 'isalnum' here raises the benchmark time from |
// Note that using 'isalnum' here raises the benchmark time from |
| 480 |
// 32ns to 58ns: |
// 32ns to 58ns: |
| 481 |
if ((unquoted[ii] < 'a' || unquoted[ii] > 'z') && |
if (unquoted[ii] == '\0') { |
| 482 |
(unquoted[ii] < 'A' || unquoted[ii] > 'Z') && |
result += "\\0"; |
| 483 |
(unquoted[ii] < '0' || unquoted[ii] > '9') && |
} else if ((unquoted[ii] < 'a' || unquoted[ii] > 'z') && |
| 484 |
unquoted[ii] != '_' && |
(unquoted[ii] < 'A' || unquoted[ii] > 'Z') && |
| 485 |
// If this is the part of a UTF8 or Latin1 character, we need |
(unquoted[ii] < '0' || unquoted[ii] > '9') && |
| 486 |
// to copy this byte without escaping. Experimentally this is |
unquoted[ii] != '_' && |
| 487 |
// what works correctly with the regexp library. |
// If this is the part of a UTF8 or Latin1 character, we need |
| 488 |
!(unquoted[ii] & 128)) { |
// to copy this byte without escaping. Experimentally this is |
| 489 |
|
// what works correctly with the regexp library. |
| 490 |
|
!(unquoted[ii] & 128)) { |
| 491 |
result += '\\'; |
result += '\\'; |
| 492 |
|
result += unquoted[ii]; |
| 493 |
|
} else { |
| 494 |
|
result += unquoted[ii]; |
| 495 |
} |
} |
|
result += unquoted[ii]; |
|
| 496 |
} |
} |
| 497 |
|
|
| 498 |
return result; |
return result; |
| 503 |
int RE::TryMatch(const StringPiece& text, |
int RE::TryMatch(const StringPiece& text, |
| 504 |
int startpos, |
int startpos, |
| 505 |
Anchor anchor, |
Anchor anchor, |
| 506 |
|
bool empty_ok, |
| 507 |
int *vec, |
int *vec, |
| 508 |
int vecsize) const { |
int vecsize) const { |
| 509 |
pcre* re = (anchor == ANCHOR_BOTH) ? re_full_ : re_partial_; |
pcre* re = (anchor == ANCHOR_BOTH) ? re_full_ : re_partial_; |
| 512 |
return 0; |
return 0; |
| 513 |
} |
} |
| 514 |
|
|
| 515 |
pcre_extra extra = { 0 }; |
pcre_extra extra = { 0, 0, 0, 0, 0, 0 }; |
| 516 |
if (options_.match_limit() > 0) { |
if (options_.match_limit() > 0) { |
| 517 |
extra.flags |= PCRE_EXTRA_MATCH_LIMIT; |
extra.flags |= PCRE_EXTRA_MATCH_LIMIT; |
| 518 |
extra.match_limit = options_.match_limit(); |
extra.match_limit = options_.match_limit(); |
| 521 |
extra.flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; |
extra.flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; |
| 522 |
extra.match_limit_recursion = options_.match_limit_recursion(); |
extra.match_limit_recursion = options_.match_limit_recursion(); |
| 523 |
} |
} |
| 524 |
|
|
| 525 |
|
int options = 0; |
| 526 |
|
if (anchor != UNANCHORED) |
| 527 |
|
options |= PCRE_ANCHORED; |
| 528 |
|
if (!empty_ok) |
| 529 |
|
options |= PCRE_NOTEMPTY; |
| 530 |
|
|
| 531 |
int rc = pcre_exec(re, // The regular expression object |
int rc = pcre_exec(re, // The regular expression object |
| 532 |
&extra, |
&extra, |
| 533 |
(text.data() == NULL) ? "" : text.data(), |
(text.data() == NULL) ? "" : text.data(), |
| 534 |
text.size(), |
text.size(), |
| 535 |
startpos, |
startpos, |
| 536 |
(anchor == UNANCHORED) ? 0 : PCRE_ANCHORED, |
options, |
| 537 |
vec, |
vec, |
| 538 |
vecsize); |
vecsize); |
| 539 |
|
|
| 552 |
rc = vecsize / 2; |
rc = vecsize / 2; |
| 553 |
} |
} |
| 554 |
|
|
|
if ((anchor == ANCHOR_BOTH) && (re_full_ == re_partial_)) { |
|
|
// We need an extra check to make sure that the match extended |
|
|
// to the end of the input string |
|
|
assert(vec[0] == 0); // PCRE_ANCHORED forces starting match |
|
|
if (vec[1] != text.size()) return 0; // Did not get ending match |
|
|
} |
|
|
|
|
| 555 |
return rc; |
return rc; |
| 556 |
} |
} |
| 557 |
|
|
| 563 |
int* vec, |
int* vec, |
| 564 |
int vecsize) const { |
int vecsize) const { |
| 565 |
assert((1 + n) * 3 <= vecsize); // results + PCRE workspace |
assert((1 + n) * 3 <= vecsize); // results + PCRE workspace |
| 566 |
int matches = TryMatch(text, 0, anchor, vec, vecsize); |
int matches = TryMatch(text, 0, anchor, true, vec, vecsize); |
| 567 |
assert(matches >= 0); // TryMatch never returns negatives |
assert(matches >= 0); // TryMatch never returns negatives |
| 568 |
if (matches == 0) |
if (matches == 0) |
| 569 |
return false; |
return false; |
| 605 |
// (as for kVecSize) |
// (as for kVecSize) |
| 606 |
int space[21]; // use stack allocation for small vecsize (common case) |
int space[21]; // use stack allocation for small vecsize (common case) |
| 607 |
int* vec = vecsize <= 21 ? space : new int[vecsize]; |
int* vec = vecsize <= 21 ? space : new int[vecsize]; |
| 608 |
bool retval = DoMatchImpl(text, anchor, consumed, args, n, vec, vecsize); |
bool retval = DoMatchImpl(text, anchor, consumed, args, n, vec, (int)vecsize); |
| 609 |
if (vec != space) delete [] vec; |
if (vec != space) delete [] vec; |
| 610 |
return retval; |
return retval; |
| 611 |
} |
} |
| 628 |
if (start >= 0) |
if (start >= 0) |
| 629 |
out->append(text.data() + start, vec[2 * n + 1] - start); |
out->append(text.data() + start, vec[2 * n + 1] - start); |
| 630 |
} else if (c == '\\') { |
} else if (c == '\\') { |
| 631 |
out->push_back('\\'); |
*out += '\\'; |
| 632 |
} else { |
} else { |
| 633 |
//fprintf(stderr, "invalid rewrite pattern: %.*s\n", |
//fprintf(stderr, "invalid rewrite pattern: %.*s\n", |
| 634 |
// rewrite.size(), rewrite.data()); |
// rewrite.size(), rewrite.data()); |
| 635 |
return false; |
return false; |
| 636 |
} |
} |
| 637 |
} else { |
} else { |
| 638 |
out->push_back(c); |
*out += c; |
| 639 |
} |
} |
| 640 |
} |
} |
| 641 |
return true; |
return true; |
| 663 |
} |
} |
| 664 |
|
|
| 665 |
bool Arg::parse_string(const char* str, int n, void* dest) { |
bool Arg::parse_string(const char* str, int n, void* dest) { |
| 666 |
|
if (dest == NULL) return true; |
| 667 |
reinterpret_cast<string*>(dest)->assign(str, n); |
reinterpret_cast<string*>(dest)->assign(str, n); |
| 668 |
return true; |
return true; |
| 669 |
} |
} |
| 670 |
|
|
| 671 |
bool Arg::parse_stringpiece(const char* str, int n, void* dest) { |
bool Arg::parse_stringpiece(const char* str, int n, void* dest) { |
| 672 |
|
if (dest == NULL) return true; |
| 673 |
reinterpret_cast<StringPiece*>(dest)->set(str, n); |
reinterpret_cast<StringPiece*>(dest)->set(str, n); |
| 674 |
return true; |
return true; |
| 675 |
} |
} |
| 676 |
|
|
| 677 |
bool Arg::parse_char(const char* str, int n, void* dest) { |
bool Arg::parse_char(const char* str, int n, void* dest) { |
| 678 |
if (n != 1) return false; |
if (n != 1) return false; |
| 679 |
|
if (dest == NULL) return true; |
| 680 |
*(reinterpret_cast<char*>(dest)) = str[0]; |
*(reinterpret_cast<char*>(dest)) = str[0]; |
| 681 |
return true; |
return true; |
| 682 |
} |
} |
| 683 |
|
|
| 684 |
bool Arg::parse_uchar(const char* str, int n, void* dest) { |
bool Arg::parse_uchar(const char* str, int n, void* dest) { |
| 685 |
if (n != 1) return false; |
if (n != 1) return false; |
| 686 |
|
if (dest == NULL) return true; |
| 687 |
*(reinterpret_cast<unsigned char*>(dest)) = str[0]; |
*(reinterpret_cast<unsigned char*>(dest)) = str[0]; |
| 688 |
return true; |
return true; |
| 689 |
} |
} |
| 732 |
long r = strtol(str, &end, radix); |
long r = strtol(str, &end, radix); |
| 733 |
if (end != str + n) return false; // Leftover junk |
if (end != str + n) return false; // Leftover junk |
| 734 |
if (errno) return false; |
if (errno) return false; |
| 735 |
|
if (dest == NULL) return true; |
| 736 |
*(reinterpret_cast<long*>(dest)) = r; |
*(reinterpret_cast<long*>(dest)) = r; |
| 737 |
return true; |
return true; |
| 738 |
} |
} |
| 750 |
unsigned long r = strtoul(str, &end, radix); |
unsigned long r = strtoul(str, &end, radix); |
| 751 |
if (end != str + n) return false; // Leftover junk |
if (end != str + n) return false; // Leftover junk |
| 752 |
if (errno) return false; |
if (errno) return false; |
| 753 |
|
if (dest == NULL) return true; |
| 754 |
*(reinterpret_cast<unsigned long*>(dest)) = r; |
*(reinterpret_cast<unsigned long*>(dest)) = r; |
| 755 |
return true; |
return true; |
| 756 |
} |
} |
| 762 |
long r; |
long r; |
| 763 |
if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse |
if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse |
| 764 |
if (r < SHRT_MIN || r > SHRT_MAX) return false; // Out of range |
if (r < SHRT_MIN || r > SHRT_MAX) return false; // Out of range |
| 765 |
*(reinterpret_cast<short*>(dest)) = r; |
if (dest == NULL) return true; |
| 766 |
|
*(reinterpret_cast<short*>(dest)) = static_cast<short>(r); |
| 767 |
return true; |
return true; |
| 768 |
} |
} |
| 769 |
|
|
| 774 |
unsigned long r; |
unsigned long r; |
| 775 |
if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse |
if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse |
| 776 |
if (r > USHRT_MAX) return false; // Out of range |
if (r > USHRT_MAX) return false; // Out of range |
| 777 |
*(reinterpret_cast<unsigned short*>(dest)) = r; |
if (dest == NULL) return true; |
| 778 |
|
*(reinterpret_cast<unsigned short*>(dest)) = static_cast<unsigned short>(r); |
| 779 |
return true; |
return true; |
| 780 |
} |
} |
| 781 |
|
|
| 786 |
long r; |
long r; |
| 787 |
if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse |
if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse |
| 788 |
if (r < INT_MIN || r > INT_MAX) return false; // Out of range |
if (r < INT_MIN || r > INT_MAX) return false; // Out of range |
| 789 |
|
if (dest == NULL) return true; |
| 790 |
*(reinterpret_cast<int*>(dest)) = r; |
*(reinterpret_cast<int*>(dest)) = r; |
| 791 |
return true; |
return true; |
| 792 |
} |
} |
| 798 |
unsigned long r; |
unsigned long r; |
| 799 |
if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse |
if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse |
| 800 |
if (r > UINT_MAX) return false; // Out of range |
if (r > UINT_MAX) return false; // Out of range |
| 801 |
|
if (dest == NULL) return true; |
| 802 |
*(reinterpret_cast<unsigned int*>(dest)) = r; |
*(reinterpret_cast<unsigned int*>(dest)) = r; |
| 803 |
return true; |
return true; |
| 804 |
} |
} |
| 819 |
long long r = strtoq(str, &end, radix); |
long long r = strtoq(str, &end, radix); |
| 820 |
#elif defined HAVE_STRTOLL |
#elif defined HAVE_STRTOLL |
| 821 |
long long r = strtoll(str, &end, radix); |
long long r = strtoll(str, &end, radix); |
| 822 |
|
#elif defined HAVE__STRTOI64 |
| 823 |
|
long long r = _strtoi64(str, &end, radix); |
| 824 |
|
#elif defined HAVE_STRTOIMAX |
| 825 |
|
long long r = strtoimax(str, &end, radix); |
| 826 |
#else |
#else |
| 827 |
#error parse_longlong_radix: cannot convert input to a long-long |
#error parse_longlong_radix: cannot convert input to a long-long |
| 828 |
#endif |
#endif |
| 829 |
if (end != str + n) return false; // Leftover junk |
if (end != str + n) return false; // Leftover junk |
| 830 |
if (errno) return false; |
if (errno) return false; |
| 831 |
|
if (dest == NULL) return true; |
| 832 |
*(reinterpret_cast<long long*>(dest)) = r; |
*(reinterpret_cast<long long*>(dest)) = r; |
| 833 |
return true; |
return true; |
| 834 |
#endif /* HAVE_LONG_LONG */ |
#endif /* HAVE_LONG_LONG */ |
| 851 |
unsigned long long r = strtouq(str, &end, radix); |
unsigned long long r = strtouq(str, &end, radix); |
| 852 |
#elif defined HAVE_STRTOLL |
#elif defined HAVE_STRTOLL |
| 853 |
unsigned long long r = strtoull(str, &end, radix); |
unsigned long long r = strtoull(str, &end, radix); |
| 854 |
|
#elif defined HAVE__STRTOI64 |
| 855 |
|
unsigned long long r = _strtoui64(str, &end, radix); |
| 856 |
|
#elif defined HAVE_STRTOIMAX |
| 857 |
|
unsigned long long r = strtoumax(str, &end, radix); |
| 858 |
#else |
#else |
| 859 |
#error parse_ulonglong_radix: cannot convert input to a long-long |
#error parse_ulonglong_radix: cannot convert input to a long-long |
| 860 |
#endif |
#endif |
| 861 |
if (end != str + n) return false; // Leftover junk |
if (end != str + n) return false; // Leftover junk |
| 862 |
if (errno) return false; |
if (errno) return false; |
| 863 |
|
if (dest == NULL) return true; |
| 864 |
*(reinterpret_cast<unsigned long long*>(dest)) = r; |
*(reinterpret_cast<unsigned long long*>(dest)) = r; |
| 865 |
return true; |
return true; |
| 866 |
#endif /* HAVE_UNSIGNED_LONG_LONG */ |
#endif /* HAVE_UNSIGNED_LONG_LONG */ |
| 878 |
double r = strtod(buf, &end); |
double r = strtod(buf, &end); |
| 879 |
if (end != buf + n) return false; // Leftover junk |
if (end != buf + n) return false; // Leftover junk |
| 880 |
if (errno) return false; |
if (errno) return false; |
| 881 |
|
if (dest == NULL) return true; |
| 882 |
*(reinterpret_cast<double*>(dest)) = r; |
*(reinterpret_cast<double*>(dest)) = r; |
| 883 |
return true; |
return true; |
| 884 |
} |
} |
| 886 |
bool Arg::parse_float(const char* str, int n, void* dest) { |
bool Arg::parse_float(const char* str, int n, void* dest) { |
| 887 |
double r; |
double r; |
| 888 |
if (!parse_double(str, n, &r)) return false; |
if (!parse_double(str, n, &r)) return false; |
| 889 |
|
if (dest == NULL) return true; |
| 890 |
*(reinterpret_cast<float*>(dest)) = static_cast<float>(r); |
*(reinterpret_cast<float*>(dest)) = static_cast<float>(r); |
| 891 |
return true; |
return true; |
| 892 |
} |
} |