/* 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
{
register const char *np;
- for (np = p; np && *np && *np != ']'; np++);
+ for (np = p; np && *np && *np != ']'; np++)
+ ;
if (np && !*np)
{
#endif /* not SYSTEM_FNMATCH */
\f
#ifndef HAVE_TIMEGM
-/* timegm is a GNU extension, but lately also available on *BSD and
- possibly elsewhere. */
+/* timegm is a GNU extension, but lately also available on *BSD
+ systems and possibly elsewhere. */
+
+/* True if YEAR is a leap year. */
+#define ISLEAP(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+/* Number of leap years in the range [y1, y2). */
+#define LEAPYEARS(y1, y2) \
+ ((y2-1)/4 - (y1-1)/4) - ((y2-1)/100 - (y1-1)/100) + ((y2-1)/400 - (y1-1)/400)
/* Inverse of gmtime: converts struct tm to time_t, assuming the data
in tm is UTC rather than local timezone. This implementation
- returns the number of seconds since 1970-01-01, converted to
- time_t. */
-
-#define IS_LEAP(year) \
- ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+ returns the number of seconds elapsed since midnight 1970-01-01,
+ converted to time_t. */
time_t
timegm (struct tm *t)
{
static const unsigned short int month_to_days[][13] = {
- { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
- { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, /* normal */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } /* leap */
};
- unsigned long secs;
- int year, days;
+ const int year = 1900 + t->tm_year;
+ unsigned long secs; /* until 2106-02-07 for 32-bit unsigned long */
+ int days;
- /* Only handles years between 1970 and 2099. */
- if (t->tm_year < 70 || t->tm_year > 129)
+ if (year < 1970)
return (time_t) -1;
- days = 365 * (t->tm_year - 70);
- /* Take into account leap years between 1970 and t->tm_year-1; all
- years divisible by four between 1968 and 2100 should be leap. */
- days += (t->tm_year - 1 - 68) / 4;
+ days = 365 * (year - 1970);
+ /* Take into account leap years between 1970 and YEAR, not counting
+ YEAR itself. */
+ days += LEAPYEARS (1970, year);
if (t->tm_mon < 0 || t->tm_mon >= 12)
return (time_t) -1;
- days += month_to_days[IS_LEAP (1900 + t->tm_year)][t->tm_mon];
+ days += month_to_days[ISLEAP (year)][t->tm_mon];
days += t->tm_mday - 1;
secs = days * 86400 + t->tm_hour * 3600 + t->tm_min * 60 + t->tm_sec;
return (time_t) secs;
}
#endif /* HAVE_TIMEGM */
+
+#ifdef NEED_STRTOLL
+/* strtoll is required by C99 and used by Wget only on systems with
+ LFS. Unfortunately, some systems have LFS, but no strtoll or
+ equivalent. These include HPUX 11.0 and Windows.
+
+ We use #ifdef NEED_STRTOLL instead of #ifndef HAVE_STRTOLL because
+ of the systems which have a suitable replacement (e.g. _strtoi64 on
+ Windows), on which Wget's str_to_wgint is instructed to use that
+ instead. */
+
+static inline int
+char_value (char c, int base)
+{
+ int value;
+ if (c < '0')
+ return -1;
+ if ('0' <= c && c <= '9')
+ value = c - '0';
+ else if ('a' <= c && c <= 'z')
+ value = c - 'a' + 10;
+ else if ('A' <= c && c <= 'Z')
+ value = c - 'A' + 10;
+ else
+ return -1;
+ if (value >= base)
+ return -1;
+ return value;
+}
+
+#define STRTOLL_MAX TYPE_MAXIMUM (strtoll_type)
+/* This definition assumes two's complement arithmetic */
+#define STRTOLL_MIN (-STRTOLL_MAX - 1)
+
+/* 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 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. */
+
+strtoll_type
+strtoll (const char *nptr, char **endptr, int base)
+{
+ strtoll_type result = 0;
+ bool negative;
+
+ if (base != 0 && (base < 2 || base > 36))
+ {
+ errno = EINVAL;
+ return 0;
+ }
+
+ while (*nptr == ' ' || *nptr == '\t')
+ ++nptr;
+ if (*nptr == '-')
+ {
+ negative = true;
+ ++nptr;
+ }
+ else if (*nptr == '+')
+ {
+ negative = false;
+ ++nptr;
+ }
+ else
+ negative = false;
+
+ /* 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')
+ {
+ if ((base == 0 || base == 16)
+ &&
+ (*(nptr + 1) == 'x' || *(nptr + 1) == 'X'))
+ {
+ 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;
+ }
+ else if (base == 0)
+ base = 10;
+
+ if (!negative)
+ {
+ /* Parse positive number, checking for overflow. */
+ 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)
+ {
+ if (result > WATERMARK
+ || (result == WATERMARK && digit > STRTOLL_MAX % base))
+ {
+ result = STRTOLL_MAX;
+ errno = ERANGE;
+ break;
+ }
+ result = base * result + digit;
+ }
+ }
+ else
+ {
+ /* Parse negative number, checking for underflow. */
+ int digit;
+ const strtoll_type WATERMARK = STRTOLL_MIN / base;
+ for (; (digit = char_value (*nptr, base)) != -1; ++nptr)
+ {
+ if (result < WATERMARK
+ || (result == WATERMARK && digit > MOD (STRTOLL_MIN, base)))
+ {
+ result = STRTOLL_MIN;
+ errno = ERANGE;
+ break;
+ }
+ result = base * result - digit;
+ }
+ }
+ out:
+ if (endptr)
+ *endptr = (char *) nptr;
+ return result;
+}
+
+#undef STRTOLL_MAX
+#undef STRTOLL_MIN
+#undef ABS
+
+#endif /* NEED_STRTOLL */