X-Git-Url: http://sjero.net/git/?p=wget;a=blobdiff_plain;f=src%2Fcmpt.c;h=4bd582c85dff8342106f552e2af008d0c4d8949d;hp=19b56265ff7b9f283206f94575fea44d0966769a;hb=4d7c5e087b2bc82c9f503dff003916d1047903ce;hpb=bb8a5f2eb92c6c05b4f76904100dd5007fd421d8 diff --git a/src/cmpt.c b/src/cmpt.c index 19b56265..4bd582c8 100644 --- a/src/cmpt.c +++ b/src/cmpt.c @@ -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 . 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 /* 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,11 +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 anecdotal evidence and conventional - wisdom I lack courage to challenge, many implementations of fnmatch - are notoriously buggy and unreliable. So we use our version by - default, except when compiling under systems where fnmatch is known - to work (currently on GNU libc-based systems and Solaris.) */ + 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 @@ -1135,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) { @@ -1224,69 +1241,188 @@ fnmatch (const char *pattern, const char *string, int flags) #endif /* not SYSTEM_FNMATCH */ #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 , with the help of - Mark Baushke 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 */