• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Init(const string & pat,const RE_Options * options)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 
Cleanup()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 
~RE()77 RE::~RE() {
78   Cleanup();
79 }
80 
format_pcre_error(int error,string & str)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 
Compile(Anchor anchor)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 
Replace(const StringPiece & rewrite,string * str) const151 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 
is_multi_char_newline_mode(int value)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 
GlobalReplace(const StringPiece & rewrite,string * str) const184 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 
Extract(const StringPiece & rewrite,const StringPiece & text,string * out) const257 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 
QuoteMeta(const StringPiece & unquoted)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 *****/
TryMatch(const StringPiece & text,int startpos,Anchor anchor,bool empty_ok,pcre2_match_data_ptr & match_data) const303 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 
DoMatchImpl(const StringPiece & text,Anchor anchor,int * consumed,const Arg * args,int n) const365 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 
DoMatch(const StringPiece & text,Anchor anchor,int * consumed,Arg const args[],int n) const407 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 
Rewrite(string * out,const StringPiece & rewrite,const StringPiece & text,pcre2_match_data_ptr const & match_data) const417 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.
NumberOfCapturingGroups() const453 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 
parse_null(const char * str,int n,void * dest)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 
parse_string(const char * str,int n,void * dest)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 
parse_stringpiece(const char * str,int n,void * dest)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 
parse_char(const char * str,int n,void * dest)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 
parse_uchar(const char * str,int n,void * dest)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
TerminateNumber(char * buf,const char * str,int n)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 
parse_long_radix(const char * str,int n,void * dest,int radix)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 
parse_ulong_radix(const char * str,int n,void * dest,int radix)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 
parse_short_radix(const char * str,int n,void * dest,int radix)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 
parse_ushort_radix(const char * str,int n,void * dest,int radix)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 
parse_int_radix(const char * str,int n,void * dest,int radix)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 
parse_uint_radix(const char * str,int n,void * dest,int radix)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 
parse_longlong_radix(const char * str,int n,void * dest,int radix)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 
parse_ulonglong_radix(const char * str,int n,void * dest,int radix)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 
parse_double(const char * str,int n,void * dest)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 
parse_float(const char * str,int n,void * dest)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