X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/73c04bcfe1096173b00431f0cdc742894b15eef0..f3c0d7a59d99c2a94c6b8822291f0e42be3773c9:/icuSources/tools/tzcode/zic.c diff --git a/icuSources/tools/tzcode/zic.c b/icuSources/tools/tzcode/zic.c index 47f92d22..0d95a002 100644 --- a/icuSources/tools/tzcode/zic.c +++ b/icuSources/tools/tzcode/zic.c @@ -3,15 +3,43 @@ ** 2006-07-17 by Arthur David Olson. */ -static char elsieid[] = "@(#)zic.c 8.7"; +/* Enable extensions and modifications for ICU. */ +#define ICU + +/* Continue executing after link failure. Even if ICU is undefined + * (for vanilla zic behavior), ICU_LINKS should be defined, since zic + * appears to fail on the 2003 data the first time through during the + * linking phase. Running zic twice, with ICU_LINKS defined, causes + * links to be handled correctly. */ +#define ICU_LINKS +#define LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH + +#ifdef ICU +/* These constants are embedded in dynamically generated header + * version.h in the standard tzcode distribution. */ +static char const PKGVERSION[]="N/A"; +static char const TZVERSION[]="N/A"; +static char const REPORT_BUGS_TO[]="N/A"; +#else +#include "version.h" +#endif #include "private.h" #include "locale.h" #include "tzfile.h" -#define ZIC_VERSION '2' +#include +#if U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS +#include +#endif + +#define ZIC_VERSION_PRE_2013 '2' +#define ZIC_VERSION '3' typedef int_fast64_t zic_t; +#define ZIC_MIN INT_FAST64_MIN +#define ZIC_MAX INT_FAST64_MAX +#define SCNdZIC SCNdFAST64 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN #define ZIC_MAX_ABBR_LEN_WO_WARN 6 @@ -26,16 +54,6 @@ typedef int_fast64_t zic_t; #define MKDIR_UMASK 0755 #endif -/* Enable extensions and modifications for ICU. */ -#define ICU - -/* Continue executing after link failure. Even if ICU is undefined - * (for vanilla zic behavior), ICU_LINKS should be defined, since zic - * appears to fail on the 2003 data the first time through during the - * linking phase. Running zic twice, with ICU_LINKS defined, causes - * links to be handled correctly. */ -#define ICU_LINKS - #ifdef ICU #include "tz2icu.h" #endif @@ -53,9 +71,6 @@ typedef int_fast64_t zic_t; #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 { @@ -63,8 +78,8 @@ struct rule { int r_linenum; const char * r_name; - int r_loyear; /* for example, 1986 */ - int r_hiyear; /* for example, 1986 */ + zic_t r_loyear; /* for example, 1986 */ + zic_t r_hiyear; /* for example, 1986 */ const char * r_yrtype; int r_lowasnum; int r_hiwasnum; @@ -75,12 +90,12 @@ struct rule { int r_dayofmonth; int r_wday; - long r_tod; /* time from midnight */ + zic_t r_tod; /* time from midnight */ int r_todisstd; /* above is standard time if TRUE */ /* or wall clock time if FALSE */ int r_todisgmt; /* above is GMT if TRUE */ /* or local time if FALSE */ - long r_stdoff; /* offset from standard time */ + zic_t r_stdoff; /* offset from standard time */ const char * r_abbrvar; /* variable part of abbreviation */ int r_todo; /* a rule to do (used in outzone) */ @@ -100,11 +115,11 @@ struct zone { int z_linenum; const char * z_name; - long z_gmtoff; + zic_t z_gmtoff; const char * z_rule; const char * z_format; - long z_stdoff; + zic_t z_stdoff; struct rule * z_rules; int z_nrules; @@ -113,96 +128,82 @@ struct zone { zic_t z_untiltime; }; -extern int getopt P((int argc, char * const argv[], - const char * options)); -extern int link P((const char * fromname, const char * toname)); +extern int getopt(int argc, char * const argv[], + const char * options); +extern int link(const char * fromname, const char * toname); extern char * optarg; extern int optind; -static void addtt P((zic_t starttime, int type)); +#if ! HAVE_LINK +# define link(from, to) (-1) +#endif +#if ! HAVE_SYMLINK +# define symlink(from, to) (-1) +#endif + +static void addtt(zic_t starttime, int type); #ifdef ICU -static int addtype P((long gmtoff, long rawoff, long dstoff, - const char * abbr, int isdst, - int ttisstd, int ttisgmt)); +static int addtype(const zic_t gmtoff, const zic_t rawoff, const zic_t dstoff, + char *const abbr, int isdst, + int ttisstd, int ttisgmt); #else -static int addtype P((long gmtoff, const char * abbr, int isdst, - int ttisstd, int ttisgmt)); +static int addtype(zic_t gmtoff, const char * abbr, int isdst, + int ttisstd, int ttisgmt); #endif -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, 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)); -static long eitol P((int i)); -static void error P((const char * message)); -static char ** getfields P((char * buf)); -static long gethms P((const char * string, const char * errstrng, - int signable)); -static void infile P((const char * filename)); -static void inleap P((char ** fields, int nfields)); -static void inlink P((char ** fields, int nfields)); -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)); -static char * memcheck P((char * tocheck)); -static int mkdirs P((char * filename)); -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 zic_t rpytime P((const struct rule * rp, int wantedy)); -static void rulesub P((struct rule * rp, +static void leapadd(zic_t t, int positive, int rolling, int count); +static void adjleap(void); +static void associate(void); +static void dolink(const char * fromfield, const char * tofield); +static char ** getfields(char * buf); +static zic_t gethms(const char * string, const char * errstrng, + int signable); +static void infile(const char * filename); +static void inleap(char ** fields, int nfields); +static void inlink(char ** fields, int nfields); +static void inrule(char ** fields, int nfields); +static int inzcont(char ** fields, int nfields); +static int inzone(char ** fields, int nfields); +static int inzsub(char ** fields, int nfields, int iscont); +static int itsdir(const char * name); +static int lowerit(int c); +static int mkdirs(char * filename); +static void newabbr(const char * abbr); +static zic_t oadd(zic_t t1, zic_t t2); +static void outzone(const struct zone * zp, int ntzones); +static zic_t rpytime(const struct rule * rp, zic_t wantedy); +static void rulesub(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 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 -static char * strerror P((int)); -#endif /* !HAVE_STRERROR */ + const char * dayp, const char * timep); +static zic_t tadd(zic_t t1, zic_t t2); +static int yearistype(int year, const char * type); +#ifdef ICU +static void emit_icu_zone(FILE* f, const char* zoneName, int zoneOffset, + const struct rule* rule, + int ruleIndex, int startYear); +static void emit_icu_link(FILE* f, const char* from, const char* to); +static void emit_icu_rule(FILE* f, const struct rule* r, int ruleIndex); +static int add_icu_final_rules(const struct rule* r1, const struct rule* r2); +#endif static int charcnt; static int errors; static const char * filename; static int leapcnt; static int leapseen; -static int leapminyear; -static int leapmaxyear; +static zic_t leapminyear; +static zic_t 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 zic_t max_year; +static zic_t min_year; static int noise; static const char * rfilename; static int rlinenum; static const char * progname; static int timecnt; +static int timecnt_alloc; static int typecnt; /* @@ -288,9 +289,11 @@ static int typecnt; static struct rule * rules; static int nrules; /* number of rules */ +static int nrules_alloc; static struct zone * zones; static int nzones; /* number of zones */ +static int nzones_alloc; struct link { const char * l_filename; @@ -301,6 +304,7 @@ struct link { static struct link * links; static int nlinks; +static int nlinks_alloc; struct lookup { const char * l_word; @@ -308,19 +312,16 @@ struct lookup { }; #ifdef ICU - /* Indices into rules[] for final rules. They will occur in pairs, * with finalRules[i] occurring before finalRules[i+1] in the year. * Each zone need only store a start year, a standard offset, and an * index into finalRules[]. FinalRules[] are aliases into rules[]. */ - -static const struct rule ** finalRules; -static int finalRulesCount; - +static const struct rule ** finalRules = NULL; +static int finalRulesCount = 0; #endif -static struct lookup const * byword P((const char * string, - const struct lookup * lp)); +static struct lookup const * byword(const char * string, + const struct lookup * lp); static struct lookup const line_codes[] = { { "Rule", LC_RULE }, @@ -399,12 +400,12 @@ static const int len_years[2] = { static struct attype { zic_t at; unsigned char type; -} attypes[TZ_MAX_TIMES]; -static long gmtoffs[TZ_MAX_TYPES]; +} * attypes; +static zic_t gmtoffs[TZ_MAX_TYPES]; #ifdef ICU /* gmtoffs[i] = rawoffs[i] + dstoffs[i] */ -static long rawoffs[TZ_MAX_TYPES]; -static long dstoffs[TZ_MAX_TYPES]; +static zic_t rawoffs[TZ_MAX_TYPES]; +static zic_t dstoffs[TZ_MAX_TYPES]; #endif static char isdsts[TZ_MAX_TYPES]; static unsigned char abbrinds[TZ_MAX_TYPES]; @@ -412,55 +413,62 @@ static char ttisstds[TZ_MAX_TYPES]; static char ttisgmts[TZ_MAX_TYPES]; static char chars[TZ_MAX_CHARS]; static zic_t trans[TZ_MAX_LEAPS]; -static long corr[TZ_MAX_LEAPS]; +static zic_t corr[TZ_MAX_LEAPS]; static char roll[TZ_MAX_LEAPS]; /* ** Memory allocation. */ -static char * -memcheck(ptr) -char * const ptr; +static _Noreturn void +memory_exhausted(const char *msg) { - if (ptr == NULL) { - const char *e = strerror(errno); + fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg); + exit(EXIT_FAILURE); +} - (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"), - progname, e); - exit(EXIT_FAILURE); - } +static ATTRIBUTE_PURE size_t +size_product(size_t nitems, size_t itemsize) +{ + if (SIZE_MAX / itemsize < nitems) + memory_exhausted("size overflow"); + return nitems * itemsize; +} + +static ATTRIBUTE_PURE void * +memcheck(void *const ptr) +{ + if (ptr == NULL) + memory_exhausted(strerror(errno)); return ptr; } -#define emalloc(size) memcheck(imalloc(size)) -#define erealloc(ptr, size) memcheck(irealloc((ptr), (size))) +#define emalloc(size) memcheck(malloc(size)) +#define erealloc(ptr, size) memcheck(realloc(ptr, size)) #define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp))) +static void * +growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc) +{ + if (nitems < *nitems_alloc) + return ptr; + else { + int amax = INT_MAX < SIZE_MAX ? INT_MAX : SIZE_MAX; + if ((amax - 1) / 3 * 2 < *nitems_alloc) + memory_exhausted("int overflow"); + *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1; + return erealloc(ptr, size_product(*nitems_alloc, itemsize)); + } +} + /* ** Error handling. */ -#if !HAVE_STRERROR -static char * -strerror(errnum) -int errnum; -{ - extern char * sys_errlist[]; - extern int sys_nerr; - - return (errnum > 0 && errnum <= sys_nerr) ? - sys_errlist[errnum] : _("Unknown system error"); -} -#endif /* !HAVE_STRERROR */ - static void -eats(name, num, rname, rnum) -const char * const name; -const int num; -const char * const rname; -const int rnum; +eats(const char *const name, const int num, const char *const rname, + const int rnum) { filename = name; linenum = num; @@ -469,24 +477,21 @@ const int rnum; } static void -eat(name, num) -const char * const name; -const int num; +eat(const char *const name, const int num) { - eats(name, num, (char *) NULL, -1); + eats(name, num, NULL, -1); } -static void -error(string) -const char * const string; +static void ATTRIBUTE_FORMAT((printf, 1, 0)) +verror(const char *const string, va_list args) { /* ** Match the format of "cc" to allow sh users to ** zic ... 2>&1 | error -t "*" -v ** on BSD systems. */ - (void) fprintf(stderr, _("\"%s\", line %d: %s"), - filename, linenum, string); + fprintf(stderr, _("\"%s\", line %d: "), filename, linenum); + vfprintf(stderr, string, args); if (rfilename != NULL) (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"), rfilename, rlinenum); @@ -494,83 +499,108 @@ const char * const string; ++errors; } -static void -warning(string) -const char * const string; +static void ATTRIBUTE_FORMAT((printf, 1, 2)) +error(const char *const string, ...) { - char * cp; + va_list args; + va_start(args, string); + verror(string, args); + va_end(args); +} - cp = ecpyalloc(_("warning: ")); - cp = ecatalloc(cp, string); - error(cp); - ifree(cp); +static void ATTRIBUTE_FORMAT((printf, 1, 2)) +warning(const char *const string, ...) +{ + va_list args; + fprintf(stderr, _("warning: ")); + va_start(args, string); + verror(string, args); + va_end(args); --errors; } -static void -usage P((void)) +static _Noreturn void +usage(FILE *stream, int status) { - (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); + (void) fprintf(stream, _("%s: usage is %s \ +[ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\ +\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\ +\n\ +Report bugs to %s.\n"), + progname, progname, REPORT_BUGS_TO); + exit(status); } #ifdef ICU - /* File into which we will write supplemental ICU data. */ -static FILE * icuFile; - -void emit_icu_zone(FILE* f, const char* zoneName, int zoneOffset, - const struct rule* rule, - int ruleIndex, int startYear) { - /* machine-readable section */ - fprintf(f, "zone %s %d %d %s", zoneName, zoneOffset, startYear, rule->r_name); - - /* human-readable section */ - fprintf(f, " # zone %s, offset %d, year >= %d, rule %s (%d)\n", - zoneName, zoneOffset, startYear, - rule->r_name, ruleIndex); +static FILE * icuFile; + +static void +emit_icu_zone(FILE* f, const char* zoneName, int zoneOffset, + const struct rule* rule, + int ruleIndex, int startYear) { + /* machine-readable section */ + fprintf(f, "zone %s %d %d %s", zoneName, zoneOffset, startYear, rule->r_name); + + /* human-readable section */ + fprintf(f, " # zone %s, offset %d, year >= %d, rule %s (%d)\n", + zoneName, zoneOffset, startYear, + rule->r_name, ruleIndex); } -void emit_icu_link(FILE* f, const char* from, const char* to) { - /* machine-readable section */ - fprintf(f, "link %s %s\n", from, to); +static void +emit_icu_link(FILE* f, const char* from, const char* to) { + /* machine-readable section */ + fprintf(f, "link %s %s\n", from, to); } static const char* DYCODE[] = {"DOM", "DOWGEQ", "DOWLEQ"}; -void emit_icu_rule(FILE* f, const struct rule* r, int ruleIndex) { - if (r->r_yrtype != NULL) { - warning("year types not supported by ICU"); - fprintf(stderr, "rule %s, file %s, line %d\n", - r->r_name, r->r_filename, r->r_linenum); +static void +emit_icu_rule(FILE* f, const struct rule* r, int ruleIndex) { + if (r->r_yrtype != NULL) { + warning("year types not supported by ICU"); + fprintf(stderr, "rule %s, file %s, line %d\n", + r->r_name, r->r_filename, r->r_linenum); } - /* machine-readable section */ - fprintf(f, "rule %s %s %d %d %d %d %d %d %d", - r->r_name, DYCODE[r->r_dycode], - r->r_month, r->r_dayofmonth, - (r->r_dycode == DC_DOM ? -1 : r->r_wday), - r->r_tod, r->r_todisstd, r->r_todisgmt, r->r_stdoff - ); - - /* human-readable section */ - fprintf(f, " # %d: %s, file %s, line %d", - ruleIndex, r->r_name, r->r_filename, r->r_linenum); - fprintf(f, ", mode %s", DYCODE[r->r_dycode]); - fprintf(f, ", %s, dom %d", mon_names[r->r_month].l_word, r->r_dayofmonth); - if (r->r_dycode != DC_DOM) { - fprintf(f, ", %s", wday_names[r->r_wday].l_word); - } - fprintf(f, ", time %d", r->r_tod); - fprintf(f, ", isstd %d", r->r_todisstd); - fprintf(f, ", isgmt %d", r->r_todisgmt); - fprintf(f, ", offset %ld", r->r_stdoff); - fprintf(f, "\n"); + /* machine-readable section */ + fprintf(f, "rule %s %s %d %d %d %lld %d %d %lld", + r->r_name, DYCODE[r->r_dycode], + r->r_month, r->r_dayofmonth, + (r->r_dycode == DC_DOM ? -1 : r->r_wday), + r->r_tod, r->r_todisstd, r->r_todisgmt, r->r_stdoff + ); + + /* human-readable section */ + fprintf(f, " # %d: %s, file %s, line %d", + ruleIndex, r->r_name, r->r_filename, r->r_linenum); + fprintf(f, ", mode %s", DYCODE[r->r_dycode]); + fprintf(f, ", %s, dom %d", mon_names[r->r_month].l_word, r->r_dayofmonth); + if (r->r_dycode != DC_DOM) { + fprintf(f, ", %s", wday_names[r->r_wday].l_word); + } + fprintf(f, ", time %lld", r->r_tod); + fprintf(f, ", isstd %d", r->r_todisstd); + fprintf(f, ", isgmt %d", r->r_todisgmt); + fprintf(f, ", offset %lld", r->r_stdoff); + fprintf(f, "\n"); } +static int +add_icu_final_rules(const struct rule* r1, const struct rule* r2) { + int i; + + for (i=0; ir_name, ((const struct rule *) cp2)->r_name); } static void -associate P((void)) +associate(void) { register struct zone * zp; register struct rule * rp; @@ -860,8 +906,7 @@ associate P((void)) register int i, j; if (nrules != 0) { - (void) qsort((void *) rules, (size_t) nrules, - (size_t) sizeof *rules, rcomp); + (void) qsort(rules, nrules, sizeof *rules, rcomp); for (i = 0; i < nrules - 1; ++i) { if (strcmp(rules[i].r_name, rules[i + 1].r_name) != 0) @@ -920,7 +965,7 @@ associate P((void)) ** a '%s' in the format is a bad thing. */ if (strchr(zp->z_format, '%') != 0) - error(_("%s in ruleless zone")); + error("%s", _("%s in ruleless zone")); } } if (errors) @@ -928,8 +973,7 @@ associate P((void)) } static void -infile(name) -const char * name; +infile(const char *name) { register FILE * fp; register char ** fields; @@ -953,7 +997,7 @@ const char * name; wantcont = FALSE; for (num = 1; ; ++num) { eat(name, num); - if (fgets(buf, (int) sizeof buf, fp) != buf) + if (fgets(buf, sizeof buf, fp) != buf) break; cp = strchr(buf, '\n'); if (cp == NULL) { @@ -1005,7 +1049,7 @@ _("%s: panic: Invalid l_value %d\n"), exit(EXIT_FAILURE); } } - ifree((char *) fields); + free(fields); } if (ferror(fp)) { (void) fprintf(stderr, _("%s: Error reading %s\n"), @@ -1031,13 +1075,11 @@ _("%s: panic: Invalid l_value %d\n"), ** Call error with errstring and return zero on errors. */ -static long -gethms(string, errstring, signable) -const char * string; -const char * const errstring; -const int signable; +static zic_t +gethms(const char *string, const char *const errstring, const int signable) { - int hh, mm, ss, sign; + zic_t hh; + int mm, ss, sign; if (string == NULL || *string == '\0') return 0; @@ -1047,33 +1089,36 @@ const int signable; sign = -1; ++string; } else sign = 1; - if (sscanf(string, scheck(string, "%d"), &hh) == 1) + if (sscanf(string, scheck(string, "%"SCNdZIC), &hh) == 1) mm = ss = 0; - else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) + else if (sscanf(string, scheck(string, "%"SCNdZIC":%d"), &hh, &mm) == 2) ss = 0; - else if (sscanf(string, scheck(string, "%d:%d:%d"), + else if (sscanf(string, scheck(string, "%"SCNdZIC":%d:%d"), &hh, &mm, &ss) != 3) { - error(errstring); + error("%s", errstring); return 0; } - if ((hh < 0 || hh >= HOURSPERDAY || + if (hh < 0 || mm < 0 || mm >= MINSPERHOUR || - ss < 0 || ss > SECSPERMIN) && - !(hh == HOURSPERDAY && mm == 0 && ss == 0)) { - error(errstring); + ss < 0 || ss > SECSPERMIN) { + error("%s", errstring); return 0; } - if (noise && hh == HOURSPERDAY) + if (ZIC_MAX / SECSPERHOUR < hh) { + error(_("time overflow")); + return 0; + } + if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0) warning(_("24:00 not handled by pre-1998 versions of zic")); - return eitol(sign) * - (eitol(hh * MINSPERHOUR + mm) * - eitol(SECSPERMIN) + eitol(ss)); + if (noise && (hh > HOURSPERDAY || + (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) +warning(_("values over 24 hours not handled by pre-2007 versions of zic")); + return oadd(sign * hh * SECSPERHOUR, + sign * (mm * SECSPERMIN + ss)); } static void -inrule(fields, nfields) -register char ** const fields; -const int nfields; +inrule(register char **const fields, const int nfields) { static struct rule r; @@ -1094,60 +1139,46 @@ const int nfields; 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 = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); rules[nrules++] = r; } static int -inzone(fields, nfields) -register char ** const fields; -const int nfields; +inzone(register char **const fields, const int nfields) { register int i; - static char * buf; if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { error(_("wrong number of fields on Zone line")); return FALSE; } if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { - buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT))); - (void) sprintf(buf, + error( _("\"Zone %s\" line and -l option are mutually exclusive"), TZDEFAULT); - error(buf); return FALSE; } if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { - buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES))); - (void) sprintf(buf, + error( _("\"Zone %s\" line and -p option are mutually exclusive"), TZDEFRULES); - error(buf); return FALSE; } for (i = 0; i < nzones; ++i) if (zones[i].z_name != NULL && strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { - buf = erealloc(buf, (int) (132 + - strlen(fields[ZF_NAME]) + - strlen(zones[i].z_filename))); - (void) sprintf(buf, + error( _("duplicate zone name %s (file \"%s\", line %d)"), fields[ZF_NAME], zones[i].z_filename, zones[i].z_linenum); - error(buf); return FALSE; } return inzsub(fields, nfields, FALSE); } static int -inzcont(fields, nfields) -register char ** const fields; -const int nfields; +inzcont(register char **const fields, const int nfields) { if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { error(_("wrong number of fields on Zone continuation line")); @@ -1157,10 +1188,7 @@ const int nfields; } static int -inzsub(fields, nfields, iscont) -register char ** const fields; -const int nfields; -const int iscont; +inzsub(register char **const fields, const int nfields, const int iscont) { register char * cp; static struct zone z; @@ -1190,7 +1218,7 @@ const int iscont; } z.z_filename = filename; z.z_linenum = linenum; - z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE); + z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), TRUE); if ((cp = strchr(fields[i_format], '%')) != 0) { if (*++cp != 's' || strchr(cp, '%') != 0) { error(_("invalid abbreviation format")); @@ -1227,8 +1255,7 @@ const int iscont; return FALSE; } } - zones = (struct zone *) (void *) erealloc((char *) zones, - (int) ((nzones + 1) * sizeof *zones)); + zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc); zones[nzones++] = z; /* ** If there was an UNTIL field on this line, @@ -1238,15 +1265,14 @@ const int iscont; } static void -inleap(fields, nfields) -register char ** const fields; -const int nfields; +inleap(register char ** const fields, const int nfields) { register const char * cp; register const struct lookup * lp; register int i, j; - int year, month, day; - long dayoff, tod; + zic_t year; + int month, day; + zic_t dayoff, tod; zic_t t; if (nfields != LEAP_FIELDS) { @@ -1255,7 +1281,7 @@ const int nfields; } dayoff = 0; cp = fields[LP_YEAR]; - if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { + if (sscanf(cp, scheck(cp, "%"SCNdZIC), &year) != 1) { /* ** Leapin' Lizards! */ @@ -1276,7 +1302,7 @@ const int nfields; --j; i = -len_years[isleap(j)]; } - dayoff = oadd(dayoff, eitol(i)); + dayoff = oadd(dayoff, i); } if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { error(_("invalid month name")); @@ -1286,7 +1312,7 @@ const int nfields; j = TM_JANUARY; while (j != month) { i = len_months[isleap(year)][j]; - dayoff = oadd(dayoff, eitol(i)); + dayoff = oadd(dayoff, i); ++j; } cp = fields[LP_DAY]; @@ -1295,7 +1321,7 @@ const int nfields; error(_("invalid day of month")); return; } - dayoff = oadd(dayoff, eitol(day - 1)); + dayoff = oadd(dayoff, day - 1); if (dayoff < 0 && !TYPE_SIGNED(zic_t)) { error(_("time before zero")); return; @@ -1342,9 +1368,7 @@ const int nfields; } static void -inlink(fields, nfields) -register char ** const fields; -const int nfields; +inlink(register char **const fields, const int nfields) { struct link l; @@ -1364,20 +1388,18 @@ const int nfields; l.l_linenum = linenum; l.l_from = ecpyalloc(fields[LF_FROM]); l.l_to = ecpyalloc(fields[LF_TO]); - links = (struct link *) (void *) erealloc((char *) links, - (int) ((nlinks + 1) * sizeof *links)); + links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); links[nlinks++] = l; } static void -rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) -register struct rule * const rp; -const char * const loyearp; -const char * const hiyearp; -const char * const typep; -const char * const monthp; -const char * const dayp; -const char * const timep; +rulesub(register struct rule *const rp, + const char *const loyearp, + const char *const hiyearp, + const char *const typep, + const char *const monthp, + const char *const dayp, + const char *const timep) { register const struct lookup * lp; register const char * cp; @@ -1415,7 +1437,7 @@ const char * const timep; } } rp->r_tod = gethms(dp, _("invalid time of day"), FALSE); - ifree(dp); + free(dp); /* ** Year work. */ @@ -1424,17 +1446,17 @@ const char * const timep; rp->r_lowasnum = lp == NULL; if (!rp->r_lowasnum) switch ((int) lp->l_value) { case YR_MINIMUM: - rp->r_loyear = INT_MIN; + rp->r_loyear = ZIC_MIN; break; case YR_MAXIMUM: - rp->r_loyear = INT_MAX; + rp->r_loyear = ZIC_MAX; break; default: /* "cannot happen" */ (void) fprintf(stderr, _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); exit(EXIT_FAILURE); - } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { + } else if (sscanf(cp, scheck(cp, "%"SCNdZIC), &rp->r_loyear) != 1) { error(_("invalid starting year")); return; } @@ -1443,10 +1465,10 @@ const char * const timep; rp->r_hiwasnum = lp == NULL; if (!rp->r_hiwasnum) switch ((int) lp->l_value) { case YR_MINIMUM: - rp->r_hiyear = INT_MIN; + rp->r_hiyear = ZIC_MIN; break; case YR_MAXIMUM: - rp->r_hiyear = INT_MAX; + rp->r_hiyear = ZIC_MAX; break; case YR_ONLY: rp->r_hiyear = rp->r_loyear; @@ -1456,7 +1478,7 @@ const char * const timep; _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); exit(EXIT_FAILURE); - } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { + } else if (sscanf(cp, scheck(cp, "%"SCNdZIC), &rp->r_hiyear) != 1) { error(_("invalid ending year")); return; } @@ -1499,12 +1521,12 @@ const char * const timep; *ep++ = 0; if (*ep++ != '=') { error(_("invalid day of month")); - ifree(dp); + free(dp); return; } if ((lp = byword(dp, wday_names)) == NULL) { error(_("invalid weekday name")); - ifree(dp); + free(dp); return; } rp->r_wday = lp->l_value; @@ -1513,63 +1535,55 @@ const char * const timep; rp->r_dayofmonth <= 0 || (rp->r_dayofmonth > len_months[1][rp->r_month])) { error(_("invalid day of month")); - ifree(dp); + free(dp); return; } } - ifree(dp); + free(dp); } static void -convert(val, buf) -const long val; -char * const buf; +convert(const int_fast32_t val, char *const buf) { register int i; register int shift; + unsigned char *const b = (unsigned char *) buf; for (i = 0, shift = 24; i < 4; ++i, shift -= 8) - buf[i] = val >> shift; + b[i] = val >> shift; } static void -convert64(val, buf) -const zic_t val; -char * const buf; +convert64(const zic_t val, char *const buf) { register int i; register int shift; + unsigned char *const b = (unsigned char *) buf; for (i = 0, shift = 56; i < 8; ++i, shift -= 8) - buf[i] = val >> shift; + b[i] = val >> shift; } static void -puttzcode(val, fp) -const long val; -FILE * const fp; +puttzcode(const int_fast32_t val, FILE *const fp) { char buf[4]; convert(val, buf); - (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); + (void) fwrite(buf, sizeof buf, 1, fp); } static void -puttzcode64(val, fp) -const zic_t val; -FILE * const fp; +puttzcode64(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); + (void) fwrite(buf, sizeof buf, 1, fp); } static int -atcomp(avp, bvp) -const void * avp; -const void * bvp; +atcomp(const void *avp, const void *bvp) { const zic_t a = ((const struct attype *) avp)->at; const zic_t b = ((const struct attype *) bvp)->at; @@ -1578,16 +1592,13 @@ const void * bvp; } static int -is32(x) -const zic_t x; +is32(const zic_t x) { return INT32_MIN <= x && x <= INT32_MAX; } static void -writezone(name, string) -const char * const name; -const char * const string; +writezone(const char *const name, const char *const string, char version) { register FILE * fp; register int i, j; @@ -1597,15 +1608,15 @@ const char * const string; static char * fullname; static const struct tzhead tzh0; static struct tzhead tzh; - zic_t ats[TZ_MAX_TIMES]; - unsigned char types[TZ_MAX_TIMES]; + zic_t *ats = emalloc(size_product(timecnt, sizeof *ats + 1)); + void *typesptr = ats + timecnt; + unsigned char *types = typesptr; /* ** Sort. */ if (timecnt > 1) - (void) qsort((void *) attypes, (size_t) timecnt, - (size_t) sizeof *attypes, atcomp); + (void) qsort(attypes, timecnt, sizeof *attypes, atcomp); /* ** Optimize. */ @@ -1617,8 +1628,11 @@ const char * const string; fromi = 0; while (fromi < timecnt && attypes[fromi].at < min_time) ++fromi; - if (isdsts[0] == 0) - while (fromi < timecnt && attypes[fromi].type == 0) + /* + ** Remember that type 0 is reserved. + */ + if (isdsts[1] == 0) + while (fromi < timecnt && attypes[fromi].type == 1) ++fromi; /* handled by default rule */ for ( ; fromi < timecnt; ++fromi) { if (toi != 0 && ((attypes[fromi].at + @@ -1673,7 +1687,7 @@ const char * const string; ++leapi32; } fullname = erealloc(fullname, - (int) (strlen(directory) + 1 + strlen(name) + 1)); + strlen(directory) + 1 + strlen(name) + 1); (void) sprintf(fullname, "%s/%s", directory, name); /* ** Remove old file, if any, to snap links. @@ -1700,7 +1714,7 @@ const char * const string; register int thistimei, thistimecnt; register int thisleapi, thisleapcnt; register int thistimelim, thisleaplim; - int writetype[TZ_MAX_TIMES]; + int writetype[TZ_MAX_TYPES]; int typemap[TZ_MAX_TYPES]; register int thistypecnt; char thischars[TZ_MAX_CHARS]; @@ -1720,7 +1734,11 @@ const char * const string; } thistimelim = thistimei + thistimecnt; thisleaplim = thisleapi + thisleapcnt; - for (i = 0; i < typecnt; ++i) + /* + ** Remember that type 0 is reserved. + */ + writetype[0] = FALSE; + for (i = 1; i < typecnt; ++i) writetype[i] = thistimecnt == timecnt; if (thistimecnt == 0) { /* @@ -1736,12 +1754,86 @@ const char * const string; /* ** For America/Godthab and Antarctica/Palmer */ + /* + ** Remember that type 0 is reserved. + */ if (thistimei == 0) - writetype[0] = TRUE; + writetype[1] = TRUE; + } +#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH + /* + ** For some pre-2011 systems: if the last-to-be-written + ** standard (or daylight) type has an offset different from the + ** most recently used offset, + ** append an (unused) copy of the most recently used type + ** (to help get global "altzone" and "timezone" variables + ** set correctly). + */ + { + register int mrudst, mrustd, hidst, histd, type; + + hidst = histd = mrudst = mrustd = -1; + for (i = thistimei; i < thistimelim; ++i) + if (isdsts[types[i]]) + mrudst = types[i]; + else mrustd = types[i]; + for (i = 0; i < typecnt; ++i) + if (writetype[i]) { + if (isdsts[i]) + hidst = i; + else histd = i; + } + if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && + gmtoffs[hidst] != gmtoffs[mrudst]) { + isdsts[mrudst] = -1; + type = addtype(gmtoffs[mrudst], +#ifdef ICU + rawoffs[mrudst], dstoffs[mrudst], +#endif + &chars[abbrinds[mrudst]], + TRUE, + ttisstds[mrudst], + ttisgmts[mrudst]); + isdsts[mrudst] = TRUE; + writetype[type] = TRUE; + } + if (histd >= 0 && mrustd >= 0 && histd != mrustd && + gmtoffs[histd] != gmtoffs[mrustd]) { + isdsts[mrustd] = -1; + type = addtype(gmtoffs[mrustd], +#ifdef ICU + rawoffs[mrudst], dstoffs[mrudst], +#endif + &chars[abbrinds[mrustd]], + FALSE, + ttisstds[mrustd], + ttisgmts[mrustd]); + isdsts[mrustd] = FALSE; + writetype[type] = TRUE; + } } +#endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ thistypecnt = 0; + /* + ** Potentially, set type 0 to that of lowest-valued time. + */ + if (thistimei > 0) { + for (i = 1; i < typecnt; ++i) + if (writetype[i] && !isdsts[i]) + break; + if (i != types[thistimei - 1]) { + i = types[thistimei - 1]; + gmtoffs[0] = gmtoffs[i]; + isdsts[0] = isdsts[i]; + ttisstds[0] = ttisstds[i]; + ttisgmts[0] = ttisgmts[i]; + abbrinds[0] = abbrinds[i]; + writetype[0] = TRUE; + writetype[i] = FALSE; + } + } for (i = 0; i < typecnt; ++i) - typemap[i] = writetype[i] ? thistypecnt++ : -1; + typemap[i] = writetype[i] ? thistypecnt++ : 0; for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i) indmap[i] = -1; thischarcnt = 0; @@ -1763,22 +1855,21 @@ const char * const string; } indmap[abbrinds[i]] = j; } -#define DO(field) (void) fwrite((void *) tzh.field, \ - (size_t) sizeof tzh.field, (size_t) 1, fp) +#define DO(field) ((void) fwrite(tzh.field, sizeof tzh.field, 1, fp)) tzh = tzh0; #ifdef ICU - * (ICUZoneinfoVersion*) &tzh.tzh_reserved = TZ_ICU_VERSION; - (void) strncpy(tzh.tzh_magic, TZ_ICU_MAGIC, sizeof tzh.tzh_magic); + * (ICUZoneinfoVersion*) &tzh.tzh_reserved = TZ_ICU_VERSION; + (void) strncpy(tzh.tzh_magic, TZ_ICU_MAGIC, sizeof tzh.tzh_magic); #else (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); #endif - 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); + tzh.tzh_version[0] = version; + convert(thistypecnt, tzh.tzh_ttisgmtcnt); + convert(thistypecnt, tzh.tzh_ttisstdcnt); + convert(thisleapcnt, tzh.tzh_leapcnt); + convert(thistimecnt, tzh.tzh_timecnt); + convert(thistypecnt, tzh.tzh_typecnt); + convert(thischarcnt, tzh.tzh_charcnt); DO(tzh_magic); DO(tzh_version); DO(tzh_reserved); @@ -1791,32 +1882,28 @@ const char * const string; #undef DO for (i = thistimei; i < thistimelim; ++i) if (pass == 1) - puttzcode((long) ats[i], fp); + puttzcode(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); + (void) fwrite(&uc, sizeof uc, 1, fp); } for (i = 0; i < typecnt; ++i) if (writetype[i]) { #ifdef ICU - puttzcode((long) rawoffs[i], fp); - puttzcode((long) dstoffs[i], fp); + puttzcode(rawoffs[i], fp); + puttzcode(dstoffs[i], fp); #else - puttzcode((long) gmtoffs[i], fp); + puttzcode(gmtoffs[i], fp); #endif (void) putc(isdsts[i], fp); (void) putc((unsigned char) indmap[abbrinds[i]], fp); } if (thischarcnt != 0) - (void) fwrite((void *) thischars, - (size_t) sizeof thischars[0], - (size_t) thischarcnt, fp); + (void) fwrite(thischars, sizeof thischars[0], + thischarcnt, fp); for (i = thisleapi; i < thisleaplim; ++i) { register zic_t todo; @@ -1838,7 +1925,7 @@ const char * const string; todo = tadd(trans[i], -gmtoffs[j]); } else todo = trans[i]; if (pass == 1) - puttzcode((long) todo, fp); + puttzcode(todo, fp); else puttzcode64(todo, fp); puttzcode(corr[i], fp); } @@ -1855,15 +1942,12 @@ const char * const string; progname, fullname); exit(EXIT_FAILURE); } + free(ats); } 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; +doabbr(char *const abbr, const char *const format, const char *const letters, + const int isdst, const int doquotes) { register char * cp; register char * slashp; @@ -1878,8 +1962,7 @@ const int doquotes; (void) strcpy(abbr, slashp + 1); } else { if (slashp > format) - (void) strncpy(abbr, format, - (unsigned) (slashp - format)); + (void) strncpy(abbr, format, slashp - format); abbr[slashp - format] = '\0'; } if (!doquotes) @@ -1899,8 +1982,7 @@ const int doquotes; } static void -updateminmax(x) -const int x; +updateminmax(const zic_t x) { if (min_year > x) min_year = x; @@ -1909,9 +1991,7 @@ const int x; } static int -stringoffset(result, offset) -char * result; -long offset; +stringoffset(char *result, zic_t offset) { register int hours; register int minutes; @@ -1927,7 +2007,7 @@ long offset; minutes = offset % MINSPERHOUR; offset /= MINSPERHOUR; hours = offset; - if (hours >= HOURSPERDAY) { + if (hours >= HOURSPERDAY * DAYSPERWEEK) { result[0] = '\0'; return -1; } @@ -1941,13 +2021,11 @@ long offset; } static int -stringrule(result, rp, dstoff, gmtoff) -char * result; -const struct rule * const rp; -const long dstoff; -const long gmtoff; +stringrule(char *result, const struct rule *const rp, const zic_t dstoff, + const zic_t gmtoff) { - register long tod; + register zic_t tod = rp->r_tod; + register int compat = 0; result = end(result); if (rp->r_dycode == DC_DOM) { @@ -1958,48 +2036,77 @@ const long gmtoff; total = 0; for (month = 0; month < rp->r_month; ++month) total += len_months[0][month]; - (void) sprintf(result, "J%d", total + rp->r_dayofmonth); + /* Omit the "J" in Jan and Feb, as that's shorter. */ + if (rp->r_month <= 1) + (void) sprintf(result, "%d", total + rp->r_dayofmonth - 1); + else + (void) sprintf(result, "J%d", total + rp->r_dayofmonth); } else { register int week; + register int wday = rp->r_wday; + register int wdayoff; if (rp->r_dycode == DC_DOWGEQ) { - week = 1 + rp->r_dayofmonth / DAYSPERWEEK; - if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth) - return -1; + wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK; + if (wdayoff) + compat = 2013; + wday -= wdayoff; + tod += wdayoff * SECSPERDAY; + week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK; } 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; + wdayoff = rp->r_dayofmonth % DAYSPERWEEK; + if (wdayoff) + compat = 2013; + wday -= wdayoff; + tod += wdayoff * SECSPERDAY; + week = rp->r_dayofmonth / DAYSPERWEEK; } } else return -1; /* "cannot happen" */ + if (wday < 0) + wday += DAYSPERWEEK; (void) sprintf(result, "M%d.%d.%d", - rp->r_month + 1, week, rp->r_wday); + rp->r_month + 1, week, 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; + if (tod < 0) { + if (compat < 2013) + compat = 2013; + } else if (SECSPERDAY <= tod) { + if (compat < 1994) + compat = 1994; + } } - return 0; + return compat; } -static void -stringzone(result, zpfirst, zonecount) -char * result; -const struct zone * const zpfirst; -const int zonecount; +static int +rule_cmp(struct rule const *a, struct rule const *b) +{ + if (!a) + return -!!b; + if (!b) + return 1; + if (a->r_hiyear != b->r_hiyear) + return a->r_hiyear < b->r_hiyear ? -1 : 1; + if (a->r_month - b->r_month != 0) + return a->r_month - b->r_month; + return a->r_dayofmonth - b->r_dayofmonth; +} + +enum { YEAR_BY_YEAR_ZONE = 1 }; + +static int +stringzone(char *result, const struct zone *const zpfirst, const int zonecount) { register const struct zone * zp; register struct rule * rp; @@ -2007,109 +2114,120 @@ const int zonecount; register struct rule * dstrp; register int i; register const char * abbrvar; + register int compat = 0; + register int c; + struct rule stdr, dstr; 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) + if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX) continue; if (rp->r_yrtype != NULL) continue; if (rp->r_stdoff == 0) { if (stdrp == NULL) stdrp = rp; - else return; + else return -1; } else { if (dstrp == NULL) dstrp = rp; - else return; + else return -1; } } if (stdrp == NULL && dstrp == NULL) { /* ** There are no rules running through "max". - ** Let's find the latest rule. + ** Find the latest std rule in stdabbrrp + ** and latest rule of any type in stdrp. */ + register struct rule *stdabbrrp = NULL; 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 (rp->r_stdoff == 0 && rule_cmp(stdabbrrp, rp) < 0) + stdabbrrp = rp; + if (rule_cmp(stdrp, rp) < 0) + 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; + return YEAR_BY_YEAR_ZONE; + + if (stdrp != NULL && stdrp->r_stdoff != 0) { + /* Perpetual DST. */ + dstr.r_month = TM_JANUARY; + dstr.r_dycode = DC_DOM; + dstr.r_dayofmonth = 1; + dstr.r_tod = 0; + dstr.r_todisstd = dstr.r_todisgmt = FALSE; + dstr.r_stdoff = stdrp->r_stdoff; + dstr.r_abbrvar = stdrp->r_abbrvar; + stdr.r_month = TM_DECEMBER; + stdr.r_dycode = DC_DOM; + stdr.r_dayofmonth = 31; + stdr.r_tod = SECSPERDAY + stdrp->r_stdoff; + stdr.r_todisstd = stdr.r_todisgmt = FALSE; + stdr.r_stdoff = 0; + stdr.r_abbrvar + = (stdabbrrp ? stdabbrrp->r_abbrvar : ""); + dstrp = &dstr; + stdrp = &stdr; + } } - if (stdrp == NULL && zp->z_nrules != 0) - return; + if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0)) + return -1; 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; + return -1; } if (dstrp == NULL) - return; + return compat; 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; + return -1; } (void) strcat(result, ","); - if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { + c = stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff); + if (c < 0) { result[0] = '\0'; - return; + return -1; } + if (compat < c) + compat = c; (void) strcat(result, ","); - if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { + c = stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff); + if (c < 0) { result[0] = '\0'; - return; + return -1; } + if (compat < c) + compat = c; + return compat; } -#ifdef ICU - -int add_icu_final_rules(const struct rule* r1, const struct rule* r2) { - int i; - - for (i=0; iz_untilrule.r_loyear); + if (i < zonecount - 1) + 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 (rp->r_lowasnum || rp->r_hiwasnum) + prodstic = FALSE; } } /* ** 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; + compat = stringzone(envvar, zpfirst, zonecount); + version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION; + do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE; +#ifdef ICU + do_extend = 0; +#endif + if (noise) { + if (!*envvar) + warning("%s %s", + _("no POSIX environment variable for zone"), + zpfirst->z_name); + else if (compat != 0 && compat != YEAR_BY_YEAR_ZONE) { + /* Circa-COMPAT clients, and earlier clients, might + not work for this zone when given dates before + 1970 or after 2038. */ + warning(_("%s: pre-%d clients may mishandle" + " distant timestamps"), + zpfirst->z_name, compat); + } + } + if (do_extend) { + /* + ** Search through a couple of extra years past the obvious + ** 400, to avoid edge cases. For example, suppose a non-POSIX + ** rule applies from 2012 onwards and has transitions in March + ** and September, plus some one-off transitions in November + ** 2013. If zic looked only at the last 400 years, it would + ** set max_year=2413, with the intent that the 400 years 2014 + ** through 2413 will be repeated. The last transition listed + ** in the tzfile would be in 2413-09, less than 400 years + ** after the last one-off transition in 2013-11. Two years + ** might be overkill, but with the kind of edge cases + ** available we're not sure that one year would suffice. + */ + enum { years_of_observations = YEARSPERREPEAT + 2 }; + + if (min_year >= ZIC_MIN + years_of_observations) + min_year -= years_of_observations; + else min_year = ZIC_MIN; + if (max_year <= ZIC_MAX - years_of_observations) + max_year += years_of_observations; + else max_year = ZIC_MAX; + /* + ** Regardless of any of the above, + ** for a "proDSTic" zone which specifies that its rules + ** always have and always will be in effect, + ** we only need one cycle to define the zone. + */ + if (prodstic) { + min_year = 1900; + max_year = min_year + years_of_observations; + } } /* - ** For the benefit of older systems, generate data through 2037. + ** For the benefit of older systems, + ** generate data from 1900 through 2037. */ + if (min_year > 1900) + min_year = 1900; if (max_year < 2037) max_year = 2037; for (i = 0; i < zonecount; ++i) { @@ -2200,54 +2369,98 @@ wp = ecpyalloc(_("no POSIX environment variable for zone")); *startbuf = '\0'; startoff = zp->z_gmtoff; #ifdef ICU - finalRuleYear = finalRuleIndex = -1; - finalRule1 = finalRule2 = NULL; - if (i == (zonecount - 1)) { /* !useuntil */ - /* Look for exactly 2 rules that end at 'max' and - * note them. Determine max(r_loyear) for the 2 of - * them. */ - for (j=0; jz_nrules; ++j) { - rp = &zp->z_rules[j]; - if (rp->r_hiyear == INT_MAX) { - if (finalRule1 == NULL) { - finalRule1 = rp; - finalRuleYear = rp->r_loyear; - } else if (finalRule2 == NULL) { - finalRule2 = rp; - if (rp->r_loyear > finalRuleYear) { - finalRuleYear = rp->r_loyear; - } - } else { - error("more than two max rules found (ICU)"); - exit(EXIT_FAILURE); - } - } - } - if (finalRule1 != NULL && finalRule2 == NULL) { - error("only one max rule found (ICU)"); - exit(EXIT_FAILURE); - } - if (finalRule1 != NULL) { - /* Swap if necessary so finalRule1 occurs before - * finalRule2 */ - if (finalRule1->r_month > finalRule2->r_month) { - const struct rule* t = finalRule1; - finalRule1 = finalRule2; - finalRule2 = t; - } - /* Add final rule to our list */ - finalRuleIndex = add_icu_final_rules(finalRule1, finalRule2); - } - } + finalRuleYear = finalRuleIndex = -1; + finalRule1 = finalRule2 = NULL; + if (i == (zonecount - 1)) { /* !useuntil */ + /* Look for exactly 2 rules that end at 'max' and + * note them. Determine max(r_loyear) for the 2 of + * them. */ + for (j=0; jz_nrules; ++j) { + rp = &zp->z_rules[j]; + if (rp->r_hiyear == ZIC_MAX) { + if (rp->r_loyear > finalRuleYear) { + finalRuleYear = rp->r_loyear; + } + if (finalRule1 == NULL) { + finalRule1 = rp; + } else if (finalRule2 == NULL) { + finalRule2 = rp; + } else { + error("more than two max rules found (ICU)"); + exit(EXIT_FAILURE); + } + } else if (rp->r_hiyear >= finalRuleYear) { + /* There might be an overriding non-max rule + * to be applied to a specific year after one of + * max rule's start year. For example, + * + * Rule Foo 2010 max ... + * Rule Foo 2015 only ... + * + * In this case, we need to change the start year of + * the final (max) rules to the next year. */ + finalRuleYear = rp->r_hiyear + 1; + + /* When above adjustment is done, max_year might need + * to be adjusted, so the final rule will be properly + * evaluated and emitted by the later code block. + * + * Note: This may push the start year of the final + * rules ahead by 1 year unnecessarily. For example, + * If there are two rules, non-max rule and max rule + * starting in the same year, such as + * + * Rule Foo 2010 only .... + * Rule Foo 2010 max .... + * + * In this case, the final (max) rule actually starts + * in 2010, instead of 2010. We could make this tool + * more intelligent to detect such situation. But pushing + * final rule start year to 1 year ahead (in the worst case) + * will just populate a few extra transitions, and it still + * works fine. So for now, we're not trying to put additional + * logic to optimize the case. + */ + if (max_year < finalRuleYear) { + max_year = finalRuleYear; + } + } + } + if (finalRule1 != NULL) { + if (finalRule2 == NULL) { + warning("only one max rule found (ICU)"); + finalRuleYear = finalRuleIndex = -1; + finalRule1 = NULL; + } else { + if (finalRule1->r_stdoff == finalRule2->r_stdoff) { + /* America/Resolute in 2009a uses a pair of rules + * which does not change the offset. ICU ignores + * such rules without actual time transitions. */ + finalRuleYear = finalRuleIndex = -1; + finalRule1 = finalRule2 = NULL; + } else { + /* Swap if necessary so finalRule1 occurs before + * finalRule2 */ + if (finalRule1->r_month > finalRule2->r_month) { + const struct rule* t = finalRule1; + finalRule1 = finalRule2; + finalRule2 = t; + } + /* Add final rule to our list */ + finalRuleIndex = add_icu_final_rules(finalRule1, finalRule2); + } + } + } + } #endif if (zp->z_nrules == 0) { stdoff = zp->z_stdoff; doabbr(startbuf, zp->z_format, - (char *) NULL, stdoff != 0, FALSE); + NULL, stdoff != 0, FALSE); type = addtype(oadd(zp->z_gmtoff, stdoff), #ifdef ICU - zp->z_gmtoff, stdoff, + zp->z_gmtoff, stdoff, #endif startbuf, stdoff != 0, startttisstd, startttisgmt); @@ -2276,12 +2489,12 @@ wp = ecpyalloc(_("no POSIX environment variable for zone")); for ( ; ; ) { register int k; register zic_t jtime, ktime; - register long offset; + register zic_t offset; INITIALIZE(ktime); if (useuntil) { /* - ** Turn untiltime into UTC + ** Turn untiltime into UT ** assuming the current gmtoff and ** stdoff values. */ @@ -2321,15 +2534,6 @@ wp = ecpyalloc(_("no POSIX environment variable for zone")); break; /* go on to next year */ rp = &zp->z_rules[k]; rp->r_todo = FALSE; -#ifdef ICU - if (year >= finalRuleYear && rp == finalRule1) { - emit_icu_zone(icuFile, - zpfirst->z_name, zp->z_gmtoff, - rp, finalRuleIndex, year); - /* only emit this for the first year */ - finalRule1 = NULL; - } -#endif if (useuntil && ktime >= untiltime) break; stdoff = rp->r_stdoff; @@ -2356,6 +2560,27 @@ wp = ecpyalloc(_("no POSIX environment variable for zone")); FALSE); } } +#ifdef ICU + if (year >= finalRuleYear && rp == finalRule1) { + /* We want to shift final year 1 year after + * the actual final rule takes effect (year + 1), + * because the previous type is valid until the first + * transition defined by the final rule. Otherwise + * we may see unexpected offset shift at the + * begining of the year when the final rule takes + * effect. + * + * Note: This may results some 64bit second transitions + * at the very end (year 2038). ICU 4.2 or older releases + * cannot handle 64bit second transitions and they are + * dropped from zoneinfo.txt. */ + emit_icu_zone(icuFile, + zpfirst->z_name, zp->z_gmtoff, + rp, finalRuleIndex, year + 1); + /* only emit this for the first year */ + finalRule1 = NULL; + } +#endif eats(zp->z_filename, zp->z_linenum, rp->r_filename, rp->r_linenum); doabbr(ab, zp->z_format, rp->r_abbrvar, @@ -2363,7 +2588,7 @@ wp = ecpyalloc(_("no POSIX environment variable for zone")); offset = oadd(zp->z_gmtoff, rp->r_stdoff); #ifdef ICU type = addtype(offset, zp->z_gmtoff, rp->r_stdoff, - ab, rp->r_stdoff != 0, + ab, rp->r_stdoff != 0, rp->r_todisstd, rp->r_todisgmt); #else type = addtype(offset, ab, rp->r_stdoff != 0, @@ -2384,8 +2609,8 @@ error(_("can't determine time zone abbreviation to use just after until time")); else addtt(starttime, #ifdef ICU addtype(startoff, - zp->z_gmtoff, startoff - zp->z_gmtoff, - startbuf, + zp->z_gmtoff, startoff - zp->z_gmtoff, + startbuf, startoff != zp->z_gmtoff, startttisstd, startttisgmt)); @@ -2409,16 +2634,52 @@ error(_("can't determine time zone abbreviation to use just after until time")); starttime = tadd(starttime, -gmtoff); } } - writezone(zpfirst->z_name, envvar); - ifree(startbuf); - ifree(ab); - ifree(envvar); + if (do_extend) { + /* + ** If we're extending the explicitly listed observations + ** for 400 years because we can't fill the POSIX-TZ field, + ** check whether we actually ended up explicitly listing + ** observations through that period. If there aren't any + ** near the end of the 400-year period, add a redundant + ** one at the end of the final year, to make it clear + ** that we are claiming to have definite knowledge of + ** the lack of transitions up to that point. + */ + struct rule xr; + struct attype *lastat; + xr.r_month = TM_JANUARY; + xr.r_dycode = DC_DOM; + xr.r_dayofmonth = 1; + xr.r_tod = 0; + for (lastat = &attypes[0], i = 1; i < timecnt; i++) + if (attypes[i].at > lastat->at) + lastat = &attypes[i]; + if (lastat->at < rpytime(&xr, max_year - 1)) { + /* + ** Create new type code for the redundant entry, + ** to prevent it being optimised away. + */ + if (typecnt >= TZ_MAX_TYPES) { + error(_("too many local time types")); + exit(EXIT_FAILURE); + } + gmtoffs[typecnt] = gmtoffs[lastat->type]; + isdsts[typecnt] = isdsts[lastat->type]; + ttisstds[typecnt] = ttisstds[lastat->type]; + ttisgmts[typecnt] = ttisgmts[lastat->type]; + abbrinds[typecnt] = abbrinds[lastat->type]; + ++typecnt; + addtt(rpytime(&xr, max_year + 1), typecnt-1); + } + } + writezone(zpfirst->z_name, envvar, version); + free(startbuf); + free(ab); + free(envvar); } static void -addtt(starttime, type) -const zic_t starttime; -int type; +addtt(const zic_t starttime, int type) { if (starttime <= min_time || (timecnt == 1 && attypes[0].at < min_time)) { @@ -2438,10 +2699,7 @@ int type; timecnt = 0; type = 0; } - if (timecnt >= TZ_MAX_TIMES) { - error(_("too many transitions?!")); - exit(EXIT_FAILURE); - } + attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc); attypes[timecnt].at = starttime; attypes[timecnt].type = type; ++timecnt; @@ -2449,18 +2707,12 @@ int type; static int #ifdef ICU -addtype(gmtoff, rawoff, dstoff, abbr, isdst, ttisstd, ttisgmt) -const long gmtoff; -const long rawoff; -const long dstoff; +addtype(const zic_t gmtoff, const zic_t rawoff, const zic_t dstoff, char *const abbr, const int isdst, + const int ttisstd, const int ttisgmt) #else -addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) -const long gmtoff; +addtype(const zic_t gmtoff, const char *const abbr, const int isdst, + const int ttisstd, const int ttisgmt) #endif -const char * const abbr; -const int isdst; -const int ttisstd; -const int ttisgmt; { register int i, j; @@ -2479,12 +2731,12 @@ const int ttisgmt; #ifdef ICU if (isdst != (dstoff != 0)) { error(_("internal error - addtype called with bad isdst/dstoff")); - (void) exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } - if (gmtoff != (rawoff + dstoff)) { + if (gmtoff != (rawoff + dstoff)) { error(_("internal error - addtype called with bad gmt/raw/dstoff")); - (void) exit(EXIT_FAILURE); - } + exit(EXIT_FAILURE); + } #endif /* ** See if there's already an entry for this zone type. @@ -2493,7 +2745,7 @@ const int ttisgmt; for (i = 0; i < typecnt; ++i) { if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && #ifdef ICU - rawoff == rawoffs[i] && dstoff == dstoffs[i] && + rawoff == rawoffs[i] && dstoff == dstoffs[i] && #endif strcmp(abbr, &chars[abbrinds[i]]) == 0 && ttisstd == ttisstds[i] && @@ -2508,10 +2760,14 @@ const int ttisgmt; error(_("too many local time types")); exit(EXIT_FAILURE); } + if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { + error(_("UT offset out of range")); + exit(EXIT_FAILURE); + } gmtoffs[i] = gmtoff; #ifdef ICU - rawoffs[i] = rawoff; - dstoffs[i] = dstoff; + rawoffs[i] = rawoff; + dstoffs[i] = dstoff; #endif isdsts[i] = isdst; ttisstds[i] = ttisstd; @@ -2528,11 +2784,7 @@ const int ttisgmt; } static void -leapadd(t, positive, rolling, count) -const zic_t t; -const int positive; -const int rolling; -int count; +leapadd(const zic_t t, const int positive, const int rolling, int count) { register int i, j; @@ -2555,17 +2807,17 @@ int count; roll[j] = roll[j - 1]; } trans[i] = t; - corr[i] = positive ? 1L : eitol(-count); + corr[i] = positive ? 1 : -count; roll[i] = rolling; ++leapcnt; } while (positive && --count != 0); } static void -adjleap P((void)) +adjleap(void) { register int i; - register long last = 0; + register zic_t last = 0; /* ** propagate leap seconds forward @@ -2577,16 +2829,14 @@ adjleap P((void)) } static int -yearistype(year, type) -const int year; -const char * const type; +yearistype(const int year, const char *const type) { static char * buf; int result; if (type == NULL || *type == '\0') return TRUE; - buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type))); + buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type)); (void) sprintf(buf, "%s %d %s", yitcommand, year, type); result = system(buf); if (WIFEXITED(result)) switch (WEXITSTATUS(result)) { @@ -2603,17 +2853,15 @@ const char * const type; } static int -lowerit(a) -int a; +lowerit(int a) { a = (unsigned char) a; return (isascii(a) && isupper(a)) ? tolower(a) : a; } -static int -ciequal(ap, bp) /* case-insensitive equality */ -register const char * ap; -register const char * bp; +/* case-insensitive equality */ +static ATTRIBUTE_PURE int +ciequal(register const char *ap, register const char *bp) { while (lowerit(*ap) == lowerit(*bp++)) if (*ap++ == '\0') @@ -2621,10 +2869,8 @@ register const char * bp; return FALSE; } -static int -itsabbr(abbr, word) -register const char * abbr; -register const char * word; +static ATTRIBUTE_PURE int +itsabbr(register const char *abbr, register const char *word) { if (lowerit(*abbr) != lowerit(*word)) return FALSE; @@ -2637,10 +2883,9 @@ register const char * word; return TRUE; } -static const struct lookup * -byword(word, table) -register const char * const word; -register const struct lookup * const table; +static ATTRIBUTE_PURE const struct lookup * +byword(register const char *const word, + register const struct lookup *const table) { register const struct lookup * foundlp; register const struct lookup * lp; @@ -2667,8 +2912,7 @@ register const struct lookup * const table; } static char ** -getfields(cp) -register char * cp; +getfields(register char *cp) { register char * dp; register char ** array; @@ -2676,8 +2920,7 @@ register char * cp; if (cp == NULL) return NULL; - array = (char **) (void *) - emalloc((int) ((strlen(cp) + 1) * sizeof *array)); + array = emalloc(size_product(strlen(cp) + 1, sizeof *array)); nsubs = 0; for ( ; ; ) { while (isascii((unsigned char) *cp) && @@ -2692,9 +2935,12 @@ register char * cp; else while ((*dp = *cp++) != '"') if (*dp != '\0') ++dp; - else error(_( + else { + error(_( "Odd number of quotation marks" )); + exit(1); + } } while (*cp != '\0' && *cp != '#' && (!isascii(*cp) || !isspace((unsigned char) *cp))); if (isascii(*cp) && isspace((unsigned char) *cp)) @@ -2705,38 +2951,28 @@ register char * cp; return array; } -static long -oadd(t1, t2) -const long t1; -const long t2; +static ATTRIBUTE_PURE zic_t +oadd(const zic_t t1, const zic_t t2) { - register long t; - - t = t1 + t2; - if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { + if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) { error(_("time overflow")); exit(EXIT_FAILURE); } - return t; + return t1 + t2; } -static zic_t -tadd(t1, t2) -const zic_t t1; -const long t2; +static ATTRIBUTE_PURE zic_t +tadd(const zic_t t1, const zic_t t2) { - register zic_t t; - if (t1 == max_time && t2 > 0) return max_time; if (t1 == min_time && t2 < 0) return min_time; - t = t1 + t2; - if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { + if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) { error(_("time overflow")); exit(EXIT_FAILURE); } - return t; + return t1 + t2; } /* @@ -2745,17 +2981,15 @@ const long t2; */ static zic_t -rpytime(rp, wantedy) -register const struct rule * const rp; -register const int wantedy; +rpytime(register const struct rule *const rp, register const zic_t wantedy) { - register int y, m, i; - register long dayoff; /* with a nod to Margaret O. */ - register zic_t t; + register int m, i; + register zic_t dayoff; /* with a nod to Margaret O. */ + register zic_t t, y; - if (wantedy == INT_MIN) + if (wantedy == ZIC_MIN) return min_time; - if (wantedy == INT_MAX) + if (wantedy == ZIC_MAX) return max_time; dayoff = 0; m = TM_JANUARY; @@ -2768,11 +3002,11 @@ register const int wantedy; --y; i = -len_years[isleap(y)]; } - dayoff = oadd(dayoff, eitol(i)); + dayoff = oadd(dayoff, i); } while (m != rp->r_month) { i = len_months[isleap(y)][m]; - dayoff = oadd(dayoff, eitol(i)); + dayoff = oadd(dayoff, i); ++m; } i = rp->r_dayofmonth; @@ -2785,12 +3019,12 @@ register const int wantedy; } } --i; - dayoff = oadd(dayoff, eitol(i)); + dayoff = oadd(dayoff, i); if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { - register long wday; + register zic_t wday; -#define LDAYSPERWEEK ((long) DAYSPERWEEK) - wday = eitol(EPOCH_WDAY); +#define LDAYSPERWEEK ((zic_t) DAYSPERWEEK) + wday = EPOCH_WDAY; /* ** Don't trust mod of negative numbers. */ @@ -2801,14 +3035,14 @@ register const int wantedy; if (wday < 0) wday += LDAYSPERWEEK; } - while (wday != eitol(rp->r_wday)) + while (wday != rp->r_wday) if (rp->r_dycode == DC_DOWGEQ) { - dayoff = oadd(dayoff, (long) 1); + dayoff = oadd(dayoff, 1); if (++wday >= LDAYSPERWEEK) wday = 0; ++i; } else { - dayoff = oadd(dayoff, (long) -1); + dayoff = oadd(dayoff, -1); if (--wday < 0) wday = LDAYSPERWEEK - 1; --i; @@ -2828,31 +3062,30 @@ will not work with pre-2004 versions of zic")); } static void -newabbr(string) -const char * const string; +newabbr(const char *const string) { register int i; if (strcmp(string, GRANDPARENTED) != 0) { register const char * cp; - register char * wp; + const char * mp; /* ** 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; + mp = 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"); +mp = _("time zone abbreviation lacks alphabetic at start"); + if (noise && cp - string < 3) +mp = _("time zone abbreviation has fewer 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 == '-')) { +mp = _("time zone abbreviation has too many alphabetics"); + if (mp == NULL && (*cp == '+' || *cp == '-')) { ++cp; if (isascii((unsigned char) *cp) && isdigit((unsigned char) *cp)) @@ -2861,15 +3094,9 @@ wp = _("time zone abbreviation has too many alphabetics"); ++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); - } +mp = _("time zone abbreviation differs from POSIX standard"); + if (mp != NULL) + warning("%s (%s)", mp, string); } i = strlen(string) + 1; if (charcnt + i > TZ_MAX_CHARS) { @@ -2877,12 +3104,11 @@ wp = _("time zone abbreviation differs from POSIX standard"); exit(EXIT_FAILURE); } (void) strcpy(&chars[charcnt], string); - charcnt += eitol(i); + charcnt += i; } static int -mkdirs(argname) -char * const argname; +mkdirs(char *argname) { register char * name; register char * cp; @@ -2892,7 +3118,7 @@ char * const argname; cp = name = ecpyalloc(argname); while ((cp = strchr(cp + 1, '/')) != 0) { *cp = '\0'; -#ifndef unix +#ifdef HAVE_DOS_FILE_NAMES /* ** DOS drive specifier? */ @@ -2901,7 +3127,7 @@ char * const argname; *cp = '/'; continue; } -#endif /* !defined unix */ +#endif if (!itsdir(name)) { /* ** It doesn't seem to exist, so we try to create it. @@ -2916,33 +3142,17 @@ char * const argname; (void) fprintf(stderr, _("%s: Can't create directory %s: %s\n"), progname, name, e); - ifree(name); + free(name); return -1; } } } *cp = '/'; } - ifree(name); + free(name); return 0; } -static long -eitol(i) -const int i; -{ - long l; - - l = i; - if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { - (void) fprintf(stderr, - _("%s: %d did not sign extend correctly\n"), - progname, i); - exit(EXIT_FAILURE); - } - return l; -} - /* ** UNIX was a registered trademark of The Open Group in 2003. */