]> sjero.net Git - wget/blobdiff - src/cmpt.c
[svn] Merge of fix for bugs 20341 and 20410.
[wget] / src / cmpt.c
index 08a92aefadab9b75f4c69809e98c46bad5d9f3fc..4bd582c85dff8342106f552e2af008d0c4d8949d 100644 (file)
@@ -1,11 +1,11 @@
 /* Replacements for routines missing on some systems.
-   Copyright (C) 1996-2005 Free Software Foundation, Inc.
+   Copyright (C) 1996-2006 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
 GNU Wget is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with Wget; if not, write to the Free Software Foundation, Inc.,
-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+along with Wget.  If not, see <http://www.gnu.org/licenses/>.
 
 In addition, as a special exception, the Free Software Foundation
 gives permission to link the code of its release of Wget with the
@@ -111,10 +110,28 @@ strncasecmp (const char *s1, const char *s2, size_t n)
   return c1 - c2;
 }
 #endif /* not HAVE_STRNCASECMP */
+
+#ifndef HAVE_MEMRCHR
+/* memrchr is a GNU extension.  It is like the memchr function, except
+   that it searches backwards from the end of the n bytes pointed to
+   by s instead of forwards from the front.  */
+
+void *
+memrchr (const void *s, int c, size_t n)
+{
+  const char *b = s;
+  const char *e = b + n;
+  while (e > b)
+    if (*--e == c)
+      return (void *) e;
+  return NULL;
+}
+#endif
 \f
 /* strptime is required by POSIX, but it is missing from Windows,
    which means we must keep a fallback implementation.  It is
-   reportedly missing or broken on many older systems as well.  */
+   reportedly missing or broken on many older Unix systems as well, so
+   it's good to have around.  */
 
 #ifndef HAVE_STRPTIME
 /* From GNU libc 2.1.3.  */
@@ -1046,9 +1063,10 @@ const unsigned short int __mon_yday[2][13] =
    and given a prefix, but many systems out there are still (as of
    this writing in 2005) broken and we must cater to them.
 
-   Additionally, according to some conventional, many historical
-   implementations of fnmatch are buggy and unreliable.  If yours is
-   such, undefine SYSTEM_FNMATCH in sysdep.h and tell us about it.  */
+   Additionally, according to some conventional wisdom, many
+   historical implementations of fnmatch are buggy and unreliable.  If
+   yours is such, undefine SYSTEM_FNMATCH in sysdep.h and tell us
+   about it.  */
 
 #ifndef SYSTEM_FNMATCH
 
@@ -1296,23 +1314,22 @@ char_value (char c, int base)
   return value;
 }
 
-#define LL strtoll_return      /* long long or __int64 */
+#define STRTOLL_MAX TYPE_MAXIMUM (strtoll_type)
+/* This definition assumes two's complement arithmetic */
+#define STRTOLL_MIN (-STRTOLL_MAX - 1)
 
-/* These constants assume 64-bit strtoll_return. */
+/* Like a%b, but always returns a positive number when A is negative.
+   (C doesn't guarantee the sign of the result.)  */
+#define MOD(a, b) ((strtoll_type) -1 % 2 == 1 ? (a) % (b) : - ((a) % (b)))
 
-/* A roundabout way of writing 2**63-1 = 9223372036854775807 */
-#define STRTOLL_OVERFLOW (((LL) 1 << 62) - 1 + ((LL) 1 << 62))
-/* A roundabout way of writing -2**63 = -9223372036854775808 */
-#define STRTOLL_UNDERFLOW (-STRTOLL_OVERFLOW - 1)
+/* A strtoll-like replacement for systems that have an integral type
+   larger than long but don't supply strtoll.  This implementation
+   makes no assumptions about the size of strtoll_type.  */
 
-/* A strtoll replacement for systems that have LFS but don't supply
-   strtoll.  The headers typedef strtoll_return to long long or to
-   __int64.  */
-
-strtoll_return
+strtoll_type
 strtoll (const char *nptr, char **endptr, int base)
 {
-  strtoll_return result = 0;
+  strtoll_type result = 0;
   bool negative;
 
   if (base != 0 && (base < 2 || base > 36))
@@ -1336,7 +1353,7 @@ strtoll (const char *nptr, char **endptr, int base)
   else
     negative = false;
 
-  /* If base is 0, determine the real base based on the beginning on
+  /* If BASE is 0, determine the real base based on the beginning on
      the number; octal numbers begin with "0", hexadecimal with "0x",
      and the others are considered octal.  */
   if (*nptr == '0')
@@ -1347,6 +1364,13 @@ strtoll (const char *nptr, char **endptr, int base)
        {
          base = 16;
          nptr += 2;
+         /* "0x" must be followed by at least one hex char.  If not,
+            return 0 and place ENDPTR on 'x'. */
+         if (!ISXDIGIT (*nptr))
+           {
+             --nptr;
+             goto out;
+           }
        }
       else if (base == 0)
        base = 8;
@@ -1357,37 +1381,48 @@ strtoll (const char *nptr, char **endptr, int base)
   if (!negative)
     {
       /* Parse positive number, checking for overflow. */
-      int val;
-      for (; (val = char_value (*nptr, base)) != -1; ++nptr)
+      int digit;
+      /* Overflow watermark.  If RESULT exceeds it, overflow occurs on
+        this digit.  If result==WATERMARK, current digit may not
+        exceed the last digit of maximum value. */
+      const strtoll_type WATERMARK = STRTOLL_MAX / base;
+      for (; (digit = char_value (*nptr, base)) != -1; ++nptr)
        {
-         strtoll_return newresult = base * result + val;
-         if (newresult < result)
+         if (result > WATERMARK
+             || (result == WATERMARK && digit > STRTOLL_MAX % base))
            {
-             result = STRTOLL_OVERFLOW;
+             result = STRTOLL_MAX;
              errno = ERANGE;
              break;
            }
-         result = newresult;
+         result = base * result + digit;
        }
     }
   else
     {
       /* Parse negative number, checking for underflow. */
-      int val;
-      for (; (val = char_value (*nptr, base)) != -1; ++nptr)
+      int digit;
+      const strtoll_type WATERMARK = STRTOLL_MIN / base;
+      for (; (digit = char_value (*nptr, base)) != -1; ++nptr)
        {
-         strtoll_return newresult = base * result - val;
-         if (newresult > result)
+         if (result < WATERMARK
+             || (result == WATERMARK && digit > MOD (STRTOLL_MIN, base)))
            {
-             result = STRTOLL_UNDERFLOW;
+             result = STRTOLL_MIN;
              errno = ERANGE;
              break;
            }
-         result = newresult;
+         result = base * result - digit;
        }
     }
+ out:
   if (endptr)
     *endptr = (char *) nptr;
   return result;
 }
+
+#undef STRTOLL_MAX
+#undef STRTOLL_MIN
+#undef ABS
+
 #endif /* NEED_STRTOLL */