/* 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,
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
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. */
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
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))
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')
{
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;
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 */