X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fmktime.c;h=f9e7b6071c490c1fab5cc0ea922d49dc3a390487;hb=fdccb1c31b8693bcda4faea73b0d81d1c3be0719;hp=02acc5206797b0bb93bb04f5dd4cdfa41e9b7589;hpb=c80984f8e3a13a265c826301e53585ad87bd761b;p=gnulib.git diff --git a/lib/mktime.c b/lib/mktime.c index 02acc5206..f9e7b6071 100644 --- a/lib/mktime.c +++ b/lib/mktime.c @@ -1,7 +1,7 @@ /* Convert a `struct tm' to a time_t value. - Copyright (C) 1993-1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1993-1999, 2002-2005, 2006, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by Paul Eggert (eggert@twinsun.com). + Contributed by Paul Eggert . This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,20 +15,16 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Define this to have a standalone program to test this implementation of mktime. */ /* #define DEBUG 1 */ -#ifdef HAVE_CONFIG_H +#ifndef _LIBC # include #endif -#ifdef _LIBC -# define STDC_HEADERS 1 -#endif - /* Assume that leap seconds are possible, unless told otherwise. If the host has a `zic' command with a `-L leapsecondfilename' option, then it supports leap seconds; otherwise it probably doesn't. */ @@ -36,28 +32,66 @@ # define LEAP_SECONDS_POSSIBLE 1 #endif -#include /* Some systems define `time_t' here. */ #include #include +#include /* For the real memcpy prototype. */ + #if DEBUG # include -# if STDC_HEADERS -# include -# include -# endif +# include /* Make it work even if the system's libc has its own mktime routine. */ # define mktime my_mktime #endif /* DEBUG */ -/* The extra casts work around common compiler bugs. */ +/* Shift A right by B bits portably, by dividing A by 2**B and + truncating towards minus infinity. A and B should be free of side + effects, and B should be in the range 0 <= B <= INT_BITS - 2, where + INT_BITS is the number of useful bits in an int. GNU code can + assume that INT_BITS is at least 32. + + ISO C99 says that A >> B is implementation-defined if A < 0. Some + implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift + right in the usual way when A < 0, so SHR falls back on division if + ordinary A >> B doesn't seem to be the usual signed shift. */ +#define SHR(a, b) \ + (-1 >> 1 == -1 \ + ? (a) >> (b) \ + : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0)) + +/* The extra casts in the following macros work around compiler bugs, + e.g., in Cray C 5.0.3.0. */ + +/* True if the arithmetic type T is an integer type. bool counts as + an integer. */ +#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) + +/* True if negative values of the signed integer type T use two's + complement, ones' complement, or signed magnitude representation, + respectively. Much GNU code assumes two's complement, but some + people like to be portable to all possible C hosts. */ +#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1) +#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0) +#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1) + +/* True if the arithmetic type T is signed. */ #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) -/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. - It is necessary at least when t == time_t. */ -#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ - ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) -#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) + +/* The maximum and minimum values for the integer type T. These + macros have undefined behavior if T is signed and has padding bits. + If this is a problem for you, please let us know how to fix it for + your host. */ +#define TYPE_MINIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) 0 \ + : TYPE_SIGNED_MAGNITUDE (t) \ + ? ~ (t) 0 \ + : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))) +#define TYPE_MAXIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) -1 \ + : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))) #ifndef TIME_T_MIN # define TIME_T_MIN TYPE_MINIMUM (time_t) @@ -65,14 +99,13 @@ #ifndef TIME_T_MAX # define TIME_T_MAX TYPE_MAXIMUM (time_t) #endif -#define TIME_T_MIDPOINT (((TIME_T_MIN + TIME_T_MAX) >> 1) + 1) +#define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1) /* Verify a requirement at compile-time (unlike assert, which is runtime). */ #define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; } -verify (time_t_is_integer, (time_t) 0.5 == 0); -verify (twos_complement_arithmetic, -1 == ~1 + 1); -verify (right_shift_propagates_sign, -1 >> 1 == -1); +verify (time_t_is_integer, TYPE_IS_INTEGER (time_t)); +verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int)); /* The code also assumes that signed integer overflow silently wraps around, but this assumption can't be stated without causing a diagnostic on some hosts. */ @@ -83,7 +116,7 @@ verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0); /* Return 1 if YEAR + TM_YEAR_BASE is a leap year. */ static inline int -leapyear (int year) +leapyear (long int year) { /* Don't add YEAR to TM_YEAR_BASE, as that might overflow. Also, work even if YEAR is negative. */ @@ -106,22 +139,15 @@ const unsigned short int __mon_yday[2][13] = }; -#ifdef _LIBC -# define my_mktime_localtime_r __localtime_r -#else -/* If we're a mktime substitute in a GNU program, then prefer - localtime to localtime_r, since many localtime_r implementations - are buggy. */ -static struct tm * -my_mktime_localtime_r (const time_t *t, struct tm *tp) -{ - struct tm *l = localtime (t); - if (! l) - return 0; - *tp = *l; - return tp; -} -#endif /* ! _LIBC */ +#ifndef _LIBC +/* Portable standalone applications should supply a that + declares a POSIX-compliant localtime_r, for the benefit of older + implementations that lack localtime_r or have a nonstandard one. + See the gnulib time_r module for one way to implement this. */ +# undef __localtime_r +# define __localtime_r localtime_r +# define __mktime_internal mktime_internal +#endif /* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) - (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks @@ -144,12 +170,12 @@ ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1, /* Compute intervening leap days correctly even if year is negative. Take care to avoid integer overflow here. */ - int a4 = (year1 >> 2) + (TM_YEAR_BASE >> 2) - ! (year1 & 3); - int b4 = (year0 >> 2) + (TM_YEAR_BASE >> 2) - ! (year0 & 3); + int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3); + int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3); int a100 = a4 / 25 - (a4 % 25 < 0); int b100 = b4 / 25 - (b4 % 25 < 0); - int a400 = a100 >> 2; - int b400 = b100 >> 2; + int a400 = SHR (a100, 2); + int b400 = SHR (b100, 2); int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); /* Compute the desired time in time_t precision. Overflow might @@ -187,10 +213,11 @@ guess_time_tm (long int year, long int yday, int hour, int min, int sec, /* Overflow occurred one way or another. Return the nearest result that is actually in range, except don't report a zero difference if the actual difference is nonzero, as that would cause a false - match. */ + match; and don't oscillate between two values, as that would + confuse the spring-forward gap detector. */ return (*t < TIME_T_MIDPOINT - ? TIME_T_MIN + (*t == TIME_T_MIN) - : TIME_T_MAX - (*t == TIME_T_MAX)); + ? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN) + : (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX)); } /* Use CONVERT to convert *T to a broken down time in *TP. @@ -200,13 +227,12 @@ static struct tm * ranged_convert (struct tm *(*convert) (const time_t *, struct tm *), time_t *t, struct tm *tp) { - struct tm *r; + struct tm *r = convert (t, tp); - if (! (r = (*convert) (t, tp)) && *t) + if (!r && *t) { time_t bad = *t; time_t ok = 0; - struct tm tm; /* BAD is a known unconvertible time_t, and OK is a known good one. Use binary search to narrow the range between BAD and OK until @@ -216,11 +242,9 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *), time_t mid = *t = (bad < 0 ? bad + ((ok - bad) >> 1) : ok + ((bad - ok) >> 1)); - if ((r = (*convert) (t, tp))) - { - tm = *r; - ok = mid; - } + r = convert (t, tp); + if (r) + ok = mid; else bad = mid; } @@ -230,8 +254,7 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *), /* The last conversion attempt failed; revert to the most recent successful attempt. */ *t = ok; - *tp = tm; - r = tp; + r = convert (t, tp); } } @@ -243,10 +266,8 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *), the monotonic and mostly-unit-linear conversion function CONVERT. Use *OFFSET to keep track of a guess at the offset of the result, compared to what the result would be for UTC without leap seconds. - If *OFFSET's guess is correct, only one CONVERT call is needed. */ -#ifndef _LIBC -static -#endif + If *OFFSET's guess is correct, only one CONVERT call is needed. + This function is external because it is used also by timegm.c. */ time_t __mktime_internal (struct tm *tp, struct tm *(*convert) (const time_t *, struct tm *), @@ -269,7 +290,9 @@ __mktime_internal (struct tm *tp, int mday = tp->tm_mday; int mon = tp->tm_mon; int year_requested = tp->tm_year; - int isdst = tp->tm_isdst; + /* Normalize the value. */ + int isdst = ((tp->tm_isdst >> (8 * sizeof (tp->tm_isdst) - 1)) + | (tp->tm_isdst != 0)); /* 1 if the previous probe was DST. */ int dst2; @@ -335,14 +358,16 @@ __mktime_internal (struct tm *tp, int LOG2_YEARS_PER_BIENNIUM = 1; int approx_requested_biennia = - ((year_requested >> LOG2_YEARS_PER_BIENNIUM) - - ((EPOCH_YEAR - TM_YEAR_BASE) >> LOG2_YEARS_PER_BIENNIUM) - + (mday >> ALOG2_DAYS_PER_BIENNIUM) - + (hour >> ALOG2_HOURS_PER_BIENNIUM) - + (min >> ALOG2_MINUTES_PER_BIENNIUM) - + (LEAP_SECONDS_POSSIBLE ? 0 : sec >> ALOG2_SECONDS_PER_BIENNIUM)); - - int approx_biennia = t0 >> ALOG2_SECONDS_PER_BIENNIUM; + (SHR (year_requested, LOG2_YEARS_PER_BIENNIUM) + - SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM) + + SHR (mday, ALOG2_DAYS_PER_BIENNIUM) + + SHR (hour, ALOG2_HOURS_PER_BIENNIUM) + + SHR (min, ALOG2_MINUTES_PER_BIENNIUM) + + (LEAP_SECONDS_POSSIBLE + ? 0 + : SHR (sec, ALOG2_SECONDS_PER_BIENNIUM))); + + int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM); int diff = approx_biennia - approx_requested_biennia; int abs_diff = diff < 0 ? - diff : diff; @@ -360,7 +385,7 @@ __mktime_internal (struct tm *tp, /* Overflow occurred. Try repairing it; this might work if the time zone offset is enough to undo the overflow. */ time_t repaired_t0 = -1 - t0; - approx_biennia = repaired_t0 >> ALOG2_SECONDS_PER_BIENNIUM; + approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM); diff = approx_biennia - approx_requested_biennia; abs_diff = diff < 0 ? - diff : diff; if (overflow_threshold < abs_diff) @@ -460,8 +485,9 @@ __mktime_internal (struct tm *tp, t2 = t1 + sec_adjustment; if (((t1 < t) != (sec_requested < 0)) | ((t2 < t1) != (sec_adjustment < 0)) - | ! (*convert) (&t, &tm)) + | ! convert (&t2, &tm)) return -1; + t = t2; } *tp = tm; @@ -486,7 +512,7 @@ mktime (struct tm *tp) __tzset (); #endif - return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset); + return __mktime_internal (tp, __localtime_r, &localtime_offset); } #ifdef weak_alias @@ -509,7 +535,6 @@ not_equal_tm (const struct tm *a, const struct tm *b) | (a->tm_mday ^ b->tm_mday) | (a->tm_mon ^ b->tm_mon) | (a->tm_year ^ b->tm_year) - | (a->tm_mday ^ b->tm_mday) | (a->tm_yday ^ b->tm_yday) | (a->tm_isdst ^ b->tm_isdst)); } @@ -635,6 +660,6 @@ main (int argc, char **argv) /* Local Variables: -compile-command: "gcc -DDEBUG -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime" +compile-command: "gcc -DDEBUG -Wall -W -O -g mktime.c -o mktime" End: */