** 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 <stdarg.h>
+#if U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS
+#include <unistd.h>
+#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
#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
#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 {
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;
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) */
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;
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;
/*
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;
static struct link * links;
static int nlinks;
+static int nlinks_alloc;
struct lookup {
const char * l_word;
};
#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 },
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];
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;
}
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);
++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; i<finalRulesCount; ++i) { /* i+=2 should work too */
+ if (r1==finalRules[i]) return i; /* [sic] pointer comparison */
+ }
+
+ finalRules = (const struct rule**) (void*) erealloc((char *) finalRules,
+ (finalRulesCount + 2) * sizeof(*finalRules));
+ finalRules[finalRulesCount++] = r1;
+ finalRules[finalRulesCount++] = r2;
+ return finalRulesCount - 2;
+}
#endif
static const char * psxrules;
static const char * yitcommand;
int
-main(argc, argv)
-int argc;
-char * argv[];
+main(int argc, char **argv)
{
register int i;
register int j;
register int c;
-#ifdef unix
+#ifdef S_IWGRP
(void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
-#endif /* defined unix */
+#endif
#if HAVE_GETTEXT
(void) setlocale(LC_ALL, "");
#ifdef TZ_DOMAINDIR
}
for (i = 1; i < argc; ++i)
if (strcmp(argv[i], "--version") == 0) {
- (void) printf("%s\n", elsieid);
+ (void) printf("zic %s%s\n", PKGVERSION, TZVERSION);
exit(EXIT_SUCCESS);
+ } else if (strcmp(argv[i], "--help") == 0) {
+ usage(stdout, EXIT_SUCCESS);
}
while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
switch (c) {
default:
- usage();
+ usage(stderr, EXIT_FAILURE);
case 'd':
if (directory == NULL)
directory = optarg;
break;
}
if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
- usage(); /* usage message by request */
+ usage(stderr, EXIT_FAILURE); /* usage message by request */
if (directory == NULL)
directory = TZDIR;
if (yitcommand == NULL)
yitcommand = "yearistype";
- setboundaries();
-
if (optind < argc && leapsec != NULL) {
infile(leapsec);
adjleap();
#ifdef ICU
if ((icuFile = fopen(ICU_ZONE_FILE, "w")) == NULL) {
- const char *e = strerror(errno);
- (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
- progname, ICU_ZONE_FILE, e);
- (void) exit(EXIT_FAILURE);
- }
+ const char *e = strerror(errno);
+ (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
+ progname, ICU_ZONE_FILE, e);
+ (void) exit(EXIT_FAILURE);
+ }
#endif
for (i = optind; i < argc; ++i)
infile(argv[i]);
eat(links[i].l_filename, links[i].l_linenum);
dolink(links[i].l_from, links[i].l_to);
#ifdef ICU
- emit_icu_link(icuFile, links[i].l_from, links[i].l_to);
+ emit_icu_link(icuFile, links[i].l_from, links[i].l_to);
#endif
if (noise)
for (j = 0; j < nlinks; ++j)
dolink(psxrules, TZDEFRULES);
}
#ifdef ICU
- for (i=0; i<finalRulesCount; ++i) {
- emit_icu_rule(icuFile, finalRules[i], i);
- }
+ for (i=0; i<finalRulesCount; ++i) {
+ emit_icu_rule(icuFile, finalRules[i], i);
+ }
#endif /*ICU*/
return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
static void
-dolink(fromfile, tofile)
-const char * const fromfile;
-const char * const tofile;
+dolink(const char *const fromfield, const char *const tofield)
{
register char * fromname;
register char * toname;
- if (fromfile[0] == '/')
- fromname = ecpyalloc(fromfile);
+ if (fromfield[0] == '/')
+ fromname = ecpyalloc(fromfield);
else {
fromname = ecpyalloc(directory);
fromname = ecatalloc(fromname, "/");
- fromname = ecatalloc(fromname, fromfile);
+ fromname = ecatalloc(fromname, fromfield);
}
- if (tofile[0] == '/')
- toname = ecpyalloc(tofile);
+ if (tofield[0] == '/')
+ toname = ecpyalloc(tofield);
else {
toname = ecpyalloc(directory);
toname = ecatalloc(toname, "/");
- toname = ecatalloc(toname, tofile);
+ toname = ecatalloc(toname, tofield);
}
/*
** We get to be careful here since
*/
if (!itsdir(toname))
(void) remove(toname);
- if (link(fromname, toname) != 0) {
+ if (link(fromname, toname) != 0
+ && access(fromname, F_OK) == 0 && !itsdir(fromname)) {
int result;
if (mkdirs(toname) != 0)
exit(EXIT_FAILURE);
result = link(fromname, toname);
-#if HAVE_SYMLINK
- if (result != 0 &&
- access(fromname, F_OK) == 0 &&
- !itsdir(fromname)) {
- const char *s = tofile;
+ if (result != 0) {
+ const char *s = fromfield;
+ const char *t;
register char * symlinkcontents = NULL;
- while ((s = strchr(s+1, '/')) != NULL)
+ do
+ t = s;
+ while ((s = strchr(s, '/'))
+ && ! strncmp (fromfield, tofield,
+ ++s - fromfield));
+
+ for (s = tofield + (t - fromfield);
+ (s = strchr(s, '/'));
+ s++)
symlinkcontents =
ecatalloc(symlinkcontents,
"../");
- symlinkcontents =
- ecatalloc(symlinkcontents,
- fromfile);
- result = symlink(symlinkcontents,
- toname);
+ symlinkcontents = ecatalloc(symlinkcontents, t);
+ result = symlink(symlinkcontents, toname);
if (result == 0)
warning(_("hard link failed, symbolic link used"));
- ifree(symlinkcontents);
+ free(symlinkcontents);
}
-#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);
+ FILE *fp, *tp;
+ int c;
+ fp = fopen(fromname, "rb");
+ if (!fp) {
+ const char *e = strerror(errno);
+ (void) fprintf(stderr,
+ _("%s: Can't read %s: %s\n"),
+ progname, fromname, e);
+ exit(EXIT_FAILURE);
+ }
+ tp = fopen(toname, "wb");
+ if (!tp) {
+ const char *e = strerror(errno);
+ (void) fprintf(stderr,
+ _("%s: Can't create %s: %s\n"),
+ progname, toname, e);
+ exit(EXIT_FAILURE);
+ }
+ while ((c = getc(fp)) != EOF)
+ putc(c, tp);
+ if (ferror(fp) || fclose(fp)) {
+ (void) fprintf(stderr,
+ _("%s: Error reading %s\n"),
+ progname, fromname);
+ exit(EXIT_FAILURE);
+ }
+ if (ferror(tp) || fclose(tp)) {
+ (void) fprintf(stderr,
+ _("%s: Error writing %s\n"),
+ progname, toname);
+ exit(EXIT_FAILURE);
+ }
+ warning(_("link failed, copy used"));
#ifndef ICU_LINKS
exit(EXIT_FAILURE);
#endif
}
}
- ifree(fromname);
- ifree(toname);
+ free(fromname);
+ free(toname);
}
#define TIME_T_BITS_IN_FILE 64
-static void
-setboundaries P((void))
-{
- register int i;
-
- min_time = -1;
- for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
- min_time *= 2;
- max_time = -(min_time + 1);
-}
+static const zic_t min_time = (zic_t) -1 << (TIME_T_BITS_IN_FILE - 1);
+static const zic_t max_time = -1 - ((zic_t) -1 << (TIME_T_BITS_IN_FILE - 1));
static int
-itsdir(name)
-const char * const name;
+itsdir(const char *const name)
{
register char * myname;
register int accres;
myname = ecpyalloc(name);
myname = ecatalloc(myname, "/.");
accres = access(myname, F_OK);
- ifree(myname);
+ free(myname);
return accres == 0;
}
*/
static int
-rcomp(cp1, cp2)
-const void * cp1;
-const void * cp2;
+rcomp(const void *cp1, const void *cp2)
{
return strcmp(((const struct rule *) cp1)->r_name,
((const struct rule *) cp2)->r_name);
}
static void
-associate P((void))
+associate(void)
{
register struct zone * zp;
register struct rule * rp;
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)
** 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)
}
static void
-infile(name)
-const char * name;
+infile(const char *name)
{
register FILE * fp;
register char ** fields;
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) {
exit(EXIT_FAILURE);
}
}
- ifree((char *) fields);
+ free(fields);
}
if (ferror(fp)) {
(void) fprintf(stderr, _("%s: Error reading %s\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;
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;
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"));
}
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;
}
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"));
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,
}
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) {
}
dayoff = 0;
cp = fields[LP_YEAR];
- if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
+ if (sscanf(cp, scheck(cp, "%"SCNdZIC), &year) != 1) {
/*
** Leapin' Lizards!
*/
--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"));
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];
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;
}
static void
-inlink(fields, nfields)
-register char ** const fields;
-const int nfields;
+inlink(register char **const fields, const int nfields)
{
struct link l;
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;
}
}
rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
- ifree(dp);
+ free(dp);
/*
** Year work.
*/
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;
}
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;
_("%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;
}
*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;
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;
}
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;
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.
*/
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 +
++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.
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];
}
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) {
/*
/*
** 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;
}
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);
#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;
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);
}
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;
(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)
}
static void
-updateminmax(x)
-const int x;
+updateminmax(const zic_t x)
{
if (min_year > x)
min_year = x;
}
static int
-stringoffset(result, offset)
-char * result;
-long offset;
+stringoffset(char *result, zic_t offset)
{
register int hours;
register int minutes;
minutes = offset % MINSPERHOUR;
offset /= MINSPERHOUR;
hours = offset;
- if (hours >= HOURSPERDAY) {
+ if (hours >= HOURSPERDAY * DAYSPERWEEK) {
result[0] = '\0';
return -1;
}
}
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) {
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;
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; i<finalRulesCount; ++i) { /* i+=2 should work too */
- if (r1==finalRules[i]) return i; /* [sic] pointer comparison */
- }
-
- finalRules = (const struct rule**) (void*) erealloc((char *) finalRules,
- (finalRulesCount + 2) * sizeof(*finalRules));
- finalRules[finalRulesCount++] = r1;
- finalRules[finalRulesCount++] = r2;
- return finalRulesCount - 2;
-}
-
-#endif /*ICU*/
-
static void
-outzone(zpfirst, zonecount)
-const struct zone * const zpfirst;
-const int zonecount;
+outzone(const struct zone * const zpfirst, const int zonecount)
{
register const struct zone * zp;
register struct rule * rp;
register int i, j;
register int usestart, useuntil;
register zic_t starttime, untiltime;
- register long gmtoff;
- register long stdoff;
- register int year;
- register long startoff;
+ register zic_t gmtoff;
+ register zic_t stdoff;
+ register zic_t year;
+ register zic_t startoff;
register int startttisstd;
register int startttisgmt;
register int type;
register char * envvar;
register int max_abbr_len;
register int max_envvar_len;
+ register int prodstic; /* all rules are min to max */
+ register int compat;
+ register int do_extend;
+ register char version;
#ifdef ICU
- int finalRuleYear, finalRuleIndex;
- const struct rule* finalRule1;
- const struct rule* finalRule2;
+ int finalRuleYear, finalRuleIndex;
+ const struct rule* finalRule1;
+ const struct rule* finalRule2;
#endif
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
timecnt = 0;
typecnt = 0;
charcnt = 0;
+ prodstic = zonecount == 1;
/*
** Thanks to Earl Chew
** for noting the need to unconditionally initialize startttisstd.
min_year = max_year = EPOCH_YEAR;
if (leapseen) {
updateminmax(leapminyear);
- updateminmax(leapmaxyear);
+ updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
}
+ /*
+ ** Reserve type 0.
+ */
+ gmtoffs[0] = isdsts[0] = ttisstds[0] = ttisgmts[0] = abbrinds[0] = -1;
+ typecnt = 1;
for (i = 0; i < zonecount; ++i) {
zp = &zpfirst[i];
- updateminmax(zp->z_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) {
*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; j<zp->z_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; j<zp->z_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);
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.
*/
}
}
#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. */
-
- /* ICU currently can support signed int32 transition
- * times. Thus, the transitions in year 2038 may be
- * truncated. At this moment (tzdata2008g), only
- * Rule Brazil is impacted by this limitation, because
- * the final set of rules are starting in 2038. Although
- * this code put the first couple of transitions populated
- * by the final rules, they will be dropped off when
- * collecting transition times. So, we need to keep
- * the start year of the final rule in 2038, not 2039.
- * Fortunately, the Brazil rules in 2038 and beyond use
- * the same base offset/dst saving amount. Thus, even
- * we skip the first couple of transitions, the final
- * rule set for 2038 works properly. So for now,
- * we do not increment the final rule start year only when
- * it falls into year 2038. We need to revisit this code
- * in future to fix the root cause of this problem (ICU
- * resource type limitation - signed int32).
- * Oct 7, 2008 - Yoshito */
- int finalStartYear = (year == 2038) ? year : year + 1;
- emit_icu_zone(icuFile,
- zpfirst->z_name, zp->z_gmtoff,
- rp, finalRuleIndex, finalStartYear);
- /* only emit this for the first year */
- finalRule1 = NULL;
- }
+ 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);
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,
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));
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)) {
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;
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;
#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.
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] &&
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;
}
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;
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
}
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)) {
}
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')
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;
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;
}
static char **
-getfields(cp)
-register char * cp;
+getfields(register char *cp)
{
register char * dp;
register char ** array;
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) &&
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))
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;
}
/*
*/
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;
--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;
}
}
--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.
*/
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;
}
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))
++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) {
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;
cp = name = ecpyalloc(argname);
while ((cp = strchr(cp + 1, '/')) != 0) {
*cp = '\0';
-#ifndef unix
+#ifdef HAVE_DOS_FILE_NAMES
/*
** DOS drive specifier?
*/
*cp = '/';
continue;
}
-#endif /* !defined unix */
+#endif
if (!itsdir(name)) {
/*
** It doesn't seem to exist, so we try to create it.
(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.
*/