Below are diffs to the time zone code to cope with 64-bit time_t systems; these reflect suggestions I've received to date. Absent negative feedback, I'll update the ftp versions on May 2, 2005. --ado diff -c -r tz/localtime.c tzexp/localtime.c *** tz/localtime.c Thu Apr 21 15:04:15 2005 --- tzexp/localtime.c Mon Apr 4 15:39:41 2005 *************** *** 5,11 **** #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 7.91"; #endif /* !defined NOID */ #endif /* !defined lint */ --- 5,11 ---- #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 7.92"; #endif /* !defined NOID */ #endif /* !defined lint */ *************** *** 98,103 **** --- 98,105 ---- 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]; *************** *** 123,128 **** --- 125,131 ---- */ static long detzcode P((const char * codep)); + static time_t detzcode64 P((const char * codep)); static const char * getzname P((const char * strp)); static const char * getnum P((const char * strp, int * nump, int min, int max)); *************** *** 221,226 **** --- 224,242 ---- return result; } + static time_t + detzcode64(codep) + const char * const codep; + { + register signed64_t result; + register int i; + + result = (codep[0] & 0x80) ? ~0L : 0L; + for (i = 0; i < 8; ++i) + result = (result << 8) | (codep[i] & 0xff); + return (time_t) result; + } + static void settzname P((void)) { *************** *** 276,284 **** 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; --- 292,308 ---- register const char * name; register struct state * const sp; { ! 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; *************** *** 316,333 **** 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); --- 340,352 ---- 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); *************** *** 342,358 **** (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++; --- 361,379 ---- (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++; *************** *** 380,387 **** register struct lsinfo * lsisp; lsisp = &sp->lsis[i]; ! lsisp->ls_trans = detzcode(p); ! p += 4; lsisp->ls_corr = detzcode(p); p += 4; } --- 401,409 ---- 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; } *************** *** 438,444 **** --- 460,488 ---- } break; } + /* + ** If this is an old file, we're done. + */ + if (u.tzhead.tzh_version[0] == '\0') + break; + /* + ** If this is a narrow integer time_t system, we're done. + */ + if (stored >= sizeof(time_t) && TYPE_INTEGRAL(time_t)) + break; + nread -= p - u.buf; + for (i = 0; i < nread; ++i) + u.buf[i] = p[i]; } + i = 2 * YEARSPERREPEAT; + sp->goback = sp->goahead = sp->timecnt > i; + sp->goback &= sp->types[i] == sp->types[0] && + sp->ats[i] - sp->ats[0] == SECSPERREPEAT; + sp->goahead &= + sp->types[sp->timecnt - 1] == + sp->types[sp->timecnt - 1 - i] && + sp->ats[sp->timecnt - 1] - sp->ats[sp->timecnt - 1 - i] == + SECSPERREPEAT; return 0; } *************** *** 1046,1051 **** --- 1090,1133 ---- 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 signed64_t icycles; + + if (t < sp->ats[0]) + seconds = sp->ats[0] - t; + else seconds = t - sp->ats[sp->timecnt - 1]; + --seconds; + tcycles = seconds / SECSPERREPEAT; + ++tcycles; + icycles = tcycles; + if (tcycles - icycles >= 1 || icycles - tcycles >= 1) + return NULL; + seconds = icycles; + seconds *= SECSPERREPEAT; + 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) *** tz/private.h Thu Apr 21 15:20:23 2005 --- tzexp/private.h Thu Apr 21 15:21:15 2005 *************** *** 21,30 **** #ifndef lint #ifndef NOID ! static char privatehid[] = "@(#)private.h 7.55"; #endif /* !defined NOID */ #endif /* !defined lint */ /* ** Defaults for preprocessor symbols. ** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'. --- 21,36 ---- #ifndef lint #ifndef NOID ! static char privatehid[] = "@(#)private.h 7.62"; #endif /* !defined NOID */ #endif /* !defined lint */ + #ifndef SIGNED64_T + #define SIGNED64_T long long + #endif /* !defined SIGNED64_T */ + + typedef SIGNED64_T signed64_t; + /* ** Defaults for preprocessor symbols. ** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'. *************** *** 308,313 **** --- 314,327 ---- 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 */ + + #ifndef SECSPERREPEAT + #define SECSPERREPEAT 12622780800 + #endif /* !defined SECSPERREPEAT */ + /* ** UNIX was a registered trademark of The Open Group in 2003. */ diff -c -r tz/tzfile.5 tzexp/tzfile.5 *** tz/tzfile.5 Thu Apr 21 15:04:14 2005 --- tzexp/tzfile.5 Thu Apr 21 15:09:16 2005 *************** *** 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.11 .\" This file is in the public domain, so clarified as of .\" 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). --- 133,145 ---- .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. .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 (arthur_david_olson@nih.gov). diff -c -r tz/tzfile.h tzexp/tzfile.h *** tz/tzfile.h Thu Apr 21 15:04:14 2005 --- tzexp/tzfile.h Thu Apr 21 15:09:17 2005 *************** *** 21,27 **** #ifndef lint #ifndef NOID ! static char tzfilehid[] = "@(#)tzfile.h 7.17"; #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,102 ---- */ /* + ** 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. + */ + + /* ** 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 1000 #endif /* !defined TZ_MAX_TIMES */ #ifndef TZ_MAX_TYPES diff -c -r tz/zic.8 tzexp/zic.8 *** tz/zic.8 Thu Apr 21 15:04:14 2005 --- tzexp/zic.8 Mon Apr 4 15:39:43 2005 *************** *** 21,28 **** .B \-L .I leapsecondfilename ] [ - .B \-s - ] [ .B \-y .I command ] [ --- 21,26 ---- *************** *** 86,96 **** .IR zic ) appears in the input. .TP - .B \-s - Limit time values stored in output files to values that are the same - whether they're taken to be signed or unsigned. - You can use this option to generate SVVS-compatible files. - .TP .BI "\-y " command Use the given .I command --- 84,89 ---- *************** *** 421,424 **** /usr/local/etc/zoneinfo standard directory used for created files .SH "SEE ALSO" newctime(3), tzfile(5), zdump(8) ! .\" @(#)zic.8 7.22 --- 414,417 ---- /usr/local/etc/zoneinfo standard directory used for created files .SH "SEE ALSO" newctime(3), tzfile(5), zdump(8) ! .\" @(#)zic.8 7.23 diff -c -r tz/zic.c tzexp/zic.c *** tz/zic.c Thu Apr 21 15:04:15 2005 --- tzexp/zic.c Mon Apr 4 15:39:43 2005 *************** *** 1,15 **** ! static char elsieid[] = "@(#)zic.c 7.122"; - /* - ** 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" #if HAVE_SYS_STAT_H #include "sys/stat.h" #endif --- 1,13 ---- ! static char elsieid[] = "@(#)zic.c 7.127"; #include "private.h" #include "locale.h" #include "tzfile.h" + #define ZIC_VERSION '2' + + typedef signed64_t zic_t; + #if HAVE_SYS_STAT_H #include "sys/stat.h" #endif *************** *** 40,45 **** --- 38,45 ---- 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 */ *************** *** 99,104 **** --- 99,105 ---- 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)); *************** *** 117,122 **** --- 118,124 ---- 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)); *************** *** 126,131 **** --- 128,134 ---- 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, *************** *** 146,158 **** 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; --- 149,162 ---- static int errors; static const char * filename; static int leapcnt; + static int leapseen; + static int leapminyear; + static int leapmaxyear; static int linenum; 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; *************** *** 449,455 **** 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); (void) exit(EXIT_FAILURE); --- 453,459 ---- 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); (void) exit(EXIT_FAILURE); *************** *** 460,466 **** static const char * directory; static const char * leapsec; static const char * yitcommand; - static int sflag = FALSE; int main(argc, argv) --- 464,469 ---- *************** *** 482,487 **** --- 485,495 ---- (void) textdomain(TZ_DOMAIN); #endif /* HAVE_GETTEXT */ progname = argv[0]; + if (8 > sizeof(signed64_t)) { + (void) fprintf(stderr, + "%s: wild compilation-time specification of SIGNED64_T\n", progname); + exit(EXIT_FAILURE); + } for (i = 1; i < argc; ++i) if (strcmp(argv[i], "--version") == 0) { (void) printf("%s\n", elsieid); *************** *** 545,551 **** noise = TRUE; break; case 's': ! sflag = TRUE; break; } if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) --- 553,559 ---- noise = TRUE; break; case 's': ! (void) printf("%s: -s ignored\n", progname); break; } if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) *************** *** 667,720 **** 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 --- 675,691 ---- 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 *************** *** 1155,1160 **** --- 1126,1136 ---- 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) { *************** *** 1309,1315 **** */ cp = loyearp; lp = byword(cp, begin_years); ! if (lp != NULL) switch ((int) lp->l_value) { case YR_MINIMUM: rp->r_loyear = INT_MIN; break; --- 1285,1292 ---- */ 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; *************** *** 1324,1337 **** } 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; --- 1301,1311 ---- } 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; *************** *** 1349,1359 **** } 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")); --- 1323,1328 ---- *************** *** 1368,1375 **** } 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: --- 1337,1342 ---- *************** *** 1423,1429 **** char * const buf; { register int i; ! register long shift; for (i = 0, shift = 24; i < 4; ++i, shift -= 8) buf[i] = val >> shift; --- 1390,1396 ---- char * const buf; { register int i; ! register int shift; for (i = 0, shift = 24; i < 4; ++i, shift -= 8) buf[i] = val >> shift; *************** *** 1430,1435 **** --- 1397,1414 ---- } 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; *************** *** 1440,1445 **** --- 1419,1435 ---- (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) void * avp; *************** *** 1452,1467 **** 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. --- 1442,1469 ---- else return 0; } + static int + is32(x) + zic_t x; + { + x >>= 31; + return x == 0 || x == ~0; + } + static void writezone(name) const char * const name; { ! 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. *************** *** 1505,1510 **** --- 1507,1542 ---- 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); *************** *** 1529,1595 **** (void) 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); --- 1561,1652 ---- (void) exit(EXIT_FAILURE); } } ! for (pass = 1; pass <= 2; ++pass) { ! register int thistimei, thistimecnt; ! register int thisleapi, thisleapcnt; ! register int thistimelim, thisleaplim; ! ! 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; #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(typecnt), tzh.tzh_ttisgmtcnt); ! convert(eitol(typecnt), tzh.tzh_ttisstdcnt); ! convert(eitol(thisleapcnt), tzh.tzh_leapcnt); ! convert(eitol(thistimecnt), tzh.tzh_timecnt); ! convert(eitol(typecnt), 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); ! if (thistimecnt > 0) ! (void) fwrite((void *) &types[thistimei], ! (size_t) sizeof types[0], ! (size_t) thistimecnt, ! fp); ! for (i = 0; i < typecnt; ++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(todo, fp); ! else puttzcode64(todo, fp); ! puttzcode(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); *************** *** 1617,1622 **** --- 1674,1689 ---- } static void + updateminmax(x) + const int x; + { + if (min_year > x) + min_year = x; + if (max_year < x) + max_year = x; + } + + static void outzone(zpfirst, zonecount) const struct zone * const zpfirst; const int zonecount; *************** *** 1649,1655 **** --- 1716,1744 ---- */ 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); + } + } + 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 (i = 0; i < zonecount; ++i) { /* ** A guess that may well be corrected later. */ *************** *** 2180,2187 **** 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) --- 2269,2274 ----