aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2020-05-15 08:52:25 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2020-05-15 09:19:27 -0700
commit61d64408a1f42b0340d37ea0c90a9f028ffb1bfd (patch)
treec74d0245a5cf6098fc0a434d3c50912610d9b89d
parent59b64f9cbbf1e98c6d187873de6c363994aee19d (diff)
downloadglibc-61d64408a1f42b0340d37ea0c90a9f028ffb1bfd.tar.xz
glibc-61d64408a1f42b0340d37ea0c90a9f028ffb1bfd.zip
Update timezone code from tzcode 2020a
This patch updates files coming from tzcode to tzcode 2020a. This is mostly for better support for Internet RFC 8536, by adding support to zic for the Expires line (new to tzcode 2020a), the -b option (new to 2019b) and the -r option (new to 2019a). One trivial change to other glibc was needed. * time/tzfile.c (__tzfile_read): Adjust to tzcode private.h renaming. * timezone/private.h, timezone/tzfile.h, timezone/version: * timezone/zdump.c, timezone/zic.c: Update from tzcode 2020a.
-rw-r--r--time/tzfile.c2
-rw-r--r--timezone/private.h37
-rw-r--r--timezone/tzfile.h20
-rw-r--r--timezone/version2
-rw-r--r--timezone/zdump.c6
-rw-r--r--timezone/zic.c814
6 files changed, 554 insertions, 327 deletions
diff --git a/time/tzfile.c b/time/tzfile.c
index 013b3d03f3..af6da1bf00 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -189,7 +189,7 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
chars = (size_t) decode (tzhead.tzh_charcnt);
num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
- num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
+ num_isgmt = (size_t) decode (tzhead.tzh_ttisutcnt);
if (__glibc_unlikely (num_isstd > num_types || num_isgmt > num_types))
goto lose;
diff --git a/timezone/private.h b/timezone/private.h
index 1ead14793b..8513663036 100644
--- a/timezone/private.h
+++ b/timezone/private.h
@@ -132,11 +132,16 @@
** Nested includes
*/
-/* Avoid clashes with NetBSD by renaming NetBSD's declarations. */
+/* Avoid clashes with NetBSD by renaming NetBSD's declarations.
+ If defining the 'timezone' variable, avoid a clash with FreeBSD's
+ 'timezone' function by renaming its declaration. */
#define localtime_rz sys_localtime_rz
#define mktime_z sys_mktime_z
#define posix2time_z sys_posix2time_z
#define time2posix_z sys_time2posix_z
+#if defined USG_COMPAT && USG_COMPAT == 2
+# define timezone sys_timezone
+#endif
#define timezone_t sys_timezone_t
#define tzalloc sys_tzalloc
#define tzfree sys_tzfree
@@ -145,6 +150,9 @@
#undef mktime_z
#undef posix2time_z
#undef time2posix_z
+#if defined USG_COMPAT && USG_COMPAT == 2
+# undef timezone
+#endif
#undef timezone_t
#undef tzalloc
#undef tzfree
@@ -198,6 +206,14 @@
# endif
#endif
+#ifndef ALTZONE
+# if defined __sun || defined _M_XENIX
+# define ALTZONE 1
+# else
+# define ALTZONE 0
+# endif
+#endif
+
#ifndef R_OK
#define R_OK 4
#endif /* !defined R_OK */
@@ -409,6 +425,10 @@ static time_t sys_time(time_t *x) { return time(x); }
typedef time_tz tz_time_t;
+# undef asctime
+# define asctime tz_asctime
+# undef asctime_r
+# define asctime_r tz_asctime_r
# undef ctime
# define ctime tz_ctime
# undef ctime_r
@@ -473,11 +493,13 @@ typedef time_tz tz_time_t;
# undef timezone
# define timezone tz_timezone
# endif
-# ifdef ALTZONE
+# if ALTZONE
# undef altzone
# define altzone tz_altzone
# endif
+char *asctime(struct tm const *);
+char *asctime_r(struct tm const *restrict, char *restrict);
char *ctime(time_t const *);
char *ctime_r(time_t const *, char *);
double difftime(time_t, time_t) ATTRIBUTE_CONST;
@@ -512,17 +534,14 @@ extern char *asctime_r(struct tm const *restrict, char *restrict);
extern char **environ;
#endif
-#if TZ_TIME_T || !HAVE_POSIX_DECLS
-# if HAVE_TZNAME
+#if 2 <= HAVE_TZNAME + (TZ_TIME_T || !HAVE_POSIX_DECLS)
extern char *tzname[];
-# endif
-# if USG_COMPAT
+#endif
+#if 2 <= USG_COMPAT + (TZ_TIME_T || !HAVE_POSIX_DECLS)
extern long timezone;
extern int daylight;
-# endif
#endif
-
-#ifdef ALTZONE
+#if 2 <= ALTZONE + (TZ_TIME_T || !HAVE_POSIX_DECLS)
extern long altzone;
#endif
diff --git a/timezone/tzfile.h b/timezone/tzfile.h
index 27a38cc74d..ee91104443 100644
--- a/timezone/tzfile.h
+++ b/timezone/tzfile.h
@@ -33,6 +33,9 @@
#define TZDEFRULES "posixrules"
#endif /* !defined TZDEFRULES */
+
+/* See Internet RFC 8536 for more details about the following format. */
+
/*
** Each file begins with. . .
*/
@@ -43,7 +46,7 @@ struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */
char tzh_reserved[15]; /* reserved; must be zero */
- char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
+ char tzh_ttisutcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
char tzh_timecnt[4]; /* coded number of transition times */
@@ -66,14 +69,15 @@ struct tzhead {
** one (char [4]) total correction after above
** tzh_ttisstdcnt (char)s indexed by type; if 1, transition
** time is standard time, if 0,
-** transition time is wall clock time
-** if absent, transition times are
-** assumed to be wall clock time
-** tzh_ttisgmtcnt (char)s indexed by type; if 1, transition
-** time is UT, if 0,
-** transition time is local time
-** if absent, transition times are
+** transition time is local (wall clock)
+** time; if absent, transition times are
** assumed to be local time
+** tzh_ttisutcnt (char)s indexed by type; if 1, transition
+** time is UT, if 0, transition time is
+** local time; if absent, transition
+** times are assumed to be local time.
+** When this is 1, the corresponding
+** std/wall indicator must also be 1.
*/
/*
diff --git a/timezone/version b/timezone/version
index 63f58006ee..7f680eec36 100644
--- a/timezone/version
+++ b/timezone/version
@@ -1 +1 @@
-2018i
+2020a
diff --git a/timezone/zdump.c b/timezone/zdump.c
index 0fc8ced96a..b532fe3eae 100644
--- a/timezone/zdump.c
+++ b/timezone/zdump.c
@@ -328,12 +328,12 @@ abbrok(const char *const abbrp, const char *const zone)
cp = abbrp;
while (is_alpha(*cp) || is_digit(*cp) || *cp == '-' || *cp == '+')
++cp;
- if (cp - abbrp < 3)
+ if (*cp)
+ wp = _("has characters other than ASCII alphanumerics, '-' or '+'");
+ else if (cp - abbrp < 3)
wp = _("has fewer than 3 characters");
else if (cp - abbrp > 6)
wp = _("has more than 6 characters");
- else if (*cp)
- wp = _("has characters other than ASCII alphanumerics, '-' or '+'");
else
return;
fflush(stdout);
diff --git a/timezone/zic.c b/timezone/zic.c
index 2ebc66a9af..2875b5544c 100644
--- a/timezone/zic.c
+++ b/timezone/zic.c
@@ -92,13 +92,10 @@ struct rule {
int r_wday;
zic_t r_tod; /* time from midnight */
- bool r_todisstd; /* above is standard time if 1 */
- /* or wall clock time if 0 */
- bool r_todisgmt; /* above is GMT if 1 */
- /* or local time if 0 */
+ bool r_todisstd; /* is r_tod standard time? */
+ bool r_todisut; /* is r_tod UT? */
bool r_isdst; /* is this daylight saving time? */
- zic_t r_stdoff; /* offset from default time (which is
- usually standard time) */
+ zic_t r_save; /* offset from standard time */
const char * r_abbrvar; /* variable part of abbreviation */
bool r_todo; /* a rule to do (used in outzone) */
@@ -118,13 +115,13 @@ struct zone {
lineno z_linenum;
const char * z_name;
- zic_t z_gmtoff;
+ zic_t z_stdoff;
char * z_rule;
const char * z_format;
char z_format_specifier;
bool z_isdst;
- zic_t z_stdoff;
+ zic_t z_save;
struct rule * z_rules;
ptrdiff_t z_nrules;
@@ -156,13 +153,14 @@ extern int optind;
static void addtt(zic_t starttime, int type);
static int addtype(zic_t, char const *, bool, bool, bool);
-static void leapadd(zic_t, bool, int, int);
+static void leapadd(zic_t, int, int);
static void adjleap(void);
static void associate(void);
static void dolink(const char *, const char *, bool);
static char ** getfields(char * buf);
static zic_t gethms(const char * string, const char * errstring);
-static zic_t getstdoff(char *, bool *);
+static zic_t getsave(char *, bool *);
+static void inexpires(char **, int);
static void infile(const char * filename);
static void inleap(char ** fields, int nfields);
static void inlink(char ** fields, int nfields);
@@ -227,13 +225,14 @@ static int typecnt;
#define LC_ZONE 1
#define LC_LINK 2
#define LC_LEAP 3
+#define LC_EXPIRES 4
/*
** Which fields are which on a Zone line.
*/
#define ZF_NAME 1
-#define ZF_GMTOFF 2
+#define ZF_STDOFF 2
#define ZF_RULE 3
#define ZF_FORMAT 4
#define ZF_TILYEAR 5
@@ -247,7 +246,7 @@ static int typecnt;
** Which fields are which on a Zone continuation line.
*/
-#define ZFC_GMTOFF 0
+#define ZFC_STDOFF 0
#define ZFC_RULE 1
#define ZFC_FORMAT 2
#define ZFC_TILYEAR 3
@@ -268,7 +267,7 @@ static int typecnt;
#define RF_MONTH 5
#define RF_DAY 6
#define RF_TOD 7
-#define RF_STDOFF 8
+#define RF_SAVE 8
#define RF_ABBRVAR 9
#define RULE_FIELDS 10
@@ -292,6 +291,9 @@ static int typecnt;
#define LP_ROLL 6
#define LEAP_FIELDS 7
+/* Expires lines are like Leap lines, except without CORR and ROLL fields. */
+#define EXPIRES_FIELDS 5
+
/*
** Year synonyms.
*/
@@ -335,6 +337,7 @@ static struct lookup const zi_line_codes[] = {
};
static struct lookup const leap_line_codes[] = {
{ "Leap", LC_LEAP },
+ { "Expires", LC_EXPIRES },
{ NULL, 0}
};
@@ -409,11 +412,11 @@ static struct attype {
bool dontmerge;
unsigned char type;
} * attypes;
-static zic_t gmtoffs[TZ_MAX_TYPES];
+static zic_t utoffs[TZ_MAX_TYPES];
static char isdsts[TZ_MAX_TYPES];
-static unsigned char abbrinds[TZ_MAX_TYPES];
+static unsigned char desigidx[TZ_MAX_TYPES];
static bool ttisstds[TZ_MAX_TYPES];
-static bool ttisgmts[TZ_MAX_TYPES];
+static bool ttisuts[TZ_MAX_TYPES];
static char chars[TZ_MAX_CHARS];
static zic_t trans[TZ_MAX_LEAPS];
static zic_t corr[TZ_MAX_LEAPS];
@@ -574,8 +577,10 @@ usage(FILE *stream, int status)
{
fprintf(stream,
_("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
- "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
- "\t[ -t localtime-link ] [ -L leapseconds ] [ filename ... ]\n\n"
+ "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]"
+ " [ -L leapseconds ] \\\n"
+ "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -t localtime-link ] \\\n"
+ "\t[ filename ... ]\n\n"
"Report bugs to %s.\n"),
progname, progname, REPORT_BUGS_TO);
if (status == EXIT_SUCCESS)
@@ -603,6 +608,51 @@ change_directory (char const *dir)
}
}
+#define TIME_T_BITS_IN_FILE 64
+
+/* The minimum and maximum values representable in a TZif file. */
+static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
+static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
+
+/* The minimum, and one less than the maximum, values specified by
+ the -r option. These default to MIN_TIME and MAX_TIME. */
+static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
+static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
+
+/* The time specified by an Expires line, or negative if no such line. */
+static zic_t leapexpires = -1;
+
+/* The time specified by an #expires comment, or negative if no such line. */
+static zic_t comment_leapexpires = -1;
+
+/* Set the time range of the output to TIMERANGE.
+ Return true if successful. */
+static bool
+timerange_option(char *timerange)
+{
+ intmax_t lo = min_time, hi = max_time;
+ char *lo_end = timerange, *hi_end;
+ if (*timerange == '@') {
+ errno = 0;
+ lo = strtoimax (timerange + 1, &lo_end, 10);
+ if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE))
+ return false;
+ }
+ hi_end = lo_end;
+ if (lo_end[0] == '/' && lo_end[1] == '@') {
+ errno = 0;
+ hi = strtoimax (lo_end + 2, &hi_end, 10);
+ if (hi_end == lo_end + 2 || hi == INTMAX_MIN)
+ return false;
+ hi -= ! (hi == INTMAX_MAX && errno == ERANGE);
+ }
+ if (*hi_end || hi < lo || max_time < lo || hi < min_time)
+ return false;
+ lo_time = lo < min_time ? min_time : lo;
+ hi_time = max_time < hi ? max_time : hi;
+ return true;
+}
+
static const char * psxrules;
static const char * lcltime;
static const char * directory;
@@ -610,11 +660,27 @@ static const char * leapsec;
static const char * tzdefault;
static const char * yitcommand;
+/* -1 if the TZif output file should be slim, 0 if default, 1 if the
+ output should be fat for backward compatibility. Currently the
+ default is fat, although this may change. */
+static int bloat;
+
+static bool
+want_bloat(void)
+{
+ return 0 <= bloat;
+}
+
+#ifndef ZIC_BLOAT_DEFAULT
+# define ZIC_BLOAT_DEFAULT "fat"
+#endif
+
int
main(int argc, char **argv)
{
register int c, k;
register ptrdiff_t i, j;
+ bool timerange_given = false;
#ifdef S_IWGRP
umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
@@ -640,10 +706,22 @@ main(int argc, char **argv)
} else if (strcmp(argv[k], "--help") == 0) {
usage(stdout, EXIT_SUCCESS);
}
- while ((c = getopt(argc, argv, "d:l:L:p:st:vy:")) != EOF && c != -1)
+ while ((c = getopt(argc, argv, "b:d:l:L:p:r:st:vy:")) != EOF && c != -1)
switch (c) {
default:
usage(stderr, EXIT_FAILURE);
+ case 'b':
+ if (strcmp(optarg, "slim") == 0) {
+ if (0 < bloat)
+ error(_("incompatible -b options"));
+ bloat = -1;
+ } else if (strcmp(optarg, "fat") == 0) {
+ if (bloat < 0)
+ error(_("incompatible -b options"));
+ bloat = 1;
+ } else
+ error(_("invalid option: -b '%s'"), optarg);
+ break;
case 'd':
if (directory == NULL)
directory = optarg;
@@ -708,12 +786,29 @@ _("%s: More than one -L option specified\n"),
case 'v':
noise = true;
break;
+ case 'r':
+ if (timerange_given) {
+ fprintf(stderr,
+_("%s: More than one -r option specified\n"),
+ progname);
+ return EXIT_FAILURE;
+ }
+ if (! timerange_option(optarg)) {
+ fprintf(stderr,
+_("%s: invalid time range: %s\n"),
+ progname, optarg);
+ return EXIT_FAILURE;
+ }
+ timerange_given = true;
+ break;
case 's':
warning(_("-s ignored"));
break;
}
if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
usage(stderr, EXIT_FAILURE); /* usage message by request */
+ if (bloat == 0)
+ bloat = strcmp(ZIC_BLOAT_DEFAULT, "slim") == 0 ? -1 : 1;
if (directory == NULL)
directory = TZDIR;
if (tzdefault == NULL)
@@ -961,11 +1056,6 @@ dolink(char const *fromfield, char const *tofield, bool staysymlink)
}
}
-#define TIME_T_BITS_IN_FILE 64
-
-static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
-static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
-
/* Return true if NAME is a directory. */
static bool
itsdir(char const *name)
@@ -1072,7 +1162,7 @@ associate(void)
** Maybe we have a local standard time offset.
*/
eat(zp->z_filename, zp->z_linenum);
- zp->z_stdoff = getstdoff(zp->z_rule, &zp->z_isdst);
+ zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
/*
** Note, though, that if there's no rule,
** a '%s' in the format is a bad thing.
@@ -1128,7 +1218,8 @@ infile(const char *name)
++nfields;
}
if (nfields == 0) {
- /* nothing to do */
+ if (name == leapsec && *buf == '#')
+ sscanf(buf, "#expires %"SCNdZIC, &comment_leapexpires);
} else if (wantcont) {
wantcont = inzcont(fields, nfields);
} else {
@@ -1153,6 +1244,10 @@ infile(const char *name)
inleap(fields, nfields);
wantcont = false;
break;
+ case LC_EXPIRES:
+ inexpires(fields, nfields);
+ wantcont = false;
+ break;
default: /* "cannot happen" */
fprintf(stderr,
_("%s: panic: Invalid l_value %d\n"),
@@ -1230,10 +1325,10 @@ warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
}
static zic_t
-getstdoff(char *field, bool *isdst)
+getsave(char *field, bool *isdst)
{
int dst = -1;
- zic_t stdoff;
+ zic_t save;
size_t fieldlen = strlen(field);
if (fieldlen != 0) {
char *ep = field + fieldlen - 1;
@@ -1242,9 +1337,9 @@ getstdoff(char *field, bool *isdst)
case 's': dst = 0; *ep = '\0'; break;
}
}
- stdoff = gethms(field, _("invalid saved time"));
- *isdst = dst < 0 ? stdoff != 0 : dst;
- return stdoff;
+ save = gethms(field, _("invalid saved time"));
+ *isdst = dst < 0 ? save != 0 : dst;
+ return save;
}
static void
@@ -1267,7 +1362,7 @@ inrule(char **fields, int nfields)
}
r.r_filename = filename;
r.r_linenum = linenum;
- r.r_stdoff = getstdoff(fields[RF_STDOFF], &r.r_isdst);
+ r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
r.r_name = ecpyalloc(fields[RF_NAME]);
@@ -1328,13 +1423,13 @@ inzsub(char **fields, int nfields, bool iscont)
register char * cp;
char * cp1;
static struct zone z;
- register int i_gmtoff, i_rule, i_format;
+ register int i_stdoff, i_rule, i_format;
register int i_untilyear, i_untilmonth;
register int i_untilday, i_untiltime;
register bool hasuntil;
if (iscont) {
- i_gmtoff = ZFC_GMTOFF;
+ i_stdoff = ZFC_STDOFF;
i_rule = ZFC_RULE;
i_format = ZFC_FORMAT;
i_untilyear = ZFC_TILYEAR;
@@ -1345,7 +1440,7 @@ inzsub(char **fields, int nfields, bool iscont)
} else if (!namecheck(fields[ZF_NAME]))
return false;
else {
- i_gmtoff = ZF_GMTOFF;
+ i_stdoff = ZF_STDOFF;
i_rule = ZF_RULE;
i_format = ZF_FORMAT;
i_untilyear = ZF_TILYEAR;
@@ -1356,7 +1451,7 @@ inzsub(char **fields, int nfields, bool iscont)
}
z.z_filename = filename;
z.z_linenum = linenum;
- z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"));
+ z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
if ((cp = strchr(fields[i_format], '%')) != 0) {
if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
|| strchr(fields[i_format], '/')) {
@@ -1410,8 +1505,8 @@ inzsub(char **fields, int nfields, bool iscont)
return hasuntil;
}
-static void
-inleap(char **fields, int nfields)
+static zic_t
+getleapdatetime(char **fields, int nfields, bool expire_line)
{
register const char * cp;
register const struct lookup * lp;
@@ -1422,10 +1517,6 @@ inleap(char **fields, int nfields)
zic_t t;
char xs;
- if (nfields != LEAP_FIELDS) {
- error(_("wrong number of fields on Leap line"));
- return;
- }
dayoff = 0;
cp = fields[LP_YEAR];
if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
@@ -1433,13 +1524,15 @@ inleap(char **fields, int nfields)
** Leapin' Lizards!
*/
error(_("invalid leaping year"));
- return;
+ return -1;
}
- if (!leapseen || leapmaxyear < year)
+ if (!expire_line) {
+ if (!leapseen || leapmaxyear < year)
leapmaxyear = year;
- if (!leapseen || leapminyear > year)
+ if (!leapseen || leapminyear > year)
leapminyear = year;
- leapseen = true;
+ leapseen = true;
+ }
j = EPOCH_YEAR;
while (j != year) {
if (year > j) {
@@ -1453,7 +1546,7 @@ inleap(char **fields, int nfields)
}
if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
error(_("invalid month name"));
- return;
+ return -1;
}
month = lp->l_value;
j = TM_JANUARY;
@@ -1466,47 +1559,60 @@ inleap(char **fields, int nfields)
if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
day <= 0 || day > len_months[isleap(year)][month]) {
error(_("invalid day of month"));
- return;
+ return -1;
}
dayoff = oadd(dayoff, day - 1);
if (dayoff < min_time / SECSPERDAY) {
error(_("time too small"));
- return;
+ return -1;
}
if (dayoff > max_time / SECSPERDAY) {
error(_("time too large"));
- return;
+ return -1;
}
t = dayoff * SECSPERDAY;
tod = gethms(fields[LP_TIME], _("invalid time of day"));
- cp = fields[LP_CORR];
- {
- register bool positive;
- int count;
-
- if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
- positive = false;
- count = 1;
- } else if (strcmp(cp, "+") == 0) {
- positive = true;
- count = 1;
- } else {
- error(_("illegal CORRECTION field on Leap line"));
- return;
- }
- if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
- error(_(
- "illegal Rolling/Stationary field on Leap line"
- ));
- return;
- }
- t = tadd(t, tod);
- if (t < 0) {
- error(_("leap second precedes Epoch"));
- return;
- }
- leapadd(t, positive, lp->l_value, count);
- }
+ t = tadd(t, tod);
+ if (t < 0)
+ error(_("leap second precedes Epoch"));
+ return t;
+}
+
+static void
+inleap(char **fields, int nfields)
+{
+ if (nfields != LEAP_FIELDS)
+ error(_("wrong number of fields on Leap line"));
+ else {
+ zic_t t = getleapdatetime(fields, nfields, false);
+ if (0 <= t) {
+ struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
+ if (!lp)
+ error(_("invalid Rolling/Stationary field on Leap line"));
+ else {
+ int correction = 0;
+ if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */
+ correction = -1;
+ else if (strcmp(fields[LP_CORR], "+") == 0)
+ correction = 1;
+ else
+ error(_("invalid CORRECTION field on Leap line"));
+ if (correction)
+ leapadd(t, correction, lp->l_value);
+ }
+ }
+ }
+}
+
+static void
+inexpires(char **fields, int nfields)
+{
+ if (nfields != EXPIRES_FIELDS)
+ error(_("wrong number of fields on Expires line"));
+ else if (0 <= leapexpires)
+ error(_("multiple Expires lines"));
+ else
+ leapexpires = getleapdatetime(fields, nfields, true);
}
static void
@@ -1549,26 +1655,26 @@ rulesub(stru