Home | History | Annotate | Download | only in pcrecpp
      1 // Copyright (c) 2010, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 //
     30 // Author: Sanjay Ghemawat
     31 
     32 #include <stdlib.h>
     33 #include <stdio.h>
     34 #include <ctype.h>
     35 #include <limits.h>      /* for SHRT_MIN, USHRT_MAX, etc */
     36 #include <string.h>      /* for memcpy */
     37 #include <assert.h>
     38 #include <errno.h>
     39 #include <string>
     40 #include <algorithm>
     41 
     42 #include "pcrecpp_internal.h"
     43 #include "pcre2.h"
     44 #include "pcrecpp.h"
     45 #include "pcre_stringpiece.h"
     46 
     47 
     48 namespace pcrecpp {
     49 
     50 // If the user doesn't ask for any options, we just use this one
     51 static RE_Options default_options;
     52 
     53 void RE::Init(const string& pat, const RE_Options* options) {
     54   pattern_ = pat;
     55   if (options == NULL) {
     56     options_ = default_options;
     57   } else {
     58     options_ = *options;
     59   }
     60   error_ = "";
     61   re_full_ = NULL;
     62   re_partial_ = NULL;
     63 
     64   re_partial_ = Compile(UNANCHORED);
     65   if (re_partial_ != NULL) {
     66     re_full_ = Compile(ANCHOR_BOTH);
     67   }
     68 }
     69 
     70 void RE::Cleanup() {
     71   if (re_full_ != NULL)         pcre2_code_free(re_full_);
     72   if (re_partial_ != NULL)      pcre2_code_free(re_partial_);
     73   error_ = "";
     74 }
     75 
     76 
     77 RE::~RE() {
     78   Cleanup();
     79 }
     80 
     81 static void format_pcre_error(int error, string & str) {
     82   PCRE2_UCHAR8 buffer[256];
     83   auto rc = pcre2_get_error_message(error, buffer, 256);
     84   str.assign(reinterpret_cast<string::value_type*>(buffer));
     85   if (rc == PCRE2_ERROR_NOMEMORY) {
     86     str.append("...");
     87   }
     88 }
     89 
     90 pcre2_code* RE::Compile(Anchor anchor) {
     91   // First, convert RE_Options into pcre options
     92   int pcre_options = 0;
     93   pcre_options = options_.all_options();
     94   typedef std::unique_ptr<pcre2_compile_context,
     95       decltype(pcre2_compile_context_free)*> compile_context_ptr;
     96   compile_context_ptr compile_context(NULL, pcre2_compile_context_free);
     97 
     98   // As of pcre2 the newline mode must be passed through the compile context.
     99   // So we only need one if the newline mode is actually set.
    100   if (options_.newline_mode()) {
    101     compile_context = compile_context_ptr(pcre2_compile_context_create(NULL),
    102     pcre2_compile_context_free);
    103     if (!compile_context) {
    104       error_ = "Unable to allocate memory for pcre2_compile_congext";
    105       return NULL;
    106     }
    107     if (pcre2_set_newline(compile_context.get(),
    108                           options_.newline_mode()) == PCRE2_ERROR_BADDATA) {
    109       error_ = "REOptions: bad newline mode given";
    110       return NULL;
    111     }
    112   }
    113 
    114   // Special treatment for anchoring.  This is needed because at
    115   // runtime pcre only provides an option for anchoring at the
    116   // beginning of a string (unless you use offset).
    117   //
    118   // There are three types of anchoring we want:
    119   //    UNANCHORED      Compile the original pattern, and use
    120   //                    a pcre unanchored match.
    121   //    ANCHOR_START    Compile the original pattern, and use
    122   //                    a pcre anchored match.
    123   //    ANCHOR_BOTH     Tack a "\z" to the end of the original pattern
    124   //                    and use a pcre anchored match.
    125 
    126   int compile_error;
    127   PCRE2_SIZE eoffset;
    128   pcre2_code* re;
    129   if (anchor != ANCHOR_BOTH) {
    130     re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(pattern_.c_str()),
    131                        pattern_.length(), pcre_options, &compile_error,
    132                        &eoffset, compile_context.get());
    133   } else {
    134     // Tack a '\z' at the end of RE.  Parenthesize it first so that
    135     // the '\z' applies to all top-level alternatives in the regexp.
    136     string wrapped = "(?:";  // A non-counting grouping operator
    137     wrapped += pattern_;
    138     wrapped += ")\\z";
    139     re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(wrapped.c_str()),
    140                        wrapped.length(), pcre_options, &compile_error, &eoffset,
    141                        compile_context.get());
    142   }
    143   if (re == NULL) {
    144     format_pcre_error(compile_error, error_);
    145   }
    146   return re;
    147 }
    148 
    149 /***** Matching interfaces *****/
    150 
    151 bool RE::Replace(const StringPiece& rewrite,
    152                  string *str) const {
    153   pcre2_match_data_ptr match_data;
    154   int matches = TryMatch(*str, 0, UNANCHORED, true, match_data);
    155   if (matches == 0)
    156     return false;
    157 
    158   string s;
    159   if (!Rewrite(&s, rewrite, *str, match_data))
    160     return false;
    161 
    162   auto vec = pcre2_get_ovector_pointer(match_data.get());
    163 
    164   assert(vec[0] >= 0);
    165   assert(vec[1] >= 0);
    166   str->replace(vec[0], vec[1] - vec[0], s);
    167   return true;
    168 }
    169 
    170 static bool is_multi_char_newline_mode(int value) {
    171   switch (value) {
    172     case PCRE2_NEWLINE_CR:
    173     case PCRE2_NEWLINE_LF:
    174       return false;
    175     case PCRE2_NEWLINE_CRLF:
    176     case PCRE2_NEWLINE_ANY:
    177     case PCRE2_NEWLINE_ANYCRLF:
    178       return true;
    179     default:
    180       return false;
    181   }
    182 }
    183 
    184 int RE::GlobalReplace(const StringPiece& rewrite,
    185                       string *str) const {
    186   int count = 0;
    187   string out;
    188   int start = 0;
    189   bool last_match_was_empty_string = false;
    190   pcre2_match_data_ptr match_data;
    191 
    192   while (start <= static_cast<int>(str->length())) {
    193     // If the previous match was for the empty string, we shouldn't
    194     // just match again: we'll match in the same way and get an
    195     // infinite loop.  Instead, we do the match in a special way:
    196     // anchored -- to force another try at the same position --
    197     // and with a flag saying that this time, ignore empty matches.
    198     // If this special match returns, that means there's a non-empty
    199     // match at this position as well, and we can continue.  If not,
    200     // we do what perl does, and just advance by one.
    201     // Notice that perl prints '@@@' for this;
    202     //    perl -le '$_ = "aa"; s/b*|aa/@/g; print'
    203     int matches;
    204     if (last_match_was_empty_string) {
    205       matches = TryMatch(*str, start, ANCHOR_START, false, match_data);
    206       if (matches <= 0) {
    207         int matchend = start + 1;     // advance one character.
    208         // If the current char is CR and we're in CRLF mode, skip LF too.
    209         // Note it's better to call pcre2_pattern_info() than to examine
    210         // all_options(), since options_ could have changed between
    211         // compile-time and now, but this is simpler and safe enough.
    212         // Modified by PH to add ANY and ANYCRLF.
    213         if (matchend < static_cast<int>(str->length()) &&
    214             (*str)[start] == '\r' && (*str)[matchend] == '\n' &&
    215             is_multi_char_newline_mode(options_.newline_mode())) {
    216           matchend++;
    217         }
    218         // We also need to advance more than one char if we're in utf8 mode.
    219 #ifdef SUPPORT_UTF8
    220         if (options_.utf8()) {
    221           while (matchend < static_cast<int>(str->length()) &&
    222                  ((*str)[matchend] & 0xc0) == 0x80)
    223             matchend++;
    224         }
    225 #endif
    226         if (start < static_cast<int>(str->length()))
    227           out.append(*str, start, matchend - start);
    228         start = matchend;
    229         last_match_was_empty_string = false;
    230         continue;
    231       }
    232     } else {
    233       matches = TryMatch(*str, start, UNANCHORED, true, match_data);
    234       if (matches <= 0)
    235         break;
    236     }
    237     auto vec = pcre2_get_ovector_pointer(match_data.get());
    238     int matchstart = vec[0], matchend = vec[1];
    239     assert(matchstart >= start);
    240     assert(matchend >= matchstart);
    241     out.append(*str, start, matchstart - start);
    242     Rewrite(&out, rewrite, *str, match_data);
    243     start = matchend;
    244     count++;
    245     last_match_was_empty_string = (matchstart == matchend);
    246   }
    247 
    248   if (count == 0)
    249     return 0;
    250 
    251   if (start < static_cast<int>(str->length()))
    252     out.append(*str, start, str->length() - start);
    253   swap(out, *str);
    254   return count;
    255 }
    256 
    257 bool RE::Extract(const StringPiece& rewrite,
    258                  const StringPiece& text,
    259                  string *out) const {
    260   pcre2_match_data_ptr match_data;
    261   int matches = TryMatch(text, 0, UNANCHORED, true, match_data);
    262   if (matches == 0)
    263     return false;
    264   out->erase();
    265   return Rewrite(out, rewrite, text, match_data);
    266 }
    267 
    268 /*static*/ string RE::QuoteMeta(const StringPiece& unquoted) {
    269   string result;
    270 
    271   // Escape any ascii character not in [A-Za-z_0-9].
    272   //
    273   // Note that it's legal to escape a character even if it has no
    274   // special meaning in a regular expression -- so this function does
    275   // that.  (This also makes it identical to the perl function of the
    276   // same name; see `perldoc -f quotemeta`.)  The one exception is
    277   // escaping NUL: rather than doing backslash + NUL, like perl does,
    278   // we do '\0', because pcre itself doesn't take embedded NUL chars.
    279   for (int ii = 0; ii < unquoted.size(); ++ii) {
    280     // Note that using 'isalnum' here raises the benchmark time from
    281     // 32ns to 58ns:
    282     if (unquoted[ii] == '\0') {
    283       result += "\\0";
    284     } else if ((unquoted[ii] < 'a' || unquoted[ii] > 'z') &&
    285                (unquoted[ii] < 'A' || unquoted[ii] > 'Z') &&
    286                (unquoted[ii] < '0' || unquoted[ii] > '9') &&
    287                unquoted[ii] != '_' &&
    288                // If this is the part of a UTF8 or Latin1 character, we need
    289                // to copy this byte without escaping.  Experimentally this is
    290                // what works correctly with the regexp library.
    291                !(unquoted[ii] & 128)) {
    292       result += '\\';
    293       result += unquoted[ii];
    294     } else {
    295       result += unquoted[ii];
    296     }
    297   }
    298 
    299   return result;
    300 }
    301 
    302 /***** Actual matching and rewriting code *****/
    303 int RE::TryMatch(const StringPiece& text,
    304                  int startpos,
    305                  Anchor anchor,
    306                  bool empty_ok,
    307                  pcre2_match_data_ptr & match_data) const {
    308   typedef std::unique_ptr<pcre2_match_context,
    309       decltype(pcre2_match_context_free)*> match_context_ptr;
    310 
    311   pcre2_code* re = (anchor == ANCHOR_BOTH) ? re_full_ : re_partial_;
    312   if (re == NULL) {
    313     //fprintf(stderr, "Matching against invalid re: %s\n", error_->c_str());
    314     return 0;
    315   }
    316   match_context_ptr match_context = match_context_ptr(
    317       pcre2_match_context_create(NULL),
    318       pcre2_match_context_free);
    319   if (!match_context)
    320     return 0;
    321 
    322   if (options_.match_limit() > 0) {
    323     pcre2_set_match_limit(match_context.get(), options_.match_limit());
    324   }
    325   if (options_.match_limit_recursion() > 0) {
    326     pcre2_set_recursion_limit(match_context.get(),
    327                               options_.match_limit_recursion());
    328   }
    329 
    330   match_data = pcre2_match_data_ptr(
    331       pcre2_match_data_create_from_pattern(re, NULL),
    332       pcre2_match_data_free);
    333   if (!match_data) {
    334     return 0;
    335   }
    336 
    337   // int options = 0;
    338   // Changed by PH as a result of bugzilla #1288
    339   int options = (options_.all_options() & PCRE2_NO_UTF_CHECK);
    340 
    341   if (anchor != UNANCHORED)
    342     options |= PCRE2_ANCHORED;
    343   if (!empty_ok)
    344     options |= PCRE2_NOTEMPTY;
    345 
    346   int rc = pcre2_match(
    347       re, reinterpret_cast<PCRE2_SPTR>((text.empty()) ? "" : text.data()),
    348       text.size(), startpos, options, match_data.get(), match_context.get());
    349 
    350   // Handle errors
    351   if (rc == PCRE2_ERROR_NOMATCH) {
    352     return 0;
    353   }
    354   if (rc == PCRE2_ERROR_PARTIAL) {
    355     // not sure what to do with partial yet
    356     return 0;
    357   } else if (rc < 0) {
    358     // For any other error condition also return 0.
    359     return 0;
    360   }
    361 
    362   return rc; // return number of matches found
    363 }
    364 
    365 bool RE::DoMatchImpl(const StringPiece& text,
    366                      Anchor anchor,
    367                      int* consumed,
    368                      const Arg* args,
    369                      int n) const {
    370   pcre2_match_data_ptr match_data;
    371   int matches = TryMatch(text, 0, anchor, true, match_data);
    372   assert(matches >= 0);  // TryMatch never returns negatives
    373   if (matches == 0)
    374     return false;
    375 
    376   auto vec = pcre2_get_ovector_pointer(match_data.get());
    377 
    378   // allow for NULL
    379   if (consumed != NULL)
    380     *consumed = vec[1];
    381 
    382   if (n == 0 || args == NULL) {
    383     // We are not interested in results
    384     return true;
    385   }
    386 
    387   if (NumberOfCapturingGroups() < n) {
    388     // RE has fewer capturing groups than number of arg pointers passed in
    389     return false;
    390   }
    391 
    392   // If we got here, we must have matched the whole pattern.
    393   // We do not need (can not do) any more checks on the value of 'matches' here
    394   // -- see the comment for TryMatch.
    395   for (int i = 0; i < n; i++) {
    396     const int start = vec[2*(i+1)];
    397     const int limit = vec[2*(i+1)+1];
    398     if (!args[i].Parse(text.data() + start, limit - start)) {
    399       // TODO: Should we indicate what the error was?
    400       return false;
    401     }
    402   }
    403 
    404   return true;
    405 }
    406 
    407 bool RE::DoMatch(const StringPiece& text,
    408                  Anchor anchor,
    409                  int* consumed,
    410                  Arg const args[],
    411                  int n) const {
    412   assert(n >= 0);
    413   bool retval = DoMatchImpl(text, anchor, consumed, args, n);
    414   return retval;
    415 }
    416 
    417 bool RE::Rewrite(string *out, const StringPiece &rewrite,
    418                  const StringPiece &text,
    419                  pcre2_match_data_ptr const & match_data) const {
    420   auto veclen = pcre2_get_ovector_count(match_data.get());
    421   auto vec = pcre2_get_ovector_pointer(match_data.get());
    422   for (const char *s = rewrite.data(), *end = s + rewrite.size();
    423        s < end; s++) {
    424     int c = *s;
    425     if (c == '\\') {
    426       c = *++s;
    427       if (isdigit(c)) {
    428         decltype(veclen) n = (c - '0');
    429         if (n >= veclen) {
    430           //fprintf(stderr, requested group %d in regexp %.*s\n",
    431           //        n, rewrite.size(), rewrite.data());
    432           return false;
    433         }
    434         int start = vec[2 * n];
    435         if (start >= 0)
    436           out->append(text.data() + start, vec[2 * n + 1] - start);
    437       } else if (c == '\\') {
    438         *out += '\\';
    439       } else {
    440         //fprintf(stderr, "invalid rewrite pattern: %.*s\n",
    441         //        rewrite.size(), rewrite.data());
    442         return false;
    443       }
    444     } else {
    445       *out += c;
    446     }
    447   }
    448   return true;
    449 }
    450 
    451 // Return the number of capturing subpatterns, or -1 if the
    452 // regexp wasn't valid on construction.
    453 int RE::NumberOfCapturingGroups() const {
    454   if (re_partial_ == NULL) return -1;
    455 
    456   int result;
    457   int pcre_retval = pcre2_pattern_info(re_partial_, PCRE2_INFO_CAPTURECOUNT,
    458                                        &result);
    459   assert(pcre_retval == 0);
    460   return result;
    461 }
    462 
    463 /***** Parsers for various types *****/
    464 
    465 bool Arg::parse_null(const char* str, int n, void* dest) {
    466   (void)str;
    467   (void)n;
    468   // We fail if somebody asked us to store into a non-NULL void* pointer
    469   return (dest == NULL);
    470 }
    471 
    472 bool Arg::parse_string(const char* str, int n, void* dest) {
    473   if (dest == NULL) return true;
    474   reinterpret_cast<string*>(dest)->assign(str, n);
    475   return true;
    476 }
    477 
    478 bool Arg::parse_stringpiece(const char* str, int n, void* dest) {
    479   if (dest == NULL) return true;
    480   reinterpret_cast<StringPiece*>(dest)->set(str, n);
    481   return true;
    482 }
    483 
    484 bool Arg::parse_char(const char* str, int n, void* dest) {
    485   if (n != 1) return false;
    486   if (dest == NULL) return true;
    487   *(reinterpret_cast<char*>(dest)) = str[0];
    488   return true;
    489 }
    490 
    491 bool Arg::parse_uchar(const char* str, int n, void* dest) {
    492   if (n != 1) return false;
    493   if (dest == NULL) return true;
    494   *(reinterpret_cast<unsigned char*>(dest)) = str[0];
    495   return true;
    496 }
    497 
    498 // Largest number spec that we are willing to parse
    499 static const int kMaxNumberLength = 32;
    500 
    501 // REQUIRES "buf" must have length at least kMaxNumberLength+1
    502 // REQUIRES "n > 0"
    503 // Copies "str" into "buf" and null-terminates if necessary.
    504 // Returns one of:
    505 //      a. "str" if no termination is needed
    506 //      b. "buf" if the string was copied and null-terminated
    507 //      c. "" if the input was invalid and has no hope of being parsed
    508 static const char* TerminateNumber(char* buf, const char* str, int n) {
    509   if ((n > 0) && isspace(*str)) {
    510     // We are less forgiving than the strtoxxx() routines and do not
    511     // allow leading spaces.
    512     return "";
    513   }
    514 
    515   // See if the character right after the input text may potentially
    516   // look like a digit.
    517   if (isdigit(str[n]) ||
    518       ((str[n] >= 'a') && (str[n] <= 'f')) ||
    519       ((str[n] >= 'A') && (str[n] <= 'F'))) {
    520     if (n > kMaxNumberLength) return ""; // Input too big to be a valid number
    521     memcpy(buf, str, n);
    522     buf[n] = '\0';
    523     return buf;
    524   } else {
    525     // We can parse right out of the supplied string, so return it.
    526     return str;
    527   }
    528 }
    529 
    530 bool Arg::parse_long_radix(const char* str,
    531                            int n,
    532                            void* dest,
    533                            int radix) {
    534   if (n == 0) return false;
    535   char buf[kMaxNumberLength+1];
    536   str = TerminateNumber(buf, str, n);
    537   char* end;
    538   errno = 0;
    539   long r = strtol(str, &end, radix);
    540   if (end != str + n) return false;   // Leftover junk
    541   if (errno) return false;
    542   if (dest == NULL) return true;
    543   *(reinterpret_cast<long*>(dest)) = r;
    544   return true;
    545 }
    546 
    547 bool Arg::parse_ulong_radix(const char* str,
    548                             int n,
    549                             void* dest,
    550                             int radix) {
    551   if (n == 0) return false;
    552   char buf[kMaxNumberLength+1];
    553   str = TerminateNumber(buf, str, n);
    554   if (str[0] == '-') return false;    // strtoul() on a negative number?!
    555   char* end;
    556   errno = 0;
    557   unsigned long r = strtoul(str, &end, radix);
    558   if (end != str + n) return false;   // Leftover junk
    559   if (errno) return false;
    560   if (dest == NULL) return true;
    561   *(reinterpret_cast<unsigned long*>(dest)) = r;
    562   return true;
    563 }
    564 
    565 bool Arg::parse_short_radix(const char* str,
    566                             int n,
    567                             void* dest,
    568                             int radix) {
    569   long r;
    570   if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse
    571   if (r < SHRT_MIN || r > SHRT_MAX) return false;       // Out of range
    572   if (dest == NULL) return true;
    573   *(reinterpret_cast<short*>(dest)) = static_cast<short>(r);
    574   return true;
    575 }
    576 
    577 bool Arg::parse_ushort_radix(const char* str,
    578                              int n,
    579                              void* dest,
    580                              int radix) {
    581   unsigned long r;
    582   if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse
    583   if (r > USHRT_MAX) return false;                      // Out of range
    584   if (dest == NULL) return true;
    585   *(reinterpret_cast<unsigned short*>(dest)) = static_cast<unsigned short>(r);
    586   return true;
    587 }
    588 
    589 bool Arg::parse_int_radix(const char* str,
    590                           int n,
    591                           void* dest,
    592                           int radix) {
    593   long r;
    594   if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse
    595   if (r < INT_MIN || r > INT_MAX) return false;         // Out of range
    596   if (dest == NULL) return true;
    597   *(reinterpret_cast<int*>(dest)) = r;
    598   return true;
    599 }
    600 
    601 bool Arg::parse_uint_radix(const char* str,
    602                            int n,
    603                            void* dest,
    604                            int radix) {
    605   unsigned long r;
    606   if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse
    607   if (r > UINT_MAX) return false;                       // Out of range
    608   if (dest == NULL) return true;
    609   *(reinterpret_cast<unsigned int*>(dest)) = r;
    610   return true;
    611 }
    612 
    613 bool Arg::parse_longlong_radix(const char* str,
    614                                int n,
    615                                void* dest,
    616                                int radix) {
    617 #ifndef HAVE_LONG_LONG
    618   return false;
    619 #else
    620   if (n == 0) return false;
    621   char buf[kMaxNumberLength+1];
    622   str = TerminateNumber(buf, str, n);
    623   char* end;
    624   errno = 0;
    625 #if defined HAVE_STRTOQ
    626   long long r = strtoq(str, &end, radix);
    627 #elif defined HAVE_STRTOLL
    628   long long r = strtoll(str, &end, radix);
    629 #elif defined HAVE__STRTOI64
    630   long long r = _strtoi64(str, &end, radix);
    631 #elif defined HAVE_STRTOIMAX
    632   long long r = strtoimax(str, &end, radix);
    633 #else
    634 #error parse_longlong_radix: cannot convert input to a long-long
    635 #endif
    636   if (end != str + n) return false;   // Leftover junk
    637   if (errno) return false;
    638   if (dest == NULL) return true;
    639   *(reinterpret_cast<long long*>(dest)) = r;
    640   return true;
    641 #endif   /* HAVE_LONG_LONG */
    642 }
    643 
    644 bool Arg::parse_ulonglong_radix(const char* str,
    645                                 int n,
    646                                 void* dest,
    647                                 int radix) {
    648 #ifndef HAVE_UNSIGNED_LONG_LONG
    649   return false;
    650 #else
    651   if (n == 0) return false;
    652   char buf[kMaxNumberLength+1];
    653   str = TerminateNumber(buf, str, n);
    654   if (str[0] == '-') return false;    // strtoull() on a negative number?!
    655   char* end;
    656   errno = 0;
    657 #if defined HAVE_STRTOQ
    658   unsigned long long r = strtouq(str, &end, radix);
    659 #elif defined HAVE_STRTOLL
    660   unsigned long long r = strtoull(str, &end, radix);
    661 #elif defined HAVE__STRTOI64
    662   unsigned long long r = _strtoui64(str, &end, radix);
    663 #elif defined HAVE_STRTOIMAX
    664   unsigned long long r = strtoumax(str, &end, radix);
    665 #else
    666 #error parse_ulonglong_radix: cannot convert input to a long-long
    667 #endif
    668   if (end != str + n) return false;   // Leftover junk
    669   if (errno) return false;
    670   if (dest == NULL) return true;
    671   *(reinterpret_cast<unsigned long long*>(dest)) = r;
    672   return true;
    673 #endif   /* HAVE_UNSIGNED_LONG_LONG */
    674 }
    675 
    676 bool Arg::parse_double(const char* str, int n, void* dest) {
    677   if (n == 0) return false;
    678   static const int kMaxLength = 200;
    679   char buf[kMaxLength];
    680   if (n >= kMaxLength) return false;
    681   memcpy(buf, str, n);
    682   buf[n] = '\0';
    683   errno = 0;
    684   char* end;
    685   double r = strtod(buf, &end);
    686   if (end != buf + n) return false;   // Leftover junk
    687   if (errno) return false;
    688   if (dest == NULL) return true;
    689   *(reinterpret_cast<double*>(dest)) = r;
    690   return true;
    691 }
    692 
    693 bool Arg::parse_float(const char* str, int n, void* dest) {
    694   double r;
    695   if (!parse_double(str, n, &r)) return false;
    696   if (dest == NULL) return true;
    697   *(reinterpret_cast<float*>(dest)) = static_cast<float>(r);
    698   return true;
    699 }
    700 
    701 
    702 #define DEFINE_INTEGER_PARSERS(name)                                    \
    703   bool Arg::parse_##name(const char* str, int n, void* dest) {          \
    704     return parse_##name##_radix(str, n, dest, 10);                      \
    705   }                                                                     \
    706   bool Arg::parse_##name##_hex(const char* str, int n, void* dest) {    \
    707     return parse_##name##_radix(str, n, dest, 16);                      \
    708   }                                                                     \
    709   bool Arg::parse_##name##_octal(const char* str, int n, void* dest) {  \
    710     return parse_##name##_radix(str, n, dest, 8);                       \
    711   }                                                                     \
    712   bool Arg::parse_##name##_cradix(const char* str, int n, void* dest) { \
    713     return parse_##name##_radix(str, n, dest, 0);                       \
    714   }
    715 
    716 DEFINE_INTEGER_PARSERS(short)      /*                                   */
    717 DEFINE_INTEGER_PARSERS(ushort)     /*                                   */
    718 DEFINE_INTEGER_PARSERS(int)        /* Don't use semicolons after these  */
    719 DEFINE_INTEGER_PARSERS(uint)       /* statements because they can cause */
    720 DEFINE_INTEGER_PARSERS(long)       /* compiler warnings if the checking */
    721 DEFINE_INTEGER_PARSERS(ulong)      /* level is turned up high enough.   */
    722 DEFINE_INTEGER_PARSERS(longlong)   /*                                   */
    723 DEFINE_INTEGER_PARSERS(ulonglong)  /*                                   */
    724 
    725 #undef DEFINE_INTEGER_PARSERS
    726 
    727 }   // namespace pcrecpp
    728