summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2012-05-25 09:18:18 -0700
committerKarl Berry <karl@freefriends.org>2012-05-25 09:18:18 -0700
commit3a5aa57f6651255916ae05c44aa3a75086c1e285 (patch)
treefc664d7c70574dc1f8ff75578e87d8502337c874
parent94a6552defb0ff9572dc33264018ae622f6e208d (diff)
downloadgnulib-3a5aa57f6651255916ae05c44aa3a75086c1e285.tar.gz
autoupdate
-rwxr-xr-xbuild-aux/config.sub3
-rw-r--r--lib/mktime.c235
2 files changed, 83 insertions, 155 deletions
diff --git a/build-aux/config.sub b/build-aux/config.sub
index 59bb593f10..6205f8423d 100755
--- a/build-aux/config.sub
+++ b/build-aux/config.sub
@@ -1543,6 +1543,9 @@ case $basic_machine in
c4x-* | tic4x-*)
os=-coff
;;
+ hexagon-*)
+ os=-elf
+ ;;
tic54x-*)
os=-coff
;;
diff --git a/lib/mktime.c b/lib/mktime.c
index e1fbf9ea19..4675443945 100644
--- a/lib/mktime.c
+++ b/lib/mktime.c
@@ -1,37 +1,37 @@
-/* Convert a 'struct tm' to a time_t value.
- Copyright (C) 1993-2012 Free Software Foundation, Inc.
+/* Convert a `struct tm' to a time_t value.
+ Copyright (C) 1993-1999, 2002-2007, 2008 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Paul Eggert <eggert@twinsun.com>.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
+ 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 Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Define this to have a standalone program to test this implementation of
mktime. */
/* #define DEBUG 1 */
-#ifndef _LIBC
+#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/* Assume that leap seconds are possible, unless told otherwise.
- If the host has a 'zic' command with a '-L leapsecondfilename' option,
+ If the host has a `zic' command with a `-L leapsecondfilename' option,
then it supports leap seconds; otherwise it probably doesn't. */
#ifndef LEAP_SECONDS_POSSIBLE
# define LEAP_SECONDS_POSSIBLE 1
#endif
+#include <sys/types.h> /* Some systems define `time_t' here. */
#include <time.h>
#include <limits.h>
@@ -42,43 +42,9 @@
# include <stdio.h>
# include <stdlib.h>
/* Make it work even if the system's libc has its own mktime routine. */
-# undef mktime
# define mktime my_mktime
#endif /* DEBUG */
-/* Some of the code in this file assumes that signed integer overflow
- silently wraps around. This assumption can't easily be programmed
- around, nor can it be checked for portably at compile-time or
- easily eliminated at run-time.
-
- Define WRAPV to 1 if the assumption is valid and if
- #pragma GCC optimize ("wrapv")
- does not trigger GCC bug 51793
- <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51793>.
- Otherwise, define it to 0; this forces the use of slower code that,
- while not guaranteed by the C Standard, works on all production
- platforms that we know about. */
-#ifndef WRAPV
-# if (((__GNUC__ == 4 && 4 <= __GNUC_MINOR__) || 4 < __GNUC__) \
- && defined __GLIBC__)
-# pragma GCC optimize ("wrapv")
-# define WRAPV 1
-# else
-# define WRAPV 0
-# endif
-#endif
-
-/* Verify a requirement at compile-time (unlike assert, which is runtime). */
-#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
-
-/* A signed type that is at least one bit wider than int. */
-#if INT_MAX <= LONG_MAX / 2
-typedef long int long_int;
-#else
-typedef long long int long_int;
-#endif
-verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
-
/* 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
@@ -89,11 +55,9 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
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 \
- && (long_int) -1 >> 1 == -1 \
- && ((time_t) -1 >> 1 == -1 || ! TYPE_SIGNED (time_t))) \
- ? (a) >> (b) \
+#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,
@@ -104,8 +68,12 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
/* True if negative values of the signed integer type T use two's
- complement, or if T is an unsigned integer type. */
+ 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))
@@ -117,11 +85,13 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
#define TYPE_MINIMUM(t) \
((t) (! TYPE_SIGNED (t) \
? (t) 0 \
- : ~ TYPE_MAXIMUM (t)))
+ : TYPE_SIGNED_MAGNITUDE (t) \
+ ? ~ (t) 0 \
+ : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
#define TYPE_MAXIMUM(t) \
((t) (! TYPE_SIGNED (t) \
? (t) -1 \
- : ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
+ : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
#ifndef TIME_T_MIN
# define TIME_T_MIN TYPE_MINIMUM (time_t)
@@ -131,11 +101,14 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
#endif
#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, TYPE_IS_INTEGER (time_t));
-verify (twos_complement_arithmetic,
- (TYPE_TWOS_COMPLEMENT (int)
- && TYPE_TWOS_COMPLEMENT (long_int)
- && TYPE_TWOS_COMPLEMENT (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. */
#define EPOCH_YEAR 1970
#define TM_YEAR_BASE 1900
@@ -143,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 (long_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. */
@@ -167,24 +140,16 @@ const unsigned short int __mon_yday[2][13] =
#ifndef _LIBC
-/* Portable standalone applications should supply a <time.h> that
+/* Portable standalone applications should supply a "time_r.h" 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. */
+# include "time_r.h"
# undef __localtime_r
# define __localtime_r localtime_r
# define __mktime_internal mktime_internal
-# include "mktime-internal.h"
#endif
-/* Return 1 if the values A and B differ according to the rules for
- tm_isdst: A and B differ if one is zero and the other positive. */
-static int
-isdst_differ (int a, int b)
-{
- return (!a != !b) && (0 <= a) && (0 <= b);
-}
-
/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
(YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
were not adjusted between the time stamps.
@@ -197,10 +162,12 @@ isdst_differ (int a, int b)
detect overflow. */
static inline time_t
-ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
+ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1,
int year0, int yday0, int hour0, int min0, int sec0)
{
verify (C99_integer_division, -1 / 2 == 0);
+ verify (long_int_year_and_yday_are_wide_enough,
+ INT_MAX <= LONG_MAX / 2 || TIME_T_MAX <= UINT_MAX);
/* Compute intervening leap days correctly even if year is negative.
Take care to avoid integer overflow here. */
@@ -223,53 +190,6 @@ ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
return seconds;
}
-/* Return the average of A and B, even if A + B would overflow. */
-static time_t
-time_t_avg (time_t a, time_t b)
-{
- return SHR (a, 1) + SHR (b, 1) + (a & b & 1);
-}
-
-/* Return 1 if A + B does not overflow. If time_t is unsigned and if
- B's top bit is set, assume that the sum represents A - -B, and
- return 1 if the subtraction does not wrap around. */
-static int
-time_t_add_ok (time_t a, time_t b)
-{
- if (! TYPE_SIGNED (time_t))
- {
- time_t sum = a + b;
- return (sum < a) == (TIME_T_MIDPOINT <= b);
- }
- else if (WRAPV)
- {
- time_t sum = a + b;
- return (sum < a) == (b < 0);
- }
- else
- {
- time_t avg = time_t_avg (a, b);
- return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;
- }
-}
-
-/* Return 1 if A + B does not overflow. */
-static int
-time_t_int_add_ok (time_t a, int b)
-{
- verify (int_no_wider_than_time_t, INT_MAX <= TIME_T_MAX);
- if (WRAPV)
- {
- time_t sum = a + b;
- return (sum < a) == (b < 0);
- }
- else
- {
- int a_odd = a & 1;
- time_t avg = SHR (a, 1) + (SHR (b, 1) + (a_odd & b));
- return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;
- }
-}
/* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
assuming that *T corresponds to *TP and that no clock adjustments
@@ -278,7 +198,7 @@ time_t_int_add_ok (time_t a, int b)
If overflow occurs, yield the minimal or maximal value, except do not
yield a value equal to *T. */
static time_t
-guess_time_tm (long_int year, long_int yday, int hour, int min, int sec,
+guess_time_tm (long int year, long int yday, int hour, int min, int sec,
const time_t *t, const struct tm *tp)
{
if (tp)
@@ -286,8 +206,9 @@ guess_time_tm (long_int year, long_int yday, int hour, int min, int sec,
time_t d = ydhms_diff (year, yday, hour, min, sec,
tp->tm_year, tp->tm_yday,
tp->tm_hour, tp->tm_min, tp->tm_sec);
- if (time_t_add_ok (*t, d))
- return *t + d;
+ time_t t1 = *t + d;
+ if ((t1 < *t) == (TYPE_SIGNED (time_t) ? d < 0 : TIME_T_MAX / 2 < d))
+ return t1;
}
/* Overflow occurred one way or another. Return the nearest result
@@ -319,7 +240,9 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
they differ by 1. */
while (bad != ok + (bad < 0 ? -1 : 1))
{
- time_t mid = *t = time_t_avg (ok, bad);
+ time_t mid = *t = (bad < 0
+ ? bad + ((ok - bad) >> 1)
+ : ok + ((bad - ok) >> 1));
r = convert (t, tp);
if (r)
ok = mid;
@@ -368,7 +291,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;
@@ -377,8 +302,8 @@ __mktime_internal (struct tm *tp,
int mon_remainder = mon % 12;
int negative_mon_remainder = mon_remainder < 0;
int mon_years = mon / 12 - negative_mon_remainder;
- long_int lyear_requested = year_requested;
- long_int year = lyear_requested + mon_years;
+ long int lyear_requested = year_requested;
+ long int year = lyear_requested + mon_years;
/* The other values need not be in range:
the remaining code handles minor overflows correctly,
@@ -390,8 +315,8 @@ __mktime_internal (struct tm *tp,
int mon_yday = ((__mon_yday[leapyear (year)]
[mon_remainder + 12 * negative_mon_remainder])
- 1);
- long_int lmday = mday;
- long_int yday = mon_yday + lmday;
+ long int lmday = mday;
+ long int yday = mon_yday + lmday;
time_t guessed_offset = *offset;
@@ -445,7 +370,7 @@ __mktime_internal (struct tm *tp,
int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
int diff = approx_biennia - approx_requested_biennia;
- int approx_abs_diff = diff < 0 ? -1 - diff : diff;
+ int abs_diff = diff < 0 ? - diff : diff;
/* IRIX 4.0.5 cc miscalculates TIME_T_MIN / 3: it erroneously
gives a positive value of 715827882. Setting a variable
@@ -456,15 +381,15 @@ __mktime_internal (struct tm *tp,
time_t overflow_threshold =
(time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
- if (overflow_threshold < approx_abs_diff)
+ if (overflow_threshold < abs_diff)
{
/* 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 = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
diff = approx_biennia - approx_requested_biennia;
- approx_abs_diff = diff < 0 ? -1 - diff : diff;
- if (overflow_threshold < approx_abs_diff)
+ abs_diff = diff < 0 ? - diff : diff;
+ if (overflow_threshold < abs_diff)
return -1;
guessed_offset += repaired_t0 - t0;
t0 = repaired_t0;
@@ -498,7 +423,7 @@ __mktime_internal (struct tm *tp,
/* We have a match. Check whether tm.tm_isdst has the requested
value, if any. */
- if (isdst_differ (isdst, tm.tm_isdst))
+ if (isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
{
/* tm.tm_isdst has the wrong value. Look for a neighboring
time with the right value, and use its UTC offset.
@@ -531,20 +456,22 @@ __mktime_internal (struct tm *tp,
for (delta = stride; delta < delta_bound; delta += stride)
for (direction = -1; direction <= 1; direction += 2)
- if (time_t_int_add_ok (t, delta * direction))
- {
- time_t ot = t + delta * direction;
- struct tm otm;
- ranged_convert (convert, &ot, &otm);
- if (! isdst_differ (isdst, otm.tm_isdst))
- {
- /* We found the desired tm_isdst.
- Extrapolate back to the desired time. */
- t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm);
- ranged_convert (convert, &t, &tm);
- goto offset_found;
- }
- }
+ {
+ time_t ot = t + delta * direction;
+ if ((ot < t) == (direction < 0))
+ {
+ struct tm otm;
+ ranged_convert (convert, &ot, &otm);
+ if (otm.tm_isdst == isdst)
+ {
+ /* We found the desired tm_isdst.
+ Extrapolate back to the desired time. */
+ t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm);
+ ranged_convert (convert, &t, &tm);
+ goto offset_found;
+ }
+ }
+ }
}
offset_found:
@@ -555,13 +482,11 @@ __mktime_internal (struct tm *tp,
/* Adjust time to reflect the tm_sec requested, not the normalized value.
Also, repair any damage from a false match due to a leap second. */
int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
- if (! time_t_int_add_ok (t, sec_requested))
- return -1;
t1 = t + sec_requested;
- if (! time_t_int_add_ok (t1, sec_adjustment))
- return -1;
t2 = t1 + sec_adjustment;
- if (! convert (&t2, &tm))
+ if (((t1 < t) != (sec_requested < 0))
+ | ((t2 < t1) != (sec_adjustment < 0))
+ | ! convert (&t2, &tm))
return -1;
t = t2;
}
@@ -583,7 +508,7 @@ mktime (struct tm *tp)
{
#ifdef _LIBC
/* POSIX.1 8.1.1 requires that whenever mktime() is called, the
- time zone names contained in the external variable 'tzname' shall
+ time zone names contained in the external variable `tzname' shall
be set as if the tzset() function had been called. */
__tzset ();
#endif
@@ -612,7 +537,7 @@ not_equal_tm (const struct tm *a, const struct tm *b)
| (a->tm_mon ^ b->tm_mon)
| (a->tm_year ^ b->tm_year)
| (a->tm_yday ^ b->tm_yday)
- | isdst_differ (a->tm_isdst, b->tm_isdst));
+ | (a->tm_isdst ^ b->tm_isdst));
}
static void
@@ -736,6 +661,6 @@ main (int argc, char **argv)
/*
Local Variables:
-compile-command: "gcc -DDEBUG -I. -Wall -W -O2 -g mktime.c -o mktime"
+compile-command: "gcc -DDEBUG -Wall -W -O -g mktime.c -o mktime"
End:
*/