summaryrefslogtreecommitdiff
path: root/time
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2007-07-12 18:26:36 +0000
committerJakub Jelinek <jakub@redhat.com>2007-07-12 18:26:36 +0000
commit0ecb606cb6cf65de1d9fc8a919bceb4be476c602 (patch)
tree2ea1f8305970753e4a657acb2ccc15ca3eec8e2c /time
parent7d58530341304d403a6626d7f7a1913165fe2f32 (diff)
2.5-18.1
Diffstat (limited to 'time')
-rw-r--r--time/Makefile5
-rw-r--r--time/adjtime.c37
-rw-r--r--time/asctime.c66
-rw-r--r--time/bug-asctime.c33
-rw-r--r--time/bug-asctime_r.c32
-rw-r--r--time/bug-mktime1.c17
-rw-r--r--time/clock.c32
-rw-r--r--time/ftime.c43
-rw-r--r--time/getitimer.c42
-rw-r--r--time/gettimeofday.c39
-rw-r--r--time/mktime.c73
-rw-r--r--time/setitimer.c44
-rw-r--r--time/settimeofday.c35
-rw-r--r--time/stime.c40
-rw-r--r--time/strptime_l.c57
-rw-r--r--time/sys/time.h20
-rw-r--r--time/time.c36
-rw-r--r--time/time.h5
-rw-r--r--time/tst-strptime.c22
-rw-r--r--time/tst-strptime2.c59
-rw-r--r--time/tst-strptime3.c55
-rw-r--r--time/tzfile.c111
22 files changed, 813 insertions, 90 deletions
diff --git a/time/Makefile b/time/Makefile
index 7acc964fdc..8ce34e4565 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1991-2002,2003,2004 Free Software Foundation, Inc.
+# Copyright (C) 1991-2003, 2004, 2005, 2007 Free Software Foundation, Inc.
# This file is part of the GNU C Library.
# The GNU C Library is free software; you can redistribute it and/or
@@ -35,7 +35,8 @@ distribute := datemsk
tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
- tst-mktime3
+ tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
+ tst-strptime3
include ../Rules
diff --git a/time/adjtime.c b/time/adjtime.c
new file mode 100644
index 0000000000..8645652188
--- /dev/null
+++ b/time/adjtime.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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.
+
+ The GNU C Library 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/time.h>
+
+/* Adjust the current time of day by the amount in DELTA.
+ If OLDDELTA is not NULL, it is filled in with the amount
+ of time adjustment remaining to be done from the last `__adjtime' call.
+ This call is restricted to the super-user. */
+int
+__adjtime (delta, olddelta)
+ const struct timeval *delta;
+ struct timeval *olddelta;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (adjtime)
+
+weak_alias (__adjtime, adjtime)
+#include <stub-tag.h>
diff --git a/time/asctime.c b/time/asctime.c
index f20b311bb5..dc4fd54f4e 100644
--- a/time/asctime.c
+++ b/time/asctime.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991,1993,1995-1997,2000,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1991,1993,1995-1997,2000,2002,2005
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -18,6 +19,7 @@
#include "../locale/localeinfo.h"
#include <errno.h>
+#include <limits.h>
#include <stdio.h>
#include <time.h>
@@ -29,17 +31,9 @@ extern const struct locale_data _nl_C_LC_TIME attribute_hidden;
static const char format[] = "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n";
static char result[ 3+1+ 3+1+20+1+20+1+20+1+20+1+20+1 + 1];
-/* Returns a string of the form "Day Mon dd hh:mm:ss yyyy\n"
- which is the representation of TP in that form. */
-char *
-asctime (const struct tm *tp)
-{
- return __asctime_r (tp, result);
-}
-libc_hidden_def (asctime)
-char *
-__asctime_r (const struct tm *tp, char *buf)
+static char *
+asctime_internal (const struct tm *tp, char *buf, size_t buflen)
{
if (tp == NULL)
{
@@ -47,15 +41,51 @@ __asctime_r (const struct tm *tp, char *buf)
return NULL;
}
- if (sprintf (buf, format,
- (tp->tm_wday < 0 || tp->tm_wday >= 7 ?
- "???" : ab_day_name (tp->tm_wday)),
- (tp->tm_mon < 0 || tp->tm_mon >= 12 ?
- "???" : ab_month_name (tp->tm_mon)),
- tp->tm_mday, tp->tm_hour, tp->tm_min,
- tp->tm_sec, 1900 + tp->tm_year) < 0)
+ /* We limit the size of the year which can be printed. Using the %d
+ format specifier used the addition of 1900 would overflow the
+ number and a negative vaue is printed. For some architectures we
+ could in theory use %ld or an evern larger integer format but
+ this would mean the output needs more space. This would not be a
+ problem if the 'asctime_r' interface would be defined sanely and
+ a buffer size would be passed. */
+ if (__builtin_expect (tp->tm_year > INT_MAX - 1900, 0))
+ {
+ eoverflow:
+ __set_errno (EOVERFLOW);
+ return NULL;
+ }
+
+ int n = __snprintf (buf, buflen, format,
+ (tp->tm_wday < 0 || tp->tm_wday >= 7 ?
+ "???" : ab_day_name (tp->tm_wday)),
+ (tp->tm_mon < 0 || tp->tm_mon >= 12 ?
+ "???" : ab_month_name (tp->tm_mon)),
+ tp->tm_mday, tp->tm_hour, tp->tm_min,
+ tp->tm_sec, 1900 + tp->tm_year);
+ if (n < 0)
return NULL;
+ if (n >= buflen)
+ goto eoverflow;
return buf;
}
+
+
+/* Like asctime, but write result to the user supplied buffer. The
+ buffer is only guaranteed to be 26 bytes in length. */
+char *
+__asctime_r (const struct tm *tp, char *buf)
+{
+ return asctime_internal (tp, buf, 26);
+}
weak_alias (__asctime_r, asctime_r)
+
+
+/* Returns a string of the form "Day Mon dd hh:mm:ss yyyy\n"
+ which is the representation of TP in that form. */
+char *
+asctime (const struct tm *tp)
+{
+ return asctime_internal (tp, result, sizeof (result));
+}
+libc_hidden_def (asctime)
diff --git a/time/bug-asctime.c b/time/bug-asctime.c
new file mode 100644
index 0000000000..0b04b475a8
--- /dev/null
+++ b/time/bug-asctime.c
@@ -0,0 +1,33 @@
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <time.h>
+
+
+static int
+do_test (void)
+{
+ int result = 0;
+ time_t t = time (NULL);
+ struct tm *tp = localtime (&t);
+ tp->tm_year = INT_MAX;
+ errno = 0;
+ char *s = asctime (tp);
+ if (s != NULL || errno != EOVERFLOW)
+ {
+ puts ("asctime did not fail correctly");
+ result = 1;
+ }
+ char buf[1000];
+ errno = 0;
+ s = asctime_r (tp, buf);
+ if (s != NULL || errno != EOVERFLOW)
+ {
+ puts ("asctime_r did not fail correctly");
+ result = 1;
+ }
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/time/bug-asctime_r.c b/time/bug-asctime_r.c
new file mode 100644
index 0000000000..86651ef1c5
--- /dev/null
+++ b/time/bug-asctime_r.c
@@ -0,0 +1,32 @@
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <time.h>
+
+
+static int
+do_test (void)
+{
+ int result = 0;
+ time_t t = time (NULL);
+ struct tm *tp = localtime (&t);
+ tp->tm_year = 10000 - 1900;
+ char buf[1000];
+ errno = 0;
+ buf[26] = '\xff';
+ char *s = asctime_r (tp, buf);
+ if (s != NULL || errno != EOVERFLOW)
+ {
+ puts ("asctime_r did not fail correctly");
+ result = 1;
+ }
+ if (buf[26] != '\xff')
+ {
+ puts ("asctime_r overwrote 27th byte in buffer");
+ result = 1;
+ }
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/time/bug-mktime1.c b/time/bug-mktime1.c
new file mode 100644
index 0000000000..e071273f05
--- /dev/null
+++ b/time/bug-mktime1.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <time.h>
+
+
+static int
+do_test (void)
+{
+ struct tm t2 = { 0, 0, 0, 1, 1, 2050 - 1900, 1, 1, 1 };
+ time_t tt2 = mktime (&t2);
+ printf ("%ld\n", (long int) tt2);
+ if (sizeof (time_t) == 4 && tt2 != -1)
+ return 1;
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/time/clock.c b/time/clock.c
new file mode 100644
index 0000000000..99dc5f47e0
--- /dev/null
+++ b/time/clock.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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.
+
+ The GNU C Library 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/times.h>
+#include <time.h>
+#include <errno.h>
+
+/* Return the time used by the program so far (user time + system time). */
+clock_t
+clock ()
+{
+ __set_errno (ENOSYS);
+ return (clock_t) -1;
+}
+
+stub_warning (clock)
+#include <stub-tag.h>
diff --git a/time/ftime.c b/time/ftime.c
new file mode 100644
index 0000000000..94dfbcc98b
--- /dev/null
+++ b/time/ftime.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 1994, 1996, 1997, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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.
+
+ The GNU C Library 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <time.h>
+#include <sys/timeb.h>
+
+int
+ftime (timebuf)
+ struct timeb *timebuf;
+{
+ int save = errno;
+ struct tm tp;
+
+ __set_errno (0);
+ if (time (&timebuf->time) == (time_t) -1 && errno != 0)
+ return -1;
+ timebuf->millitm = 0;
+
+ if (__localtime_r (&timebuf->time, &tp) == NULL)
+ return -1;
+
+ timebuf->timezone = tp.tm_gmtoff / 60;
+ timebuf->dstflag = tp.tm_isdst;
+
+ __set_errno (save);
+ return 0;
+}
diff --git a/time/getitimer.c b/time/getitimer.c
new file mode 100644
index 0000000000..d9f3063e1e
--- /dev/null
+++ b/time/getitimer.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 1991, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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.
+
+ The GNU C Library 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stddef.h>
+#include <errno.h>
+#include <sys/time.h>
+
+/* Set *VALUE to the current setting of timer WHICH.
+ Return 0 on success, -1 on errors. */
+int
+__getitimer (which, value)
+ enum __itimer_which which;
+ struct itimerval *value;
+{
+ if (value == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (getitimer)
+
+weak_alias (__getitimer, getitimer)
+#include <stub-tag.h>
diff --git a/time/gettimeofday.c b/time/gettimeofday.c
new file mode 100644
index 0000000000..f4a170c9e7
--- /dev/null
+++ b/time/gettimeofday.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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.
+
+ The GNU C Library 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/time.h>
+
+#undef __gettimeofday
+
+/* Get the current time of day and timezone information,
+ putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled.
+ Returns 0 on success, -1 on errors. */
+int
+__gettimeofday (tv, tz)
+ struct timeval *tv;
+ struct timezone *tz;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (gettimeofday)
+
+INTDEF(__gettimeofday)
+weak_alias (__gettimeofday, gettimeofday)
+#include <stub-tag.h>
diff --git a/time/mktime.c b/time/mktime.c
index c6ae56ee60..8f00c72e09 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -1,7 +1,7 @@
/* Convert a `struct tm' to a time_t value.
- Copyright (C) 1993-1999, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1993-1999, 2002-2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
- Contributed by Paul Eggert (eggert@twinsun.com).
+ 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
@@ -38,10 +38,11 @@
#include <limits.h>
+#include <string.h> /* For the real memcpy prototype. */
+
#if DEBUG
# include <stdio.h>
# include <stdlib.h>
-# include <string.h>
/* Make it work even if the system's libc has its own mktime routine. */
# define mktime my_mktime
#endif /* DEBUG */
@@ -61,13 +62,38 @@
? (a) >> (b) \
: (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
-/* The extra casts work around common compiler bugs. */
+/* 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)
@@ -80,8 +106,8 @@
/* 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 (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. */
@@ -190,10 +216,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.
@@ -203,13 +230,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
@@ -219,11 +245,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;
}
@@ -233,8 +257,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);
}
}
@@ -463,7 +486,7 @@ __mktime_internal (struct tm *tp,
t2 = t1 + sec_adjustment;
if (((t1 < t) != (sec_requested < 0))
| ((t2 < t1) != (sec_adjustment < 0))
- | ! (*convert) (&t2, &tm))
+ | ! convert (&t2, &tm))
return -1;
t = t2;
}
diff --git a/time/setitimer.c b/time/setitimer.c
new file mode 100644
index 0000000000..755fa06a7b
--- /dev/null
+++ b/time/setitimer.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 1991, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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.
+
+ The GNU C Library 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stddef.h>
+#include <errno.h>
+#include <sys/time.h>
+
+/* Set the timer WHICH to *NEW. If OLD is not NULL,
+ set *OLD to the old value of timer WHICH.
+ Returns 0 on success, -1 on errors. */
+int
+__setitimer (which, new, old)
+ enum __itimer_which which;
+ const struct itimerval *new;
+ struct itimerval *old;
+{
+ if (new == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (setitimer)
+
+weak_alias (__setitimer, setitimer)
+#include <stub-tag.h>
diff --git a/time/settimeofday.c b/time/settimeofday.c
new file mode 100644
index 0000000000..abff6f92a1
--- /dev/null
+++ b/time/settimeofday.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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.
+
+ The GNU C Library 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/time.h>
+
+/* Set the current time of day and timezone information.
+ This call is restricted to the super-user. */
+int
+__settimeofday (tv, tz)
+ const struct timeval *tv;
+ const struct timezone *tz;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (settimeofday)
+
+weak_alias (__settimeofday, settimeofday)
+#include <stub-tag.h>
diff --git a/time/stime.c b/time/stime.c
new file mode 100644
index 0000000000..5ed1b040e2
--- /dev/null
+++ b/time/stime.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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.
+
+ The GNU C Library 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <time.h>
+#include <stddef.h>
+
+/* Set the system clock to *WHEN. */
+
+int
+stime (when)
+ const time_t *when;
+{
+ if (when == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+stub_warning (stime)
+#include <stub-tag.h>
diff --git a/time/strptime_l.c b/time/strptime_l.c
index df98099f0a..443a6fa88e 100644
--- a/time/strptime_l.c
+++ b/time/strptime_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -400,6 +400,7 @@ __strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
/* Does not match a month name. */
return NULL;
tm->tm_mon = cnt;
+ have_mon = 1;
want_xday = 1;
break;
case 'c':
@@ -539,10 +540,12 @@ __strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
}
#endif
if (!match_string (HERE_AM_STR, rp))
- if (match_string (HERE_PM_STR, rp))
- is_pm = 1;
- else
- return NULL;
+ {
+ if (match_string (HERE_PM_STR, rp))
+ is_pm = 1;
+ else
+ return NULL;
+ }
break;
case 'r':
#ifdef _NL_CURRENT
@@ -685,6 +688,42 @@ __strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
case 'Z':
/* XXX How to handle this? */
break;
+ case 'z':
+ /* We recognize two formats: if two digits are given, these
+ specify hours. If fours digits are used, minutes are
+ also specified. */
+ {
+ val = 0;
+ while (*rp == ' ')
+ ++rp;
+ if (*rp != '+' && *rp != '-')
+ return NULL;
+ bool neg = *rp++ == '-';
+ int n = 0;
+ while (n < 4 && *rp >= '0' && *rp <= '9')
+ {
+ val = val * 10 + *rp++ - '0';
+ ++n;
+ }
+ if (n == 2)
+ val *= 100;
+ else if (n != 4)
+ /* Only two or four digits recognized. */
+ return NULL;
+ else
+ {
+ /* We have to convert the minutes into decimal. */
+ if (val % 100 >= 60)
+ return NULL;
+ val = (val / 100) * 100 + ((val % 100) * 50) / 30;
+ }
+ if (val > 1200)
+ return NULL;
+ tm->tm_gmtoff = (val * 3600) / 100;
+ if (neg)
+ tm->tm_gmtoff = -tm->tm_gmtoff;
+ }
+ break;
case 'E':
#ifdef _NL_CURRENT
switch (*fmt++)
@@ -1047,11 +1086,15 @@ __strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
tm->tm_mday =
(tm->tm_yday
- __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
+ have_mon = 1;
+ have_mday = 1;
}
- day_of_the_week (tm);
+ /* Don't crash in day_of_the_week if tm_mon is uninitialized. */
+ if (have_mon || (unsigned) tm->tm_mon <= 11)
+ day_of_the_week (tm);
}
- if (want_xday && !have_yday)
+ if (want_xday && !have_yday && (have_mon || (unsigned) tm->tm_mon <= 11))
day_of_the_year (tm);
if ((have_uweek || have_wweek) && have_wday)
diff --git a/time/sys/time.h b/time/sys/time.h
index 515ea7ec68..177696b08a 100644
--- a/time/sys/time.h
+++ b/time/sys/time.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-1994,1996-2002,2003 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1994,1996-2002,2003,2005,2006
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -70,13 +71,14 @@ typedef void *__restrict __timezone_ptr_t;
NOTE: This form of timezone information is obsolete.
Use the functions and variables declared in <time.h> instead. */
extern int gettimeofday (struct timeval *__restrict __tv,
- __timezone_ptr_t __tz) __THROW;
+ __timezone_ptr_t __tz) __THROW __nonnull ((1));
#ifdef __USE_BSD
/* Set the current time of day and timezone information.
This call is restricted to the super-user. */
extern int settimeofday (__const struct timeval *__tv,
- __const struct timezone *__tz) __THROW;
+ __const struct timezone *__tz)
+ __THROW __nonnull ((1));
/* Adjust the current time of day by the amount in DELTA.
If OLDDELTA is not NULL, it is filled in with the amount
@@ -136,17 +138,25 @@ extern int setitimer (__itimer_which_t __which,
FILE to TVP[1]. If TVP is a null pointer, use the current time instead.
Returns 0 on success, -1 on errors. */
extern int utimes (__const char *__file, __const struct timeval __tvp[2])
- __THROW;
+ __THROW __nonnull ((1));
#ifdef __USE_BSD
/* Same as `utimes', but does not follow symbolic links. */
extern int lutimes (__const char *__file, __const struct timeval __tvp[2])
- __THROW;
+ __THROW __nonnull ((1));
/* Same as `utimes', but takes an open file descriptor instead of a name. */
extern int futimes (int __fd, __const struct timeval __tvp[2]) __THROW;
#endif
+#ifdef __USE_ATFILE
+/* Change the access time of FILE relative to FD to TVP[0] and the
+ modification time of FILE to TVP[1]. If TVP is a null pointer, use
+ the current time instead. Returns 0 on success, -1 on errors. */
+extern int futimesat (int __fd, __const char *__file,
+ __const struct timeval __tvp[2]) __THROW;
+#endif
+
#ifdef __USE_BSD
/* Convenience macros for operations on timevals.
diff --git a/time/time.c b/time/time.c
new file mode 100644
index 0000000000..ec66f119df
--- /dev/null
+++ b/time/time.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 1991,96,97,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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.
+
+ The GNU C Library 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <time.h>
+
+/* Return the time now, and store it in *TIMER if not NULL. */
+time_t
+time (timer)
+ time_t *timer;
+{
+ __set_errno (ENOSYS);
+
+ if (timer != NULL)
+ *timer = (time_t) -1;
+ return (time_t) -1;
+}
+libc_hidden_def (time)
+
+stub_warning (time)
+#include <stub-tag.h>
diff --git a/time/time.h b/time/time.h
index 27e0d8bc36..6c8f79d422 100644
--- a/time/time.h
+++ b/time/time.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-1999,2000,2001,2002,2003 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1999,2000,2001,2002,2003,2006
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -113,6 +114,8 @@ typedef __timer_t timer_t;
defined __need_timespec)
# define __timespec_defined 1
+# include <bits/types.h> /* This defines __time_t for us. */
+
/* POSIX.1b structure for a time value. This is like a `struct timeval' but
has nanoseconds instead of microseconds. */
struct timespec
diff --git a/time/tst-strptime.c b/time/tst-strptime.c
index a0b2ebedd2..6356aa0d41 100644
--- a/time/tst-strptime.c
+++ b/time/tst-strptime.c
@@ -42,6 +42,10 @@ static const struct
{ "C", "19990502123412", "%Y%m%d%H%M%S", 0, 121, 4, 2 },
{ "C", "2001 20 Mon", "%Y %U %a", 1, 140, 4, 21 },
{ "C", "2001 21 Mon", "%Y %W %a", 1, 140, 4, 21 },
+ { "ja_JP.EUC-JP", "2000-01-01 08:12:21 AM", "%Y-%m-%d %I:%M:%S %p",
+ 6, 0, 0, 1 },
+ { "en_US.ISO-8859-1", "2000-01-01 08:12:21 PM", "%Y-%m-%d %I:%M:%S %p",
+ 6, 0, 0, 1 },
{ "ja_JP.EUC-JP", "2001 20 \xb7\xee", "%Y %U %a", 1, 140, 4, 21 },
{ "ja_JP.EUC-JP", "2001 21 \xb7\xee", "%Y %W %a", 1, 140, 4, 21 },
};
@@ -73,7 +77,14 @@ test_tm (void)
{
memset (&tm, '\0', sizeof (tm));
- if (*strptime (tm_tests[i].input, tm_tests[i].format, &tm) != '\0')
+ char *ret = strptime (tm_tests[i].input, tm_tests[i].format, &tm);
+ if (ret == NULL)
+ {
+ printf ("strptime returned NULL for `%s'\n", tm_tests[i].input);
+ result = 1;
+ continue;
+ }
+ else if (*ret != '\0')
{
printf ("not all of `%s' read\n", tm_tests[i].input);
result = 1;
@@ -127,7 +138,14 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
- if (*strptime (day_tests[i].input, day_tests[i].format, &tm) != '\0')
+ char *ret = strptime (day_tests[i].input, day_tests[i].format, &tm);
+ if (ret == NULL)
+ {
+ printf ("strptime returned NULL for `%s'\n", day_tests[i].input);
+ result = 1;
+ continue;
+ }
+ else if (*ret != '\0')
{
printf ("not all of `%s' read\n", day_tests[i].input);
result = 1;
diff --git a/time/tst-strptime2.c b/time/tst-strptime2.c
new file mode 100644
index 0000000000..73552bb8f8
--- /dev/null
+++ b/time/tst-strptime2.c
@@ -0,0 +1,59 @@
+#include <limits.h>
+#include <stdio.h>
+#include <time.h>
+
+
+static const struct
+{
+ const char *fmt;
+ long int gmtoff;
+} tests[] =
+ {
+ { "1113472456 +1000", 36000 },
+ { "1113472456 -1000", -36000 },
+ { "1113472456 +10", 36000 },
+ { "1113472456 -10", -36000 },
+ { "1113472456 +1030", 37800 },
+ { "1113472456 -1030", -37800 },
+ { "1113472456 +0030", 1800 },
+ { "1113472456 -0030", -1800 },
+ { "1113472456 -1330", LONG_MAX },
+ { "1113472456 +1330", LONG_MAX },
+ { "1113472456 -1060", LONG_MAX },
+ { "1113472456 +1060", LONG_MAX },
+ { "1113472456 1030", LONG_MAX },
+ };
+#define ntests (sizeof (tests) / sizeof (tests[0]))
+
+
+int
+main (void)
+{
+ int result = 0;
+
+ for (int i = 0; i < ntests; ++i)
+ {
+ struct tm tm;
+
+ if (strptime (tests[i].fmt, "%s %z", &tm) == NULL)
+ {
+ if (tests[i].gmtoff != LONG_MAX)
+ {
+ printf ("round %d: strptime unexpectedly failed\n", i);
+ result = 1;
+ }
+ continue;
+ }
+
+ if (tm.tm_gmtoff != tests[i].gmtoff)
+ {
+ printf ("round %d: tm_gmtoff is %ld\n", i, (long int) tm.tm_gmtoff);
+ result = 1;
+ }
+ }
+
+ if (result == 0)
+ puts ("all OK");
+
+ return 0;
+}
diff --git a/time/tst-strptime3.c b/time/tst-strptime3.c
new file mode 100644
index 0000000000..9a8c6485e7
--- /dev/null
+++ b/time/tst-strptime3.c
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+int
+main (void)
+{
+ int result = 0;
+ struct tm tm;
+
+ memset (&tm, 0xaa, sizeof (tm));
+
+ /* Test we don't crash on uninitialized struct tm.
+ Some fields might contain bogus values until everything
+ needed is initialized, but we shouldn't crash. */
+ if (strptime ("2007", "%Y", &tm) == NULL
+ || strptime ("12", "%d", &tm) == NULL
+ || strptime ("Feb", "%b", &tm) == NULL
+ || strptime ("13", "%M", &tm) == NULL
+ || strptime ("21", "%S", &tm) == NULL
+ || strptime ("16", "%H", &tm) == NULL)
+ {
+ puts ("strptimes failed");
+ result = 1;
+ }
+
+ if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
+ || tm.tm_mday != 12 || tm.tm_mon != 1 || tm.tm_year != 107
+ || tm.tm_wday != 1 || tm.tm_yday != 42)
+ {
+ puts ("unexpected tm content");
+ result = 1;
+ }
+
+ if (strptime ("8", "%d", &tm) == NULL)
+ {
+ puts ("strptime failed");
+ result = 1;
+ }
+
+ if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
+ || tm.tm_mday != 8 || tm.tm_mon != 1 || tm.tm_year != 107
+ || tm.tm_wday != 4 || tm.tm_yday != 38)
+ {
+ puts ("unexpected tm content");
+ result = 1;
+ }
+
+ if (result == 0)
+ puts ("all OK");
+
+ return 0;
+}
diff --git a/time/tzfile.c b/time/tzfile.c
index e95fd55f36..6e7ee4a240 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -71,24 +71,34 @@ static inline int
__attribute ((always_inline))
decode (const void *ptr)
{
- if ((BYTE_ORDER == BIG_ENDIAN) && sizeof (int) == 4)
+ if (BYTE_ORDER == BIG_ENDIAN && sizeof (int) == 4)
return *(const int *) ptr;
- else if (BYTE_ORDER == LITTLE_ENDIAN && sizeof (int) == 4)
+ if (sizeof (int) == 4)
return bswap_32 (*(const int *) ptr);
- else
- {
- const unsigned char *p = ptr;
- int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
- result = (result << 8) | *p++;
- result = (result << 8) | *p++;
- result = (result << 8) | *p++;
- result = (result << 8) | *p++;
+ const unsigned char *p = ptr;
+ int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
- return result;
- }
+ result = (result << 8) | *p++;
+ result = (result << 8) | *p++;
+ result = (result << 8) | *p++;
+ result = (result << 8) | *p++;
+
+ return result;
}
+
+static inline int64_t
+__attribute ((always_inline))
+decode64 (const void *ptr)
+{
+ if ((BYTE_ORDER == BIG_ENDIAN))
+ return *(const int64_t *) ptr;
+
+ return bswap_64 (*(const int64_t *) ptr);
+}
+
+
void
__tzfile_read (const char *file, size_t extra, char **extrap)
{
@@ -102,6 +112,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
size_t types_idx;
size_t leaps_idx;
int was_using_tzfile = __use_tzfile;
+ int trans_width = 4;
+
+ if (sizeof (time_t) != 4 && sizeof (time_t) != 8)
+ abort ();
__use_tzfile = 0;
@@ -185,8 +199,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
/* No threads reading this stream. */
__fsetlocking (f, FSETLOCKING_BYCALLER);
+ read_again:
if (__builtin_expect (fread_unlocked ((void *) &tzhead, sizeof (tzhead),
- 1, f) != 1, 0))
+ 1, f) != 1, 0)
+ || memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) != 0)
goto lose;
num_transitions = (size_t) decode (tzhead.tzh_timecnt);
@@ -196,6 +212,26 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
+ /* For platforms with 64-bit time_t we use the new format if available. */
+ if (sizeof (time_t) == 8 && trans_width == 4
+ && tzhead.tzh_version[0] != '\0')
+ {
+ /* We use the 8-byte format. */
+ trans_width = 8;
+
+ /* Position the stream before the second header. */
+ size_t to_skip = (num_transitions * (4 + 1)
+ + num_types * 6
+ + chars
+ + num_leaps * 8
+ + num_isstd
+ + num_isgmt);
+ if (fseek (f, to_skip, SEEK_CUR) != 0)
+ goto lose;
+
+ goto read_again;
+ }
+
total_size = num_transitions * (sizeof (time_t) + 1);
total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
& ~(__alignof__ (struct ttinfo) - 1));
@@ -205,10 +241,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
& ~(__alignof__ (struct leap) - 1));
leaps_idx = total_size;
total_size += num_leaps * sizeof (struct leap);
- /* This is for the extra memory required by the caller. */
- total_size += extra;
- transitions = (time_t *) malloc (total_size);
+ /* Allocate enough memory including the extra block requested by the
+ caller. */
+ transitions = (time_t *) malloc (total_size + extra);
if (transitions == NULL)
goto lose;
@@ -220,14 +256,11 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
if (extra > 0)
*extrap = (char *) &leaps[num_leaps];
- if (sizeof (time_t) < 4)
- abort ();
-
- if (sizeof (time_t) == 4)
+ if (sizeof (time_t) == 4 || trans_width == 8)
{
- if (__builtin_expect (fread_unlocked (transitions, 1,
- (4 + 1) * num_transitions, f)
- != (4 + 1) * num_transitions, 0))
+ if (__builtin_expect (fread_unlocked (transitions, trans_width + 1,
+ num_transitions, f)
+ != num_transitions, 0))
goto lose;
}
else
@@ -245,7 +278,9 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
if (__builtin_expect (type_idxs[i] >= num_types, 0))
goto lose;
- if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4)
+ if ((BYTE_ORDER != BIG_ENDIAN && (sizeof (time_t) == 4 || trans_width == 4))
+ || (BYTE_ORDER == BIG_ENDIAN && sizeof (time_t) == 8
+ && trans_width == 4))
{
/* Decode the transition times, stored as 4-byte integers in
network (big-endian) byte order. We work from the end of
@@ -255,6 +290,13 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
while (i-- > 0)
transitions[i] = decode ((char *) transitions + i * 4);
}
+ else if (BYTE_ORDER != BIG_ENDIAN && sizeof (time_t) == 8)
+ {
+ /* Decode the transition times, stored as 8-byte integers in
+ network (big-endian) byte order. */
+ for (i = 0; i < num_transitions; ++i)
+ transitions[i] = decode64 ((char *) transitions + i * 8);
+ }
for (i = 0; i < num_types; ++i)
{
@@ -280,13 +322,16 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
for (i = 0; i < num_leaps; ++i)
{
- unsigned char x[4];
- if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
- 0))
+ unsigned char x[8];
+ if (__builtin_expect (fread_unlocked (x, 1, trans_width, f)
+ != trans_width, 0))
goto lose;
- leaps[i].transition = (time_t) decode (x);
- if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
- 0))
+ if (sizeof (time_t) == 4 || trans_width == 4)
+ leaps[i].transition = (time_t) decode (x);
+ else
+ leaps[i].transition = (time_t) decode64 (x);
+
+ if (__builtin_expect (fread_unlocked (x, 1, 4, f) != 4, 0))
goto lose;
leaps[i].change = (long int) decode (x);
}
@@ -311,6 +356,12 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
while (i < num_types)
types[i++].isgmt = 0;
+ /* XXX When a version 2 file is available it can contain a POSIX TZ-style
+ formatted string which specifies how times past the last one specified
+ are supposed to be handled. We might want to handle this at some
+ point. But it might be overhead since most/all? files have an
+ open-ended last entry. */
+
fclose (f);
/* First "register" all timezone names. */