#ifndef lint
#ifndef NOID
-static char elsieid[] = "@(#)zic.c 7.7";
+static char elsieid[] = "@(#)zic.c 7.21";
#endif /* !defined NOID */
#endif /* !defined lint */
static void addtt P((time_t starttime, int type));
static int addtype P((long gmtoff, const char * abbr, int isdst,
- int ttisstd));
+ int ttisstd));
static void leapadd P((time_t t, int positive, int rolling, int count));
static void adjleap P((void));
static void associate P((void));
static const char * filename;
static int leapcnt;
static int linenum;
+static int max_int;
static time_t max_time;
static int max_year;
+static int min_int;
static time_t min_time;
static int min_year;
static int noise;
** Find the next non-continuation zone entry.
*/
for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
- ;
+ continue;
outzone(&zones[i], j - i);
}
/*
register char * fromname;
register char * toname;
- fromname = ecpyalloc(directory);
- fromname = ecatalloc(fromname, "/");
- fromname = ecatalloc(fromname, fromfile);
- toname = ecpyalloc(directory);
- toname = ecatalloc(toname, "/");
- toname = ecatalloc(toname, tofile);
+ if (fromfile[0] == '/')
+ fromname = fromfile;
+ else {
+ fromname = ecpyalloc(directory);
+ fromname = ecatalloc(fromname, "/");
+ fromname = ecatalloc(fromname, fromfile);
+ }
+ if (tofile[0] == '/')
+ toname = tofile;
+ else {
+ toname = ecpyalloc(directory);
+ toname = ecatalloc(toname, "/");
+ toname = ecatalloc(toname, tofile);
+ }
/*
** We get to be careful here since
** there's a fair chance of root running us.
if (!itsdir(toname))
(void) remove(toname);
if (link(fromname, toname) != 0) {
- (void) fprintf(stderr, "%s: Can't link from %s to ",
- progname, fromname);
- (void) perror(toname);
- (void) exit(EXIT_FAILURE);
+ if (mkdirs(toname) != 0)
+ (void) exit(EXIT_FAILURE);
+ if (link(fromname, toname) != 0) {
+ (void) fprintf(stderr, "%s: Can't link from %s to ",
+ progname, fromname);
+ (void) perror(toname);
+ (void) exit(EXIT_FAILURE);
+ }
}
- ifree(fromname);
- ifree(toname);
+ if (fromname != fromfile)
+ ifree(fromname);
+ if (toname != tofile)
+ ifree(toname);
}
static void
setboundaries()
{
register time_t bit;
+ register int bii;
for (bit = 1; bit > 0; bit <<= 1)
- ;
+ continue;
if (bit == 0) { /* time_t is an unsigned type */
tt_signed = FALSE;
min_time = 0;
}
min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
+
+ for (bii = 1; bii > 0; bii <<= 1)
+ continue;
+ min_int = bii;
+ max_int = -1 - bii;
}
static int
if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
buf = erealloc(buf, 132 + strlen(TZDEFAULT));
(void) sprintf(buf,
- "\"Zone %s\" line and -l option are mutually exclusive",
+"\"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, 132 + strlen(TZDEFRULES));
(void) sprintf(buf,
- "\"Zone %s\" line and -p option are mutually exclusive",
+"\"Zone %s\" line and -p option are mutually exclusive",
TZDEFRULES);
error(buf);
return FALSE;
fields[i_untilyear],
"only",
"",
- (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan",
+ (nfields > i_untilmonth) ?
+ fields[i_untilmonth] : "Jan",
(nfields > i_untilday) ? fields[i_untilday] : "1",
(nfields > i_untiltime) ? fields[i_untiltime] : "0");
- z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear);
- if (iscont && nzones > 0 && z.z_untiltime < max_time &&
+ z.z_untiltime = rpytime(&z.z_untilrule,
+ z.z_untilrule.r_loyear);
+ if (iscont && nzones > 0 &&
z.z_untiltime > min_time &&
+ z.z_untiltime < max_time &&
+ zones[nzones - 1].z_untiltime > min_time &&
+ zones[nzones - 1].z_untiltime < max_time &&
zones[nzones - 1].z_untiltime >= z.z_untiltime) {
error("Zone continuation line end time is not after end time of previous line");
- return FALSE;
+ return FALSE;
}
}
zones = (struct zone *) erealloc((char *) zones,
}
dayoff = 0;
cp = fields[LP_YEAR];
- if (sscanf(cp, scheck(cp, "%d"), &year) != 1 ||
- year < min_year || year > max_year) {
+ if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
/*
* Leapin' Lizards!
*/
cp = loyearp;
if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
case YR_MINIMUM:
- rp->r_loyear = min_year;
+ rp->r_loyear = min_int;
break;
case YR_MAXIMUM:
- rp->r_loyear = max_year;
+ rp->r_loyear = max_int;
break;
default: /* "cannot happen" */
(void) fprintf(stderr,
"%s: panic: Invalid l_value %d\n",
progname, lp->l_value);
(void) exit(EXIT_FAILURE);
- } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 ||
- rp->r_loyear < min_year || rp->r_loyear > max_year) {
- if (noise)
- error("invalid starting year");
- if (rp->r_loyear > max_year)
- return;
+ } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
+ error("invalid starting year");
+ return;
}
cp = hiyearp;
if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
case YR_MINIMUM:
- rp->r_hiyear = min_year;
+ rp->r_hiyear = min_int;
break;
case YR_MAXIMUM:
- rp->r_hiyear = max_year;
+ rp->r_hiyear = max_int;
break;
case YR_ONLY:
rp->r_hiyear = rp->r_loyear;
"%s: panic: Invalid l_value %d\n",
progname, lp->l_value);
(void) exit(EXIT_FAILURE);
- } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 ||
- rp->r_hiyear < min_year || rp->r_hiyear > max_year) {
- if (noise)
- error("invalid ending year");
- if (rp->r_hiyear < min_year)
- return;
+ } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
+ error("invalid ending year");
+ return;
}
- if (rp->r_hiyear < min_year)
- return;
- if (rp->r_loyear < min_year)
- rp->r_loyear = min_year;
- if (rp->r_hiyear > max_year)
- rp->r_hiyear = max_year;
if (rp->r_loyear > rp->r_hiyear) {
error("starting year greater than ending year");
return;
typecnt = 0;
charcnt = 0;
/*
- ** Two guesses. . .the second may well be corrected later.
+ ** A guess that may well be corrected later.
*/
- gmtoff = zpfirst->z_gmtoff;
stdoff = 0;
/*
** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)
starttime = 0;
#endif /* defined lint */
for (i = 0; i < zonecount; ++i) {
- usestart = i > 0;
- useuntil = i < (zonecount - 1);
zp = &zpfirst[i];
+ usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
+ useuntil = i < (zonecount - 1);
+ if (useuntil && zp->z_untiltime <= min_time)
+ continue;
+ gmtoff = zp->z_gmtoff;
eat(zp->z_filename, zp->z_linenum);
startisdst = -1;
if (zp->z_nrules == 0) {
- type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff),
- zp->z_format, zp->z_stdoff != 0,
- startttisstd);
+ stdoff = zp->z_stdoff;
+ (void) strcpy(startbuf, zp->z_format);
+ type = addtype(oadd(zp->z_gmtoff, stdoff),
+ startbuf, stdoff != 0, startttisstd);
if (usestart)
addtt(starttime, type);
- gmtoff = zp->z_gmtoff;
- stdoff = zp->z_stdoff;
+ else if (stdoff != 0)
+ addtt(min_time, type);
} else for (year = min_year; year <= max_year; ++year) {
if (useuntil && year > zp->z_untilrule.r_hiyear)
break;
** assuming the current gmtoff and
** stdoff values.
*/
- offset = gmtoff;
- if (!zp->z_untilrule.r_todisstd)
- offset = oadd(offset, stdoff);
untiltime = tadd(zp->z_untiltime,
- -offset);
+ -gmtoff);
+ if (!zp->z_untilrule.r_todisstd)
+ untiltime = tadd(untiltime,
+ -stdoff);
}
/*
** Find the rule (of those to do, if any)
if (useuntil && ktime >= untiltime)
break;
if (usestart) {
- if (ktime < starttime) {
- stdoff = rp->r_stdoff;
- startoff = oadd(zp->z_gmtoff,
- rp->r_stdoff);
- (void) sprintf(startbuf,
- zp->z_format,
- rp->r_abbrvar);
- startisdst =
- rp->r_stdoff != 0;
- continue;
+ if (ktime < starttime) {
+ stdoff = rp->r_stdoff;
+ startoff = oadd(zp->z_gmtoff,
+ rp->r_stdoff);
+ (void) sprintf(startbuf, zp->z_format,
+ rp->r_abbrvar);
+ startisdst = rp->r_stdoff != 0;
+ continue;
+ }
+ usestart = FALSE;
+ if (ktime != starttime) {
+ if (startisdst < 0 &&
+ zp->z_gmtoff !=
+ (zp - 1)->z_gmtoff) {
+ type = (timecnt == 0) ? 0 :
+ types[timecnt - 1];
+ startoff = oadd(gmtoffs[type],
+ -(zp - 1)->z_gmtoff);
+ startisdst = startoff != 0;
+ startoff = oadd(startoff,
+ zp->z_gmtoff);
+ (void) strcpy(startbuf,
+ &chars[abbrinds[type]]);
}
- if (ktime != starttime &&
- startisdst >= 0)
+ if (startisdst >= 0)
addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd));
- usestart = FALSE;
+ }
}
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
offset = oadd(zp->z_gmtoff, rp->r_stdoff);
type = addtype(offset, buf, rp->r_stdoff != 0,
rp->r_todisstd);
- if (timecnt != 0 || rp->r_stdoff != 0)
- addtt(ktime, type);
- gmtoff = zp->z_gmtoff;
+ addtt(ktime, type);
stdoff = rp->r_stdoff;
}
}
** Now we may get to set starttime for the next zone line.
*/
if (useuntil) {
- starttime = tadd(zp->z_untiltime,
- -gmtoffs[types[timecnt - 1]]);
+ starttime = tadd(zp->z_untiltime, -gmtoff);
startttisstd = zp->z_untilrule.r_todisstd;
+ if (!startttisstd)
+ starttime = tadd(starttime, -stdoff);
}
}
writezone(zpfirst->z_name);
{
if (timecnt != 0 && type == types[timecnt - 1])
return; /* easy enough! */
+ if (timecnt == 0 && type == 0 && isdsts[0] == 0)
+ return; /* handled by default rule */
if (timecnt >= TZ_MAX_TIMES) {
error("too many transitions?!");
(void) exit(EXIT_FAILURE);
register long dayoff; /* with a nod to Margaret O. */
register time_t t;
+ if (wantedy == min_int)
+ return min_time;
+ if (wantedy == max_int)
+ return max_time;
dayoff = 0;
m = TM_JANUARY;
y = EPOCH_YEAR;
} else {
dayoff = oadd(dayoff, (long) -1);
if (--wday < 0)
- wday = LDAYSPERWEEK;
+ wday = LDAYSPERWEEK - 1;
--i;
}
if (i < 0 || i >= len_months[isleap(y)][m]) {
(void) exit(EXIT_FAILURE);
}
}
- if (dayoff < 0 && !tt_signed) {
- if (wantedy == rp->r_loyear)
- return min_time;
- error("time before zero");
- (void) exit(EXIT_FAILURE);
- }
+ if (dayoff < 0 && !tt_signed)
+ return min_time;
t = (time_t) dayoff * SECSPERDAY;
/*
** Cheap overflow check.
*/
- if (t / SECSPERDAY != dayoff) {
- if (wantedy == rp->r_hiyear)
- return max_time;
- if (wantedy == rp->r_loyear)
- return min_time;
- error("time overflow");
- (void) exit(EXIT_FAILURE);
- }
+ if (t / SECSPERDAY != dayoff)
+ return (dayoff > 0) ? max_time : min_time;
return tadd(t, rp->r_tod);
}
register int i;
i = strlen(string) + 1;
- if (charcnt + i >= TZ_MAX_CHARS) {
+ if (charcnt + i > TZ_MAX_CHARS) {
error("too many, or too long, time zone abbreviations");
(void) exit(EXIT_FAILURE);
}
charcnt += eitol(i);
}
+
static int
-mkdirs(name)
-char * const name;
+mkdirs(argname)
+char * const argname;
{
register char * cp;
+ /* We must make a copy in case the
+ passed pointer is a read-only string. */
+ char *name = ecpyalloc (argname);
- if ((cp = name) == NULL || *cp == '\0')
- return 0;
+ if (*cp == '\0') {
+ ifree (name);
+ return 0;
+ }
while ((cp = strchr(cp + 1, '/')) != 0) {
*cp = '\0';
#ifndef unix
"%s: Can't create directory ",
progname);
(void) perror(name);
+ free (name);
return -1;
}
}
*cp = '/';
}
+ free (name);
return 0;
}
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",
+ (void) fprintf(stderr,
+ "%s: %d did not sign extend correctly\n",
progname, i);
(void) exit(EXIT_FAILURE);
}