/[pcre]/code/trunk/pcrecpp.cc
ViewVC logotype

Diff of /code/trunk/pcrecpp.cc

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 81 by nigel, Sat Feb 24 21:40:59 2007 UTC revision 486 by ph10, Tue Jan 5 17:44:57 2010 UTC
# Line 1  Line 1 
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
# Line 29  Line 29 
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>
# Line 37  Line 41 
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 {
# Line 53  static const int kMaxArgs = 16; Line 55  static const int kMaxArgs = 16;
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;
# Line 61  static const string empty_string; Line 79  static const string empty_string;
79  // If the user doesn't ask for any options, we just use this one  // If the user doesn't ask for any options, we just use this one
80  static RE_Options default_options;  static RE_Options default_options;
81    
82  void RE::Init(const char* pat, const RE_Options* options) {  void RE::Init(const string& pat, const RE_Options* options) {
83    pattern_ = pat;    pattern_ = pat;
84    if (options == NULL) {    if (options == NULL) {
85      options_ = default_options;      options_ = default_options;
# Line 74  void RE::Init(const char* pat, const RE_ Line 92  void RE::Init(const char* pat, const RE_
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, '|') == 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() {
100      if (re_full_ != NULL)         (*pcre_free)(re_full_);
101      if (re_partial_ != NULL)      (*pcre_free)(re_partial_);
102      if (error_ != &empty_string)  delete error_;
103    }
104    
105    
106  RE::~RE() {  RE::~RE() {
107    if (re_full_ != NULL && re_full_ != re_partial_) (*pcre_free)(re_full_);    Cleanup();
   if (re_partial_ != NULL)                         (*pcre_free)(re_partial_);  
   if (error_ != &empty_string)                     delete error_;  
108  }  }
109    
110    
111  pcre* RE::Compile(Anchor anchor) {  pcre* RE::Compile(Anchor anchor) {
112    // First, convert RE_Options into pcre options    // First, convert RE_Options into pcre options
113    int pcre_options = 0;    int pcre_options = 0;
# Line 318  bool RE::FindAndConsume(StringPiece* inp Line 331  bool RE::FindAndConsume(StringPiece* inp
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    
# Line 332  bool RE::Replace(const StringPiece& rewr Line 345  bool RE::Replace(const StringPiece& rewr
345    return true;    return true;
346  }  }
347    
348    // 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.
350    // Modified by PH to add PCRE_NEWLINE_ANY and PCRE_NEWLINE_ANYCRLF.
351    
352    static int NewlineMode(int pcre_options) {
353      // TODO: if we can make it threadsafe, cache this var
354      int newline_mode = 0;
355      /* 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|
357                          PCRE_NEWLINE_ANY|PCRE_NEWLINE_ANYCRLF)) {
358        newline_mode = (pcre_options &
359                        (PCRE_NEWLINE_CRLF|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|
360                         PCRE_NEWLINE_ANY|PCRE_NEWLINE_ANYCRLF));
361      } else {
362        int newline;
363        pcre_config(PCRE_CONFIG_NEWLINE, &newline);
364        if (newline == 10)
365          newline_mode = PCRE_NEWLINE_LF;
366        else if (newline == 13)
367          newline_mode = PCRE_NEWLINE_CR;
368        else if (newline == 3338)
369          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
375          assert(NULL == "Unexpected return value from pcre_config(NEWLINE)");
376      }
377      return newline_mode;
378    }
379    
380  int RE::GlobalReplace(const StringPiece& rewrite,  int RE::GlobalReplace(const StringPiece& rewrite,
381                        string *str) const {                        string *str) const {
382    int count = 0;    int count = 0;
# Line 339  int RE::GlobalReplace(const StringPiece& Line 384  int RE::GlobalReplace(const StringPiece&
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        // anchored -- to force another try at the same position --
394        // and with a flag saying that this time, ignore empty matches.
395        // If this special match returns, that means there's a non-empty
396        // match at this position as well, and we can continue.  If not,
397        // we do what perl does, and just advance by one.
398        // Notice that perl prints '@@@' for this;
399        //    perl -le '$_ = "aa"; s/b*|aa/@/g; print'
400        int matches;
401        if (last_match_was_empty_string) {
402          matches = TryMatch(*str, start, ANCHOR_START, false, vec, kVecSize);
403          if (matches <= 0) {
404            int matchend = start + 1;     // advance one character.
405            // If the current char is CR and we're in CRLF mode, skip LF too.
406            // Note it's better to call pcre_fullinfo() than to examine
407            // all_options(), since options_ could have changed bewteen
408            // compile-time and now, but this is simpler and safe enough.
409            // Modified by PH to add ANY and ANYCRLF.
410            if (matchend < static_cast<int>(str->length()) &&
411                (*str)[start] == '\r' && (*str)[matchend] == '\n' &&
412                (NewlineMode(options_.all_options()) == PCRE_NEWLINE_CRLF ||
413                 NewlineMode(options_.all_options()) == PCRE_NEWLINE_ANY ||
414                 NewlineMode(options_.all_options()) == PCRE_NEWLINE_ANYCRLF)) {
415              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
425            if (start < static_cast<int>(str->length()))
426              out.append(*str, start, matchend - start);
427            start = matchend;
428            last_match_was_empty_string = false;
429            continue;
430          }
431        } else {
432          matches = TryMatch(*str, start, UNANCHORED, true, vec, kVecSize);
433          if (matches <= 0)
434            break;
435        }
436      int matchstart = vec[0], matchend = vec[1];      int matchstart = vec[0], matchend = vec[1];
437      assert(matchstart >= start);      assert(matchstart >= start);
438      assert(matchend >= matchstart);      assert(matchend >= matchstart);
439      if (matchstart == matchend && matchstart == lastend) {      out.append(*str, start, matchstart - start);
440        // advance one character if we matched an empty string at the same      Rewrite(&out, rewrite, *str, vec, matches);
441        // place as the last match occurred      start = matchend;
442        if (start < static_cast<int>(str->length()))      lastend = matchend;
443          out.push_back((*str)[start]);      count++;
444        start++;      last_match_was_empty_string = (matchstart == matchend);
     } else {  
       out.append(*str, start, matchstart - start);  
       Rewrite(&out, rewrite, *str, vec, matches);  
       start = matchend;  
       lastend = matchend;  
       count++;  
     }  
445    }    }
446    
447    if (count == 0)    if (count == 0)
# Line 375  bool RE::Extract(const StringPiece& rewr Line 457  bool RE::Extract(const StringPiece& rewr
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();
464    return Rewrite(out, rewrite, text, vec, matches);    return Rewrite(out, rewrite, text, vec, matches);
465  }  }
466    
467    /*static*/ string RE::QuoteMeta(const StringPiece& unquoted) {
468      string result;
469    
470      // Escape any ascii character not in [A-Za-z_0-9].
471      //
472      // 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
474      // that.  (This also makes it identical to the perl function of the
475      // 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) {
479        // Note that using 'isalnum' here raises the benchmark time from
480        // 32ns to 58ns:
481        if (unquoted[ii] == '\0') {
482          result += "\\0";
483        } else if ((unquoted[ii] < 'a' || unquoted[ii] > 'z') &&
484                   (unquoted[ii] < 'A' || unquoted[ii] > 'Z') &&
485                   (unquoted[ii] < '0' || unquoted[ii] > '9') &&
486                   unquoted[ii] != '_' &&
487                   // If this is the part of a UTF8 or Latin1 character, we need
488                   // to copy this byte without escaping.  Experimentally this is
489                   // what works correctly with the regexp library.
490                   !(unquoted[ii] & 128)) {
491          result += '\\';
492          result += unquoted[ii];
493        } else {
494          result += unquoted[ii];
495        }
496      }
497    
498      return result;
499    }
500    
501  /***** Actual matching and rewriting code *****/  /***** Actual matching and rewriting code *****/
502    
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_;
# Line 395  int RE::TryMatch(const StringPiece& text Line 512  int RE::TryMatch(const StringPiece& text
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();
519    }    }
520      if (options_.match_limit_recursion() > 0) {
521        extra.flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
522        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(),                       (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    
# Line 424  int RE::TryMatch(const StringPiece& text Line 552  int RE::TryMatch(const StringPiece& text
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    
# Line 442  bool RE::DoMatchImpl(const StringPiece& Line 563  bool RE::DoMatchImpl(const StringPiece&
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;
570    
571    *consumed = vec[1];    *consumed = vec[1];
572    
573    if (args == NULL) {    if (n == 0 || args == NULL) {
574      // We are not interested in results      // We are not interested in results
575      return true;      return true;
576    }    }
577    
578      if (NumberOfCapturingGroups() < n) {
579        // RE has fewer capturing groups than number of arg pointers passed in
580        return false;
581      }
582    
583    // If we got here, we must have matched the whole pattern.    // If we got here, we must have matched the whole pattern.
584    // We do not need (can not do) any more checks on the value of 'matches' here    // We do not need (can not do) any more checks on the value of 'matches' here
585    // -- see the comment for TryMatch.    // -- see the comment for TryMatch.
# Line 502  bool RE::Rewrite(string *out, const Stri Line 628  bool RE::Rewrite(string *out, const Stri
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;
# Line 517  bool RE::Rewrite(string *out, const Stri Line 643  bool RE::Rewrite(string *out, const Stri
643    
644  // Return the number of capturing subpatterns, or -1 if the  // Return the number of capturing subpatterns, or -1 if the
645  // regexp wasn't valid on construction.  // regexp wasn't valid on construction.
646  int RE::NumberOfCapturingGroups() {  int RE::NumberOfCapturingGroups() const {
647    if (re_partial_ == NULL) return -1;    if (re_partial_ == NULL) return -1;
648    
649    int result;    int result;
# Line 537  bool Arg::parse_null(const char* str, in Line 663  bool Arg::parse_null(const char* str, in
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  }  }
# Line 602  bool Arg::parse_long_radix(const char* s Line 732  bool Arg::parse_long_radix(const char* s
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  }  }
# Line 613  bool Arg::parse_ulong_radix(const char* Line 744  bool Arg::parse_ulong_radix(const char*
744    if (n == 0) return false;    if (n == 0) return false;
745    char buf[kMaxNumberLength+1];    char buf[kMaxNumberLength+1];
746    str = TerminateNumber(buf, str, n);    str = TerminateNumber(buf, str, n);
747      if (str[0] == '-') return false;    // strtoul() on a negative number?!
748    char* end;    char* end;
749    errno = 0;    errno = 0;
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  }  }
# Line 629  bool Arg::parse_short_radix(const char* Line 762  bool Arg::parse_short_radix(const char*
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    
# Line 640  bool Arg::parse_ushort_radix(const char* Line 774  bool Arg::parse_ushort_radix(const char*
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    
# Line 651  bool Arg::parse_int_radix(const char* st Line 786  bool Arg::parse_int_radix(const char* st
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  }  }
# Line 662  bool Arg::parse_uint_radix(const char* s Line 798  bool Arg::parse_uint_radix(const char* s
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  }  }
# Line 682  bool Arg::parse_longlong_radix(const cha Line 819  bool Arg::parse_longlong_radix(const cha
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 */
# Line 702  bool Arg::parse_ulonglong_radix(const ch Line 844  bool Arg::parse_ulonglong_radix(const ch
844    if (n == 0) return false;    if (n == 0) return false;
845    char buf[kMaxNumberLength+1];    char buf[kMaxNumberLength+1];
846    str = TerminateNumber(buf, str, n);    str = TerminateNumber(buf, str, n);
847      if (str[0] == '-') return false;    // strtoull() on a negative number?!
848    char* end;    char* end;
849    errno = 0;    errno = 0;
850  #if defined HAVE_STRTOQ  #if defined HAVE_STRTOQ
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 */
# Line 730  bool Arg::parse_double(const char* str, Line 878  bool Arg::parse_double(const char* str,
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  }  }
# Line 737  bool Arg::parse_double(const char* str, Line 886  bool Arg::parse_double(const char* str,
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  }  }
# Line 756  bool Arg::parse_float(const char* str, i Line 906  bool Arg::parse_float(const char* str, i
906      return parse_##name##_radix(str, n, dest, 0);                       \      return parse_##name##_radix(str, n, dest, 0);                       \
907    }    }
908    
909  DEFINE_INTEGER_PARSERS(short);  DEFINE_INTEGER_PARSERS(short)      /*                                   */
910  DEFINE_INTEGER_PARSERS(ushort);  DEFINE_INTEGER_PARSERS(ushort)     /*                                   */
911  DEFINE_INTEGER_PARSERS(int);  DEFINE_INTEGER_PARSERS(int)        /* Don't use semicolons after these  */
912  DEFINE_INTEGER_PARSERS(uint);  DEFINE_INTEGER_PARSERS(uint)       /* statements because they can cause */
913  DEFINE_INTEGER_PARSERS(long);  DEFINE_INTEGER_PARSERS(long)       /* compiler warnings if the checking */
914  DEFINE_INTEGER_PARSERS(ulong);  DEFINE_INTEGER_PARSERS(ulong)      /* level is turned up high enough.   */
915  DEFINE_INTEGER_PARSERS(longlong);  DEFINE_INTEGER_PARSERS(longlong)   /*                                   */
916  DEFINE_INTEGER_PARSERS(ulonglong);  DEFINE_INTEGER_PARSERS(ulonglong)  /*                                   */
917    
918  #undef DEFINE_INTEGER_PARSERS  #undef DEFINE_INTEGER_PARSERS
919    

Legend:
Removed from v.81  
changed lines
  Added in v.486

  ViewVC Help
Powered by ViewVC 1.1.5