summaryrefslogtreecommitdiff
path: root/elsie.nci.nih.gov/src/zic.c
diff options
context:
space:
mode:
Diffstat (limited to 'elsie.nci.nih.gov/src/zic.c')
-rw-r--r--elsie.nci.nih.gov/src/zic.c233
1 files changed, 142 insertions, 91 deletions
diff --git a/elsie.nci.nih.gov/src/zic.c b/elsie.nci.nih.gov/src/zic.c
index 636649b..5d5f1cd 100644
--- a/elsie.nci.nih.gov/src/zic.c
+++ b/elsie.nci.nih.gov/src/zic.c
@@ -76,6 +76,7 @@ struct zone {
zic_t z_gmtoff;
const char * z_rule;
const char * z_format;
+ char z_format_specifier;
zic_t z_stdoff;
@@ -130,6 +131,9 @@ static void rulesub(struct rule * rp,
static zic_t tadd(zic_t t1, zic_t t2);
static bool yearistype(int year, const char * type);
+/* Bound on length of what %z can expand to. */
+enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
+
static int charcnt;
static bool errors;
static bool warnings;
@@ -139,7 +143,7 @@ static bool leapseen;
static zic_t leapminyear;
static zic_t leapmaxyear;
static int linenum;
-static int max_abbrvar_len;
+static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
static int max_format_len;
static zic_t max_year;
static zic_t min_year;
@@ -443,7 +447,8 @@ verror(const char *const string, va_list args)
** zic ... 2>&1 | error -t "*" -v
** on BSD systems.
*/
- fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
+ if (filename)
+ fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
vfprintf(stderr, string, args);
if (rfilename != NULL)
fprintf(stderr, _(" (rule from \"%s\", line %d)"),
@@ -492,7 +497,7 @@ usage(FILE *stream, int status)
fprintf(stream,
_("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
"\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
- "\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\n"
+ "\t[ -L leapseconds ] [ filename ... ]\n\n"
"Report bugs to %s.\n"),
progname, progname, REPORT_BUGS_TO);
if (status == EXIT_SUCCESS)
@@ -595,7 +600,7 @@ _("%s: More than one -L option specified\n"),
noise = true;
break;
case 's':
- warning(_("-s ignored\n"));
+ warning(_("-s ignored"));
break;
}
if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
@@ -648,36 +653,43 @@ _("%s: More than one -L option specified\n"),
return errors ? EXIT_FAILURE : EXIT_SUCCESS;
}
-static void
+static bool
componentcheck(char const *name, char const *component,
char const *component_end)
{
enum { component_len_max = 14 };
size_t component_len = component_end - component;
if (component_len == 0) {
- fprintf(stderr, _("%s: file name '%s' contains empty component"),
- progname, name);
- exit(EXIT_FAILURE);
+ if (!*name)
+ error (_("empty file name"));
+ else
+ error (_(component == name
+ ? "file name '%s' begins with '/'"
+ : *component_end
+ ? "file name '%s' contains '//'"
+ : "file name '%s' ends with '/'"),
+ name);
+ return false;
}
if (0 < component_len && component_len <= 2
&& component[0] == '.' && component_end[-1] == '.') {
- fprintf(stderr, _("%s: file name '%s' contains"
- " '%.*s' component"),
- progname, name, (int) component_len, component);
- exit(EXIT_FAILURE);
+ error(_("file name '%s' contains '%.*s' component"),
+ name, (int) component_len, component);
+ return false;
}
- if (!noise)
- return;
- if (0 < component_len && component[0] == '-')
- warning(_("file name '%s' component contains leading '-'"),
- name);
- if (component_len_max < component_len)
- warning(_("file name '%s' contains overlength component"
- " '%.*s...'"),
- name, component_len_max, component);
+ if (noise) {
+ if (0 < component_len && component[0] == '-')
+ warning(_("file name '%s' component contains leading '-'"),
+ name);
+ if (component_len_max < component_len)
+ warning(_("file name '%s' contains overlength component"
+ " '%.*s...'"),
+ name, component_len_max, component);
+ }
+ return true;
}
-static void
+static bool
namecheck(const char *name)
{
register char const *cp;
@@ -701,14 +713,14 @@ namecheck(const char *name)
? _("file name '%s' contains byte '%c'")
: _("file name '%s' contains byte '\\%o'")),
name, c);
- return;
}
if (c == '/') {
- componentcheck(name, component, cp);
+ if (!componentcheck(name, component, cp))
+ return false;
component = cp + 1;
}
}
- componentcheck(name, component, cp);
+ return componentcheck(name, component, cp);
}
static char *
@@ -727,13 +739,12 @@ relname(char const *dir, char const *base)
}
static void
-dolink(const char *const fromfield, const char *const tofield)
+dolink(char const *fromfield, char const *tofield)
{
register char * fromname;
register char * toname;
register int fromisdir;
- namecheck(tofield);
fromname = relname(directory, fromfield);
toname = relname(directory, tofield);
/*
@@ -813,8 +824,8 @@ warning(_("hard link failed, symbolic link used"));
#define TIME_T_BITS_IN_FILE 64
-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 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);
/* Estimated time of the Big Bang, in seconds since the POSIX epoch.
rounded downward to the negation of a power of two that is
@@ -848,7 +859,7 @@ static const zic_t big_bang_time = BIG_BANG;
/* Return 1 if NAME is a directory, 0 if it's something else, -1 if trouble. */
static int
-itsdir(const char *const name)
+itsdir(char const *name)
{
struct stat st;
int res = stat(name, &st);
@@ -948,7 +959,7 @@ associate(void)
** Note, though, that if there's no rule,
** a '%s' in the format is a bad thing.
*/
- if (strchr(zp->z_format, '%') != 0)
+ if (zp->z_format_specifier == 's')
error("%s", _("%s in ruleless zone"));
}
}
@@ -1020,9 +1031,9 @@ infile(const char *name)
break;
case LC_LEAP:
if (name != leapsec)
- warning(
-_("%s: Leap line in non leap seconds file %s\n"),
- progname, name);
+ warning(_("%s: Leap line in non leap"
+ " seconds file %s"),
+ progname, name);
else inleap(fields, nfields);
wantcont = false;
break;
@@ -1090,7 +1101,7 @@ warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
}
static void
-inrule(register char **const fields, const int nfields)
+inrule(char **fields, int nfields)
{
static struct rule r;
@@ -1116,7 +1127,7 @@ inrule(register char **const fields, const int nfields)
}
static bool
-inzone(register char **const fields, const int nfields)
+inzone(char **fields, int nfields)
{
register int i;
@@ -1150,7 +1161,7 @@ _("duplicate zone name %s (file \"%s\", line %d)"),
}
static bool
-inzcont(register char **const fields, const int nfields)
+inzcont(char **fields, int nfields)
{
if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
error(_("wrong number of fields on Zone continuation line"));
@@ -1163,6 +1174,7 @@ static bool
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_untilyear, i_untilmonth;
@@ -1178,7 +1190,9 @@ inzsub(char **fields, int nfields, bool iscont)
i_untilday = ZFC_TILDAY;
i_untiltime = ZFC_TILTIME;
z.z_name = NULL;
- } else {
+ } else if (!namecheck(fields[ZF_NAME]))
+ return false;
+ else {
i_gmtoff = ZF_GMTOFF;
i_rule = ZF_RULE;
i_format = ZF_FORMAT;
@@ -1192,13 +1206,21 @@ inzsub(char **fields, int nfields, bool iscont)
z.z_linenum = linenum;
z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
if ((cp = strchr(fields[i_format], '%')) != 0) {
- if (*++cp != 's' || strchr(cp, '%') != 0) {
+ if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
+ || strchr(fields[i_format], '/')) {
error(_("invalid abbreviation format"));
return false;
}
}
z.z_rule = ecpyalloc(fields[i_rule]);
- z.z_format = ecpyalloc(fields[i_format]);
+ z.z_format = cp1 = ecpyalloc(fields[i_format]);
+ z.z_format_specifier = cp ? *cp : '\0';
+ if (z.z_format_specifier == 'z') {
+ if (noise)
+ warning(_("format '%s' not handled by pre-2015 versions of zic"),
+ z.z_format);
+ cp1[cp - fields[i_format]] = 's';
+ }
if (max_format_len < strlen(z.z_format))
max_format_len = strlen(z.z_format);
hasuntil = nfields > i_untilyear;
@@ -1237,7 +1259,7 @@ inzsub(char **fields, int nfields, bool iscont)
}
static void
-inleap(register char ** const fields, const int nfields)
+inleap(char **fields, int nfields)
{
register const char * cp;
register const struct lookup * lp;
@@ -1342,7 +1364,7 @@ inleap(register char ** const fields, const int nfields)
}
static void
-inlink(register char **const fields, const int nfields)
+inlink(char **fields, int nfields)
{
struct link l;
@@ -1354,10 +1376,8 @@ inlink(register char **const fields, const int nfields)
error(_("blank FROM field on Link line"));
return;
}
- if (*fields[LF_TO] == '\0') {
- error(_("blank TO field on Link line"));
- return;
- }
+ if (! namecheck(fields[LF_TO]))
+ return;
l.l_filename = filename;
l.l_linenum = linenum;
l.l_from = ecpyalloc(fields[LF_FROM]);
@@ -1367,13 +1387,9 @@ inlink(register char **const fields, const int nfields)
}
static void
-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)
+rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
+ const char *typep, const char *monthp, const char *dayp,
+ const char *timep)
{
register const struct lookup * lp;
register const char * cp;
@@ -1587,7 +1603,6 @@ writezone(const char *const name, const char *const string, char version)
void *typesptr = ats + timecnt;
unsigned char *types = typesptr;
- namecheck(name);
/*
** Sort.
*/
@@ -1884,19 +1899,59 @@ writezone(const char *const name, const char *const string, char version)
free(fullname);
}
+static char const *
+abbroffset(char *buf, zic_t offset)
+{
+ char sign = '+';
+ int seconds, minutes;
+
+ if (offset < 0) {
+ offset = -offset;
+ sign = '-';
+ }
+
+ seconds = offset % SECSPERMIN;
+ offset /= SECSPERMIN;
+ minutes = offset % MINSPERHOUR;
+ offset /= MINSPERHOUR;
+ if (100 <= offset) {
+ error(_("%%z UTC offset magnitude exceeds 99:59:59"));
+ return "%z";
+ } else {
+ char *p = buf;
+ *p++ = sign;
+ *p++ = '0' + offset / 10;
+ *p++ = '0' + offset % 10;
+ if (minutes | seconds) {
+ *p++ = '0' + minutes / 10;
+ *p++ = '0' + minutes % 10;
+ if (seconds) {
+ *p++ = '0' + seconds / 10;
+ *p++ = '0' + seconds % 10;
+ }
+ }
+ *p = '\0';
+ return buf;
+ }
+}
+
static size_t
-doabbr(char *const abbr, const char *const format, const char *const letters,
+doabbr(char *abbr, struct zone const *zp, char const *letters,
bool isdst, bool doquotes)
{
register char * cp;
register char * slashp;
register size_t len;
+ char const *format = zp->z_format;
slashp = strchr(format, '/');
if (slashp == NULL) {
- if (letters == NULL)
- strcpy(abbr, format);
- else sprintf(abbr, format, letters);
+ char letterbuf[PERCENT_Z_LEN_BOUND + 1];
+ if (zp->z_format_specifier == 'z')
+ letters = abbroffset(letterbuf, -zp->z_gmtoff);
+ else if (!letters)
+ letters = "%s";
+ sprintf(abbr, format, letters);
} else if (isdst) {
strcpy(abbr, slashp + 1);
} else {
@@ -2121,7 +2176,7 @@ stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
return -1;
abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
- len = doabbr(result, zp->z_format, abbrvar, false, true);
+ len = doabbr(result, zp, abbrvar, false, true);
offsetlen = stringoffset(result + len, -zp->z_gmtoff);
if (! offsetlen) {
result[0] = '\0';
@@ -2130,7 +2185,7 @@ stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
len += offsetlen;
if (dstrp == NULL)
return compat;
- len += doabbr(result + len, zp->z_format, dstrp->r_abbrvar, true, true);
+ len += doabbr(result + len, zp, dstrp->r_abbrvar, true, true);
if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
offsetlen = stringoffset(result + len,
-(zp->z_gmtoff + dstrp->r_stdoff));
@@ -2161,7 +2216,7 @@ stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
}
static void
-outzone(const struct zone * const zpfirst, const int zonecount)
+outzone(const struct zone *zpfirst, int zonecount)
{
register const struct zone * zp;
register struct rule * rp;
@@ -2301,8 +2356,7 @@ outzone(const struct zone * const zpfirst, const int zonecount)
startoff = zp->z_gmtoff;
if (zp->z_nrules == 0) {
stdoff = zp->z_stdoff;
- doabbr(startbuf, zp->z_format,
- NULL, stdoff != 0, false);
+ doabbr(startbuf, zp, NULL, stdoff != 0, false);
type = addtype(oadd(zp->z_gmtoff, stdoff),
startbuf, stdoff != 0, startttisstd,
startttisgmt);
@@ -2369,6 +2423,16 @@ outzone(const struct zone * const zpfirst, const int zonecount)
if (k < 0 || jtime < ktime) {
k = j;
ktime = jtime;
+ } else if (jtime == ktime) {
+ char const *dup_rules_msg =
+ _("two rules for same instant");
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ warning("%s", dup_rules_msg);
+ rp = &zp->z_rules[k];
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ error("%s", dup_rules_msg);
}
}
if (k < 0)
@@ -2384,7 +2448,7 @@ outzone(const struct zone * const zpfirst, const int zonecount)
if (ktime < starttime) {
startoff = oadd(zp->z_gmtoff,
stdoff);
- doabbr(startbuf, zp->z_format,
+ doabbr(startbuf, zp,
rp->r_abbrvar,
rp->r_stdoff != 0,
false);
@@ -2394,7 +2458,7 @@ outzone(const struct zone * const zpfirst, const int zonecount)
startoff == oadd(zp->z_gmtoff,
stdoff)) {
doabbr(startbuf,
- zp->z_format,
+ zp,
rp->r_abbrvar,
rp->r_stdoff !=
false,
@@ -2403,7 +2467,7 @@ outzone(const struct zone * const zpfirst, const int zonecount)
}
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
- doabbr(ab, zp->z_format, rp->r_abbrvar,
+ doabbr(ab, zp, rp->r_abbrvar,
rp->r_stdoff != 0, false);
offset = oadd(zp->z_gmtoff, rp->r_stdoff);
type = addtype(offset, ab, rp->r_stdoff != 0,
@@ -2484,7 +2548,7 @@ error(_("can't determine time zone abbreviation to use just after until time"));
}
static void
-addtt(const zic_t starttime, int type)
+addtt(zic_t starttime, int type)
{
if (starttime <= big_bang_time ||
(timecnt == 1 && attypes[0].at < big_bang_time)) {
@@ -2595,7 +2659,7 @@ adjleap(void)
}
static bool
-yearistype(const int year, const char *const type)
+yearistype(int year, const char *type)
{
static char * buf;
int result;
@@ -2693,8 +2757,7 @@ itsabbr(register const char *abbr, register const char *word)
}
static ATTRIBUTE_PURE const struct lookup *
-byword(register const char *const word,
- register const struct lookup *const table)
+byword(const char *word, const struct lookup *table)
{
register const struct lookup * foundlp;
register const struct lookup * lp;
@@ -2766,7 +2829,7 @@ time_overflow(void)
}
static ATTRIBUTE_PURE zic_t
-oadd(const zic_t t1, const zic_t t2)
+oadd(zic_t t1, zic_t t2)
{
if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
time_overflow();
@@ -2774,7 +2837,7 @@ oadd(const zic_t t1, const zic_t t2)
}
static ATTRIBUTE_PURE zic_t
-tadd(const zic_t t1, const zic_t t2)
+tadd(zic_t t1, zic_t t2)
{
if (t1 < 0) {
if (t2 < min_time - t1) {
@@ -2798,7 +2861,7 @@ tadd(const zic_t t1, const zic_t t2)
*/
static zic_t
-rpytime(register const struct rule *const rp, register const zic_t wantedy)
+rpytime(const struct rule *rp, zic_t wantedy)
{
register int m, i;
register zic_t dayoff; /* with a nod to Margaret O. */
@@ -2879,7 +2942,7 @@ will not work with pre-2004 versions of zic"));
}
static void
-newabbr(const char *const string)
+newabbr(const char *string)
{
register int i;
@@ -2887,27 +2950,15 @@ newabbr(const char *const string)
register const char * cp;
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;
mp = NULL;
- while (is_alpha(*cp))
+ while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
+ || *cp == '-' || *cp == '+')
++cp;
- if (cp - string == 0)
-mp = _("time zone abbreviation lacks alphabetic at start");
if (noise && cp - string < 3)
-mp = _("time zone abbreviation has fewer than 3 alphabetics");
+ mp = _("time zone abbreviation has fewer than 3 characters");
if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
-mp = _("time zone abbreviation has too many alphabetics");
- if (mp == NULL && (*cp == '+' || *cp == '-')) {
- ++cp;
- if (is_digit(*cp))
- if (*cp++ == '1' &&
- *cp >= '0' && *cp <= '4')
- ++cp;
- }
+ mp = _("time zone abbreviation has too many characters");
if (*cp != '\0')
mp = _("time zone abbreviation differs from POSIX standard");
if (mp != NULL)
@@ -2952,7 +3003,7 @@ mkdirs(char *argname)
if (itsdir(name) <= 0) {
char const *e = strerror(err);
warning(_("%s: Can't create directory"
- " %s: %s\n"),
+ " %s: %s"),
progname, name, e);
free(name);
return false;