]> sjero.net Git - wget/blobdiff - src/cmpt.c
[svn] Merge of fix for bugs 20341 and 20410.
[wget] / src / cmpt.c
index 9589da868750a3ec400a9fae4d872cb12ad3d901..4bd582c85dff8342106f552e2af008d0c4d8949d 100644 (file)
@@ -1,11 +1,11 @@
 /* Replacements for routines missing on some systems.
-   Copyright (C) 1995-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., 675 Mass Ave, Cambridge, MA 02139, 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
 
@@ -1133,7 +1151,8 @@ fnmatch (const char *pattern, const char *string, int flags)
            {
              register const char *np;
 
-             for (np = p; np && *np && *np != ']'; np++);
+             for (np = p; np && *np && *np != ']'; np++)
+               ;
 
              if (np && !*np)
                {
@@ -1222,69 +1241,188 @@ fnmatch (const char *pattern, const char *string, int flags)
 #endif /* not SYSTEM_FNMATCH */
 \f
 #ifndef HAVE_TIMEGM
-/* timegm is a GNU extension typically unavailable on non-glibc-based
-   platforms. */
+/* 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.
-
-   mktime is similar but assumes struct tm, also known as the
-   "broken-down" form of time, is in local time zone.  This
-   implementation of timegm uses mktime to make the conversion
-   understanding that an offset will be introduced by the local time
-   assumption.
-
-   timegm then measures the introduced offset by applying gmtime to
-   the initial result and applying mktime to the resulting
-   "broken-down" form.  The difference between the two mktime results
-   is the measured offset which is then subtracted from the initial
-   mktime result to yield a calendar time which is the value returned.
-
-   tm_isdst in struct tm is set to 0 to force mktime to introduce a
-   consistent offset (the non DST offset) since tm and tm+o might be
-   on opposite sides of a DST change.
-
-   Some implementations of mktime return -1 for the nonexistent
-   localtime hour at the beginning of DST.  In this event, use
-   mktime(tm - 1hr) + 3600.
-
-   Schematically
-     mktime(tm)   --> t+o
-     gmtime(t+o)  --> tm+o
-     mktime(tm+o) --> t+2o
-     t+o - (t+2o - t+o) = t
-
-   Contributed by Roger Beeman <beeman@cisco.com>, with the help of
-   Mark Baushke <mdb@cisco.com> and other experts at CISCO.  Further
-   improved by Roger with assistance from Edward J. Sabol based on
-   input by Jamie Zawinski.  */
+   in tm is UTC rather than local timezone.  This implementation
+   returns the number of seconds elapsed since midnight 1970-01-01,
+   converted to time_t.  */
 
 time_t
 timegm (struct tm *t)
 {
-  time_t tl, tb;
-  struct tm *tg;
+  static const unsigned short int month_to_days[][13] = {
+    { 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 */
+  };
+  const int year = 1900 + t->tm_year;
+  unsigned long secs;  /* until 2106-02-07 for 32-bit unsigned long */
+  int days;
+
+  if (year < 1970)
+    return (time_t) -1;
+
+  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[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;
+    }
 
-  tl = mktime (t);
-  if (tl == -1)
+  while (*nptr == ' ' || *nptr == '\t')
+    ++nptr;
+  if (*nptr == '-')
     {
-      t->tm_hour--;
-      tl = mktime (t);
-      if (tl == -1)
-       return -1; /* can't deal with contents of T */
-      tl += 3600;
+      negative = true;
+      ++nptr;
     }
-  tg = gmtime (&tl);
-  tg->tm_isdst = 0;
-  tb = mktime (tg);
-  if (tb == -1)
+  else if (*nptr == '+')
     {
-      tg->tm_hour--;
-      tb = mktime (tg);
-      if (tb == -1)
-       return -1; /* can't deal with output from gmtime */
-      tb += 3600;
+      negative = false;
+      ++nptr;
     }
-  return (tl - (tb - tl));
+  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;
 }
-#endif /* HAVE_TIMEGM */
+
+#undef STRTOLL_MAX
+#undef STRTOLL_MIN
+#undef ABS
+
+#endif /* NEED_STRTOLL */