aboutsummaryrefslogtreecommitdiff
path: root/time
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1997-11-13 00:21:19 +0000
committerUlrich Drepper <drepper@redhat.com>1997-11-13 00:21:19 +0000
commitfe0ec73edb48eff3785f29ddbac75cae5f8b361b (patch)
treed862765d3e48bfde1ee82de94b4e4f039ee7f205 /time
parentcc3fa755128c70f8afc2d604936f33e4d7d652d8 (diff)
downloadglibc-fe0ec73edb48eff3785f29ddbac75cae5f8b361b.zip
glibc-fe0ec73edb48eff3785f29ddbac75cae5f8b361b.tar.gz
glibc-fe0ec73edb48eff3785f29ddbac75cae5f8b361b.tar.bz2
1997-11-13 01:07 Ulrich Drepper <drepper@cygnus.com> * manual/arith.texi: Update documentation according to most recent ISO C 9X draft. Document fma, fdim, fmin, and fmax. * manual/math.texi: Allow multiple defitino of mul etc. * math/complex.h (I): Define using _Complex_U not _Imaginary_I. * math/libm-test.c: Add tests for fma. * math/math.h: Describe DECIMAL_DIG macro. Pretty print. * sysdeps/alpha/fpu/bits/mathdef.h: Define INFINITY as of type float. Define DECIMAL_DIG. * sysdeps/generic/bits/mathdef.h: Likewise. * sysdeps/i386/bits/mathdef.h: Likewise. * sysdeps/m68k/fpu/bits/mathdef.h: Likewise. * sysdeps/powerpc/bits/mathdef.h: Likewise. * sysdeps/sparc/fpu/bits/mathdef.h: Likewise. * sysdeps/ieee754/bits/nan.h: Define NAN as of type float. * sysdeps/m68k/bits/nan.h. Likewise. Remove NANF and NANL. 1997-11-12 17:50 Ulrich Drepper <drepper@cygnus.com> * sunrpc/xcrypt.c: Don't process #ident preprocessor instruction. Reported by Philip Blundell <pb@nexus.co.uk>. * string/strndup.c: Use K&R like definition. * sysdeps/unix/sysv/linux/getcwd.c: New file. Use kernel information instead of longish search for the name. * sysdeps/posix/getcwd.c: Add support for use of the code as a backup solution. 1997-11-12 15:31 Philip Blundell <pb@nexus.co.uk> * sysdeps/unix/sysv/linux/arm/sysdep.h (SYS_ify): Don't add SWI_BASE in twice. * sysdeps/unix/sysv/linux/arm/profil-counter.h (profil_counter): Use correct name to access PC. * sysdeps/unix/arm/sysdep.S: Include <bits/errno.h> not <errnos.h>. * sysdeps/generic/bits/types.h: Add __ino64_t and __off64_t. * sysdeps/generic/bits/stat.h: Add struct stat64. 1997-11-12 16:08 Ulrich Drepper <drepper@cygnus.com> * intl/loadmsgcat.c [_LIBC] (fstat): Don't define as __fstat since now we have a definition as _fxstat. * libio/fileops.c: Likewise. * libio/oldfileops.c: Likewise. Reported by Andreas Jaeger <aj@arthur.rhein-neckar.de>. 1997-11-12 Andreas Jaeger <aj@arthur.rhein-neckar.de> * sysdeps/wordsize-32/inttypes.h (SIG_ATOMIC_MAX): Correct value. * sysdeps/wordsize-64/inttypes.h (SIG_ATOMIC_MAX): Likewise. 1997-11-11 Paul Eggert <eggert@twinsun.com> Add overflow checking for 64-bit time_t and 32-bit int. * time/time.h (__offtime): Now returns int. * time/offtime.c (__offtime): Return nonzero if successful; check for tm_year overflow. (DIV): New macro. (LEAPS_THRU_END_OF): Handle negative years correctly. * time/tzset.c (__tz_convert): Return NULL if offtime cannot convert. * time/mktime.c (ranged_convert): New function. (ydhms_tm_diff): Return nonzero if TP is null. (__mktime_internal): Handle cases correctly even if they are near or past the limits of time_t values that can be broken down to struct tm. (print_tm, check_result, main): Diagnose localtime failures. * manual/time.texi: Document the fact that localtime returns 0 if the time can't be represented. 1997-11-12 06:03 Ulrich Drepper <drepper@cygnus.com> * time/strftime.c (memset_space, memset_zero): Use MEMPCPY, not mempcpy. Patch by Ken'ichi Handa <handa@etl.go.jp>. * manual/time.texi: Document %F and %f format for strftime. * manual/arith.texi: Document copysign, nextafter and nan. 1997-11-06 Andreas Jaeger <aj@arthur.rhein-neckar.de> * test-installation.pl: New file. Tests for some installation problems.
Diffstat (limited to 'time')
-rw-r--r--time/mktime.c164
-rw-r--r--time/offtime.c11
-rw-r--r--time/strftime.c6
-rw-r--r--time/time.h9
-rw-r--r--time/tzset.c9
5 files changed, 145 insertions, 54 deletions
diff --git a/time/mktime.c b/time/mktime.c
index 7a94c21..406f55e 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -102,6 +102,9 @@ const unsigned short int __mon_yday[2][13] =
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
+static struct tm *ranged_convert __P ((struct tm *(*) __P ((const time_t *,
+ struct tm *)),
+ time_t *, struct tm *));
static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
time_t __mktime_internal __P ((struct tm *,
struct tm *(*) (const time_t *, struct tm *),
@@ -134,30 +137,36 @@ localtime_r (t, tp)
measured in seconds, ignoring leap seconds.
YEAR uses the same numbering as TM->tm_year.
All values are in range, except possibly YEAR.
+ If TP is null, return a nonzero value.
If overflow occurs, yield the low order bits of the correct answer. */
static time_t
ydhms_tm_diff (year, yday, hour, min, sec, tp)
int year, yday, hour, min, sec;
const struct tm *tp;
{
- /* Compute intervening leap days correctly even if year is negative.
- Take care to avoid int overflow. time_t overflow is OK, since
- only the low order bits of the correct time_t answer are needed.
- Don't convert to time_t until after all divisions are done, since
- time_t might be unsigned. */
- int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
- int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
- int a100 = a4 / 25 - (a4 % 25 < 0);
- int b100 = b4 / 25 - (b4 % 25 < 0);
- int a400 = a100 >> 2;
- int b400 = b100 >> 2;
- int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
- time_t years = year - (time_t) tp->tm_year;
- time_t days = (365 * years + intervening_leap_days
- + (yday - tp->tm_yday));
- return (60 * (60 * (24 * days + (hour - tp->tm_hour))
- + (min - tp->tm_min))
- + (sec - tp->tm_sec));
+ if (!tp)
+ return 1;
+ else
+ {
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow. time_t overflow is OK, since
+ only the low order bits of the correct time_t answer are needed.
+ Don't convert to time_t until after all divisions are done, since
+ time_t might be unsigned. */
+ int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
+ int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = a100 >> 2;
+ int b400 = b100 >> 2;
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ time_t years = year - (time_t) tp->tm_year;
+ time_t days = (365 * years + intervening_leap_days
+ + (yday - tp->tm_yday));
+ return (60 * (60 * (24 * days + (hour - tp->tm_hour))
+ + (min - tp->tm_min))
+ + (sec - tp->tm_sec));
+ }
}
@@ -178,6 +187,54 @@ mktime (tp)
return __mktime_internal (tp, localtime_r, &localtime_offset);
}
+/* Use CONVERT to convert *T to a broken down time in *TP.
+ If *T is out of range for conversion, adjust it so that
+ it is the nearest in-range value and then convert that. */
+static struct tm *
+ranged_convert (convert, t, tp)
+ struct tm *(*convert) __P ((const time_t *, struct tm *));
+ time_t *t;
+ struct tm *tp;
+{
+ struct tm *r;
+
+ if (! (r = (*convert) (t, tp)) && *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
+ they differ by 1. */
+ while (bad != ok + (bad < 0 ? -1 : 1))
+ {
+ time_t mid = *t = (bad < 0
+ ? bad + ((ok - bad) >> 1)
+ : ok + ((bad - ok) >> 1));
+ if ((r = (*convert) (t, tp)))
+ {
+ tm = *r;
+ ok = mid;
+ }
+ else
+ bad = mid;
+ }
+
+ if (!r && ok)
+ {
+ /* The last conversion attempt failed;
+ revert to the most recent successful attempt. */
+ *t = ok;
+ *tp = tm;
+ r = tp;
+ }
+ }
+
+ return r;
+}
+
+
/* Convert *TP to a time_t value, inverting
the monotonic and mostly-unit-linear conversion function CONVERT.
Use *OFFSET to keep track of a guess at the offset of the result,
@@ -243,7 +300,8 @@ __mktime_internal (tp, convert, offset)
t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
for (t = t0 + *offset;
- (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
+ (dt = ydhms_tm_diff (year, yday, hour, min, sec,
+ ranged_convert (convert, &t, &tm)));
t += dt)
if (--remaining_probes == 0)
return -1;
@@ -263,7 +321,7 @@ __mktime_internal (tp, convert, offset)
{
struct tm otm;
if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
- (*convert) (&ot, &otm))))
+ ranged_convert (convert, &ot, &otm))))
{
t = ot;
tm = otm;
@@ -283,7 +341,8 @@ __mktime_internal (tp, convert, offset)
/* 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. */
t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
- (*convert) (&t, &tm);
+ if (! (*convert) (&t, &tm))
+ return -1;
}
#endif
@@ -333,25 +392,28 @@ static void
print_tm (tp)
struct tm *tp;
{
- printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
- tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
- tp->tm_hour, tp->tm_min, tp->tm_sec,
- tp->tm_yday, tp->tm_wday, tp->tm_isdst);
+ if (tp)
+ printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
+ tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec,
+ tp->tm_yday, tp->tm_wday, tp->tm_isdst);
+ else
+ printf ("0");
}
static int
-check_result (tk, tmk, tl, tml)
+check_result (tk, tmk, tl, lt)
time_t tk;
struct tm tmk;
time_t tl;
- struct tm tml;
+ struct tm *lt;
{
- if (tk != tl || not_equal_tm (&tmk, &tml))
+ if (tk != tl || !lt || not_equal_tm (&tmk, lt))
{
printf ("mktime (");
print_tm (&tmk);
printf (")\nyields (");
- print_tm (&tml);
+ print_tm (lt);
printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
return 1;
}
@@ -366,6 +428,7 @@ main (argc, argv)
{
int status = 0;
struct tm tm, tmk, tml;
+ struct tm *lt;
time_t tk, tl;
char trailer;
@@ -382,11 +445,16 @@ main (argc, argv)
tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
tmk = tm;
tl = mktime (&tmk);
- tml = *localtime (&tl);
+ lt = localtime (&tl);
+ if (lt)
+ {
+ tml = *lt;
+ lt = &tml;
+ }
printf ("mktime returns %ld == ", (long) tl);
print_tm (&tmk);
printf ("\n");
- status = check_result (tl, tmk, tl, tml);
+ status = check_result (tl, tmk, tl, lt);
}
else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
{
@@ -397,19 +465,35 @@ main (argc, argv)
if (argc == 4)
for (tl = from; tl <= to; tl += by)
{
- tml = *localtime (&tl);
- tmk = tml;
- tk = mktime (&tmk);
- status |= check_result (tk, tmk, tl, tml);
+ lt = localtime (&tl);
+ if (lt)
+ {
+ tmk = tml = *lt;
+ tk = mktime (&tmk);
+ status |= check_result (tk, tmk, tl, tml);
+ }
+ else
+ {
+ printf ("localtime (%ld) yields 0\n", (long) tl);
+ status = 1;
+ }
}
else
for (tl = from; tl <= to; tl += by)
{
/* Null benchmark. */
- tml = *localtime (&tl);
- tmk = tml;
- tk = tl;
- status |= check_result (tk, tmk, tl, tml);
+ lt = localtime (&tl);
+ if (lt)
+ {
+ tmk = tml = *lt;
+ tk = tl;
+ status |= check_result (tk, tmk, tl, tml);
+ }
+ else
+ {
+ printf ("localtime (%ld) yields 0\n", (long) tl);
+ status = 1;
+ }
}
}
else
@@ -426,6 +510,6 @@ main (argc, argv)
/*
Local Variables:
-compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
+compile-command: "gcc -DDEBUG -D__EXTENSIONS__ -DHAVE_LIMITS_H -DHAVE_LOCALTIME_R -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"
End:
*/
diff --git a/time/offtime.c b/time/offtime.c
index a4b59ed..52e4070 100644
--- a/time/offtime.c
+++ b/time/offtime.c
@@ -26,8 +26,9 @@ extern const unsigned short int __mon_yday[2][13];
/* Compute the `struct tm' representation of *T,
offset OFFSET seconds east of UTC,
- and store year, yday, mon, mday, wday, hour, min, sec into *TP. */
-void
+ and store year, yday, mon, mday, wday, hour, min, sec into *TP.
+ Return nonzero if successful. */
+int
__offtime (t, offset, tp)
const time_t *t;
long int offset;
@@ -59,7 +60,8 @@ __offtime (t, offset, tp)
tp->tm_wday += 7;
y = 1970;
-#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
+#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
+#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
while (days < 0 || days >= (__isleap (y) ? 366 : 365))
{
@@ -73,6 +75,8 @@ __offtime (t, offset, tp)
y = yg;
}
tp->tm_year = y - 1900;
+ if (tp->tm_year != y - 1900)
+ return 0;
tp->tm_yday = days;
ip = __mon_yday[__isleap(y)];
for (y = 11; days < (long int) ip[y]; --y)
@@ -80,4 +84,5 @@ __offtime (t, offset, tp)
days -= ip[y];
tp->tm_mon = y;
tp->tm_mday = days + 1;
+ return 1;
}
diff --git a/time/strftime.c b/time/strftime.c
index e66a444..0ebc913 100644
--- a/time/strftime.c
+++ b/time/strftime.c
@@ -182,7 +182,7 @@ localtime_r (t, tp)
return tp;
}
# endif /* ! HAVE_LOCALTIME_R */
-#endif /* ! defined (_LIBC) */
+#endif /* ! defined _LIBC */
#if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
@@ -202,7 +202,7 @@ static const char zeroes[16] = /* "0000000000000000" */
do \
{ \
int _this = _len > 16 ? 16 : _len; \
- (P) = mempcpy ((P), spaces, _this); \
+ (P) = MEMPCPY ((P), spaces, _this); \
_len -= _this; \
} \
while (_len > 0); \
@@ -215,7 +215,7 @@ static const char zeroes[16] = /* "0000000000000000" */
do \
{ \
int _this = _len > 16 ? 16 : _len; \
- (P) = mempcpy ((P), zeroes, _this); \
+ (P) = MEMPCPY ((P), zeroes, _this); \
_len -= _this; \
} \
while (_len > 0); \
diff --git a/time/time.h b/time/time.h
index f60599d..3e039ad 100644
--- a/time/time.h
+++ b/time/time.h
@@ -226,10 +226,11 @@ extern struct tm *localtime_r __P ((__const time_t *__timer,
/* Compute the `struct tm' representation of *T,
offset OFFSET seconds east of UTC,
- and store year, yday, mon, mday, wday, hour, min, sec into *TP. */
-extern void __offtime __P ((__const time_t *__timer,
- long int __offset,
- struct tm *__TP));
+ and store year, yday, mon, mday, wday, hour, min, sec into *TP.
+ Return nonzero if successful. */
+extern int __offtime __P ((__const time_t *__timer,
+ long int __offset,
+ struct tm *__tp));
/* Return a string of the form "Day Mon dd hh:mm:ss yyyy\n"
that is the representation of TP in this format. */
diff --git a/time/tzset.c b/time/tzset.c
index 0793027..64e2087 100644
--- a/time/tzset.c
+++ b/time/tzset.c
@@ -616,8 +616,7 @@ __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
}
else
{
- __offtime (timer, 0, tp);
- if (! tz_compute (*timer, tp))
+ if (! (__offtime (timer, 0, tp) && tz_compute (*timer, tp)))
tp = NULL;
leap_correction = 0L;
leap_extra_secs = 0;
@@ -638,8 +637,10 @@ __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
tp->tm_gmtoff = 0L;
}
- __offtime (timer, tp->tm_gmtoff - leap_correction, tp);
- tp->tm_sec += leap_extra_secs;
+ if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
+ tp->tm_sec += leap_extra_secs;
+ else
+ tp = NULL;
}
__libc_lock_unlock (tzset_lock);