summaryrefslogtreecommitdiff
path: root/lib/libc/time
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2005-07-05 13:40:52 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2005-07-05 13:40:52 +0000
commit9bb16badc66573c132b67bb6f23e8ca692eedb65 (patch)
treee31874322aa666685b8c54d940f1c35e8ccf6c3c /lib/libc/time
parent61fb473f97cfd7b86cb2e1e5308693c7c2a9cadf (diff)
Update to tzcode2005j.
Diffstat (limited to 'lib/libc/time')
-rw-r--r--lib/libc/time/README14
-rw-r--r--lib/libc/time/asctime.c37
-rw-r--r--lib/libc/time/ctime.38
-rw-r--r--lib/libc/time/difftime.c100
-rw-r--r--lib/libc/time/ialloc.c10
-rw-r--r--lib/libc/time/localtime.c385
-rw-r--r--lib/libc/time/private.h47
-rw-r--r--lib/libc/time/scheck.c6
-rw-r--r--lib/libc/time/strftime.c128
-rw-r--r--lib/libc/time/tz-art.htm4
-rw-r--r--lib/libc/time/tz-link.htm96
-rw-r--r--lib/libc/time/tzfile.h37
-rw-r--r--lib/libc/time/zdump.829
-rw-r--r--lib/libc/time/zdump.c425
-rw-r--r--lib/libc/time/zic.c201
15 files changed, 1041 insertions, 486 deletions
diff --git a/lib/libc/time/README b/lib/libc/time/README
index c143c778e96..180384cb1c5 100644
--- a/lib/libc/time/README
+++ b/lib/libc/time/README
@@ -1,5 +1,5 @@
-$OpenBSD: README,v 1.4 2002/04/04 19:12:08 millert Exp $
-@(#)README 7.11
+$OpenBSD: README,v 1.5 2005/07/05 13:40:51 millert Exp $
+@(#)README 7.12
"What time is it?" -- Richard Deacon as The King
"Any time you want it to be." -- Frank Baxter as The Scientist
@@ -53,8 +53,10 @@ substituting your desired installation directory for "$HOME/tzdir":
To use the new functions, use a "-ltz" option when compiling or linking.
-Historical local time information has been included here not because it
-is particularly useful, but rather to:
+Historical local time information has been included here to:
+
+* provide a compendium of data about the history of civil time
+ that is useful even if the data are not 100% accurate;
* give an idea of the variety of local time rules that have
existed in the past and thus an idea of the variety that may be
@@ -64,7 +66,9 @@ is particularly useful, but rather to:
system.
The information in the time zone data files is by no means authoritative;
-if you know that the rules are different from those in a file, by all means
+the files currently do not even attempt to covar all time stamps before
+1970, and there are undoubtedly errors even for time stamps since 1970.
+If you know that the rules are different from those in a file, by all means
feel free to change file (and please send the changed version to
tz@elsie.nci.nih.gov for use in the future). Europeans take note!
diff --git a/lib/libc/time/asctime.c b/lib/libc/time/asctime.c
index 3004075cf0b..f9b299a0740 100644
--- a/lib/libc/time/asctime.c
+++ b/lib/libc/time/asctime.c
@@ -3,9 +3,15 @@
** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
*/
+/*
+** Avoid the temptation to punt entirely to strftime;
+** the output of strftime is supposed to be locale specific
+** whereas the output of asctime is supposed to be constant.
+*/
+
#if defined(LIBC_SCCS) && !defined(lint) && !defined(NOID)
-static char elsieid[] = "@(#)asctime.c 7.22";
-static char rcsid[] = "$OpenBSD: asctime.c,v 1.11 2005/03/06 01:40:05 cloder Exp $";
+static char elsieid[] = "@(#)asctime.c 7.31";
+static char rcsid[] = "$OpenBSD: asctime.c,v 1.12 2005/07/05 13:40:51 millert Exp $";
#endif /* LIBC_SCCS and not lint */
/*LINTLIBRARY*/
@@ -14,10 +20,6 @@ static char rcsid[] = "$OpenBSD: asctime.c,v 1.11 2005/03/06 01:40:05 cloder Exp
#include "tzfile.h"
#include "thread_private.h"
-#if STRICTLY_STANDARD_ASCTIME
-#define ASCTIME_FMT "%.3s %.3s%3d %.2d:%.2d:%.2d %ld\n"
-#define ASCTIME_FMT_B ASCTIME_FMT
-#else /* !STRICTLY_STANDARD_ASCTIME */
/*
** Some systems only handle "%.2d"; others only handle "%02d";
** "%02.2d" makes (most) everybody happy.
@@ -29,17 +31,20 @@ static char rcsid[] = "$OpenBSD: asctime.c,v 1.11 2005/03/06 01:40:05 cloder Exp
** Vintage programs are coded for years that are always four digits long
** and may assume that the newline always lands in the same place.
** For years that are less than four digits, we pad the output with
-** spaces before the newline to get the newline in the traditional place.
+** leading zeroes to get the newline in the traditional place.
+** The -4 ensures that we get four characters of output even if
+** we call a strftime variant that produces fewer characters for some years.
+** The ISO C 1999 and POSIX 1003.1-2004 standards prohibit padding the year,
+** but many implementations pad anyway; most likely the standards are buggy.
*/
-#define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4ld\n"
+#define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4s\n"
/*
** For years that are more than four digits we put extra spaces before the year
** so that code trying to overwrite the newline won't end up overwriting
** a digit within a year and truncating the year (operating on the assumption
** that no output is better than wrong output).
*/
-#define ASCTIME_FMT_B "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %ld\n"
-#endif /* !STRICTLY_STANDARD_ASCTIME */
+#define ASCTIME_FMT_B "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %s\n"
#define STD_ASCTIME_BUF_SIZE 26
/*
@@ -69,7 +74,7 @@ int bufsize;
};
register const char * wn;
register const char * mn;
- long year;
+ char year[INT_STRLEN_MAXIMUM(int) + 2];
int len;
if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
@@ -78,9 +83,15 @@ int bufsize;
if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
mn = "???";
else mn = mon_name[timeptr->tm_mon];
- year = timeptr->tm_year + (long) TM_YEAR_BASE;
+ /*
+ ** Use strftime's %Y to generate the year, to avoid overflow problems
+ ** when computing timeptr->tm_year + TM_YEAR_BASE.
+ ** Assume that strftime is unaffected by other out-of-range members
+ ** (e.g., timeptr->tm_mday) when processing "%Y".
+ */
+ (void) strftime(year, sizeof year, "%Y", timeptr);
len = snprintf(buf, bufsize,
- ((year >= -999 && year <= 9999) ? ASCTIME_FMT : ASCTIME_FMT_B),
+ ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
wn, mn,
timeptr->tm_mday, timeptr->tm_hour,
timeptr->tm_min, timeptr->tm_sec,
diff --git a/lib/libc/time/ctime.3 b/lib/libc/time/ctime.3
index d7bc31615f2..f262932ab41 100644
--- a/lib/libc/time/ctime.3
+++ b/lib/libc/time/ctime.3
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ctime.3,v 1.29 2004/10/18 22:33:43 millert Exp $
+.\" $OpenBSD: ctime.3,v 1.30 2005/07/05 13:40:51 millert Exp $
.\"
.\"
.Dd February 16, 1999
@@ -63,13 +63,13 @@ string of the form
.Pp
.Dl Thu Nov 24 18:22:48 1986\en
.Pp
-Years requiring fewer than four characters are padded with trailing spaces.
+Years requiring fewer than four characters are padded with leading zeroes.
For years longer than four characters, the string is of the form
.Pp
.Dl Thu Nov 24 18:22:48\ \ \ \ \ 81986\en
.Pp
with five spaces before the year.
-This unusual format is designed to make it less likely that older
+These unusual formats are designed to make it less likely that older
software that expects exactly 26 bytes of output will mistakenly output
misleading values for out-of-range years.
.Pp
@@ -99,7 +99,7 @@ functions return pointers to
structures, described below.
.Fn localtime
corrects for the time zone and any time zone adjustments
-(such as Daylight Saving Time in the U.S.A.).
+(such as Daylight Saving Time in the United States).
After filling in the
.Li tm
structure,
diff --git a/lib/libc/time/difftime.c b/lib/libc/time/difftime.c
index d5fa21fec35..efc0da2695e 100644
--- a/lib/libc/time/difftime.c
+++ b/lib/libc/time/difftime.c
@@ -1,82 +1,64 @@
/*
** This file is in the public domain, so clarified as of
-** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov).
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
*/
#if defined(LIBC_SCCS) && !defined(lint) && !defined(NOID)
-static char elsieid[] = "@(#)difftime.c 7.9";
-static char rcsid[] = "$OpenBSD: difftime.c,v 1.6 2002/04/04 19:12:09 millert Exp $";
+static char elsieid[] = "@(#)difftime.c 7.18";
+static char rcsid[] = "$OpenBSD: difftime.c,v 1.7 2005/07/05 13:40:51 millert Exp $";
#endif /* LIBC_SCCS and not lint */
/*LINTLIBRARY*/
-#include "private.h"
-
-/*
-** Algorithm courtesy Paul Eggert (eggert@twinsun.com).
-*/
-
-#ifdef HAVE_LONG_DOUBLE
-#define long_double long double
-#endif /* defined HAVE_LONG_DOUBLE */
-#ifndef HAVE_LONG_DOUBLE
-#define long_double double
-#endif /* !defined HAVE_LONG_DOUBLE */
+#include "private.h" /* for time_t, TYPE_INTEGRAL, and TYPE_SIGNED */
double
difftime(time1, time0)
const time_t time1;
const time_t time0;
{
- time_t delta;
- time_t hibit;
-
- {
- time_t tt;
- double d;
- long_double ld;
-
- if (sizeof tt < sizeof d)
- return (double) time1 - (double) time0;
- if (sizeof tt < sizeof ld)
- return (long_double) time1 - (long_double) time0;
+ /*
+ ** If (sizeof (double) > sizeof (time_t)) simply convert and subtract
+ ** (assuming that the larger type has more precision).
+ ** This is the common real-world case circa 2004.
+ */
+ if (sizeof (double) > sizeof (time_t))
+ return (double) time1 - (double) time0;
+ if (!TYPE_INTEGRAL(time_t)) {
+ /*
+ ** time_t is floating.
+ */
+ return time1 - time0;
+ }
+ if (!TYPE_SIGNED(time_t)) {
+ /*
+ ** time_t is integral and unsigned.
+ ** The difference of two unsigned values can't overflow
+ ** if the minuend is greater than or equal to the subtrahend.
+ */
+ if (time1 >= time0)
+ return time1 - time0;
+ else return -((double) (time0 - time1));
}
- if (time1 < time0)
- return -difftime(time0, time1);
/*
- ** As much as possible, avoid loss of precision
- ** by computing the difference before converting to double.
+ ** time_t is integral and signed.
+ ** Handle cases where both time1 and time0 have the same sign
+ ** (meaning that their difference cannot overflow).
*/
- delta = time1 - time0;
- if (delta >= 0)
- return delta;
+ if ((time1 < 0) == (time0 < 0))
+ return time1 - time0;
/*
- ** Repair delta overflow.
+ ** time1 and time0 have opposite signs.
+ ** Punt if unsigned long is too narrow.
*/
- hibit = (~ (time_t) 0) << (TYPE_BIT(time_t) - 1);
+ if (sizeof (unsigned long) < sizeof (time_t))
+ return (double) time1 - (double) time0;
/*
- ** The following expression rounds twice, which means
- ** the result may not be the closest to the true answer.
- ** For example, suppose time_t is 64-bit signed int,
- ** long_double is IEEE 754 double with default rounding,
- ** time1 = 9223372036854775807 and time0 = -1536.
- ** Then the true difference is 9223372036854777343,
- ** which rounds to 9223372036854777856
- ** with a total error of 513.
- ** But delta overflows to -9223372036854774273,
- ** which rounds to -9223372036854774784, and correcting
- ** this by subtracting 2 * (long_double) hibit
- ** (i.e. by adding 2**64 = 18446744073709551616)
- ** yields 9223372036854776832, which
- ** rounds to 9223372036854775808
- ** with a total error of 1535 instead.
- ** This problem occurs only with very large differences.
- ** It's too painful to fix this portably.
- ** We are not alone in this problem;
- ** some C compilers round twice when converting
- ** large unsigned types to small floating types,
- ** so if time_t is unsigned the "return delta" above
- ** has the same double-rounding problem with those compilers.
+ ** Stay calm...decent optimizers will eliminate the complexity below.
*/
- return delta - 2 * (long_double) hibit;
+ if (time1 >= 0 /* && time0 < 0 */)
+ return (unsigned long) time1 +
+ (unsigned long) (-(time0 + 1)) + 1;
+ return -(double) ((unsigned long) time0 +
+ (unsigned long) (-(time1 + 1)) + 1);
}
diff --git a/lib/libc/time/ialloc.c b/lib/libc/time/ialloc.c
index 10055e77559..395f92a8a4f 100644
--- a/lib/libc/time/ialloc.c
+++ b/lib/libc/time/ialloc.c
@@ -5,7 +5,7 @@
#if defined(LIBC_SCCS) && !defined(lint) && !defined(NOID)
static char elsieid[] = "@(#)ialloc.c 8.29";
-static char rcsid[] = "$OpenBSD: ialloc.c,v 1.8 2003/03/13 15:47:34 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: ialloc.c,v 1.9 2005/07/05 13:40:51 millert Exp $";
#endif /* LIBC_SCCS and not lint */
/*LINTLIBRARY*/
@@ -41,7 +41,7 @@ const int size;
if (pointer == NULL)
return imalloc(size);
p = realloc((void *) pointer, (size_t) nonzero(size));
- if (p == NULL && pointer)
+ if (p == NULL)
free(pointer);
return p;
}
@@ -53,7 +53,6 @@ const char * const new;
{
register char * result;
register int oldsize, newsize;
- int size;
newsize = (new == NULL) ? 0 : strlen(new);
if (old == NULL)
@@ -62,12 +61,9 @@ const char * const new;
return old;
else
oldsize = strlen(old);
- size = oldsize + newsize + 1;
- if ((result = irealloc(old, size)) != NULL)
+ if ((result = irealloc(old, oldsize + newsize + 1)) != NULL)
if (new != NULL)
(void) strlcpy(result + oldsize, new, newsize + 1);
- else
- free(old);
return result;
}
diff --git a/lib/libc/time/localtime.c b/lib/libc/time/localtime.c
index e9bb299afe9..f49fca6042c 100644
--- a/lib/libc/time/localtime.c
+++ b/lib/libc/time/localtime.c
@@ -4,8 +4,8 @@
*/
#if defined(LIBC_SCCS) && !defined(lint) && !defined(NOID)
-static char elsieid[] = "@(#)localtime.c 7.80";
-static char rcsid[] = "$OpenBSD: localtime.c,v 1.25 2004/10/18 22:33:43 millert Exp $";
+static char elsieid[] = "@(#)localtime.c 7.95";
+static char rcsid[] = "$OpenBSD: localtime.c,v 1.26 2005/07/05 13:40:51 millert Exp $";
#endif /* LIBC_SCCS and not lint */
/*
@@ -19,8 +19,22 @@ static char rcsid[] = "$OpenBSD: localtime.c,v 1.25 2004/10/18 22:33:43 millert
#include "private.h"
#include "tzfile.h"
#include "fcntl.h"
+#include "float.h" /* for FLT_MAX and DBL_MAX */
#include "thread_private.h"
+#ifndef TZ_ABBR_MAX_LEN
+#define TZ_ABBR_MAX_LEN 16
+#endif /* !defined TZ_ABBR_MAX_LEN */
+
+#ifndef TZ_ABBR_CHAR_SET
+#define TZ_ABBR_CHAR_SET \
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
+#endif /* !defined TZ_ABBR_CHAR_SET */
+
+#ifndef TZ_ABBR_ERR_CHAR
+#define TZ_ABBR_ERR_CHAR '_'
+#endif /* !defined TZ_ABBR_ERR_CHAR */
+
/*
** SunOS 4.1.1 headers lack O_BINARY.
*/
@@ -46,16 +60,16 @@ static char rcsid[] = "$OpenBSD: localtime.c,v 1.25 2004/10/18 22:33:43 millert
** 5. They might reference tm.TM_ZONE after calling offtime.
** What's best to do in the above cases is open to debate;
** for now, we just set things up so that in any of the five cases
-** WILDABBR is used. Another possibility: initialize tzname[0] to the
+** WILDABBR is used. Another possibility: initialize tzname[0] to the
** string "tzname[0] used before set", and similarly for the other cases.
-** And another: initialize tzname[0] to "ERA", with an explanation in the
+** And another: initialize tzname[0] to "ERA", with an explanation in the
** manual page of what this "time zone abbreviation" means (doing this so
** that tzname[0] has the "normal" length of three characters).
*/
#define WILDABBR " "
#endif /* !defined WILDABBR */
-static char wildabbr[] = "WILDABBR";
+static char wildabbr[] = WILDABBR;
static const char gmt[] = "GMT";
@@ -123,17 +137,19 @@ struct rule {
static long detzcode P((const char * codep));
static const char * getzname P((const char * strp));
+static const char * getqzname P((const char * strp, const char delim));
static const char * getnum P((const char * strp, int * nump, int min,
int max));
static const char * getsecs P((const char * strp, long * secsp));
static const char * getoffset P((const char * strp, long * offsetp));
static const char * getrule P((const char * strp, struct rule * rulep));
static void gmtload P((struct state * sp));
-static void gmtsub P((const time_t * timep, long offset,
+static struct tm * gmtsub P((const time_t * timep, long offset,
struct tm * tmp));
-static void localsub P((const time_t * timep, long offset,
+static struct tm * localsub P((const time_t * timep, long offset,
struct tm * tmp));
static int increment_overflow P((int * number, int delta));
+static int leaps_thru_end_of P((int y));
static int long_increment_overflow P((long * number, int delta));
static int long_normalize_overflow P((long * tensptr,
int * unitsptr, int base));
@@ -141,18 +157,18 @@ static int normalize_overflow P((int * tensptr, int * unitsptr,
int base));
static void settzname P((void));
static time_t time1 P((struct tm * tmp,
- void(*funcp) P((const time_t *,
+ struct tm * (*funcp) P((const time_t *,
long, struct tm *)),
long offset));
static time_t time2 P((struct tm *tmp,
- void(*funcp) P((const time_t *,
+ struct tm * (*funcp) P((const time_t *,
long, struct tm*)),
long offset, int * okayp));
static time_t time2sub P((struct tm *tmp,
- void(*funcp) P((const time_t *,
+ struct tm * (*funcp) P((const time_t *,
long, struct tm*)),
long offset, int * okayp, int do_norm_secs));
-static void timesub P((const time_t * timep, long offset,
+static struct tm * timesub P((const time_t * timep, long offset,
const struct state * sp, struct tm * tmp));
static int tmcomp P((const struct tm * atmp,
const struct tm * btmp));
@@ -269,6 +285,24 @@ settzname P((void))
tzname[ttisp->tt_isdst] =
&sp->chars[ttisp->tt_abbrind];
}
+ /*
+ ** Finally, scrub the abbreviations.
+ ** First, replace bogus characters.
+ */
+ for (i = 0; i < sp->charcnt; ++i)
+ if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
+ sp->chars[i] = TZ_ABBR_ERR_CHAR;
+ /*
+ ** Second, truncate long abbreviations.
+ */
+ for (i = 0; i < sp->typecnt; ++i) {
+ register const struct ttinfo * const ttisp = &sp->ttis[i];
+ register char * cp = &sp->chars[ttisp->tt_abbrind];
+
+ if (strlen(cp) > TZ_ABBR_MAX_LEN &&
+ strcmp(cp, GRANDPARENTED) != 0)
+ *(cp + TZ_ABBR_MAX_LEN) = '\0';
+ }
}
static int
@@ -415,6 +449,33 @@ register struct state * const sp;
return -1;
}
}
+ /*
+ ** Out-of-sort ats should mean we're running on a
+ ** signed time_t system but using a data file with
+ ** unsigned values (or vice versa).
+ */
+ for (i = 0; i < sp->timecnt - 2; ++i)
+ if (sp->ats[i] > sp->ats[i + 1]) {
+ ++i;
+ if (TYPE_SIGNED(time_t)) {
+ /*
+ ** Ignore the end (easy).
+ */
+ sp->timecnt = i;
+ } else {
+ /*
+ ** Ignore the beginning (harder).
+ */
+ register int j;
+
+ for (j = 0; j + i < sp->timecnt; ++j) {
+ sp->ats[j] = sp->ats[j + i];
+ sp->types[j] = sp->types[j + i];
+ }
+ sp->timecnt = j;
+ }
+ break;
+ }
}
return 0;
}
@@ -430,7 +491,7 @@ static const int year_lengths[2] = {
/*
** Given a pointer into a time zone string, scan until a character that is not
-** a valid character in a zone name is found. Return a pointer to that
+** a valid character in a zone name is found. Return a pointer to that
** character.
*/
@@ -447,6 +508,27 @@ register const char * strp;
}
/*
+** Given a pointer into an extended time zone string, scan until the ending
+** delimiter of the zone name is located. Return a pointer to the delimiter.
+**
+** As with getzname above, the legal character set is actually quite
+** restricted, with other characters producing undefined results.
+** We choose not to care - allowing almost anything to be in the zone abbrev.
+*/
+
+static const char *
+getqzname(strp, delim)
+register const char * strp;
+const char delim;
+{
+ register char c;
+
+ while ((c = *strp) != '\0' && c != delim)
+ ++strp;
+ return strp;
+}
+
+/*
** Given a pointer into a time zone string, extract a number from that string.
** Check that the number is within a specified range; if it is not, return
** NULL.
@@ -511,7 +593,7 @@ long * const secsp;
*secsp += num * SECSPERMIN;
if (*strp == ':') {
++strp;
- /* `SECSPERMIN' allows for leap seconds. */
+ /* `SECSPERMIN' allows for leap seconds. */
strp = getnum(strp, &num, 0, SECSPERMIN);
if (strp == NULL)
return NULL;
@@ -550,7 +632,7 @@ long * const offsetp;
/*
** Given a pointer into a time zone string, extract a rule in the form
-** date[/time]. See POSIX section 8 for the format of "date" and "time".
+** date[/time]. See POSIX section 8 for the format of "date" and "time".
** If a valid rule is not found, return NULL.
** Otherwise, return a pointer to the first character not part of the rule.
*/
@@ -669,7 +751,7 @@ const long offset;
dow += DAYSPERWEEK;
/*
- ** "dow" is the day-of-week of the first day of the month. Get
+ ** "dow" is the day-of-week of the first day of the month. Get
** the day-of-month (zero-origin) of the first "dow" day of the
** month.
*/
@@ -692,7 +774,7 @@ const long offset;
/*
** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
- ** question. To get the Epoch-relative time of the specified local
+ ** question. To get the Epoch-relative time of the specified local
** time on that day, add the transition time and the current offset
** from UTC.
*/
@@ -730,10 +812,18 @@ const int lastditch;
stdlen = (sizeof sp->chars) - 1;
stdoffset = 0;
} else {
- name = getzname(name);
- stdlen = name - stdname;
- if (stdlen < 3)
- return -1;
+ if (*name == '<') {
+ name++;
+ stdname = name;
+ name = getqzname(name, '>');
+ if (*name != '>')
+ return (-1);
+ stdlen = name - stdname;
+ name++;
+ } else {
+ name = getzname(name);
+ stdlen = name - stdname;
+ }
if (*name == '\0')
return -1;
name = getoffset(name, &stdoffset);
@@ -744,11 +834,18 @@ const int lastditch;
if (load_result != 0)
sp->leapcnt = 0; /* so, we're off a little */
if (*name != '\0') {
- dstname = name;
- name = getzname(name);
- dstlen = name - dstname; /* length of DST zone name */
- if (dstlen < 3)
- return -1;
+ if (*name == '<') {
+ dstname = ++name;
+ name = getqzname(name, '>');
+ if (*name != '>')
+ return -1;
+ dstlen = name - dstname;
+ name++;
+ } else {
+ dstname = name;
+ name = getzname(name);
+ dstlen = name - dstname; /* length of DST zone name */
+ }
if (*name != '\0' && *name != ',' && *name != ';') {
name = getoffset(name, &dstoffset);
if (name == NULL)
@@ -1014,14 +1111,14 @@ tzset P((void))
/*
** The easy way to behave "as if no library function calls" localtime
** is to not call it--so we drop its guts into "localsub", which can be
-** freely called. (And no, the PANS doesn't require the above behavior--
+** freely called. (And no, the PANS doesn't require the above behavior--
** but it *is* desirable.)
**
** The unused offset argument is for the benefit of mktime variants.
*/
/*ARGSUSED*/
-static void
+static struct tm *
localsub(timep, offset, tmp)
const time_t * const timep;
const long offset;
@@ -1030,14 +1127,13 @@ struct tm * const tmp;
register struct state * sp;
register const struct ttinfo * ttisp;
register int i;
+ register struct tm * result;
const time_t t = *timep;
sp = lclptr;
#ifdef ALL_STATE
- if (sp == NULL) {
- gmtsub(timep, offset, tmp);
- return;
- }
+ if (sp == NULL)
+ return gmtsub(timep, offset, tmp);
#endif /* defined ALL_STATE */
if (sp->timecnt == 0 || t < sp->ats[0]) {
i = 0;
@@ -1050,7 +1146,7 @@ struct tm * const tmp;
for (i = 1; i < sp->timecnt; ++i)
if (t < sp->ats[i])
break;
- i = sp->types[i - 1];
+ i = (int) sp->types[i - 1];
}
ttisp = &sp->ttis[i];
/*
@@ -1059,12 +1155,13 @@ struct tm * const tmp;
** t += ttisp->tt_gmtoff;
** timesub(&t, 0L, sp, tmp);
*/
- timesub(&t, ttisp->tt_gmtoff, sp, tmp);
+ result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
tmp->tm_isdst = ttisp->tt_isdst;
tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
#ifdef TM_ZONE
tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
#endif /* defined TM_ZONE */
+ return result;
}
/*
@@ -1099,12 +1196,14 @@ const time_t * const timep;
** gmtsub is to gmtime as localsub is to localtime.
*/
-static void
+static struct tm *
gmtsub(timep, offset, tmp)
const time_t * const timep;
const long offset;
struct tm * const tmp;
{
+ register struct tm * result;
+
_THREAD_PRIVATE_MUTEX_LOCK(gmt);
if (!gmt_is_set) {
gmt_is_set = TRUE;
@@ -1115,7 +1214,7 @@ struct tm * const tmp;
gmtload(gmtptr);
}
_THREAD_PRIVATE_MUTEX_UNLOCK(gmt);
- timesub(timep, offset, gmtptr, tmp);
+ result = timesub(timep, offset, gmtptr, tmp);
#ifdef TM_ZONE
/*
** Could get fancy here and deliver something such as
@@ -1135,6 +1234,7 @@ struct tm * const tmp;
#endif /* State Farm */
}
#endif /* defined TM_ZONE */
+ return result;
}
/*
@@ -1170,13 +1270,25 @@ offtime(timep, offset)
const time_t * const timep;
const long offset;
{
- gmtsub(timep, offset, &tm);
- return &tm;
+ return gmtsub(timep, offset, &tm);
}
#endif /* defined STD_INSPIRED */
-static void
+/*
+** Return the number of leap years through the end of the given year
+** where, to make the math easy, the answer for year zero is defined as zero.
+*/
+
+static int
+leaps_thru_end_of(y)
+register const int y;
+{
+ return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
+ -(leaps_thru_end_of(-(y + 1)) + 1);
+}
+
+static struct tm *
timesub(timep, offset, sp, tmp)
const time_t * const timep;
const long offset;
@@ -1184,10 +1296,10 @@ register const struct state * const sp;
register struct tm * const tmp;
{
register const struct lsinfo * lp;
- register long days;
+ register time_t tdays;
+ register int idays; /* unsigned would be so 2003 */
register long rem;
- register long y;
- register int yleap;
+ int y;
register const int * ip;
register long corr;
register int hit;
@@ -1221,60 +1333,93 @@ register struct tm * const tmp;
break;
}
}
- days = *timep / SECSPERDAY;
- rem = *timep % SECSPERDAY;
-#ifdef mc68k
- if (*timep == 0x80000000) {
- /*
- ** A 3B1 muffs the division on the most negative number.
- */
- days = -24855;
- rem = -11648;
+ y = EPOCH_YEAR;
+ tdays = *timep / SECSPERDAY;
+ rem = *timep - tdays * SECSPERDAY;
+ while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
+ int newy;
+ register time_t tdelta;
+ register int idelta;
+ register int leapdays;
+
+ tdelta = tdays / DAYSPERLYEAR;
+ idelta = tdelta;
+ if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
+ return NULL;
+ if (idelta == 0)
+ idelta = (tdays < 0) ? -1 : 1;
+ newy = y;
+ if (increment_overflow(&newy, idelta))
+ return NULL;
+ leapdays = leaps_thru_end_of(newy - 1) -
+ leaps_thru_end_of(y - 1);
+ tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
+ tdays -= leapdays;
+ y = newy;
+ }
+ {
+ register long seconds;
+
+ seconds = tdays * SECSPERDAY + 0.5;
+ tdays = seconds / SECSPERDAY;
+ rem += seconds - tdays * SECSPERDAY;
}
-#endif /* defined mc68k */
- rem += (offset - corr);
+ /*
+ ** Given the range, we can now fearlessly cast...
+ */
+ idays = tdays;
+ rem += offset - corr;
while (rem < 0) {
rem += SECSPERDAY;
- --days;
+ --idays;
}
while (rem >= SECSPERDAY) {
rem -= SECSPERDAY;
- ++days;
+ ++idays;
}
+ while (idays < 0) {
+ if (increment_overflow(&y, -1))
+ return NULL;
+ idays += year_lengths[isleap(y)];
+ }
+ while (idays >= year_lengths[isleap(y)]) {
+ idays -= year_lengths[isleap(y)];
+ if (increment_overflow(&y, 1))
+ return NULL;
+ }
+ tmp->tm_year = y;
+ if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
+ return NULL;
+ tmp->tm_yday = idays;
+ /*
+ ** The "extra" mods below avoid overflow problems.
+ */
+ tmp->tm_wday = EPOCH_WDAY +
+ ((y - EPOCH_YEAR) % DAYSPERWEEK) *
+ (DAYSPERNYEAR % DAYSPERWEEK) +
+ leaps_thru_end_of(y - 1) -
+ leaps_thru_end_of(EPOCH_YEAR - 1) +
+ idays;
+ tmp->tm_wday %= DAYSPERWEEK;
+ if (tmp->tm_wday < 0)
+ tmp->tm_wday += DAYSPERWEEK;
tmp->tm_hour = (int) (rem / SECSPERHOUR);
- rem = rem % SECSPERHOUR;
+ rem %= SECSPERHOUR;
tmp->tm_min = (int) (rem / SECSPERMIN);
/*
** A positive leap second requires a special
- ** representation. This uses "... ??:59:60" et seq.
+ ** representation. This uses "... ??:59:60" et seq.
*/
tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
- tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
- if (tmp->tm_wday < 0)
- tmp->tm_wday += DAYSPERWEEK;
- y = EPOCH_YEAR;
-#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
- while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
- register long newy;
-
- newy = y + days / DAYSPERNYEAR;
- if (days < 0)
- --newy;
- days -= (newy - y) * DAYSPERNYEAR +
- LEAPS_THRU_END_OF(newy - 1) -
- LEAPS_THRU_END_OF(y - 1);
- y = newy;
- }
- tmp->tm_year = y - TM_YEAR_BASE;
- tmp->tm_yday = (int) days;
- ip = mon_lengths[yleap];
- for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
- days = days - (long) ip[tmp->tm_mon];
- tmp->tm_mday = (int) (days + 1);
+ ip = mon_lengths[isleap(y)];
+ for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
+ idays -= ip[tmp->tm_mon];
+ tmp->tm_mday = (int) (idays + 1);
tmp->tm_isdst = 0;
#ifdef TM_GMTOFF
tmp->TM_GMTOFF = offset;
#endif /* defined TM_GMTOFF */
+ return tmp;
}
char *
@@ -1284,7 +1429,7 @@ const time_t * const timep;
/*
** Section 4.12.3.2 of X3.159-1989 requires that
** The ctime function converts the calendar time pointed to by timer
-** to local time in the form of a string. It is equivalent to
+** to local time in the form of a string. It is equivalent to
** asctime(localtime(timer))
*/
return asctime(localtime(timep));
@@ -1295,9 +1440,9 @@ ctime_r(timep, buf)
const time_t * const timep;
char * buf;
{
- struct tm tm;
+ struct tm mytm;
- return asctime_r(localtime_r(timep, &tm), buf);
+ return asctime_r(localtime_r(timep, &mytm), buf);
}
/*
@@ -1305,7 +1450,7 @@ char * buf;
** The "best" way to do mktime I think is based on an idea of Bob
** Kridle's (so its said...) from a long time ago.
** [kridle@xinet.com as of 1996-01-16.]
-** It does a binary search of the time_t space. Since time_t's are
+** It does a binary search of the time_t space. Since time_t's are
** just 32 bits, its a max of 32 iterations (even at 64 bits it
** would still be very reasonable).
*/
@@ -1391,17 +1536,18 @@ register const struct tm * const btmp;
static time_t
time2sub(tmp, funcp, offset, okayp, do_norm_secs)
struct tm * const tmp;
-void (* const funcp) P((const time_t*, long, struct tm*));
+struct tm * (* const funcp) P((const time_t*, long, struct tm*));
const long offset;
int * const okayp;
const int do_norm_secs;
{
register const struct state * sp;
register int dir;
- register int bits;
register int i, j;
register int saved_seconds;
register long li;
+ register time_t lo;
+ register time_t hi;
long y;
time_t newt;
time_t t;
@@ -1454,7 +1600,7 @@ const int do_norm_secs;
return WRONG;
yourtm.tm_year = y;
if (yourtm.tm_year != y)
- return WRONG;
+ return WRONG;
if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
saved_seconds = 0;
else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
@@ -1475,27 +1621,49 @@ const int do_norm_secs;
yourtm.tm_sec = 0;
}
/*
- ** Divide the search space in half
- ** (this works whether time_t is signed or unsigned).
+ ** Do a binary search (this works whatever time_t's type is).
*/
- bits = TYPE_BIT(time_t) - 1;
- /*
- ** If time_t is signed, then 0 is just above the median,
- ** assuming two's complement arithmetic.
- ** If time_t is unsigned, then (1 << bits) is just above the median.
- */
- t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
+ if (!TYPE_SIGNED(time_t)) {
+ lo = 0;
+ hi = lo - 1;
+ } else if (!TYPE_INTEGRAL(time_t)) {
+ if (sizeof(time_t) > sizeof(float))
+ hi = (time_t) DBL_MAX;
+ else hi = (time_t) FLT_MAX;
+ lo = -hi;
+ } else {
+ lo = 1;
+ for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
+ lo *= 2;
+ hi = -(lo + 1);
+ }
for ( ; ; ) {
- (*funcp)(&t, offset, &mytm);
- dir = tmcomp(&mytm, &yourtm);
+ t = lo / 2 + hi / 2;
+ if (t < lo)
+ t = lo;
+ else if (t > hi)
+ t = hi;
+ if ((*funcp)(&t, offset, &mytm) == NULL) {
+ /*
+ ** Assume that t is too extreme to be represented in
+ ** a struct tm; arrange things so that it is less
+ ** extreme on the next pass.
+ */
+ dir = (t > 0) ? 1 : -1;
+ } else dir = tmcomp(&mytm, &yourtm);
if (dir != 0) {
- if (bits-- < 0)
+ if (t == lo) {
+ ++t;
+ ++lo;
+ } else if (t == hi) {
+ --t;
+ --hi;
+ }
+ if (lo > hi)
return WRONG;
- if (bits < 0)
- --t; /* may be needed if new t is minimal */
- else if (dir > 0)
- t -= ((time_t) 1) << bits;
- else t += ((time_t) 1) << bits;
+ if (dir > 0)
+ hi = t;
+ else lo = t;
continue;
}
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
@@ -1524,7 +1692,8 @@ const int do_norm_secs;
continue;
newt = t + sp->ttis[j].tt_gmtoff -
sp->ttis[i].tt_gmtoff;
- (*funcp)(&newt, offset, &mytm);
+ if ((*funcp)(&newt, offset, &mytm) == NULL)
+ continue;
if (tmcomp(&mytm, &yourtm) != 0)
continue;
if (mytm.tm_isdst != yourtm.tm_isdst)
@@ -1543,15 +1712,15 @@ label:
if ((newt < t) != (saved_seconds < 0))
return WRONG;
t = newt;
- (*funcp)(&t, offset, tmp);
- *okayp = TRUE;
+ if ((*funcp)(&t, offset, tmp))
+ *okayp = TRUE;
return t;
}
static time_t
time2(tmp, funcp, offset, okayp)
struct tm * const tmp;
-void (* const funcp) P((const time_t*, long, struct tm*));
+struct tm * (* const funcp) P((const time_t*, long, struct tm*));
const long offset;
int * const okayp;
{
@@ -1569,7 +1738,7 @@ int * const okayp;
static time_t
time1(tmp, funcp, offset)
struct tm * const tmp;
-void (* const funcp) P((const time_t *, long, struct tm *));
+struct tm * (* const funcp) P((const time_t *, long, struct tm *));
const long offset;
{
register time_t t;
@@ -1755,7 +1924,7 @@ time_t t;
tzset();
/*
** For a positive leap second hit, the result
- ** is not unique. For a negative leap second
+ ** is not unique. For a negative leap second
** hit, the corresponding time doesn't exist,
** so we return an adjacent second.
*/
diff --git a/lib/libc/time/private.h b/lib/libc/time/private.h
index 72a1a785323..8f8c737e870 100644
--- a/lib/libc/time/private.h
+++ b/lib/libc/time/private.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: private.h,v 1.16 2004/10/18 22:33:43 millert Exp $ */
+/* $OpenBSD: private.h,v 1.17 2005/07/05 13:40:51 millert Exp $ */
#ifndef PRIVATE_H
#define PRIVATE_H
@@ -14,7 +14,6 @@
#define PCTS 1
#define XPG4_1994_04_09 1
#define STD_INSPIRED 1
-#define HAVE_LONG_DOUBLE 1
#define HAVE_STRERROR 1
#define NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU 1
@@ -33,11 +32,13 @@
#if 0
#ifndef lint
#ifndef NOID
-static char privatehid[] = "@(#)private.h 7.54";
+static char privatehid[] = "@(#)private.h 7.55";
#endif /* !defined NOID */
#endif /* !defined lint */
#endif
+#define GRANDPARENTED "Local time zone must be set--see zic manual page"
+
/*
** Defaults for preprocessor symbols.
** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
@@ -106,13 +107,13 @@ static char privatehid[] = "@(#)private.h 7.54";
#include "time.h"
#include "stdlib.h"
-#if HAVE_GETTEXT - 0
+#if HAVE_GETTEXT
#include "libintl.h"
-#endif /* HAVE_GETTEXT - 0 */
+#endif /* HAVE_GETTEXT */
-#if HAVE_SYS_WAIT_H - 0
+#if HAVE_SYS_WAIT_H
#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
-#endif /* HAVE_SYS_WAIT_H - 0 */
+#endif /* HAVE_SYS_WAIT_H */
#ifndef WIFEXITED
#define WIFEXITED(status) (((status) & 0xff) == 0)
@@ -121,20 +122,20 @@ static char privatehid[] = "@(#)private.h 7.54";
#define WEXITSTATUS(status) (((status) >> 8) & 0xff)
#endif /* !defined WEXITSTATUS */
-#if HAVE_UNISTD_H - 0
+#if HAVE_UNISTD_H
#include "unistd.h" /* for F_OK and R_OK */
-#endif /* HAVE_UNISTD_H - 0 */
+#endif /* HAVE_UNISTD_H */
-#if !(HAVE_UNISTD_H - 0)
+#if !HAVE_UNISTD_H
#ifndef F_OK
#define F_OK 0
#endif /* !defined F_OK */
#ifndef R_OK
#define R_OK 4
#endif /* !defined R_OK */
-#endif /* !(HAVE_UNISTD_H - 0) */
+#endif /* !HAVE_UNISTD_H */
-/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
+/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
/*
@@ -224,6 +225,7 @@ extern char * asctime_r();
/*
** Private function declarations.
*/
+
char * icalloc P((int nelem, int elsize));
char * icatalloc P((char * old, const char * new));
char * icpyalloc P((const char * string));
@@ -231,8 +233,7 @@ char * imalloc P((int n));
void * irealloc P((void * pointer, int size));
void icfree P((char * pointer));
void ifree P((char * pointer));
-char * scheck P((const char *string, const char *format));
-
+char * scheck P((const char *string, char *format));
/*
** Finally, some convenience items.
@@ -254,6 +255,15 @@ char * scheck P((const char *string, const char *format));
#define TYPE_SIGNED(type) (((type) -1) < 0)
#endif /* !defined TYPE_SIGNED */
+/*
+** Since the definition of TYPE_INTEGRAL contains floating point numbers,
+** it cannot be used in preprocessor directives.
+*/
+
+#ifndef TYPE_INTEGRAL
+#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
+#endif /* !defined TYPE_INTEGRAL */
+
#ifndef INT_STRLEN_MAXIMUM
/*
** 302 / 1000 is log10(2.0) rounded up.
@@ -262,7 +272,8 @@ char * scheck P((const char *string, const char *format));
** add one more for a minus sign if the type is signed.
*/
#define INT_STRLEN_MAXIMUM(type) \
- ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
+ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
+ 1 + TYPE_SIGNED(type))
#endif /* !defined INT_STRLEN_MAXIMUM */
/*
@@ -296,11 +307,11 @@ char * scheck P((const char *string, const char *format));
*/
#ifndef _
-#if HAVE_GETTEXT - 0
+#if HAVE_GETTEXT
#define _(msgid) gettext(msgid)
-#else /* !(HAVE_GETTEXT - 0) */
+#else /* !HAVE_GETTEXT */
#define _(msgid) msgid
-#endif /* !(HAVE_GETTEXT - 0) */
+#endif /* !HAVE_GETTEXT */
#endif /* !defined _ */
#ifndef TZ_DOMAIN
diff --git a/lib/libc/time/scheck.c b/lib/libc/time/scheck.c
index ad3db5b38d9..9f44c0724da 100644
--- a/lib/libc/time/scheck.c
+++ b/lib/libc/time/scheck.c
@@ -4,8 +4,8 @@
*/
#if defined(LIBC_SCCS) && !defined(lint) && !defined(NOID)
-static char elsieid[] = "@(#)scheck.c 8.15";
-static char rcsid[] = "$OpenBSD: scheck.c,v 1.6 2003/02/14 18:24:53 millert Exp $";
+static char elsieid[] = "@(#)scheck.c 8.16";
+static char rcsid[] = "$OpenBSD: scheck.c,v 1.7 2005/07/05 13:40:51 millert Exp $";
#endif /* LIBC_SCCS and not lint */
/*LINTLIBRARY*/
@@ -15,7 +15,7 @@ static char rcsid[] = "$OpenBSD: scheck.c,v 1.6 2003/02/14 18:24:53 millert Exp
char *
scheck(string, format)
const char * const string;
-const char * const format;
+char * const format;
{
register char * fbuf;
register const char * fp;
diff --git a/lib/libc/time/strftime.c b/lib/libc/time/strftime.c
index 8246302c69d..cfa345569f9 100644
--- a/lib/libc/time/strftime.c
+++ b/lib/libc/time/strftime.c
@@ -1,12 +1,6 @@
-/*
-** XXX To do: figure out correct (as distinct from standard-mandated)
-** output for "two digits of year" and "century" formats when
-** the year is negative or less than 100. --ado, 2004-09-09
-*/
-
#if defined(LIBC_SCCS) && !defined(lint) && !defined(NOID)
-static char elsieid[] = "@(#)strftime.c 7.64";
-static char *rcsid = "$OpenBSD: strftime.c,v 1.14 2004/10/18 22:33:43 millert Exp $";
+static char elsieid[] = "@(#)strftime.c 7.75";
+static char *rcsid = "$OpenBSD: strftime.c,v 1.15 2005/07/05 13:40:51 millert Exp $";
#endif /* LIBC_SCCS and not lint */
#include "private.h"
@@ -109,7 +103,7 @@ static const struct lc_time_T C_time_locale = {
** C99 requires this format.
** Previously this code used "%D %X", but we now conform to C99.
** Note that
- ** "%a %b %d %H:%M:%S %Y"
+ ** "%a %b %d %H:%M:%S %Y"
** is used by Solaris 2.3.
*/
"%a %b %e %T %Y",
@@ -126,10 +120,9 @@ static const struct lc_time_T C_time_locale = {
static char * _add P((const char *, char *, const char *));
static char * _conv P((int, const char *, char *, const char *));
-static char * _lconv P((long, const char *, char *, const char *));
-static char * _fmt P((const char *, const struct tm *, char *, const char *, int *));
-
-size_t strftime P((char *, size_t, const char *, const struct tm *));
+static char * _fmt P((const char *, const struct tm *, char *, const char *,
+ int *));
+static char * _yconv P((int, int, int, int, char *, const char *));
extern char * tzname[];
@@ -137,7 +130,6 @@ extern char * tzname[];
#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
#endif /* !defined YEAR_2000_NAME */
-
#define IN_NONE 0
#define IN_SOME 1
#define IN_THIS 2
@@ -232,9 +224,8 @@ label:
** something completely different.
** (ado, 1993-05-24)
*/
- pt = _conv((int) ((t->tm_year +
- (long) TM_YEAR_BASE) / 100),
- "%02d", pt, ptlim);
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
+ pt, ptlim);
continue;
case 'c':
{
@@ -289,7 +280,7 @@ label:
** t->tm_hour % 12 : 12, 2, ' ');
** ...and has been changed to the below to
** match SunOS 4.1.1 and Arnold Robbins'
- ** strftime version 3.0. That is, "%k" and
+ ** strftime version 3.0. That is, "%k" and
** "%l" have been swapped.
** (ado, 1993-05-24)
*/
@@ -309,7 +300,7 @@ label:
** _conv(t->tm_hour, 2, ' ');
** ...and has been changed to the below to
** match SunOS 4.1.1 and Arnold Robbin's
- ** strftime version 3.0. That is, "%k" and
+ ** strftime version 3.0. That is, "%k" and
** "%l" have been swapped.
** (ado, 1993-05-24)
*/
@@ -384,7 +375,7 @@ label:
case 'G': /* ISO 8601 year (four digits) */
case 'g': /* ISO 8601 year (two digits) */
/*
-** From Arnold Robbins' strftime version 3.0: "the week number of the
+** From Arnold Robbins' strftime version 3.0: "the week number of the
** year (the first Monday as the first day of week 1) as a decimal number
** (01-53)."
** (ado, 1993-05-24)
@@ -397,18 +388,19 @@ label:
** might also contain days from the previous year and the week before week
** 01 of a year is the last week (52 or 53) of the previous year even if
** it contains days from the new year. A week starts with Monday (day 1)
-** and ends with Sunday (day 7). For example, the first week of the year
+** and ends with Sunday (day 7). For example, the first week of the year
** 1997 lasts from 1996-12-30 to 1997-01-05..."
** (ado, 1996-01-02)
*/
{
- long year;
+ int year;
+ int base;
int yday;
int wday;
int w;
year = t->tm_year;
- year += TM_YEAR_BASE;
+ base = TM_YEAR_BASE;
yday = t->tm_yday;
wday = t->tm_wday;
for ( ; ; ) {
@@ -416,7 +408,7 @@ label:
int bot;
int top;
- len = isleap(year) ?
+ len = isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
/*
@@ -435,7 +427,7 @@ label:
top += DAYSPERWEEK;
top += len;
if (yday >= top) {
- ++year;
+ ++base;
w = 1;
break;
}
@@ -444,8 +436,8 @@ label:
DAYSPERWEEK);
break;
}
- --year;
- yday += isleap(year) ?
+ --base;
+ yday += isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
}
@@ -461,9 +453,9 @@ label:
pt, ptlim);
else if (*format == 'g') {
*warnp = IN_ALL;
- pt = _conv((int) (year % 100),
- "%02d", pt, ptlim);
- } else pt = _lconv(year, "%04ld",
+ pt = _yconv(year, base, 0, 1,
+ pt, ptlim);
+ } else pt = _yconv(year, base, 1, 1,
pt, ptlim);
}
continue;
@@ -501,13 +493,12 @@ label:
continue;
case 'y':
*warnp = IN_ALL;
- pt = _conv((int) ((t->tm_year +
- (long) TM_YEAR_BASE) % 100),
- "%02d", pt, ptlim);
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
+ pt, ptlim);
continue;
case 'Y':
- pt = _lconv(t->tm_year + (long) TM_YEAR_BASE,
- "%04ld", pt, ptlim);
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
+ pt, ptlim);
continue;
case 'Z':
#ifdef TM_ZONE
@@ -537,12 +528,12 @@ label:
/*
** C99 says that the UTC offset must
** be computed by looking only at
- ** tm_isdst. This requirement is
+ ** tm_isdst. This requirement is
** incorrect, since it means the code
** must rely on magic (in this case
** altzone and timezone), and the
** magic might not have the correct
- ** offset. Doing things correctly is
+ ** offset. Doing things correctly is
** tricky and requires disobeying C99;
** see GNU C strftime for details.
** For now, punt and conform to the
@@ -571,9 +562,10 @@ label:
diff = -diff;
} else sign = "+";
pt = _add(sign, pt, ptlim);
- diff /= 60;
- pt = _conv((diff/60)*100 + diff%60,
- "%04d", pt, ptlim);
+ diff /= SECSPERMIN;
+ diff = (diff / MINSPERHOUR) * 100 +
+ (diff % MINSPERHOUR);
+ pt = _conv(diff, "%04d", pt, ptlim);
}
continue;
case '+':
@@ -583,7 +575,7 @@ label:
case '%':
/*
** X311J/88-090 (4.12.3.5): if conversion char is
- ** undefined, behavior is undefined. Print out the
+ ** undefined, behavior is undefined. Print out the
** character itself as printf(3) also does.
*/
default:
@@ -611,26 +603,54 @@ const char * const ptlim;
}
static char *
-_lconv(n, format, pt, ptlim)
-const long n;
-const char * const format;
-char * const pt;
+_add(str, pt, ptlim)
+const char * str;
+char * pt;
const char * const ptlim;
{
- char buf[INT_STRLEN_MAXIMUM(long) + 1];
-
- (void) snprintf(buf, sizeof buf, format, n);
- return _add(buf, pt, ptlim);
+ while (pt < ptlim && (*pt = *str++) != '\0')
+ ++pt;
+ return pt;
}
+/*
+** POSIX and the C Standard are unclear or inconsistent about
+** what %C and %y do if the year is negative or exceeds 9999.
+** Use the convention that %C concatenated with %y yields the
+** same output as %Y, and that %Y contains at least 4 bytes,
+** with more only if necessary.
+*/
+
static char *
-_add(str, pt, ptlim)
-const char * str;
+_yconv(a, b, convert_top, convert_yy, pt, ptlim)
+const int a;
+const int b;
+const int convert_top;
+const int convert_yy;
char * pt;
const char * const ptlim;
{
- while (pt < ptlim && (*pt = *str++) != '\0')
- ++pt;
+ register int lead;
+ register int trail;
+
+#define DIVISOR 100
+ trail = a % DIVISOR + b % DIVISOR;
+ lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
+ trail %= DIVISOR;
+ if (trail < 0 && lead > 0) {
+ trail += DIVISOR;
+ --lead;
+ } else if (lead < 0 && trail > 0) {
+ trail -= DIVISOR;
+ ++lead;
+ }
+ if (convert_top) {
+ if (lead == 0 && trail < 0)
+ pt = _add("-0", pt, ptlim);
+ else pt = _conv(lead, "%02d", pt, ptlim);
+ }
+ if (convert_yy)
+ pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt, ptlim);
return pt;
}
@@ -679,7 +699,7 @@ _loc P((void))
** Slurp the locale file into the cache.
*/
namesize = strlen(name) + 1;
- if (sizeof filename <
+ if (sizeof filename <
((sizeof locale_home) + namesize + (sizeof lc_time)))
goto no_locale;
oldsun = 0;
diff --git a/lib/libc/time/tz-art.htm b/lib/libc/time/tz-art.htm
index 56f78ace2e0..962246d74c1 100644
--- a/lib/libc/time/tz-art.htm
+++ b/lib/libc/time/tz-art.htm
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="US-ASCII"?>
-<!DOCTYPE html
+<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
@@ -10,7 +10,7 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
<body>
<h1>Time and the Arts</h1>
<address>
-@(#)tz-art.htm 7.53
+@(#)tz-art.htm 7.54
</address>
<p>
Please send corrections to this web page to the
diff --git a/lib/libc/time/tz-link.htm b/lib/libc/time/tz-link.htm
index e55d1f6a288..76ae60be8b7 100644
--- a/lib/libc/time/tz-link.htm
+++ b/lib/libc/time/tz-link.htm
@@ -9,7 +9,7 @@
<meta http-equiv="Content-type" content='text/html; charset="US-ASCII"' />
<meta name="DC.Creator" content="Eggert, Paul" />
<meta name="DC.Contributor" content="Olson, Arthur David" />
-<meta name="DC.Date" content="2004-09-22" />
+<meta name="DC.Date" content="2005-03-11" />
<meta name="DC.Description"
content="Sources of information about time zones and daylight saving time" />
<meta name="DC.Identifier" content="http://www.twinsun.com/tz/tz-link.htm" />
@@ -19,7 +19,7 @@
<body>
<h1>Sources for Time Zone and Daylight Saving Time Data</h1>
<address>
-@(#)tz-link.htm 7.44
+@(#)tz-link.htm 7.48
</address>
<p>
Please send corrections to this web page to the
@@ -36,9 +36,9 @@ This database (often called <code>tz</code> or <code>zoneinfo</code>)
is used by several implementations,
including
<a href="http://www.gnu.org/software/libc/">the
-<acronym title="GNU's Not Unix">GNU</acronym>
+<abbr title="GNU's Not Unix">GNU</abbr>
C Library</a> used in
-<a href="http://www.linux.org/"><acronym>GNU</acronym>/Linux</a>,
+<a href="http://www.linux.org/"><abbr>GNU</abbr>/Linux</a>,
<a href="http://www.freebsd.org/">FreeBSD</a>,
<a href="http://www.netbsd.org/">NetBSD</a>,
<a href="http://www.openbsd.org/">OpenBSD</a>,
@@ -80,7 +80,7 @@ where <code><var>C</var></code> is the code's version;
similarly, the data are in <code>tzdata<var>D</var>.tar.gz</code>,
where <code><var>D</var></code> is the data's version.
The following shell commands download
-these files to a <acronym>GNU</acronym>/Linux or similar host;
+these files to a <abbr>GNU</abbr>/Linux or similar host;
see the downloaded
<code>README</code> file for what to do next.</p>
<pre style="margin-left: 2em"><code><a href="http://www.gnu.org/software/wget/">wget</a> 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
@@ -136,7 +136,9 @@ title="Internet Engineering Task Force">IETF</abbr>
Calendaring and Scheduling Working Group (<abbr
title="Calendaring and Scheduling Working Group">calsch</abbr>)</a>
covers time zone
-data; see its VTIMEZONE calendar component.</li>
+data; see its VTIMEZONE calendar component.
+The <a href='http://www.calconnect.org/'>Calendaring and Scheduling
+Consortium</a> is promoting further work in this area.</li>
<li>The <a
href="http://lists.w3.org/Archives/Public/www-rdf-calendar/">www-rdf-calendar</a>
list discusses <a
@@ -157,12 +159,12 @@ definition that corresponded to iCalendar.</li>
</ul>
<h2>Other <code>tz</code> compilers</h2>
<ul>
-<li><a href="http://www.dachaplin.dsl.pipex.com/vzic">Vzic iCalendar
+<li><a href="http://dialspace.dial.pipex.com/prod/dialspace/town/pipexdsl/s/asbm26/vzic/">Vzic iCalendar
Timezone Converter</a> describes a program Vzic that compiles
<code>tz</code> source into iCalendar-compatible VTIMEZONE files.
Vzic is freely
available under the <a
-href="http://www.gnu.org/copyleft/gpl.html"><acronym>GNU</acronym>
+href="http://www.gnu.org/copyleft/gpl.html"><abbr>GNU</abbr>
General Public License (<abbr
title="General Public License">GPL</abbr>)</a>.</li>
<li><a
@@ -178,7 +180,7 @@ transition in the <code>tz</code> database.</li>
<li><a href="http://oss.software.ibm.com/icu/"><abbr
title="International Components for Unicode">ICU</abbr></a>
contains a C/C++ library for internationalization that
-has a compiler from <samp>tz</samp> source
+has a compiler from <code>tz</code> source
into an <abbr>ICU</abbr>-specific format.
<abbr>ICU</abbr> is freely available under a
<abbr title="Berkeley Software Distribution">BSD</abbr>-style license.</li>
@@ -196,18 +198,18 @@ It is freely available under a <abbr>BSD</abbr>-style license.</li>
<h2>Other <code>tz</code> binary file readers</h2>
<ul>
<li>The <a
-href="http://www.gnu.org/software/libc/"><acronym>GNU</acronym> C
+href="http://www.gnu.org/software/libc/"><abbr>GNU</abbr> C
Library</a>
has an independent, thread-safe implementation of
a <code>tz</code> binary file reader.
This library is freely available under the
<a href="http://www.gnu.org/copyleft/lesser.html">
-<acronym>GNU</acronym> Lesser General Public License
+<abbr>GNU</abbr> Lesser General Public License
(<abbr title="Lesser General Public License">LGPL</abbr>)</a>,
-and is widely used in <acronym>GNU</acronym>/Linux systems.</li>
+and is widely used in <abbr>GNU</abbr>/Linux systems.</li>
<li><a href="http://www.bmsi.com/java/#TZ">ZoneInfo.java</a>
is a <code>tz</code> binary file reader written in Java.
-It is freely available under the <acronym>GNU</acronym>
+It is freely available under the <abbr>GNU</abbr>
<abbr>LGPL</abbr>.</li>
<li><a href="http://s.keim.free.fr/tz/doc.html">Python time zones</a>
is a <code>tz</code> binary file reader written in Python.
@@ -216,12 +218,17 @@ It is freely available under a <abbr>BSD</abbr>-style license.</li>
<h2>Other <code>tz</code>-based time zone conversion software</h2>
<ul>
<li><a href="http://java.sun.com/">Sun Java</a> releases since 1.4
-contain a copy of a subset of a recent <samp>tz</samp> database in a
+contain a copy of a subset of a recent <code>tz</code> database in a
Java-specific format.</li>
<li><a
href="http://www1.tip.nl/~t876506/AboutTimeZonesHC.html">HyperCard
time zones calculator</a> is a HyperCard stack.</li>
<li><a
+href="http://www.veladg.com/velaterra.html">VelaTerra</a> is
+a Mac OS X program. Its developers
+<a href="http://www.veladg.com/tzoffer.html">offer free
+licenses</a> to <code>tz</code> contributors.</li>
+<li><a
href="http://www.cimmyt.org/timezone/">World Time Explorer</a> is a
Microsoft Windows program.</li>
</ul>
@@ -243,10 +250,7 @@ is another time zone database.</li>
contains data from the Time Service Department of the
<abbr>US</abbr> Naval Observatory, used as the source
for the <code>usno*</code> files in the <code>tz</code> distribution.</li>
-<li><a href="http://www.airportcitycodes.com/aaa/">Airlines, Airplanes
-and Airports</a> lists current standard times for thousands of
-airports around the world. This seems to be derived from
-the <a href="http://www.iata.org/ps/publications/9179.htm">Standard
+<li>The <a href="http://www.iata.org/ps/publications/9179.htm">Standard
Schedules Information Manual</a> of the
the <a href="http://www.iata.org/">International Air Transport
Association</a>,
@@ -285,7 +289,7 @@ zone boundaries for multizone countries</a> summarizes legal
boundaries between time zones within countries.</li>
<li>Manifold.net's <a
href="http://www.manifold.net/download/freemaps.html">Free Maps and
-<acronym title="Geographic Information Systems">GIS</acronym>
+<abbr title="Geographic Information Systems">GIS</abbr>
Data</a> includes a Manifold-format map of
world time zone boundaries distributed under the
<abbr>GPL</abbr>.</li>
@@ -299,11 +303,15 @@ Time Zones and Time Zone Data</a>.</li>
</ul>
<h2>Civil time concepts and history</h2>
<ul>
-<li><a href="http://physics.nist.gov/time">A Walk through Time</a>
+<li><a href="http://physics.nist.gov/GenInt/Time/time.html">A
+Walk through Time</a>
surveys the evolution of timekeeping.</li>
<li><a href="http://webexhibits.org/daylightsaving/">About Daylight
Saving Time - History, rationale, laws &amp; dates</a>
is an overall history of <abbr>DST</abbr>.</li>
+<li><a href="http://www.seizethedaylight.com/dst/">Who Knew? A Brief
+History of Daylight Saving Time</a> summarizes some of the contentious
+history of <abbr>DST</abbr>.</li>
<li><a href="http://toi.iriti.cnr.it/">The
Time of Internet</a>
describes time zones and daylight saving time,
@@ -410,8 +418,8 @@ Times</a> explains more abstruse astronomical time scales like
<abbr title="Barycentric Dynamic Time">TDB</abbr>.</li>
<li>The <a href="http://www.iau.org/"><abbr
title="International Astronomical Union">IAU</abbr></a>'s <a
-href="http://www.iau-sofa.rl.ac.uk/"><acronym
-title="Standards Of Fundamental Astronomy">SOFA</acronym></a>
+href="http://www.iau-sofa.rl.ac.uk/"><abbr
+title="Standards Of Fundamental Astronomy">SOFA</abbr></a>
initiative publishes Fortran
code for converting among time scales like
<abbr title="International Atomic Time">TAI</abbr>,
@@ -447,7 +455,7 @@ title="Global Positioning System">GPS</abbr> World</a>
(1999-11), 50&ndash;57 and discussed further in R. A. Nelson et al.,
<a href="http://www.cl.cam.ac.uk/~mgk25/time/metrologia-leapsecond.pdf">The
leap second: its history and possible future</a>,
-<a href="http://www.bipm.fr/metrologia/metrologia.html">Metrologia</a>
+<a href="http://www.bipm.fr/metrologia/">Metrologia</a>
<strong>38</strong> (2001), 509&ndash;529.
<a href="http://www.ucolick.org/~sla/leapsecs/onlinebib.html">The
Future of Leap Seconds</a> catalogs information about this
@@ -459,12 +467,11 @@ contentious issue.</li>
<a href="http://www.cl.cam.ac.uk/~mgk25/iso-time.html">A Summary of
the International Standard Date and Time Notation</a> is a good
summary of
-<abbr title="International Organization for Standardization">ISO</abbr>
-8601:1988 - Data elements and interchange formats - Information interchange
-- Representation of dates and times (which has been superseded by
<a
-href="http://www.iso.org/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780"><abbr>ISO</abbr>
-8601:2000</a>).</li>
+href="http://www.iso.org/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=40874"><abbr
+title="International Organization for Standardization">ISO</abbr>
+8601:2004 -- Data elements and interchange formats -- Information
+interchange -- Representation of dates and times</a>.</li>
<li>
Section 3.3 of <a
href="ftp://ftp.rfc-editor.org/in-notes/rfc2822.txt">Internet
@@ -482,13 +489,21 @@ protocols.</li>
Best of Dates, the Worst of Dates</a> covers many problems encountered
by software developers when handling dates and time stamps.</li>
<li><a
-href="http://oss.software.ibm.com/cvs/icu/~checkout~/icuhtml/design/formatting/time_zone_localization.html">Time
-Zone Localization</a> is a proposed mechanism for localizing time zone
-labels and abbreviations; for example, one might use it to specify
+href="http://ibm.com/software/globalization/icu"><abbr
+title="International Components for Unicode">ICU</abbr></a> contains a
+mechanism for localizing time zone
+labels and abbreviations; for example, one can use it to specify
Russian translations for "Eastern European Summer Time",
"<abbr title="Eastern European Summer Time">EEST</abbr>",
-and <code>Europe/Bucharest</code>.</li>
-<li> Alphabetic time zone abbreviations should not be used as unique
+and <code>Europe/Bucharest</code>.
+This mechanism is part of the
+<a href="http://unicode.org/cldr/">Unicode
+<abbr title="Common Locale Data Repository">CLDR</abbr> Project</a>;
+for example, the <a
+href="http://www.unicode.org/cldr/data/diff/by_type/dates_timeZoneNames.html">By-Type
+Chart for //ldml/dates/timeZoneNames/&hellip;</a>
+shows values for time zone names in many locales.</li>
+<li>Alphabetic time zone abbreviations should not be used as unique
identifiers for <abbr>UTC</abbr> offsets as they are ambiguous in
practice. For example, "<abbr>EST</abbr>" denotes 5 hours behind
<abbr>UTC</abbr> in English-speaking North America, but it denotes 10
@@ -499,6 +514,21 @@ French-speaking North Americans prefer
database contains English abbreviations for all time stamps but in
many cases these are merely inventions of the database
maintainers.</li>
+<li>Numeric time zone abbreviations typically count hours east of
+<abbr>UTC</abbr>, e.g., <code>+09</code> for Japan and
+<code>-10</code> for Hawaii. However, the <abbr>POSIX</abbr>
+<code>TZ</code> environment variable uses the opposite convention. For
+example, one might use <code>TZ="JST-9"</code> and
+<code>TZ="HST10"</code> for Japan and Hawaii, respectively. If the
+<code>tz</code> database is available, it is usually better to use
+settings like <code>TZ="Asia/Tokyo"</code> and
+<code>TZ="Pacific/Honolulu"</code> instead, as this should avoid
+confusion, handle old timestamps better, and insulate you better from
+any future changes to the rules. One should never set
+<abbr>POSIX</abbr> <code>TZ</code> to a value like
+<code>"GMT-9"</code>, though, since this would falsely claim that
+local time is nine hours ahead of <abbr>UTC</abbr> and the time zone
+is called "<abbr>GMT</abbr>".</li>
</ul>
<h2>Related indexes</h2>
<ul>
diff --git a/lib/libc/time/tzfile.h b/lib/libc/time/tzfile.h
index 40331f46bc6..96d7d05a3ff 100644
--- a/lib/libc/time/tzfile.h
+++ b/lib/libc/time/tzfile.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tzfile.h,v 1.5 1998/01/18 23:25:00 millert Exp $ */
+/* $OpenBSD: tzfile.h,v 1.6 2005/07/05 13:40:51 millert Exp $ */
#ifndef TZFILE_H
@@ -24,7 +24,7 @@
#if 0
#ifndef lint
#ifndef NOID
-static char tzfilehid[] = "@(#)tzfile.h 7.14";
+static char tzfilehid[] = "@(#)tzfile.h 7.17";
#endif /* !defined NOID */
#endif /* !defined lint */
#endif
@@ -160,33 +160,20 @@ struct tzhead {
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY
-/*
-** Accurate only for the past couple of centuries;
-** that will probably do.
-*/
-
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
-#ifndef USG
-
/*
-** Use of the underscored variants may cause problems if you move your code to
-** certain System-V-based systems; for maximum portability, use the
-** underscore-free variants. The underscored variants are provided for
-** backward compatibility only; they may disappear from future versions of
-** this file.
+** Since everything in isleap is modulo 400 (or a factor of 400), we know that
+** isleap(y) == isleap(y % 400)
+** and so
+** isleap(a + b) == isleap((a + b) % 400)
+** or
+** isleap(a + b) == isleap(a % 400 + b % 400)
+** This is true even if % means modulo rather than Fortran remainder
+** (which is allowed by C89 but not C99).
+** We use this to avoid addition overflow problems.
*/
-#define SECS_PER_MIN SECSPERMIN
-#define MINS_PER_HOUR MINSPERHOUR
-#define HOURS_PER_DAY HOURSPERDAY
-#define DAYS_PER_WEEK DAYSPERWEEK
-#define DAYS_PER_NYEAR DAYSPERNYEAR
-#define DAYS_PER_LYEAR DAYSPERLYEAR
-#define SECS_PER_HOUR SECSPERHOUR
-#define SECS_PER_DAY SECSPERDAY
-#define MONS_PER_YEAR MONSPERYEAR
-
-#endif /* !defined USG */
+#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
#endif /* !defined TZFILE_H */
diff --git a/lib/libc/time/zdump.8 b/lib/libc/time/zdump.8
index 6eaa952075a..8819f8aa1da 100644
--- a/lib/libc/time/zdump.8
+++ b/lib/libc/time/zdump.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: zdump.8,v 1.9 2004/04/01 11:37:02 jmc Exp $
+.\" $OpenBSD: zdump.8,v 1.10 2005/07/05 13:40:51 millert Exp $
.Dd May 23, 1999
.Dt ZDUMP 8
.Os
@@ -8,7 +8,13 @@
.Sh SYNOPSIS
.Nm zdump
.Op Fl v
-.Op Fl c Ar cutoffyear
+.Sm off
+.Oo
+.Fl c No \ \&
+.Op Ar loyear,
+.Ar hiyear
+.Oc
+.Sm on
.Ar zonename Ar ...
.Sh DESCRIPTION
.Nm
@@ -18,8 +24,10 @@ named on the command line.
.Pp
These options are available:
.Bl -tag -width Fl
-.It Fl c Ar cutoffyear
-Cut off the verbose output near the start of the given year.
+.It Fl c Ar Op loyear, Ns hiyear
+Cut off verbose output near the start of the given year(s).
+By default,
+the program cuts off verbose output near the starts of the years -500 and 2500.
.It Fl v
For each
.Ar zonename
@@ -36,10 +44,21 @@ if the given time is Daylight Saving Time or
.Dq isdst=0
otherwise.
.El
+.Sh LIMITATIONS
+The
+.Fl v
+option may not be used on systems with floating-point
+.Li time_t
+values that are neither float nor double.
+.Pp
+Time discontinuities are found by sampling the results returned by localtime
+at twelve-hour intervals.
+This works in all real-world cases;
+one can construct artificial time zones for which this fails.
.Sh SEE ALSO
.Xr ctime 3 ,
.Xr tzfile 5 ,
.Xr zic 8
-.\" @(#)zdump.8 7.4
+.\" @(#)zdump.8 7.7
.\" This file is in the public domain, so clarified as of
.\" 2003-02-14 by Arthur David Olson (arthur_david_olson@nih.gov).
diff --git a/lib/libc/time/zdump.c b/lib/libc/time/zdump.c
index 77ba168f464..351dc65fa63 100644
--- a/lib/libc/time/zdump.c
+++ b/lib/libc/time/zdump.c
@@ -4,9 +4,8 @@
*/
#if defined(LIBC_SCCS) && !defined(lint) && !defined(NOID)
-static char elsieid[] = "@(#)zdump.c 7.31";
-static char rcsid[] = "$OpenBSD: zdump.c,v 1.15 2004/10/19 05:01:01 deraadt Exp $";
-static char elsieid[] = "@(#)zdump.c 7.40";
+static char elsieid[] = "@(#)zdump.c 7.65";
+static char rcsid[] = "$OpenBSD: zdump.c,v 1.16 2005/07/05 13:40:51 millert Exp $";
#endif /* LIBC_SCCS and not lint */
/*
@@ -17,9 +16,19 @@ static char elsieid[] = "@(#)zdump.c 7.40";
#include "stdio.h" /* for stdout, stderr, perror */
#include "string.h" /* for strlcpy */
+#include "ctype.h" /* for isascii, isalpha, isdigit */
#include "sys/types.h" /* for time_t */
#include "time.h" /* for struct tm */
#include "stdlib.h" /* for exit, malloc, atoi */
+#include "float.h" /* for FLT_MAX and DBL_MAX */
+
+#ifndef ZDUMP_LO_YEAR
+#define ZDUMP_LO_YEAR (-500)
+#endif /* !defined ZDUMP_LO_YEAR */
+
+#ifndef ZDUMP_HI_YEAR
+#define ZDUMP_HI_YEAR 2500
+#endif /* !defined ZDUMP_HI_YEAR */
#ifndef MAX_STRING_LENGTH
#define MAX_STRING_LENGTH 1024
@@ -70,9 +79,20 @@ static char elsieid[] = "@(#)zdump.c 7.40";
#endif /* !defined DAYSPERNYEAR */
#ifndef isleap
-#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
#endif /* !defined isleap */
+#ifndef isleap_sum
+/*
+** See tzfile.h for details on isleap_sum.
+*/
+#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
+#endif /* !defined isleap_sum */
+
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR)
+#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY)
+
#if HAVE_GETTEXT
#include "locale.h" /* for setlocale */
#include "libintl.h"
@@ -124,18 +144,100 @@ static char elsieid[] = "@(#)zdump.c 7.40";
extern char ** environ;
extern int getopt P((int argc, char * const argv[],
- const char * options));
+ const char * options));
extern char * optarg;
extern int optind;
extern char * tzname[2];
+static time_t absolute_min_time;
+static time_t absolute_max_time;
+static size_t longest;
+static char * progname;
+static int warned;
+
static char * abbr P((struct tm * tmp));
+static void abbrok P((const char * abbr, const char * zone));
static long delta P((struct tm * newp, struct tm * oldp));
+static void dumptime P((const struct tm * tmp));
static time_t hunt P((char * name, time_t lot, time_t hit));
-static size_t longest;
-static char * progname;
+static void setabsolutes P((void));
static void show P((char * zone, time_t t, int v));
-static void dumptime P((const struct tm * tmp));
+static const char * tformat P((void));
+static time_t yeartot P((long y));
+
+#ifndef TYPECHECK
+#define my_localtime localtime
+#else /* !defined TYPECHECK */
+static struct tm *
+my_localtime(tp)
+time_t * tp;
+{
+ register struct tm * tmp;
+
+ tmp = localtime(tp);
+ if (tp != NULL && tmp != NULL) {
+ struct tm tm;
+ register time_t t;
+
+ tm = *tmp;
+ t = mktime(&tm);
+ if (t - *tp >= 1 || *tp - t >= 1) {
+ (void) fflush(stdout);
+ (void) fprintf(stderr, "\n%s: ", progname);
+ (void) fprintf(stderr, tformat(), *tp);
+ (void) fprintf(stderr, " ->");
+ (void) fprintf(stderr, " year=%d", tmp->tm_year);
+ (void) fprintf(stderr, " mon=%d", tmp->tm_mon);
+ (void) fprintf(stderr, " mday=%d", tmp->tm_mday);
+ (void) fprintf(stderr, " hour=%d", tmp->tm_hour);
+ (void) fprintf(stderr, " min=%d", tmp->tm_min);
+ (void) fprintf(stderr, " sec=%d", tmp->tm_sec);
+ (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
+ (void) fprintf(stderr, " -> ");
+ (void) fprintf(stderr, tformat(), t);
+ (void) fprintf(stderr, "\n");
+ }
+ }
+ return tmp;
+}
+#endif /* !defined TYPECHECK */
+
+static void
+abbrok(abbr, zone)
+const char * const abbr;
+const char * const zone;
+{
+ register const char * cp;
+ register char * wp;
+
+ if (warned)
+ return;
+ cp = abbr;
+ wp = NULL;
+ while (isascii(*cp) && isalpha(*cp))
+ ++cp;
+ if (cp - abbr == 0)
+ wp = _("lacks alphabetic at start");
+ if (cp - abbr < 3)
+ wp = _("has fewer than 3 alphabetics");
+ if (cp - abbr > 6)
+ wp = _("has more than 6 alphabetics");
+ if (wp == NULL && (*cp == '+' || *cp == '-')) {
+ ++cp;
+ if (isascii(*cp) && isdigit(*cp))
+ if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
+ ++cp;
+ }
+ if (*cp != '\0')
+ wp = _("differs from POSIX standard");
+ if (wp == NULL)
+ return;
+ (void) fflush(stdout);
+ (void) fprintf(stderr,
+ "%s: warning: zone \"%s\" abbreviation \"%s\" %s\n",
+ progname, zone, abbr, wp);
+ warned = TRUE;
+}
int
main(argc, argv)
@@ -145,20 +247,24 @@ char * argv[];
register int i;
register int c;
register int vflag;
- register char * cutoff;
- register int cutyear;
- register long cuttime;
- char ** fakeenv;
+ register char * cutarg;
+ register long cutloyear = ZDUMP_LO_YEAR;
+ register long cuthiyear = ZDUMP_HI_YEAR;
+ register time_t cutlotime;
+ register time_t cuthitime;
+ register char ** fakeenv;
time_t now;
time_t t;
time_t newt;
- time_t hibit;
struct tm tm;
struct tm newtm;
+ register struct tm * tmp;
+ register struct tm * newtmp;
- INITIALIZE(cuttime);
+ INITIALIZE(cutlotime);
+ INITIALIZE(cuthitime);
#if HAVE_GETTEXT
- (void) setlocale(LC_MESSAGES, "");
+ (void) setlocale(LC_ALL, "");
#ifdef TZ_DOMAINDIR
(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
#endif /* defined TEXTDOMAINDIR */
@@ -166,39 +272,50 @@ char * argv[];
#endif /* HAVE_GETTEXT */
progname = argv[0];
vflag = 0;
- cutoff = NULL;
+ cutarg = NULL;
while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
if (c == 'v')
vflag = 1;
- else cutoff = optarg;
+ else cutarg = optarg;
if ((c != EOF && c != -1) ||
(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
(void) fprintf(stderr,
-_("%s: usage is %s [-v] [-c cutoffyear] zonename ...\n"),
- argv[0], argv[0]);
+_("usage %s [-v] [-c [loyear,]hiyear] zonename ...\n"),
+ progname);
(void) exit(EXIT_FAILURE);
}
- if (cutoff != NULL) {
- int y;
-
- cutyear = atoi(cutoff);
- cuttime = 0;
- for (y = EPOCH_YEAR; y < cutyear; ++y)
- cuttime += DAYSPERNYEAR + isleap(y);
- cuttime *= SECSPERHOUR * HOURSPERDAY;
+ if (vflag) {
+ if (cutarg != NULL) {
+ long lo;
+ long hi;
+ char dummy;
+
+ if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
+ cuthiyear = hi;
+ } else if (sscanf(cutarg, "%ld,%ld%c",
+ &lo, &hi, &dummy) == 2) {
+ cutloyear = lo;
+ cuthiyear = hi;
+ } else {
+(void) fprintf(stderr, _("%s: wild -c argument %s\n"),
+ progname, cutarg);
+ (void) exit(EXIT_FAILURE);
+ }
+ }
+ setabsolutes();
+ cutlotime = yeartot(cutloyear);
+ cuthitime = yeartot(cuthiyear);
}
(void) time(&now);
longest = 0;
for (i = optind; i < argc; ++i)
if (strlen(argv[i]) > longest)
longest = strlen(argv[i]);
- for (hibit = 1; (hibit << 1) != 0; hibit <<= 1)
- continue;
{
register int from;
register int to;
- for (i = 0; environ[i] != NULL; ++i)
+ for (i = 0; environ[i] != NULL; ++i)
continue;
fakeenv = (char **) malloc((size_t) ((i + 2) *
sizeof *fakeenv));
@@ -223,58 +340,129 @@ _("%s: usage is %s [-v] [-c cutoffyear] zonename ...\n"),
show(argv[i], now, FALSE);
continue;
}
- /*
- ** Get lowest value of t.
- */
- t = hibit;
- if (t > 0) /* time_t is unsigned */
- t = 0;
+ warned = FALSE;
+ t = absolute_min_time;
show(argv[i], t, TRUE);
t += SECSPERHOUR * HOURSPERDAY;
show(argv[i], t, TRUE);
- tm = *localtime(&t);
- strlcpy(buf, abbr(&tm), (sizeof buf));
+ if (t < cutlotime)
+ t = cutlotime;
+ tmp = my_localtime(&t);
+ if (tmp != NULL) {
+ tm = *tmp;
+ strlcpy(buf, abbr(&tm), sizeof buf);
+ }
for ( ; ; ) {
- if (cutoff != NULL && t >= cuttime)
+ if (t >= cuthitime)
break;
newt = t + SECSPERHOUR * 12;
- if (cutoff != NULL && newt >= cuttime)
+ if (newt >= cuthitime)
break;
if (newt <= t)
break;
- newtm = *localtime(&newt);
- if (delta(&newtm, &tm) != (newt - t) ||
+ newtmp = localtime(&newt);
+ if (newtmp != NULL)
+ newtm = *newtmp;
+ if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
+ (delta(&newtm, &tm) != (newt - t) ||
newtm.tm_isdst != tm.tm_isdst ||
- strcmp(abbr(&newtm), buf) != 0) {
+ strcmp(abbr(&newtm), buf) != 0)) {
newt = hunt(argv[i], t, newt);
- newtm = *localtime(&newt);
- strlcpy(buf, abbr(&newtm),
- (sizeof buf));
+ newtmp = localtime(&newt);
+ if (newtmp != NULL) {
+ newtm = *newtmp;
+ strlcpy(buf, abbr(&newtm),
+ sizeof buf);
+ }
}
t = newt;
tm = newtm;
+ tmp = newtmp;
}
- /*
- ** Get highest value of t.
- */
- t = ~((time_t) 0);
- if (t < 0) /* time_t is signed */
- t &= ~hibit;
+ t = absolute_max_time;
t -= SECSPERHOUR * HOURSPERDAY;
show(argv[i], t, TRUE);
t += SECSPERHOUR * HOURSPERDAY;
show(argv[i], t, TRUE);
}
if (fflush(stdout) || ferror(stdout)) {
- (void) fprintf(stderr, "%s: ", argv[0]);
+ (void) fprintf(stderr, "%s: ", progname);
(void) perror(_("Error writing standard output"));
(void) exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
+ /* If exit fails to exit... */
+ return EXIT_FAILURE;
+}
- /* gcc -Wall pacifier */
- for ( ; ; )
- continue;
+static void
+setabsolutes()
+{
+ if (0.5 == (time_t) 0.5) {
+ /*
+ ** time_t is floating.
+ */
+ if (sizeof (time_t) == sizeof (float)) {
+ absolute_min_time = (time_t) -FLT_MAX;
+ absolute_max_time = (time_t) FLT_MAX;
+ } else if (sizeof (time_t) == sizeof (double)) {
+ absolute_min_time = (time_t) -DBL_MAX;
+ absolute_max_time = (time_t) DBL_MAX;
+ } else {
+ (void) fprintf(stderr,
+_("%s: use of -v on system with floating time_t other than float or double\n"),
+ progname);
+ (void) exit(EXIT_FAILURE);
+ }
+ } else if (0 > (time_t) -1) {
+ /*
+ ** time_t is signed.
+ */
+ register time_t hibit;
+
+ for (hibit = 1; (hibit * 2) != 0; hibit *= 2)
+ continue;
+ absolute_min_time = hibit;
+ absolute_max_time = -(hibit + 1);
+ } else {
+ /*
+ ** time_t is unsigned.
+ */
+ absolute_min_time = 0;
+ absolute_max_time = absolute_min_time - 1;
+ }
+}
+
+static time_t
+yeartot(y)
+const long y;
+{
+ register long myy;
+ register long seconds;
+ register time_t t;
+
+ myy = EPOCH_YEAR;
+ t = 0;
+ while (myy != y) {
+ if (myy < y) {
+ seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
+ ++myy;
+ if (t > absolute_max_time - seconds) {
+ t = absolute_max_time;
+ break;
+ }
+ t += seconds;
+ } else {
+ --myy;
+ seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
+ if (t < absolute_min_time + seconds) {
+ t = absolute_min_time;
+ break;
+ }
+ t -= seconds;
+ }
+ }
+ return t;
}
static time_t
@@ -283,25 +471,39 @@ char * name;
time_t lot;
time_t hit;
{
- time_t t;
- struct tm lotm;
- struct tm tm;
- static char loab[MAX_STRING_LENGTH];
-
- lotm = *localtime(&lot);
- strlcpy(loab, abbr(&lotm), (sizeof loab));
- while ((hit - lot) >= 2) {
- t = lot / 2 + hit / 2;
+ time_t t;
+ long diff;
+ struct tm lotm;
+ register struct tm * lotmp;
+ struct tm tm;
+ register struct tm * tmp;
+ char loab[MAX_STRING_LENGTH];
+
+ lotmp = my_localtime(&lot);
+ if (lotmp != NULL) {
+ lotm = *lotmp;
+ (void) strlcpy(loab, abbr(&lotm), sizeof loab);
+ }
+ for ( ; ; ) {
+ diff = (long) (hit - lot);
+ if (diff < 2)
+ break;
+ t = lot;
+ t += diff / 2;
if (t <= lot)
++t;
else if (t >= hit)
--t;
- tm = *localtime(&t);
- if (delta(&tm, &lotm) == (t - lot) &&
+ tmp = my_localtime(&t);
+ if (tmp != NULL)
+ tm = *tmp;
+ if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
+ (delta(&tm, &lotm) == (t - lot) &&
tm.tm_isdst == lotm.tm_isdst &&
- strcmp(abbr(&tm), loab) == 0) {
+ strcmp(abbr(&tm), loab) == 0)) {
lot = t;
lotm = tm;
+ lotmp = tmp;
} else hit = t;
}
show(name, lot, TRUE);
@@ -318,14 +520,14 @@ delta(newp, oldp)
struct tm * newp;
struct tm * oldp;
{
- long result;
- int tmy;
+ register long result;
+ register int tmy;
if (newp->tm_year < oldp->tm_year)
return -delta(oldp, newp);
result = 0;
for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
- result += DAYSPERNYEAR + isleap(tmy + (long) TM_YEAR_BASE);
+ result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
result += newp->tm_yday - oldp->tm_yday;
result *= HOURSPERDAY;
result += newp->tm_hour - oldp->tm_hour;
@@ -342,24 +544,34 @@ char * zone;
time_t t;
int v;
{
- struct tm * tmp;
+ register struct tm * tmp;
(void) printf("%-*s ", (int) longest, zone);
if (v) {
- dumptime(gmtime(&t));
- (void) printf(" UTC = ");
+ tmp = gmtime(&t);
+ if (tmp == NULL) {
+ (void) printf(tformat(), t);
+ } else {
+ dumptime(tmp);
+ (void) printf(" UTC");
+ }
+ (void) printf(" = ");
}
- tmp = localtime(&t);
+ tmp = my_localtime(&t);
dumptime(tmp);
- if (*abbr(tmp) != '\0')
- (void) printf(" %s", abbr(tmp));
- if (v) {
- (void) printf(" isdst=%d", tmp->tm_isdst);
+ if (tmp != NULL) {
+ if (*abbr(tmp) != '\0')
+ (void) printf(" %s", abbr(tmp));
+ if (v) {
+ (void) printf(" isdst=%d", tmp->tm_isdst);
#ifdef TM_GMTOFF
- (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
+ (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
#endif /* defined TM_GMTOFF */
+ }
}
(void) printf("\n");
+ if (tmp != NULL && *abbr(tmp) != '\0')
+ abbrok(abbr(tmp), zone);
}
static char *
@@ -375,6 +587,33 @@ struct tm * tmp;
return (result == NULL) ? &nada : result;
}
+/*
+** The code below can fail on certain theoretical systems;
+** it works on all known real-world systems as of 2004-12-30.
+*/
+
+static const char *
+tformat()
+{
+ if (0.5 == (time_t) 0.5) { /* floating */
+ if (sizeof (time_t) > sizeof (double))
+ return "%Lg";
+ return "%g";
+ }
+ if (0 > (time_t) -1) { /* signed */
+ if (sizeof (time_t) > sizeof (long))
+ return "%lld";
+ if (sizeof (time_t) > sizeof (int))
+ return "%ld";
+ return "%d";
+ }
+ if (sizeof (time_t) > sizeof (unsigned long))
+ return "%llu";
+ if (sizeof (time_t) > sizeof (unsigned int))
+ return "%lu";
+ return "%u";
+}
+
static void
dumptime(timeptr)
register const struct tm * timeptr;
@@ -388,7 +627,13 @@ register const struct tm * timeptr;
};
register const char * wn;
register const char * mn;
+ register int lead;
+ register int trail;
+ if (timeptr == NULL) {
+ (void) printf("NULL");
+ return;
+ }
/*
** The packaged versions of localtime and gmtime never put out-of-range
** values in tm_wday or tm_mon, but since this code might be compiled
@@ -402,9 +647,23 @@ register const struct tm * timeptr;
(int) (sizeof mon_name / sizeof mon_name[0]))
mn = "???";
else mn = mon_name[timeptr->tm_mon];
- (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d %ld",
+ (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
wn, mn,
timeptr->tm_mday, timeptr->tm_hour,
- timeptr->tm_min, timeptr->tm_sec,
- timeptr->tm_year + (long) TM_YEAR_BASE);
+ timeptr->tm_min, timeptr->tm_sec);
+#define DIVISOR 10
+ trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
+ lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
+ trail / DIVISOR;
+ trail %= DIVISOR;
+ if (trail < 0 && lead > 0) {
+ trail += DIVISOR;
+ --lead;
+ } else if (lead < 0 && trail > 0) {
+ trail -= DIVISOR;
+ ++lead;
+ }
+ if (lead == 0)
+ (void) printf("%d", trail);
+ else (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
}
diff --git a/lib/libc/time/zic.c b/lib/libc/time/zic.c
index b813ecd191a..036534f9edd 100644
--- a/lib/libc/time/zic.c
+++ b/lib/libc/time/zic.c
@@ -4,14 +4,24 @@
*/
#if defined(LIBC_SCCS) && !defined(lint) && !defined(NOID)
-static char elsieid[] = "@(#)zic.c 7.116";
-static char rcsid[] = "$OpenBSD: zic.c,v 1.23 2004/06/28 14:47:41 millert Exp $";
+static char elsieid[] = "@(#)zic.c 7.124";
+static char rcsid[] = "$OpenBSD: zic.c,v 1.24 2005/07/05 13:40:51 millert Exp $";
#endif /* LIBC_SCCS and not lint */
+/*
+** Regardless of the type of time_t, we do our work using this type.
+*/
+
+typedef int zic_t;
+
#include "private.h"
#include "locale.h"
#include "tzfile.h"
+#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
+#define ZIC_MAX_ABBR_LEN_WO_WARN 6
+#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
+
#if HAVE_SYS_STAT_H
#include "sys/stat.h"
#endif
@@ -23,7 +33,7 @@ static char rcsid[] = "$OpenBSD: zic.c,v 1.23 2004/06/28 14:47:41 millert Exp $"
/*
** On some ancient hosts, predicates like `isspace(C)' are defined
-** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
+** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
** which says they are defined only if C == ((unsigned char) C) || C == EOF.
** Neither the C Standard nor Posix require that `isascii' exist.
** For portability, we check both ancient and modern requirements.
@@ -58,7 +68,7 @@ struct rule {
const char * r_abbrvar; /* variable part of abbreviation */
int r_todo; /* a rule to do (used in outzone) */
- time_t r_temp; /* used in outzone */
+ zic_t r_temp; /* used in outzone */
};
/*
@@ -84,7 +94,7 @@ struct zone {
int z_nrules;
struct rule z_untilrule;
- time_t z_untiltime;
+ zic_t z_untiltime;
};
extern int getopt P((int argc, char * const argv[],
@@ -93,10 +103,10 @@ extern int link P((const char * fromname, const char * toname));
extern char * optarg;
extern int optind;
-static void addtt P((time_t starttime, int type));
+static void addtt P((zic_t starttime, int type));
static int addtype P((long gmtoff, const char * abbr, int isdst,
int ttisstd, int ttisgmt));
-static void leapadd P((time_t t, int positive, int rolling, int count));
+static void leapadd P((zic_t t, int positive, int rolling, int count));
static void adjleap P((void));
static void associate P((void));
static int ciequal P((const char * ap, const char * bp));
@@ -129,30 +139,30 @@ static long oadd P((long t1, long t2));
static void outzone P((const struct zone * zp, int ntzones));
static void puttzcode P((long code, FILE * fp));
static int rcomp P((const void * leftp, const void * rightp));
-static time_t rpytime P((const struct rule * rp, int wantedy));
+static zic_t rpytime P((const struct rule * rp, int wantedy));
static void rulesub P((struct rule * rp,
const char * loyearp, const char * hiyearp,
const char * typep, const char * monthp,
const char * dayp, const char * timep));
static void setboundaries P((void));
-static time_t tadd P((time_t t1, long t2));
+static zic_t tadd P((zic_t t1, long t2));
static void usage P((void));
static void writezone P((const char * name));
static int yearistype P((int year, const char * type));
-#if !(HAVE_STRERROR - 0)
+#if !HAVE_STRERROR
static char * strerror P((int));
-#endif /* !(HAVE_STRERROR - 0) */
+#endif /* !HAVE_STRERROR */
static int charcnt;
static int errors;
static const char * filename;
static int leapcnt;
static int linenum;
-static time_t max_time;
+static zic_t max_time;
static int max_year;
static int max_year_representable;
-static time_t min_time;
+static zic_t min_time;
static int min_year;
static int min_year_representable;
static int noise;
@@ -342,7 +352,7 @@ static const int len_years[2] = {
};
static struct attype {
- time_t at;
+ zic_t at;
unsigned char type;
} attypes[TZ_MAX_TIMES];
static long gmtoffs[TZ_MAX_TYPES];
@@ -351,7 +361,7 @@ static unsigned char abbrinds[TZ_MAX_TYPES];
static char ttisstds[TZ_MAX_TYPES];
static char ttisgmts[TZ_MAX_TYPES];
static char chars[TZ_MAX_CHARS];
-static time_t trans[TZ_MAX_LEAPS];
+static zic_t trans[TZ_MAX_LEAPS];
static long corr[TZ_MAX_LEAPS];
static char roll[TZ_MAX_LEAPS];
@@ -382,7 +392,7 @@ char * const ptr;
** Error handling.
*/
-#if !(HAVE_STRERROR - 0)
+#if !HAVE_STRERROR
static char *
strerror(errnum)
int errnum;
@@ -393,7 +403,7 @@ int errnum;
return (errnum > 0 && errnum <= sys_nerr) ?
sys_errlist[errnum] : _("Unknown system error");
}
-#endif /* !(HAVE_STRERROR - 0) */
+#endif /* !HAVE_STRERROR */
static void
eats(name, num, rname, rnum)
@@ -450,8 +460,8 @@ const char * const string;
static void
usage P((void))
{
- (void) fprintf(stderr, _("%s: usage is %s [-sv] [-d directory] [-L leapsecondfilename] [-l timezone]\n\t[-p timezone] [-y command] [filename ...]\n"),
- progname, progname);
+ (void) fprintf(stderr, _("usage: %s [-sv] [-d directory] [-L leapsecondfilename] [-l timezone]\n\t[-p timezone] [-y command] [filename ...]\n"),
+ progname);
(void) exit(EXIT_FAILURE);
}
@@ -474,13 +484,13 @@ char * argv[];
#ifdef unix
(void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
#endif /* defined unix */
-#if HAVE_GETTEXT - 0
- (void) setlocale(LC_MESSAGES, "");
+#if HAVE_GETTEXT
+ (void) setlocale(LC_ALL, "");
#ifdef TZ_DOMAINDIR
(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
#endif /* defined TEXTDOMAINDIR */
(void) textdomain(TZ_DOMAIN);
-#endif /* HAVE_GETTEXT - 0 */
+#endif /* HAVE_GETTEXT */
progname = argv[0];
while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != -1)
switch (c) {
@@ -576,6 +586,11 @@ _("%s: More than one -L option specified\n"),
for (i = 0; i < nlinks; ++i) {
eat(links[i].l_filename, links[i].l_linenum);
dolink(links[i].l_from, links[i].l_to);
+ if (noise)
+ for (j = 0; j < nlinks; ++j)
+ if (strcmp(links[i].l_to,
+ links[j].l_from) == 0)
+ warning(_("link to link"));
}
if (lcltime != NULL) {
eat("command line", 1);
@@ -623,7 +638,7 @@ const char * const tofile;
(void) exit(EXIT_FAILURE);
result = link(fromname, toname);
-#if (HAVE_SYMLINK - 0)
+#if HAVE_SYMLINK
if (result != 0 && errno == EXDEV)
result = symlink(fromname, toname);
#endif
@@ -656,25 +671,36 @@ const char * const tofile;
*/
#define MAX_BITS_IN_FILE 32
-#define TIME_T_BITS_IN_FILE ((TYPE_BIT(time_t) < MAX_BITS_IN_FILE) ? TYPE_BIT(time_t) : MAX_BITS_IN_FILE)
+#define TIME_T_BITS_IN_FILE ((TYPE_BIT(zic_t) < MAX_BITS_IN_FILE) ? \
+ TYPE_BIT(zic_t) : MAX_BITS_IN_FILE)
static void
setboundaries P((void))
{
- if (TYPE_SIGNED(time_t)) {
- min_time = ~ (time_t) 0;
- min_time <<= TIME_T_BITS_IN_FILE - 1;
- max_time = ~ (time_t) 0 - min_time;
+ register int i;
+
+ if (TYPE_SIGNED(zic_t)) {
+ min_time = -1;
+ for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
+ min_time *= 2;
+ max_time = -(min_time + 1);
if (sflag)
min_time = 0;
} else {
min_time = 0;
max_time = 2 - sflag;
- max_time <<= TIME_T_BITS_IN_FILE - 1;
+ for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
+ max_time *= 2;
--max_time;
}
- min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
- max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
+ {
+ time_t t;
+
+ t = (time_t) min_time;
+ min_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
+ t = (time_t) max_time;
+ max_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
+ }
min_year_representable = min_year;
max_year_representable = max_year;
}
@@ -773,7 +799,7 @@ associate P((void))
*/
eat(zp->z_filename, zp->z_linenum);
zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
- TRUE);
+ TRUE);
/*
** Note, though, that if there's no rule,
** a '%s' in the format is a bad thing.
@@ -1079,7 +1105,9 @@ const int iscont;
zones[nzones - 1].z_untiltime > min_time &&
zones[nzones - 1].z_untiltime < max_time &&
zones[nzones - 1].z_untiltime >= z.z_untiltime) {
- error(_("Zone continuation line end time is not after end time of previous line"));
+ error(_(
+"Zone continuation line end time is not after end time of previous line"
+ ));
return FALSE;
}
}
@@ -1103,7 +1131,7 @@ const int nfields;
register int i, j;
int year, month, day;
long dayoff, tod;
- time_t t;
+ zic_t t;
if (nfields != LEAP_FIELDS) {
error(_("wrong number of fields on Leap line"));
@@ -1112,11 +1140,11 @@ const int nfields;
dayoff = 0;
cp = fields[LP_YEAR];
if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
- /*
- * Leapin' Lizards!
- */
- error(_("invalid leaping year"));
- return;
+ /*
+ ** Leapin' Lizards!
+ */
+ error(_("invalid leaping year"));
+ return;
}
j = EPOCH_YEAR;
while (j != year) {
@@ -1147,7 +1175,7 @@ const int nfields;
return;
}
dayoff = oadd(dayoff, eitol(day - 1));
- if (dayoff < 0 && !TYPE_SIGNED(time_t)) {
+ if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
error(_("time before zero"));
return;
}
@@ -1159,7 +1187,7 @@ const int nfields;
error(_("time too large"));
return;
}
- t = (time_t) dayoff * SECSPERDAY;
+ t = (zic_t) dayoff * SECSPERDAY;
tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
cp = fields[LP_CORR];
{
@@ -1183,7 +1211,9 @@ const int nfields;
return;
}
if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
- error(_("illegal Rolling/Stationary field on Leap line"));
+ error(_(
+ "illegal Rolling/Stationary field on Leap line"
+ ));
return;
}
leapadd(tadd(t, tod), positive, lp->l_value, count);
@@ -1421,7 +1451,7 @@ const char * const name;
register int i, j;
static char * fullname;
static struct tzhead tzh;
- time_t ats[TZ_MAX_TIMES];
+ zic_t ats[TZ_MAX_TIMES];
unsigned char types[TZ_MAX_TIMES];
size_t len;
@@ -1446,14 +1476,13 @@ const char * const name;
while (fromi < timecnt && attypes[fromi].type == 0)
++fromi; /* handled by default rule */
for ( ; fromi < timecnt; ++fromi) {
- if (toi != 0
- && ((attypes[fromi].at
- + gmtoffs[attypes[toi - 1].type])
- <= (attypes[toi - 1].at
- + gmtoffs[toi == 1 ? 0
- : attypes[toi - 2].type]))) {
- attypes[toi - 1].type = attypes[fromi].type;
- continue;
+ if (toi != 0 && ((attypes[fromi].at +
+ gmtoffs[attypes[toi - 1].type]) <=
+ (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
+ : attypes[toi - 2].type]))) {
+ attypes[toi - 1].type =
+ attypes[fromi].type;
+ continue;
}
if (toi == 0 ||
attypes[toi - 1].type != attypes[fromi].type)
@@ -1500,7 +1529,8 @@ const char * const name;
convert(eitol(typecnt), tzh.tzh_typecnt);
convert(eitol(charcnt), tzh.tzh_charcnt);
(void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
-#define DO(field) (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp)
+#define DO(field) (void) fwrite((void *) tzh.field, \
+ (size_t) sizeof tzh.field, (size_t) 1, fp)
DO(tzh_magic);
DO(tzh_reserved);
DO(tzh_ttisgmtcnt);
@@ -1589,7 +1619,7 @@ const int zonecount;
register struct rule * rp;
register int i, j;
register int usestart, useuntil;
- register time_t starttime, untiltime;
+ register zic_t starttime, untiltime;
register long gmtoff;
register long stdoff;
register int year;
@@ -1658,7 +1688,7 @@ const int zonecount;
}
for ( ; ; ) {
register int k;
- register time_t jtime, ktime;
+ register zic_t jtime, ktime;
register long offset;
char buf[BUFSIZ];
@@ -1723,13 +1753,12 @@ const int zonecount;
}
if (*startbuf == '\0' &&
startoff == oadd(zp->z_gmtoff,
- stdoff)) {
+ stdoff))
doabbr(startbuf,
sizeof(startbuf),
zp->z_format,
rp->r_abbrvar,
rp->r_stdoff != 0);
- }
}
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
@@ -1775,7 +1804,7 @@ error(_("can't determine time zone abbreviation to use just after until time"));
static void
addtt(starttime, type)
-const time_t starttime;
+const zic_t starttime;
int type;
{
if (starttime <= min_time ||
@@ -1859,7 +1888,7 @@ const int ttisgmt;
static void
leapadd(t, positive, rolling, count)
-const time_t t;
+const zic_t t;
const int positive;
const int rolling;
int count;
@@ -2023,7 +2052,9 @@ register char * cp;
else while ((*dp = *cp++) != '"')
if (*dp != '\0')
++dp;
- else error(_("Odd number of quotation marks"));
+ else error(_(
+ "Odd number of quotation marks"
+ ));
} while (*cp != '\0' && *cp != '#' &&
(!isascii(*cp) || !isspace((unsigned char) *cp)));
if (isascii(*cp) && isspace((unsigned char) *cp))
@@ -2049,12 +2080,12 @@ const long t2;
return t;
}
-static time_t
+static zic_t
tadd(t1, t2)
-const time_t t1;
+const zic_t t1;
const long t2;
{
- register time_t t;
+ register zic_t t;
if (t1 == max_time && t2 > 0)
return max_time;
@@ -2073,14 +2104,14 @@ const long t2;
** 1970, 00:00 LOCAL time - in that year that the rule refers to.
*/
-static time_t
+static zic_t
rpytime(rp, wantedy)
register const struct rule * const rp;
register const int wantedy;
{
register int y, m, i;
register long dayoff; /* with a nod to Margaret O. */
- register time_t t;
+ register zic_t t;
if (wantedy == INT_MIN)
return min_time;
@@ -2144,16 +2175,17 @@ register const int wantedy;
}
if (i < 0 || i >= len_months[isleap(y)][m]) {
if (noise)
- warning(_("rule goes past start/end of month--will not work with pre-2004 versions of zic"));
+ warning(_("rule goes past start/end of month--\
+will not work with pre-2004 versions of zic"));
}
}
- if (dayoff < 0 && !TYPE_SIGNED(time_t))
+ if (dayoff < 0 && !TYPE_SIGNED(zic_t))
return min_time;
if (dayoff < min_time / SECSPERDAY)
return min_time;
if (dayoff > max_time / SECSPERDAY)
return max_time;
- t = (time_t) dayoff * SECSPERDAY;
+ t = (zic_t) dayoff * SECSPERDAY;
return tadd(t, rp->r_tod);
}
@@ -2163,6 +2195,41 @@ const char * const string;
{
register int i;
+ if (strcmp(string, GRANDPARENTED) != 0) {
+ register const char * cp;
+ register char * wp;
+
+ /*
+ ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
+ ** optionally followed by a + or - and a number from 1 to 14.
+ */
+ cp = string;
+ wp = NULL;
+ while (isascii(*cp) && isalpha(*cp))
+ ++cp;
+ if (cp - string == 0)
+wp = _("time zone abbreviation lacks alphabetic at start");
+ if (noise && cp - string > 3)
+wp = _("time zone abbreviation has more than 3 alphabetics");
+ if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
+wp = _("time zone abbreviation has too many alphabetics");
+ if (wp == NULL && (*cp == '+' || *cp == '-')) {
+ ++cp;
+ if (isascii(*cp) && isdigit(*cp))
+ if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
+ ++cp;
+ }
+ if (*cp != '\0')
+wp = _("time zone abbreviation differs from POSIX standard");
+ if (wp != NULL) {
+ wp = ecpyalloc(wp);
+ wp = ecatalloc(wp, " (");
+ wp = ecatalloc(wp, string);
+ wp = ecatalloc(wp, ")");
+ warning(wp);
+ ifree(wp);
+ }
+ }
i = strlen(string) + 1;
if (charcnt + i > TZ_MAX_CHARS) {
error(_("too many, or too long, time zone abbreviations"));