latest proposed 64-bit changes
Arthur David Olson
olsona at lecserver.nci.nih.gov
Thu Jan 19 17:59:10 UTC 2006
Here's the latest version of proposed changes to the time zone package to
cope with 64-bit time values. As usual, these are differences from the
stuff that's available at ftp://elsie.nci.nih.gov/pub/tz{code,data}2005r.tar.gz.
I ran the package before and after these changes through the zgress
wringer that I sent out on Tuesday; here on elsie (a 32-bit system)
I get the same results from a zdump of all the binary data files
whether I use the before or after zdump and whether I use the
before or after data files.
For those who missed earlier rounds: the "new" version of zic generates a
three-part binary file; the file starts off with "Tzif2" (rather than the
old "Tzif\0"). The first part (other than the change in the magic "Tzif" string)
is identical in format to the existing time zone binary files. The second part
has the same format except that 64 bits are stored for each time value (rather
than the old 32 bits). The third part is a newline-enclosed POSIX-format
time zone string (such as "EST5EDT,M3.2.0,M11.1.0") if the future of the zone
can be represented with such a string, or a newline-enclosed null string
otherwise.
If a zone's future can't be represented by a POSIX string, the new zic
generates 400 years worth of 64-bit time transition information; the stuff
in "localtime.c" sees if there's 400 years worth of regularity at the end of
the data and, if so, does its work modulo 400 to extend the data into the
very far future.
Given the magnitude of these changes I'll wait a while for feedback;
since these changes have already been around the block a couple of times
and since they pass the regression test, I won't wait too long.
Absent negative feedback, expect the changes to show up in the ftp version
on Presidents' Day (2006-02-20).
The changes below also reflect Roland McGrath's scheck suggestions.
--ado
*** tzftp/tzfile.5 Thu Dec 22 09:31:16 2005
--- tzexp3/tzfile.5 Tue Jan 17 14:42:56 2006
***************
*** 9,15 ****
.IR tzset (3)
begin with the magic characters "TZif" to identify then as
time zone information files,
! followed by sixteen bytes reserved for future use,
followed by six four-byte values of type
.BR long ,
written in a ``standard'' byte order
--- 9,17 ----
.IR tzset (3)
begin with the magic characters "TZif" to identify then as
time zone information files,
! followed by a character identifying the version of the file's format
! (as of 2005, either an ASCII NUL or a '2')
! followed by fifteen bytes containing zeroes reserved for future use,
followed by six four-byte values of type
.BR long ,
written in a ``standard'' byte order
***************
*** 131,138 ****
.I tzh_timecnt
is zero or the time argument is less than the first transition time recorded
in the file.
.SH SEE ALSO
newctime(3)
! .\" @(#)tzfile.5 7.12
.\" This file is in the public domain, so clarified as of
.\" 1996-06-05 by Arthur David Olson.
--- 133,150 ----
.I tzh_timecnt
is zero or the time argument is less than the first transition time recorded
in the file.
+ .PP
+ For version-2-format time zone files,
+ the above header and data is followed by a second header and data,
+ identical in format except that
+ eight bytes are used for each transition time or leap second time.
+ After the second header and data comes a newline-encloded,
+ POSIX-TZ-environment-variable-style string for use in handling instants
+ after the last transition time stored in the file
+ (with nothing between the newlines if there is no POSIX representation for
+ such instants).
.SH SEE ALSO
newctime(3)
! .\" @(#)tzfile.5 7.13
.\" This file is in the public domain, so clarified as of
.\" 1996-06-05 by Arthur David Olson.
*** tzftp/Makefile Thu Dec 22 09:31:13 2005
--- tzexp3/Makefile Tue Jan 17 14:42:54 2006
***************
*** 1,4 ****
! # @(#)Makefile 7.109
# Change the line below for your time zone (after finding the zone you want in
# the time zone files, or adding it to a time zone file).
--- 1,4 ----
! # @(#)Makefile 7.110
# Change the line below for your time zone (after finding the zone you want in
# the time zone files, or adding it to a time zone file).
***************
*** 95,100 ****
--- 95,101 ----
# -DHAVE_SETTIMEOFDAY=1 if settimeofday has just 1 arg (SVR4)
# -DHAVE_SETTIMEOFDAY=2 if settimeofday uses 2nd arg (4.3BSD)
# -DHAVE_SETTIMEOFDAY=3 if settimeofday ignores 2nd arg (4.4BSD)
+ # -DHAVE_STDINT_H=1 if you have a pre-C99 compiler with "stdint.h"
# -DHAVE_STRERROR=0 if your system lacks the strerror function
# -DHAVE_SYMLINK=0 if your system lacks the symlink function
# -DHAVE_SYS_STAT_H=0 if your compiler lacks a "sys/stat.h"
*** tzftp/tzfile.h Thu Dec 22 09:31:16 2005
--- tzexp3/tzfile.h Tue Jan 17 15:05:09 2006
***************
*** 21,27 ****
#ifndef lint
#ifndef NOID
! static char tzfilehid[] = "@(#)tzfile.h 7.18";
#endif /* !defined NOID */
#endif /* !defined lint */
--- 21,27 ----
#ifndef lint
#ifndef NOID
! static char tzfilehid[] = "@(#)tzfile.h 7.19";
#endif /* !defined NOID */
#endif /* !defined lint */
***************
*** 49,55 ****
struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
! char tzh_reserved[16]; /* reserved for future use */
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
--- 49,56 ----
struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
! char tzh_version[1]; /* '\0' or '2' as of 2005 */
! char tzh_reserved[15]; /* reserved--must be zero */
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
***************
*** 84,101 ****
*/
/*
** In the current implementation, "tzset()" refuses to deal with files that
** exceed any of the limits below.
*/
#ifndef TZ_MAX_TIMES
! /*
! ** The TZ_MAX_TIMES value below is enough to handle a bit more than a
! ** year's worth of solar time (corrected daily to the nearest second) or
! ** 138 years of Pacific Presidential Election time
! ** (where there are three time zone transitions every fourth year).
! */
! #define TZ_MAX_TIMES 370
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
--- 85,106 ----
*/
/*
+ ** If tzh_version is '2' or greater, the above is followed by a second instance
+ ** of tzhead and a second instance of the data in which each coded transition
+ ** time uses 8 rather than 4 chars,
+ ** then a POSIX-TZ-environment-variable-style string for use in handling
+ ** instants after the last transition time stored in the file
+ ** (with nothing between the newlines if there is no POSIX representation for
+ ** such instants).
+ */
+
+ /*
** In the current implementation, "tzset()" refuses to deal with files that
** exceed any of the limits below.
*/
#ifndef TZ_MAX_TIMES
! #define TZ_MAX_TIMES 1200
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
*** tzftp/private.h Thu Dec 22 09:31:15 2005
--- tzexp3/private.h Tue Jan 17 15:36:50 2006
***************
*** 21,27 ****
#ifndef lint
#ifndef NOID
! static char privatehid[] = "@(#)private.h 7.55";
#endif /* !defined NOID */
#endif /* !defined lint */
--- 21,27 ----
#ifndef lint
#ifndef NOID
! static char privatehid[] = "@(#)private.h 7.62";
#endif /* !defined NOID */
#endif /* !defined lint */
***************
*** 48,53 ****
--- 48,57 ----
#define HAVE_SETTIMEOFDAY 3
#endif /* !defined HAVE_SETTIMEOFDAY */
+ #ifndef HAVE_STDINT_H
+ #define HAVE_STDINT_H (199901 <= __STDC_VERSION__)
+ #endif /* !defined HAVE_STDINT_H */
+
#ifndef HAVE_STRERROR
#define HAVE_STRERROR 1
#endif /* !defined HAVE_STRERROR */
***************
*** 89,95 ****
#include "stdio.h"
#include "errno.h"
#include "string.h"
! #include "limits.h" /* for CHAR_BIT */
#include "time.h"
#include "stdlib.h"
--- 93,99 ----
#include "stdio.h"
#include "errno.h"
#include "string.h"
! #include "limits.h" /* for CHAR_BIT et al. */
#include "time.h"
#include "stdlib.h"
***************
*** 124,129 ****
--- 128,152 ----
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
+ #if HAVE_STDINT_H
+ #include <stdint.h>
+ #endif /* !HAVE_STDINT_H */
+
+ #ifndef INT_FAST64_MAX
+ #ifdef LLONG_MAX
+ typedef long long int_fast64_t;
+ #else /* !defined LLONG_MAX */
+ typedef long int_fast64_t;
+ #endif /* !defined LLONG_MAX */
+ #endif /* !defined INT_FAST64_MAX */
+
+ #ifndef INT32_MAX
+ #define INT32_MAX 0x7fffffff
+ #endif /* !defined INT32_MAX */
+ #ifndef INT32_MIN
+ #define INT32_MIN (-1 - INT32_MAX)
+ #endif /* !defined INT32_MIN */
+
/*
** Workarounds for compilers/systems.
*/
***************
*** 211,224 ****
** Private function declarations.
*/
! char * icalloc P((int nelem, int elsize));
! char * icatalloc P((char * old, const char * new));
! char * icpyalloc P((const char * string));
! 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, char *format));
/*
** Finally, some convenience items.
--- 234,247 ----
** Private function declarations.
*/
! char * icalloc P((int nelem, int elsize));
! char * icatalloc P((char * old, const char * new));
! char * icpyalloc P((const char * string));
! char * imalloc P((int n));
! void * irealloc P((void * pointer, int size));
! void icfree P((char * pointer));
! void ifree P((char * pointer));
! const char * scheck P((const char * string, const char * format));
/*
** Finally, some convenience items.
***************
*** 310,316 ****
--- 333,359 ----
char *ctime_r P((time_t const *, char *));
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+ #ifndef YEARSPERREPEAT
+ #define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
+ #endif /* !defined YEARSPERREPEAT */
+
/*
+ ** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
+ */
+
+ #ifndef AVGSECSPERYEAR
+ #define AVGSECSPERYEAR 31556952
+ #endif /* !defined AVGSECSPERYEAR */
+
+ #ifndef SECSPERREPEAT
+ #define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
+ #endif /* !defined SECSPERREPEAT */
+
+ #ifndef SECSPERREPEAT_BITS
+ #define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
+ #endif /* !defined SECSPERREPEAT_BITS */
+
+ /*
** UNIX was a registered trademark of The Open Group in 2003.
*/
*** tzftp/localtime.c Thu Dec 22 09:31:14 2005
--- tzexp3/localtime.c Tue Jan 17 14:42:54 2006
***************
*** 5,11 ****
#ifndef lint
#ifndef NOID
! static char elsieid[] = "@(#)localtime.c 7.97";
#endif /* !defined NOID */
#endif /* !defined lint */
--- 5,11 ----
#ifndef lint
#ifndef NOID
! static char elsieid[] = "@(#)localtime.c 7.98";
#endif /* !defined NOID */
#endif /* !defined lint */
***************
*** 110,115 ****
--- 110,117 ----
int timecnt;
int typecnt;
int charcnt;
+ int goback;
+ int goahead;
time_t ats[TZ_MAX_TIMES];
unsigned char types[TZ_MAX_TIMES];
struct ttinfo ttis[TZ_MAX_TYPES];
***************
*** 135,142 ****
*/
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));
--- 137,146 ----
*/
static long detzcode P((const char * codep));
+ static time_t detzcode64 P((const char * codep));
+ static int differ_by_repeat P((time_t t1, time_t t0));
static const char * getzname P((const char * strp));
! static const char * getqzname P((const char * strp, const int 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));
***************
*** 173,179 ****
const struct tm * btmp));
static time_t transtime P((time_t janfirst, int year,
const struct rule * rulep, long offset));
! static int tzload P((const char * name, struct state * sp));
static int tzparse P((const char * name, struct state * sp,
int lastditch));
--- 177,184 ----
const struct tm * btmp));
static time_t transtime P((time_t janfirst, int year,
const struct rule * rulep, long offset));
! static int tzload P((const char * name, struct state * sp,
! int doextend));
static int tzparse P((const char * name, struct state * sp,
int lastditch));
***************
*** 234,239 ****
--- 239,257 ----
return result;
}
+ static time_t
+ detzcode64(codep)
+ const char * const codep;
+ {
+ register time_t result;
+ register int i;
+
+ result = (codep[0] & 0x80) ? ~0L : 0L;
+ for (i = 0; i < 8; ++i)
+ result = result * 256 + (codep[i] & 0xff);
+ return result;
+ }
+
static void
settzname P((void))
{
***************
*** 303,315 ****
}
static int
! tzload(name, sp)
register const char * name;
register struct state * const sp;
{
! register const char * p;
! register int i;
! register int fid;
if (name == NULL && (name = TZDEFAULT) == NULL)
return -1;
--- 321,353 ----
}
static int
! differ_by_repeat(t1, t0)
! const time_t t1;
! const time_t t0;
! {
! if (TYPE_INTEGRAL(time_t) &&
! TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
! return 0;
! return t1 - t0 == SECSPERREPEAT;
! }
!
! static int
! tzload(name, sp, doextend)
register const char * name;
register struct state * const sp;
+ register const int doextend;
{
! register const char * p;
! register int i;
! register int fid;
! register int stored;
! register int nread;
! union {
! struct tzhead tzhead;
! char buf[2 * sizeof(struct tzhead) +
! 2 * sizeof *sp +
! 4 * TZ_MAX_TIMES];
! } u;
if (name == NULL && (name = TZDEFAULT) == NULL)
return -1;
***************
*** 347,364 ****
if ((fid = open(name, OPEN_MODE)) == -1)
return -1;
}
! {
! struct tzhead * tzhp;
! union {
! struct tzhead tzhead;
! char buf[sizeof *sp + sizeof *tzhp];
! } u;
int ttisstdcnt;
int ttisgmtcnt;
- i = read(fid, u.buf, sizeof u.buf);
- if (close(fid) != 0)
- return -1;
ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
--- 385,397 ----
if ((fid = open(name, OPEN_MODE)) == -1)
return -1;
}
! nread = read(fid, u.buf, sizeof u.buf);
! if (close(fid) < 0 || nread <= 0)
! return -1;
! for (stored = 4; stored <= 8; stored *= 2) {
int ttisstdcnt;
int ttisgmtcnt;
ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
***************
*** 373,389 ****
(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
return -1;
! if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */
sp->timecnt + /* types */
! sp->typecnt * (4 + 2) + /* ttinfos */
sp->charcnt + /* chars */
! sp->leapcnt * (4 + 4) + /* lsinfos */
ttisstdcnt + /* ttisstds */
ttisgmtcnt) /* ttisgmts */
return -1;
for (i = 0; i < sp->timecnt; ++i) {
! sp->ats[i] = detzcode(p);
! p += 4;
}
for (i = 0; i < sp->timecnt; ++i) {
sp->types[i] = (unsigned char) *p++;
--- 406,424 ----
(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
return -1;
! if (nread - (p - u.buf) <
! sp->timecnt * stored + /* ats */
sp->timecnt + /* types */
! sp->typecnt * 6 + /* ttinfos */
sp->charcnt + /* chars */
! sp->leapcnt * (stored + 4) + /* lsinfos */
ttisstdcnt + /* ttisstds */
ttisgmtcnt) /* ttisgmts */
return -1;
for (i = 0; i < sp->timecnt; ++i) {
! sp->ats[i] = (stored == 4) ?
! detzcode(p) : detzcode64(p);
! p += stored;
}
for (i = 0; i < sp->timecnt; ++i) {
sp->types[i] = (unsigned char) *p++;
***************
*** 411,418 ****
register struct lsinfo * lsisp;
lsisp = &sp->lsis[i];
! lsisp->ls_trans = detzcode(p);
! p += 4;
lsisp->ls_corr = detzcode(p);
p += 4;
}
--- 446,454 ----
register struct lsinfo * lsisp;
lsisp = &sp->lsis[i];
! lsisp->ls_trans = (stored == 4) ?
! detzcode(p) : detzcode64(p);
! p += stored;
lsisp->ls_corr = detzcode(p);
p += 4;
}
***************
*** 469,475 ****
--- 505,567 ----
}
break;
}
+ /*
+ ** If this is an old file, we're done.
+ */
+ if (u.tzhead.tzh_version[0] == '\0')
+ break;
+ nread -= p - u.buf;
+ for (i = 0; i < nread; ++i)
+ u.buf[i] = p[i];
+ /*
+ ** If this is a narrow integer time_t system, we're done.
+ */
+ if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
+ break;
}
+ if (doextend && nread > 2 &&
+ u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
+ sp->typecnt + 2 <= TZ_MAX_TYPES) {
+ struct state ts;
+ register int result;
+
+ u.buf[nread - 1] = '\0';
+ result = tzparse(&u.buf[1], &ts, FALSE);
+ if (result == 0 && ts.typecnt == 2 &&
+ sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
+ for (i = 0; i < 2; ++i)
+ ts.ttis[i].tt_abbrind +=
+ sp->charcnt;
+ for (i = 0; i < ts.charcnt; ++i)
+ sp->chars[sp->charcnt++] =
+ ts.chars[i];
+ i = 0;
+ while (i < ts.timecnt &&
+ ts.ats[i] <=
+ sp->ats[sp->timecnt - 1])
+ ++i;
+ while (i < ts.timecnt &&
+ sp->timecnt < TZ_MAX_TIMES) {
+ sp->ats[sp->timecnt] =
+ ts.ats[i];
+ sp->types[sp->timecnt] =
+ sp->typecnt +
+ ts.types[i];
+ ++sp->timecnt;
+ ++i;
+ }
+ sp->ttis[sp->typecnt++] = ts.ttis[0];
+ sp->ttis[sp->typecnt++] = ts.ttis[1];
+ }
+ }
+ i = 2 * YEARSPERREPEAT;
+ sp->goback = sp->goahead = sp->timecnt > i;
+ sp->goback &= sp->types[i] == sp->types[0] &&
+ differ_by_repeat(sp->ats[i], sp->ats[0]);
+ sp->goahead &=
+ sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
+ differ_by_repeat(sp->ats[sp->timecnt - 1],
+ sp->ats[sp->timecnt - 1 - i]);
return 0;
}
***************
*** 502,520 ****
/*
** 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;
--- 594,612 ----
/*
** 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 don't do any checking here; checking is done later in common-case code.
*/
static const char *
getqzname(strp, delim)
register const char * strp;
! const int delim;
{
! register int c;
while ((c = *strp) != '\0' && c != delim)
++strp;
***************
*** 823,831 ****
if (name == NULL)
return -1;
}
! load_result = tzload(TZDEFRULES, sp);
if (load_result != 0)
sp->leapcnt = 0; /* so, we're off a little */
if (*name != '\0') {
if (*name == '<') {
dstname = ++name;
--- 915,924 ----
if (name == NULL)
return -1;
}
! load_result = tzload(TZDEFRULES, sp, FALSE);
if (load_result != 0)
sp->leapcnt = 0; /* so, we're off a little */
+ sp->timecnt = 0;
if (*name != '\0') {
if (*name == '<') {
dstname = ++name;
***************
*** 865,875 ****
return -1;
sp->typecnt = 2; /* standard time and DST */
/*
! ** Two transitions per year, from EPOCH_YEAR to 2037.
*/
- sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
- if (sp->timecnt > TZ_MAX_TIMES)
- return -1;
sp->ttis[0].tt_gmtoff = -dstoffset;
sp->ttis[0].tt_isdst = 1;
sp->ttis[0].tt_abbrind = stdlen + 1;
--- 958,965 ----
return -1;
sp->typecnt = 2; /* standard time and DST */
/*
! ** Two transitions per year, from EPOCH_YEAR forward.
*/
sp->ttis[0].tt_gmtoff = -dstoffset;
sp->ttis[0].tt_isdst = 1;
sp->ttis[0].tt_abbrind = stdlen + 1;
***************
*** 879,885 ****
atp = sp->ats;
typep = sp->types;
janfirst = 0;
! for (year = EPOCH_YEAR; year <= 2037; ++year) {
starttime = transtime(janfirst, year, &start,
stdoffset);
endtime = transtime(janfirst, year, &end,
--- 969,979 ----
atp = sp->ats;
typep = sp->types;
janfirst = 0;
! for (year = EPOCH_YEAR;
! sp->timecnt + 2 <= TZ_MAX_TIMES;
! ++year) {
! time_t newfirst;
!
starttime = transtime(janfirst, year, &start,
stdoffset);
endtime = transtime(janfirst, year, &end,
***************
*** 895,902 ****
*atp++ = endtime;
*typep++ = 1; /* DST ends */
}
! janfirst += year_lengths[isleap(year)] *
SECSPERDAY;
}
} else {
register long theirstdoffset;
--- 989,1001 ----
*atp++ = endtime;
*typep++ = 1; /* DST ends */
}
! sp->timecnt += 2;
! newfirst = janfirst;
! newfirst += year_lengths[isleap(year)] *
SECSPERDAY;
+ if (newfirst <= janfirst)
+ break;
+ janfirst = newfirst;
}
} else {
register long theirstdoffset;
***************
*** 1011,1017 ****
gmtload(sp)
struct state * const sp;
{
! if (tzload(gmt, sp) != 0)
(void) tzparse(gmt, sp, TRUE);
}
--- 1110,1116 ----
gmtload(sp)
struct state * const sp;
{
! if (tzload(gmt, sp, TRUE) != 0)
(void) tzparse(gmt, sp, TRUE);
}
***************
*** 1038,1044 ****
}
}
#endif /* defined ALL_STATE */
! if (tzload((char *) NULL, lclptr) != 0)
gmtload(lclptr);
settzname();
}
--- 1137,1143 ----
}
}
#endif /* defined ALL_STATE */
! if (tzload((char *) NULL, lclptr, TRUE) != 0)
gmtload(lclptr);
settzname();
}
***************
*** 1080,1086 ****
lclptr->ttis[0].tt_gmtoff = 0;
lclptr->ttis[0].tt_abbrind = 0;
(void) strcpy(lclptr->chars, gmt);
! } else if (tzload(name, lclptr) != 0)
if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
(void) gmtload(lclptr);
settzname();
--- 1179,1185 ----
lclptr->ttis[0].tt_gmtoff = 0;
lclptr->ttis[0].tt_abbrind = 0;
(void) strcpy(lclptr->chars, gmt);
! } else if (tzload(name, lclptr, TRUE) != 0)
if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
(void) gmtload(lclptr);
settzname();
***************
*** 1113,1118 ****
--- 1212,1256 ----
if (sp == NULL)
return gmtsub(timep, offset, tmp);
#endif /* defined ALL_STATE */
+ if ((sp->goback && t < sp->ats[0]) ||
+ (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
+ time_t newt = t;
+ register time_t seconds;
+ register time_t tcycles;
+ register int_fast64_t icycles;
+
+ if (t < sp->ats[0])
+ seconds = sp->ats[0] - t;
+ else seconds = t - sp->ats[sp->timecnt - 1];
+ --seconds;
+ tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
+ ++tcycles;
+ icycles = tcycles;
+ if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
+ return NULL;
+ seconds = icycles;
+ seconds *= YEARSPERREPEAT;
+ seconds *= AVGSECSPERYEAR;
+ if (t < sp->ats[0])
+ newt += seconds;
+ else newt -= seconds;
+ if (newt < sp->ats[0] ||
+ newt > sp->ats[sp->timecnt - 1])
+ return NULL; /* "cannot happen" */
+ result = localsub(&newt, offset, tmp);
+ if (result == tmp) {
+ register time_t newy;
+
+ newy = tmp->tm_year;
+ if (t < sp->ats[0])
+ newy -= icycles * YEARSPERREPEAT;
+ else newy += icycles * YEARSPERREPEAT;
+ tmp->tm_year = newy;
+ if (tmp->tm_year != newy)
+ return NULL;
+ }
+ return result;
+ }
if (sp->timecnt == 0 || t < sp->ats[0]) {
i = 0;
while (sp->ttis[i].tt_isdst)
*** tzftp/zic.c Thu Dec 22 09:31:15 2005
--- tzexp3/zic.c Tue Jan 17 15:17:09 2006
***************
*** 1,15 ****
! static char elsieid[] = "@(#)zic.c 7.128";
- /*
- ** 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 */
--- 1,13 ----
! static char elsieid[] = "@(#)zic.c 7.129";
#include "private.h"
#include "locale.h"
#include "tzfile.h"
+ #define ZIC_VERSION '2'
+
+ typedef int_fast64_t zic_t;
+
#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
#define ZIC_MAX_ABBR_LEN_WO_WARN 6
#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
***************
*** 36,41 ****
--- 34,44 ----
#define isascii(x) 1
#endif
+ #define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
+ #define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */
+
+ #define end(cp) (strchr((cp), '\0'))
+
struct rule {
const char * r_filename;
int r_linenum;
***************
*** 44,49 ****
--- 47,54 ----
int r_loyear; /* for example, 1986 */
int r_hiyear; /* for example, 1986 */
const char * r_yrtype;
+ int r_lowasnum;
+ int r_hiwasnum;
int r_month; /* 0..11 */
***************
*** 103,111 ****
static void associate P((void));
static int ciequal P((const char * ap, const char * bp));
static void convert P((long val, char * buf));
static void dolink P((const char * fromfile, const char * tofile));
static void doabbr P((char * abbr, const char * format,
! const char * letters, int isdst));
static void eat P((const char * name, int num));
static void eats P((const char * name, int num,
const char * rname, int rnum));
--- 108,117 ----
static void associate P((void));
static int ciequal P((const char * ap, const char * bp));
static void convert P((long val, char * buf));
+ static void convert64 P((zic_t val, char * buf));
static void dolink P((const char * fromfile, const char * tofile));
static void doabbr P((char * abbr, const char * format,
! const char * letters, int isdst, int doquotes));
static void eat P((const char * name, int num));
static void eats P((const char * name, int num,
const char * rname, int rnum));
***************
*** 121,126 ****
--- 127,133 ----
static int inzcont P((char ** fields, int nfields));
static int inzone P((char ** fields, int nfields));
static int inzsub P((char ** fields, int nfields, int iscont));
+ static int is32 P((zic_t x));
static int itsabbr P((const char * abbr, const char * word));
static int itsdir P((const char * name));
static int lowerit P((int c));
***************
*** 130,135 ****
--- 137,143 ----
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 void puttzcode64 P((zic_t code, FILE * fp));
static int rcomp P((const void * leftp, const void * rightp));
static zic_t rpytime P((const struct rule * rp, int wantedy));
static void rulesub P((struct rule * rp,
***************
*** 136,145 ****
const char * loyearp, const char * hiyearp,
const char * typep, const char * monthp,
const char * dayp, const char * timep));
static void setboundaries P((void));
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
--- 144,158 ----
const char * loyearp, const char * hiyearp,
const char * typep, const char * monthp,
const char * dayp, const char * timep));
+ static int stringoffset P((char * result, long offset));
+ static int stringrule P((char * result, const struct rule * rp,
+ long dstoff, long gmtoff));
+ static void stringzone P((char * result,
+ const struct zone * zp, int ntzones));
static void setboundaries P((void));
static zic_t tadd P((zic_t t1, long t2));
static void usage P((void));
! static void writezone P((const char * name, const char * string));
static int yearistype P((int year, const char * type));
#if !HAVE_STRERROR
***************
*** 150,162 ****
static int errors;
static const char * filename;
static int leapcnt;
static int linenum;
static zic_t max_time;
static int max_year;
- static int max_year_representable;
static zic_t min_time;
static int min_year;
- static int min_year_representable;
static int noise;
static const char * rfilename;
static int rlinenum;
--- 163,178 ----
static int errors;
static const char * filename;
static int leapcnt;
+ static int leapseen;
+ static int leapminyear;
+ static int leapmaxyear;
static int linenum;
+ static int max_abbrvar_len;
+ static int max_format_len;
static zic_t max_time;
static int max_year;
static zic_t min_time;
static int min_year;
static int noise;
static const char * rfilename;
static int rlinenum;
***************
*** 453,459 ****
usage P((void))
{
(void) fprintf(stderr, _("%s: usage is %s \
! [ --version ] [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),
progname, progname);
exit(EXIT_FAILURE);
--- 469,475 ----
usage P((void))
{
(void) fprintf(stderr, _("%s: usage is %s \
! [ --version ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),
progname, progname);
exit(EXIT_FAILURE);
***************
*** 464,470 ****
static const char * directory;
static const char * leapsec;
static const char * yitcommand;
- static int sflag = FALSE;
int
main(argc, argv)
--- 480,485 ----
***************
*** 486,491 ****
--- 501,511 ----
(void) textdomain(TZ_DOMAIN);
#endif /* HAVE_GETTEXT */
progname = argv[0];
+ if (TYPE_BIT(zic_t) < 64) {
+ (void) fprintf(stderr, "%s: %s\n", progname,
+ _("wild compilation-time specification of zic_t"));
+ exit(EXIT_FAILURE);
+ }
for (i = 1; i < argc; ++i)
if (strcmp(argv[i], "--version") == 0) {
(void) printf("%s\n", elsieid);
***************
*** 549,555 ****
noise = TRUE;
break;
case 's':
! sflag = TRUE;
break;
}
if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
--- 569,575 ----
noise = TRUE;
break;
case 's':
! (void) printf("%s: -s ignored\n", progname);
break;
}
if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
***************
*** 671,724 ****
ifree(toname);
}
! #ifndef INT_MAX
! #define INT_MAX ((int) (((unsigned)~0)>>1))
! #endif /* !defined INT_MAX */
- #ifndef INT_MIN
- #define INT_MIN ((int) ~(((unsigned)~0)>>1))
- #endif /* !defined INT_MIN */
-
- /*
- ** The tz file format currently allows at most 32-bit quantities.
- ** This restriction should be removed before signed 32-bit values
- ** wrap around in 2038, but unfortunately this will require a
- ** change to the tz file format.
- */
-
- #define MAX_BITS_IN_FILE 32
- #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))
{
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;
! for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
! max_time *= 2;
! --max_time;
! }
! {
! 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;
}
static int
--- 691,707 ----
ifree(toname);
}
! #define TIME_T_BITS_IN_FILE 64
static void
setboundaries P((void))
{
register int i;
! min_time = -1;
! for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
! min_time *= 2;
! max_time = -(min_time + 1);
}
static int
***************
*** 993,998 ****
--- 976,983 ----
fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
r.r_name = ecpyalloc(fields[RF_NAME]);
r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
+ if (max_abbrvar_len < strlen(r.r_abbrvar))
+ max_abbrvar_len = strlen(r.r_abbrvar);
rules = (struct rule *) (void *) erealloc((char *) rules,
(int) ((nrules + 1) * sizeof *rules));
rules[nrules++] = r;
***************
*** 1098,1103 ****
--- 1083,1090 ----
}
z.z_rule = ecpyalloc(fields[i_rule]);
z.z_format = ecpyalloc(fields[i_format]);
+ if (max_format_len < strlen(z.z_format))
+ max_format_len = strlen(z.z_format);
hasuntil = nfields > i_untilyear;
if (hasuntil) {
z.z_untilrule.r_filename = filename;
***************
*** 1159,1164 ****
--- 1146,1156 ----
error(_("invalid leaping year"));
return;
}
+ if (!leapseen || leapmaxyear < year)
+ leapmaxyear = year;
+ if (!leapseen || leapminyear < year)
+ leapminyear = year;
+ leapseen = TRUE;
j = EPOCH_YEAR;
while (j != year) {
if (year > j) {
***************
*** 1313,1319 ****
*/
cp = loyearp;
lp = byword(cp, begin_years);
! if (lp != NULL) switch ((int) lp->l_value) {
case YR_MINIMUM:
rp->r_loyear = INT_MIN;
break;
--- 1305,1312 ----
*/
cp = loyearp;
lp = byword(cp, begin_years);
! rp->r_lowasnum = lp == NULL;
! if (!rp->r_lowasnum) switch ((int) lp->l_value) {
case YR_MINIMUM:
rp->r_loyear = INT_MIN;
break;
***************
*** 1328,1341 ****
} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
error(_("invalid starting year"));
return;
- } else if (noise) {
- if (rp->r_loyear < min_year_representable)
- warning(_("starting year too low to be represented"));
- else if (rp->r_loyear > max_year_representable)
- warning(_("starting year too high to be represented"));
}
cp = hiyearp;
! if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
case YR_MINIMUM:
rp->r_hiyear = INT_MIN;
break;
--- 1321,1331 ----
} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
error(_("invalid starting year"));
return;
}
cp = hiyearp;
! lp = byword(cp, end_years);
! rp->r_hiwasnum = lp == NULL;
! if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
case YR_MINIMUM:
rp->r_hiyear = INT_MIN;
break;
***************
*** 1353,1363 ****
} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
error(_("invalid ending year"));
return;
- } else if (noise) {
- if (rp->r_loyear < min_year_representable)
- warning(_("ending year too low to be represented"));
- else if (rp->r_loyear > max_year_representable)
- warning(_("ending year too high to be represented"));
}
if (rp->r_loyear > rp->r_hiyear) {
error(_("starting year greater than ending year"));
--- 1343,1348 ----
***************
*** 1372,1379 ****
}
rp->r_yrtype = ecpyalloc(typep);
}
- if (rp->r_loyear < min_year && rp->r_loyear > 0)
- min_year = rp->r_loyear;
/*
** Day work.
** Accept things such as:
--- 1357,1362 ----
***************
*** 1427,1433 ****
char * const buf;
{
register int i;
! register long shift;
for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
buf[i] = val >> shift;
--- 1410,1416 ----
char * const buf;
{
register int i;
! register int shift;
for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
buf[i] = val >> shift;
***************
*** 1434,1439 ****
--- 1417,1434 ----
}
static void
+ convert64(val, buf)
+ const zic_t val;
+ char * const buf;
+ {
+ register int i;
+ register int shift;
+
+ for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
+ buf[i] = val >> shift;
+ }
+
+ static void
puttzcode(val, fp)
const long val;
FILE * const fp;
***************
*** 1444,1471 ****
(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
}
static int
atcomp(avp, bvp)
! void * avp;
! void * bvp;
{
! if (((struct attype *) avp)->at < ((struct attype *) bvp)->at)
! return -1;
! else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at)
! return 1;
! else return 0;
}
static void
! writezone(name)
const char * const name;
{
! register FILE * fp;
! register int i, j;
! static char * fullname;
! static struct tzhead tzh;
! zic_t ats[TZ_MAX_TIMES];
! unsigned char types[TZ_MAX_TIMES];
/*
** Sort.
--- 1439,1488 ----
(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
}
+ static void
+ puttzcode64(val, fp)
+ const zic_t val;
+ FILE * const fp;
+ {
+ char buf[8];
+
+ convert64(val, buf);
+ (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
+ }
+
static int
atcomp(avp, bvp)
! const void * avp;
! const void * bvp;
{
! const zic_t a = ((const struct attype *) avp)->at;
! const zic_t b = ((const struct attype *) bvp)->at;
!
! return (a < b) ? -1 : (a > b);
}
+ static int
+ is32(x)
+ const zic_t x;
+ {
+ return INT32_MIN <= x && x <= INT32_MAX;
+ }
+
static void
! writezone(name, string)
const char * const name;
+ const char * const string;
{
! register FILE * fp;
! register int i, j;
! register int leapcnt32, leapi32;
! register int timecnt32, timei32;
! register int pass;
! static char * fullname;
! static const struct tzhead tzh0;
! static struct tzhead tzh;
! zic_t ats[TZ_MAX_TIMES];
! unsigned char types[TZ_MAX_TIMES];
/*
** Sort.
***************
*** 1509,1514 ****
--- 1526,1561 ----
ats[i] = attypes[i].at;
types[i] = attypes[i].type;
}
+ /*
+ ** Correct for leap seconds.
+ */
+ for (i = 0; i < timecnt; ++i) {
+ j = leapcnt;
+ while (--j >= 0)
+ if (ats[i] >= trans[j]) {
+ ats[i] = tadd(ats[i], corr[j]);
+ break;
+ }
+ }
+ /*
+ ** Figure out 32-bit-limited starts and counts.
+ */
+ timecnt32 = timecnt;
+ timei32 = 0;
+ leapcnt32 = leapcnt;
+ leapi32 = 0;
+ while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
+ --timecnt32;
+ while (timecnt32 > 0 && !is32(ats[timei32])) {
+ --timecnt32;
+ ++timei32;
+ }
+ while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
+ --leapcnt32;
+ while (leapcnt32 > 0 && !is32(trans[leapi32])) {
+ --leapcnt32;
+ ++leapi32;
+ }
fullname = erealloc(fullname,
(int) (strlen(directory) + 1 + strlen(name) + 1));
(void) sprintf(fullname, "%s/%s", directory, name);
***************
*** 1533,1599 ****
exit(EXIT_FAILURE);
}
}
! convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
! convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
! convert(eitol(leapcnt), tzh.tzh_leapcnt);
! convert(eitol(timecnt), tzh.tzh_timecnt);
! 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)
! DO(tzh_magic);
! DO(tzh_reserved);
! DO(tzh_ttisgmtcnt);
! DO(tzh_ttisstdcnt);
! DO(tzh_leapcnt);
! DO(tzh_timecnt);
! DO(tzh_typecnt);
! DO(tzh_charcnt);
#undef DO
! for (i = 0; i < timecnt; ++i) {
! j = leapcnt;
! while (--j >= 0)
! if (ats[i] >= trans[j]) {
! ats[i] = tadd(ats[i], corr[j]);
! break;
}
! puttzcode((long) ats[i], fp);
}
! if (timecnt > 0)
! (void) fwrite((void *) types, (size_t) sizeof types[0],
! (size_t) timecnt, fp);
! for (i = 0; i < typecnt; ++i) {
! puttzcode((long) gmtoffs[i], fp);
! (void) putc(isdsts[i], fp);
! (void) putc(abbrinds[i], fp);
! }
! if (charcnt != 0)
! (void) fwrite((void *) chars, (size_t) sizeof chars[0],
! (size_t) charcnt, fp);
! for (i = 0; i < leapcnt; ++i) {
! if (roll[i]) {
! if (timecnt == 0 || trans[i] < ats[0]) {
! j = 0;
! while (isdsts[j])
! if (++j >= typecnt) {
! j = 0;
! break;
! }
! } else {
! j = 1;
! while (j < timecnt && trans[i] >= ats[j])
! ++j;
! j = types[j - 1];
! }
! puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
! } else puttzcode((long) trans[i], fp);
! puttzcode((long) corr[i], fp);
! }
! for (i = 0; i < typecnt; ++i)
! (void) putc(ttisstds[i], fp);
! for (i = 0; i < typecnt; ++i)
! (void) putc(ttisgmts[i], fp);
if (ferror(fp) || fclose(fp)) {
(void) fprintf(stderr, _("%s: Error writing %s\n"),
progname, fullname);
--- 1580,1699 ----
exit(EXIT_FAILURE);
}
}
! for (pass = 1; pass <= 2; ++pass) {
! register int thistimei, thistimecnt;
! register int thisleapi, thisleapcnt;
! register int thistimelim, thisleaplim;
! int writetype[TZ_MAX_TIMES];
! int typemap[TZ_MAX_TYPES];
! register int thistypecnt;
!
! if (pass == 1) {
! thistimei = timei32;
! thistimecnt = timecnt32;
! thisleapi = leapi32;
! thisleapcnt = leapcnt32;
! } else {
! thistimei = 0;
! thistimecnt = timecnt;
! thisleapi = 0;
! thisleapcnt = leapcnt;
! }
! thistimelim = thistimei + thistimecnt;
! thisleaplim = thisleapi + thisleapcnt;
! for (i = 0; i < typecnt; ++i)
! writetype[i] = thistimecnt == timecnt;
! if (thistimecnt == 0)
! writetype[types[thistimelim - 1]] = TRUE;
! else {
! for (i = thistimei - 1; i < thistimelim; ++i)
! if (i >= 0)
! writetype[types[i]] = TRUE;
! /*
! ** For America/Godthab and Antarctica/Palmer
! */
! if (thistimei == 0)
! writetype[0] = TRUE;
! }
! thistypecnt = 0;
! for (i = 0; i < typecnt; ++i)
! typemap[i] = writetype[i] ? thistypecnt++ : -1;
#define DO(field) (void) fwrite((void *) tzh.field, \
(size_t) sizeof tzh.field, (size_t) 1, fp)
! tzh = tzh0;
! (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
! tzh.tzh_version[0] = ZIC_VERSION;
! convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
! convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
! convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
! convert(eitol(thistimecnt), tzh.tzh_timecnt);
! convert(eitol(thistypecnt), tzh.tzh_typecnt);
! convert(eitol(charcnt), tzh.tzh_charcnt);
! DO(tzh_magic);
! DO(tzh_version);
! DO(tzh_reserved);
! DO(tzh_ttisgmtcnt);
! DO(tzh_ttisstdcnt);
! DO(tzh_leapcnt);
! DO(tzh_timecnt);
! DO(tzh_typecnt);
! DO(tzh_charcnt);
#undef DO
! for (i = thistimei; i < thistimelim; ++i)
! if (pass == 1)
! puttzcode((long) ats[i], fp);
! else puttzcode64(ats[i], fp);
! for (i = thistimei; i < thistimelim; ++i) {
! unsigned char uc;
!
! uc = typemap[types[i]];
! (void) fwrite((void *) &uc,
! (size_t) sizeof uc,
! (size_t) 1,
! fp);
! }
! for (i = 0; i < typecnt; ++i)
! if (writetype[i]) {
! puttzcode(gmtoffs[i], fp);
! (void) putc(isdsts[i], fp);
! (void) putc(abbrinds[i], fp);
}
! if (charcnt != 0)
! (void) fwrite((void *) chars, (size_t) sizeof chars[0],
! (size_t) charcnt, fp);
! for (i = thisleapi; i < thisleaplim; ++i) {
! register zic_t todo;
!
! if (roll[i]) {
! if (timecnt == 0 || trans[i] < ats[0]) {
! j = 0;
! while (isdsts[j])
! if (++j >= typecnt) {
! j = 0;
! break;
! }
! } else {
! j = 1;
! while (j < timecnt &&
! trans[i] >= ats[j])
! ++j;
! j = types[j - 1];
! }
! todo = tadd(trans[i], -gmtoffs[j]);
! } else todo = trans[i];
! if (pass == 1)
! puttzcode((long) todo, fp);
! else puttzcode64(todo, fp);
! puttzcode(corr[i], fp);
! }
! for (i = 0; i < typecnt; ++i)
! if (writetype[i])
! (void) putc(ttisstds[i], fp);
! for (i = 0; i < typecnt; ++i)
! if (writetype[i])
! (void) putc(ttisgmts[i], fp);
}
! (void) fprintf(fp, "\n%s\n", string);
if (ferror(fp) || fclose(fp)) {
(void) fprintf(stderr, _("%s: Error writing %s\n"),
progname, fullname);
***************
*** 1602,1626 ****
}
static void
! doabbr(abbr, format, letters, isdst)
char * const abbr;
const char * const format;
const char * const letters;
const int isdst;
{
! if (strchr(format, '/') == NULL) {
if (letters == NULL)
(void) strcpy(abbr, format);
else (void) sprintf(abbr, format, letters);
! } else if (isdst)
! (void) strcpy(abbr, strchr(format, '/') + 1);
! else {
! (void) strcpy(abbr, format);
! *strchr(abbr, '/') = '\0';
}
}
static void
outzone(zpfirst, zonecount)
const struct zone * const zpfirst;
const int zonecount;
--- 1702,1928 ----
}
static void
! doabbr(abbr, format, letters, isdst, doquotes)
char * const abbr;
const char * const format;
const char * const letters;
const int isdst;
+ const int doquotes;
{
! register char * cp;
! register char * slashp;
! register int len;
!
! slashp = strchr(format, '/');
! if (slashp == NULL) {
if (letters == NULL)
(void) strcpy(abbr, format);
else (void) sprintf(abbr, format, letters);
! } else if (isdst) {
! (void) strcpy(abbr, slashp + 1);
! } else {
! if (slashp > format)
! (void) strncpy(abbr, format,
! (unsigned) (slashp - format));
! abbr[slashp - format] = '\0';
}
+ if (!doquotes)
+ return;
+ for (cp = abbr; *cp != '\0'; ++cp)
+ if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
+ strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
+ break;
+ len = strlen(abbr);
+ if (len > 0 && *cp == '\0')
+ return;
+ abbr[len + 2] = '\0';
+ abbr[len + 1] = '>';
+ for ( ; len > 0; --len)
+ abbr[len] = abbr[len - 1];
+ abbr[0] = '<';
}
static void
+ updateminmax(x)
+ const int x;
+ {
+ if (min_year > x)
+ min_year = x;
+ if (max_year < x)
+ max_year = x;
+ }
+
+ static int
+ stringoffset(result, offset)
+ char * result;
+ long offset;
+ {
+ register int hours;
+ register int minutes;
+ register int seconds;
+
+ result[0] = '\0';
+ if (offset < 0) {
+ (void) strcpy(result, "-");
+ offset = -offset;
+ }
+ seconds = offset % SECSPERMIN;
+ offset /= SECSPERMIN;
+ minutes = offset % MINSPERHOUR;
+ offset /= MINSPERHOUR;
+ hours = offset;
+ if (hours >= HOURSPERDAY) {
+ result[0] = '\0';
+ return -1;
+ }
+ (void) sprintf(end(result), "%d", hours);
+ if (minutes != 0 || seconds != 0) {
+ (void) sprintf(end(result), ":%02d", minutes);
+ if (seconds != 0)
+ (void) sprintf(end(result), ":%02d", seconds);
+ }
+ return 0;
+ }
+
+ static int
+ stringrule(result, rp, dstoff, gmtoff)
+ char * result;
+ const struct rule * const rp;
+ const long dstoff;
+ const long gmtoff;
+ {
+ register long tod;
+
+ result = end(result);
+ if (rp->r_dycode == DC_DOM) {
+ register int month, total;
+
+ if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
+ return -1;
+ total = 0;
+ for (month = 0; month < rp->r_month; ++month)
+ total += len_months[0][month];
+ (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
+ } else {
+ register int week;
+
+ if (rp->r_dycode == DC_DOWGEQ) {
+ week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
+ if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth)
+ return -1;
+ } else if (rp->r_dycode == DC_DOWLEQ) {
+ if (rp->r_dayofmonth == len_months[1][rp->r_month])
+ week = 5;
+ else {
+ week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
+ if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth)
+ return -1;
+ }
+ } else return -1; /* "cannot happen" */
+ (void) sprintf(result, "M%d.%d.%d",
+ rp->r_month + 1, week, rp->r_wday);
+ }
+ tod = rp->r_tod;
+ if (rp->r_todisgmt)
+ tod += gmtoff;
+ if (rp->r_todisstd && rp->r_stdoff == 0)
+ tod += dstoff;
+ if (tod < 0) {
+ result[0] = '\0';
+ return -1;
+ }
+ if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
+ (void) strcat(result, "/");
+ if (stringoffset(end(result), tod) != 0)
+ return -1;
+ }
+ return 0;
+ }
+
+ static void
+ stringzone(result, zpfirst, zonecount)
+ char * result;
+ const struct zone * const zpfirst;
+ const int zonecount;
+ {
+ register const struct zone * zp;
+ register struct rule * rp;
+ register struct rule * stdrp;
+ register struct rule * dstrp;
+ register int i;
+ register const char * abbrvar;
+
+ result[0] = '\0';
+ zp = zpfirst + zonecount - 1;
+ stdrp = dstrp = NULL;
+ for (i = 0; i < zp->z_nrules; ++i) {
+ rp = &zp->z_rules[i];
+ if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
+ continue;
+ if (rp->r_yrtype != NULL)
+ continue;
+ if (rp->r_stdoff == 0) {
+ if (stdrp == NULL)
+ stdrp = rp;
+ else return;
+ } else {
+ if (dstrp == NULL)
+ dstrp = rp;
+ else return;
+ }
+ }
+ if (stdrp == NULL && dstrp == NULL) {
+ /*
+ ** There are no rules running through "max".
+ ** Let's find the latest rule.
+ */
+ for (i = 0; i < zp->z_nrules; ++i) {
+ rp = &zp->z_rules[i];
+ if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
+ (rp->r_hiyear == stdrp->r_hiyear &&
+ rp->r_month > stdrp->r_month))
+ stdrp = rp;
+ }
+ if (stdrp != NULL && stdrp->r_stdoff != 0)
+ return; /* We end up in DST (a POSIX no-no). */
+ /*
+ ** Horrid special case: if year is 2037,
+ ** presume this is a zone handled on a year-by-year basis;
+ ** do not try to apply a rule to the zone.
+ */
+ if (stdrp != NULL && stdrp->r_hiyear == 2037)
+ return;
+ }
+ if (stdrp == NULL && zp->z_nrules != 0)
+ return;
+ abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
+ doabbr(result, zp->z_format, abbrvar, FALSE, TRUE);
+ if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
+ result[0] = '\0';
+ return;
+ }
+ if (dstrp == NULL)
+ return;
+ doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
+ if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
+ if (stringoffset(end(result),
+ -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
+ result[0] = '\0';
+ return;
+ }
+ (void) strcat(result, ",");
+ if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
+ result[0] = '\0';
+ return;
+ }
+ (void) strcat(result, ",");
+ if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
+ result[0] = '\0';
+ return;
+ }
+ }
+
+ static void
outzone(zpfirst, zonecount)
const struct zone * const zpfirst;
const int zonecount;
***************
*** 1637,1644 ****
register int startttisstd;
register int startttisgmt;
register int type;
! char startbuf[BUFSIZ];
INITIALIZE(untiltime);
INITIALIZE(starttime);
/*
--- 1939,1955 ----
register int startttisstd;
register int startttisgmt;
register int type;
! register char * startbuf;
! register char * ab;
! register char * envvar;
! register int max_abbr_len;
! register int max_envvar_len;
+ max_abbr_len = 2 + max_format_len + max_abbrvar_len;
+ max_envvar_len = 2 * max_abbr_len + 5 * 9;
+ startbuf = emalloc(max_abbr_len + 1);
+ ab = emalloc(max_abbr_len + 1);
+ envvar = emalloc(max_envvar_len + 1);
INITIALIZE(untiltime);
INITIALIZE(starttime);
/*
***************
*** 1653,1659 ****
--- 1964,2012 ----
*/
startttisstd = FALSE;
startttisgmt = FALSE;
+ min_year = max_year = EPOCH_YEAR;
+ if (leapseen) {
+ updateminmax(leapminyear);
+ updateminmax(leapmaxyear);
+ }
for (i = 0; i < zonecount; ++i) {
+ zp = &zpfirst[i];
+ updateminmax(zp->z_untilrule.r_loyear);
+ for (j = 0; j < zp->z_nrules; ++j) {
+ rp = &zp->z_rules[j];
+ if (rp->r_lowasnum)
+ updateminmax(rp->r_loyear);
+ if (rp->r_hiwasnum)
+ updateminmax(rp->r_hiyear);
+ }
+ }
+ /*
+ ** Generate lots of data if a rule can't cover all future times.
+ */
+ stringzone(envvar, zpfirst, zonecount);
+ if (noise && envvar[0] == '\0') {
+ register char * wp;
+
+ wp = ecpyalloc(_("no POSIX environment variable for zone"));
+ wp = ecatalloc(wp, " ");
+ wp = ecatalloc(wp, zpfirst->z_name);
+ warning(wp);
+ ifree(wp);
+ }
+ if (envvar[0] == '\0') {
+ if (min_year >= INT_MIN + YEARSPERREPEAT)
+ min_year -= YEARSPERREPEAT;
+ else min_year = INT_MIN;
+ if (max_year <= INT_MAX - YEARSPERREPEAT)
+ max_year += YEARSPERREPEAT;
+ else max_year = INT_MAX;
+ }
+ /*
+ ** For the benefit of older systems, generate data through 2037.
+ */
+ if (max_year < 2037)
+ max_year = 2037;
+ for (i = 0; i < zonecount; ++i) {
/*
** A guess that may well be corrected later.
*/
***************
*** 1670,1676 ****
if (zp->z_nrules == 0) {
stdoff = zp->z_stdoff;
doabbr(startbuf, zp->z_format,
! (char *) NULL, stdoff != 0);
type = addtype(oadd(zp->z_gmtoff, stdoff),
startbuf, stdoff != 0, startttisstd,
startttisgmt);
--- 2023,2029 ----
if (zp->z_nrules == 0) {
stdoff = zp->z_stdoff;
doabbr(startbuf, zp->z_format,
! (char *) NULL, stdoff != 0, FALSE);
type = addtype(oadd(zp->z_gmtoff, stdoff),
startbuf, stdoff != 0, startttisstd,
startttisgmt);
***************
*** 1700,1706 ****
register int k;
register zic_t jtime, ktime;
register long offset;
- char buf[BUFSIZ];
INITIALIZE(ktime);
if (useuntil) {
--- 2053,2058 ----
***************
*** 1756,1779 ****
stdoff);
doabbr(startbuf, zp->z_format,
rp->r_abbrvar,
! rp->r_stdoff != 0);
continue;
}
if (*startbuf == '\0' &&
startoff == oadd(zp->z_gmtoff,
! stdoff))
doabbr(startbuf,
zp->z_format,
rp->r_abbrvar,
rp->r_stdoff !=
! 0);
}
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
! doabbr(buf, zp->z_format, rp->r_abbrvar,
! rp->r_stdoff != 0);
offset = oadd(zp->z_gmtoff, rp->r_stdoff);
! type = addtype(offset, buf, rp->r_stdoff != 0,
rp->r_todisstd, rp->r_todisgmt);
addtt(ktime, type);
}
--- 2108,2134 ----
stdoff);
doabbr(startbuf, zp->z_format,
rp->r_abbrvar,
! rp->r_stdoff != 0,
! FALSE);
continue;
}
if (*startbuf == '\0' &&
startoff == oadd(zp->z_gmtoff,
! stdoff)) {
doabbr(startbuf,
zp->z_format,
rp->r_abbrvar,
rp->r_stdoff !=
! 0,
! FALSE);
! }
}
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
! doabbr(ab, zp->z_format, rp->r_abbrvar,
! rp->r_stdoff != 0, FALSE);
offset = oadd(zp->z_gmtoff, rp->r_stdoff);
! type = addtype(offset, ab, rp->r_stdoff != 0,
rp->r_todisstd, rp->r_todisgmt);
addtt(ktime, type);
}
***************
*** 1806,1812 ****
starttime = tadd(starttime, -gmtoff);
}
}
! writezone(zpfirst->z_name);
}
static void
--- 2161,2170 ----
starttime = tadd(starttime, -gmtoff);
}
}
! writezone(zpfirst->z_name, envvar);
! ifree(startbuf);
! ifree(ab);
! ifree(envvar);
}
static void
***************
*** 2185,2192 ****
will not work with pre-2004 versions of zic"));
}
}
- if (dayoff < 0 && !TYPE_SIGNED(zic_t))
- return min_time;
if (dayoff < min_time / SECSPERDAY)
return min_time;
if (dayoff > max_time / SECSPERDAY)
--- 2543,2548 ----
***************
*** 2212,2218 ****
cp = string;
wp = NULL;
while (isascii((unsigned char) *cp) &&
! isalpha((unsigned char) *cp))
++cp;
if (cp - string == 0)
wp = _("time zone abbreviation lacks alphabetic at start");
--- 2568,2574 ----
cp = string;
wp = NULL;
while (isascii((unsigned char) *cp) &&
! isspace((unsigned char) *cp))
++cp;
if (cp - string == 0)
wp = _("time zone abbreviation lacks alphabetic at start");
*** tzftp/scheck.c Thu Dec 22 09:31:15 2005
--- tzexp3/scheck.c Tue Jan 17 14:42:55 2006
***************
*** 1,6 ****
#ifndef lint
#ifndef NOID
! static char elsieid[] = "@(#)scheck.c 8.16";
#endif /* !defined lint */
#endif /* !defined NOID */
--- 1,6 ----
#ifndef lint
#ifndef NOID
! static char elsieid[] = "@(#)scheck.c 8.17";
#endif /* !defined lint */
#endif /* !defined NOID */
***************
*** 8,27 ****
#include "private.h"
! char *
scheck(string, format)
const char * const string;
! char * const format;
{
register char * fbuf;
register const char * fp;
register char * tp;
register int c;
! register char * result;
char dummy;
- static char nada;
! result = &nada;
if (string == NULL || format == NULL)
return result;
fbuf = imalloc((int) (2 * strlen(format) + 4));
--- 8,26 ----
#include "private.h"
! const char *
scheck(string, format)
const char * const string;
! const char * const format;
{
register char * fbuf;
register const char * fp;
register char * tp;
register int c;
! register const char * result;
char dummy;
! result = "";
if (string == NULL || format == NULL)
return result;
fbuf = imalloc((int) (2 * strlen(format) + 4));
More information about the tz
mailing list