diff options
Diffstat (limited to 'timezone/zic.c')
-rw-r--r-- | timezone/zic.c | 988 |
1 files changed, 723 insertions, 265 deletions
diff --git a/timezone/zic.c b/timezone/zic.c index 9bb8662e55..f7393ea7ba 100644 --- a/timezone/zic.c +++ b/timezone/zic.c @@ -1,9 +1,22 @@ -static char elsieid[] = "@(#)zic.c 7.116"; +/* +** This file is in the public domain, so clarified as of +** 2006-07-17 by Arthur David Olson. +*/ + +static char elsieid[] = "@(#)zic.c 8.7"; #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 */ + #if HAVE_SYS_STAT_H #include "sys/stat.h" #endif @@ -15,7 +28,7 @@ static char elsieid[] = "@(#)zic.c 7.116"; /* ** 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. @@ -26,6 +39,11 @@ static char elsieid[] = "@(#)zic.c 7.116"; #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; @@ -34,6 +52,8 @@ struct rule { 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 */ @@ -50,7 +70,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 */ }; /* @@ -76,7 +96,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[], @@ -85,17 +105,18 @@ 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)); 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)); + 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)); @@ -111,6 +132,7 @@ static void inrule P((char ** fields, int nfields)); 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)); @@ -120,33 +142,42 @@ static void newabbr P((const char * abbr)); 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 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 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 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 void writezone P((const char * name, const char * string)); 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 leapseen; +static int leapminyear; +static int leapmaxyear; static int linenum; -static time_t max_time; +static int max_abbrvar_len; +static int max_format_len; +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; static const char * rfilename; static int rlinenum; @@ -334,7 +365,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]; @@ -343,7 +374,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]; @@ -360,7 +391,7 @@ char * const ptr; (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, e); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } return ptr; } @@ -374,7 +405,7 @@ char * const ptr; ** Error handling. */ -#if !(HAVE_STRERROR - 0) +#if !HAVE_STRERROR static char * strerror(errnum) int errnum; @@ -385,7 +416,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) @@ -442,9 +473,11 @@ const char * const string; static void 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"), + (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); + exit(EXIT_FAILURE); } static const char * psxrules; @@ -452,7 +485,6 @@ static const char * lcltime; static const char * directory; static const char * leapsec; static const char * yitcommand; -static int sflag = FALSE; int main(argc, argv) @@ -466,19 +498,23 @@ 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_CTYPE, ""); - (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]; + 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); - (void) exit(EXIT_SUCCESS); + exit(EXIT_SUCCESS); } while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1) switch (c) { @@ -491,7 +527,7 @@ char * argv[]; (void) fprintf(stderr, _("%s: More than one -d option specified\n"), progname); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } break; case 'l': @@ -501,7 +537,7 @@ _("%s: More than one -d option specified\n"), (void) fprintf(stderr, _("%s: More than one -l option specified\n"), progname); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } break; case 'p': @@ -511,7 +547,7 @@ _("%s: More than one -l option specified\n"), (void) fprintf(stderr, _("%s: More than one -p option specified\n"), progname); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } break; case 'y': @@ -521,7 +557,7 @@ _("%s: More than one -p option specified\n"), (void) fprintf(stderr, _("%s: More than one -y option specified\n"), progname); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } break; case 'L': @@ -531,14 +567,14 @@ _("%s: More than one -y option specified\n"), (void) fprintf(stderr, _("%s: More than one -L option specified\n"), progname); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } break; case 'v': noise = TRUE; break; case 's': - sflag = TRUE; + (void) printf("%s: -s ignored\n", progname); break; } if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) @@ -558,7 +594,7 @@ _("%s: More than one -L option specified\n"), for (i = optind; i < argc; ++i) infile(argv[i]); if (errors) - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); associate(); for (i = 0; i < nzones; i = j) { /* @@ -574,6 +610,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); @@ -618,85 +659,54 @@ const char * const tofile; int result; if (mkdirs(toname) != 0) - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); result = link(fromname, toname); -#if (HAVE_SYMLINK - 0) +#if HAVE_SYMLINK if (result != 0 && - access(fromname, F_OK) == 0 && - !itsdir(fromname)) { - const char *s = tofile; - register char * symlinkcontents = NULL; - while ((s = strchr(s+1, '/')) != NULL) - symlinkcontents = ecatalloc(symlinkcontents, "../"); - symlinkcontents = ecatalloc(symlinkcontents, fromname); - - result = unlink(toname); - if (result != 0 && errno != ENOENT) { - const char *e = strerror(errno); - - (void) fprintf(stderr, - _("%s: Can't unlink %s: %s\n"), - progname, toname, e); - (void) exit(EXIT_FAILURE); - } - - result = symlink(symlinkcontents, toname); - if (result == 0) + access(fromname, F_OK) == 0 && + !itsdir(fromname)) { + const char *s = tofile; + register char * symlinkcontents = NULL; + + while ((s = strchr(s+1, '/')) != NULL) + symlinkcontents = + ecatalloc(symlinkcontents, + "../"); + symlinkcontents = + ecatalloc(symlinkcontents, + fromname); + result = symlink(symlinkcontents, + toname); + if (result == 0) warning(_("hard link failed, symbolic link used")); - ifree(symlinkcontents); + ifree(symlinkcontents); } -#endif +#endif /* HAVE_SYMLINK */ if (result != 0) { const char *e = strerror(errno); (void) fprintf(stderr, _("%s: Can't link from %s to %s: %s\n"), progname, fromname, toname, e); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } } ifree(fromname); 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(time_t) < MAX_BITS_IN_FILE) ? TYPE_BIT(time_t) : MAX_BITS_IN_FILE) +#define TIME_T_BITS_IN_FILE 64 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; - if (sflag) - min_time = 0; - } else { - min_time = 0; - max_time = 2 - sflag; - max_time <<= TIME_T_BITS_IN_FILE - 1; - --max_time; - } - min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year; - max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year; - min_year_representable = min_year; - max_year_representable = max_year; + 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 @@ -793,7 +803,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. @@ -803,7 +813,7 @@ associate P((void)) } } if (errors) - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } static void @@ -827,7 +837,7 @@ const char * name; (void) fprintf(stderr, _("%s: Can't open %s: %s\n"), progname, name, e); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } wantcont = FALSE; for (num = 1; ; ++num) { @@ -837,7 +847,7 @@ const char * name; cp = strchr(buf, '\n'); if (cp == NULL) { error(_("line too long")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } *cp = '\0'; fields = getfields(buf); @@ -881,7 +891,7 @@ _("%s: Leap line in non leap seconds file %s\n"), (void) fprintf(stderr, _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } } ifree((char *) fields); @@ -889,14 +899,14 @@ _("%s: panic: Invalid l_value %d\n"), if (ferror(fp)) { (void) fprintf(stderr, _("%s: Error reading %s\n"), progname, filename); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } if (fp != stdin && fclose(fp)) { const char *e = strerror(errno); (void) fprintf(stderr, _("%s: Error closing %s: %s\n"), progname, filename, e); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } if (wantcont) error(_("expected continuation line not found")); @@ -971,6 +981,8 @@ const int nfields; 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; @@ -1076,6 +1088,8 @@ const int iscont; } 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; @@ -1096,7 +1110,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; } } @@ -1120,7 +1136,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")); @@ -1129,12 +1145,17 @@ 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; } + if (!leapseen || leapmaxyear < year) + leapmaxyear = year; + if (!leapseen || leapminyear > year) + leapminyear = year; + leapseen = TRUE; j = EPOCH_YEAR; while (j != year) { if (year > j) { @@ -1164,7 +1185,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; } @@ -1176,7 +1197,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]; { @@ -1200,7 +1221,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); @@ -1287,7 +1310,8 @@ const char * const timep; */ cp = loyearp; lp = byword(cp, begin_years); - if (lp != NULL) switch ((int) lp->l_value) { + rp->r_lowasnum = lp == NULL; + if (!rp->r_lowasnum) switch ((int) lp->l_value) { case YR_MINIMUM: rp->r_loyear = INT_MIN; break; @@ -1298,18 +1322,15 @@ const char * const timep; (void) fprintf(stderr, _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } 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) { + 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; @@ -1323,15 +1344,10 @@ const char * const timep; (void) fprintf(stderr, _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } 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")); @@ -1346,8 +1362,6 @@ const char * const timep; } 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: @@ -1401,13 +1415,25 @@ const long val; char * const buf; { register int i; - register long shift; + register int shift; for (i = 0, shift = 24; i < 4; ++i, shift -= 8) buf[i] = val >> shift; } 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; @@ -1418,28 +1444,50 @@ FILE * const fp; (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; -void * bvp; +const void * avp; +const 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; + 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) +writezone(name, string) const char * const name; +const char * const string; { - register FILE * fp; - register int i, j; - static char * fullname; - static struct tzhead tzh; - time_t ats[TZ_MAX_TIMES]; - unsigned char types[TZ_MAX_TIMES]; + 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. @@ -1462,14 +1510,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) @@ -1484,6 +1531,36 @@ const char * const name; 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] - corr[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); @@ -1495,102 +1572,388 @@ const char * const name; (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"), progname, fullname, e); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } if ((fp = fopen(fullname, "wb")) == NULL) { if (mkdirs(fullname) != 0) - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); if ((fp = fopen(fullname, "wb")) == NULL) { const char *e = strerror(errno); (void) fprintf(stderr, _("%s: Can't create %s: %s\n"), progname, fullname, e); - (void) exit(EXIT_FAILURE); + 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; + 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; + char thischars[TZ_MAX_CHARS]; + char thischarcnt; + int indmap[TZ_MAX_CHARS]; + + 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) { + /* + ** No transition times fall in the current + ** (32- or 64-bit) window. + */ + if (typecnt != 0) + writetype[typecnt - 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; + for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i) + indmap[i] = -1; + thischarcnt = 0; + for (i = 0; i < typecnt; ++i) { + register char * thisabbr; + + if (!writetype[i]) + continue; + if (indmap[abbrinds[i]] >= 0) + continue; + thisabbr = &chars[abbrinds[i]]; + for (j = 0; j < thischarcnt; ++j) + if (strcmp(&thischars[j], thisabbr) == 0) + break; + if (j == thischarcnt) { + (void) strcpy(&thischars[(int) thischarcnt], + thisabbr); + thischarcnt += strlen(thisabbr) + 1; } - 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]; + indmap[abbrinds[i]] = j; + } +#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(thischarcnt), 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((unsigned char) indmap[abbrinds[i]], fp); } - 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 (thischarcnt != 0) + (void) fwrite((void *) thischars, + (size_t) sizeof thischars[0], + (size_t) thischarcnt, 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); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } } static void -doabbr(abbr, format, letters, isdst) +doabbr(abbr, format, letters, isdst, doquotes) char * const abbr; const char * const format; const char * const letters; const int isdst; +const int doquotes; { - if (strchr(format, '/') == NULL) { + 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, strchr(format, '/') + 1); - else { - (void) strcpy(abbr, format); - *strchr(abbr, '/') = '\0'; + } 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; } } @@ -1603,7 +1966,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; @@ -1611,8 +1974,17 @@ const int zonecount; register int startttisstd; register int startttisgmt; register int type; - char startbuf[BUFSIZ]; - + 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); /* @@ -1622,11 +1994,53 @@ const int zonecount; typecnt = 0; charcnt = 0; /* - ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au) + ** Thanks to Earl Chew ** for noting the need to unconditionally initialize startttisstd. */ 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. @@ -1644,7 +2058,7 @@ const int zonecount; if (zp->z_nrules == 0) { stdoff = zp->z_stdoff; doabbr(startbuf, zp->z_format, - (char *) NULL, stdoff != 0); + (char *) NULL, stdoff != 0, FALSE); type = addtype(oadd(zp->z_gmtoff, stdoff), startbuf, stdoff != 0, startttisstd, startttisgmt); @@ -1672,9 +2086,8 @@ const int zonecount; } for ( ; ; ) { register int k; - register time_t jtime, ktime; + register zic_t jtime, ktime; register long offset; - char buf[BUFSIZ]; INITIALIZE(ktime); if (useuntil) { @@ -1730,23 +2143,27 @@ const int zonecount; stdoff); doabbr(startbuf, zp->z_format, rp->r_abbrvar, - rp->r_stdoff != 0); + 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); + 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(buf, zp->z_format, rp->r_abbrvar, - rp->r_stdoff != 0); + doabbr(ab, zp->z_format, rp->r_abbrvar, + rp->r_stdoff != 0, FALSE); offset = oadd(zp->z_gmtoff, rp->r_stdoff); - type = addtype(offset, buf, rp->r_stdoff != 0, + type = addtype(offset, ab, rp->r_stdoff != 0, rp->r_todisstd, rp->r_todisgmt); addtt(ktime, type); } @@ -1779,12 +2196,15 @@ error(_("can't determine time zone abbreviation to use just after until time")); starttime = tadd(starttime, -gmtoff); } } - writezone(zpfirst->z_name); + writezone(zpfirst->z_name, envvar); + ifree(startbuf); + ifree(ab); + ifree(envvar); } static void addtt(starttime, type) -const time_t starttime; +const zic_t starttime; int type; { if (starttime <= min_time || @@ -1803,7 +2223,7 @@ int type; } if (timecnt >= TZ_MAX_TIMES) { error(_("too many transitions?!")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } attypes[timecnt].at = starttime; attypes[timecnt].type = type; @@ -1822,15 +2242,15 @@ const int ttisgmt; if (isdst != TRUE && isdst != FALSE) { error(_("internal error - addtype called with bad isdst")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } if (ttisstd != TRUE && ttisstd != FALSE) { error(_("internal error - addtype called with bad ttisstd")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } if (ttisgmt != TRUE && ttisgmt != FALSE) { error(_("internal error - addtype called with bad ttisgmt")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } /* ** See if there's already an entry for this zone type. @@ -1849,7 +2269,7 @@ const int ttisgmt; */ if (typecnt >= TZ_MAX_TYPES) { error(_("too many local time types")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } gmtoffs[i] = gmtoff; isdsts[i] = isdst; @@ -1868,7 +2288,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; @@ -1877,13 +2297,13 @@ int count; if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { error(_("too many leap seconds")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } for (i = 0; i < leapcnt; ++i) if (t <= trans[i]) { if (t == trans[i]) { error(_("repeated leap second moment")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } break; } @@ -1938,7 +2358,7 @@ const char * const type; (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"), progname, buf, result); for ( ; ; ) - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } static int @@ -2019,8 +2439,9 @@ register char * cp; emalloc((int) ((strlen(cp) + 1) * sizeof *array)); nsubs = 0; for ( ; ; ) { - while (isascii(*cp) && isspace((unsigned char) *cp)) - ++cp; + while (isascii((unsigned char) *cp) && + isspace((unsigned char) *cp)) + ++cp; if (*cp == '\0' || *cp == '#') break; array[nsubs++] = dp = cp; @@ -2030,7 +2451,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)) @@ -2051,17 +2474,17 @@ const long t2; t = t1 + t2; if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { error(_("time overflow")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } 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; @@ -2070,7 +2493,7 @@ const long t2; t = t1 + t2; if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { error(_("time overflow")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } return t; } @@ -2080,14 +2503,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; @@ -2117,7 +2540,7 @@ register const int wantedy; --i; else { error(_("use of 2/29 in non leap-year")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } } --i; @@ -2151,18 +2574,15 @@ 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)) - return min_time; if (dayoff < min_time / SECSPERDAY) return min_time; if (dayoff > max_time / SECSPERDAY) return max_time; - t = (time_t) dayoff * SECSPERDAY; - if (t > 0 && max_time - t < rp->r_tod) - return max_time; + t = (zic_t) dayoff * SECSPERDAY; return tadd(t, rp->r_tod); } @@ -2172,10 +2592,48 @@ 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((unsigned char) *cp) && + isalpha((unsigned char) *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((unsigned char) *cp) && + isdigit((unsigned char) *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")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } (void) strcpy(&chars[charcnt], string); charcnt += eitol(i); @@ -2239,7 +2697,7 @@ const int i; (void) fprintf(stderr, _("%s: %d did not sign extend correctly\n"), progname, i); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } return l; } |