diff options
Diffstat (limited to 'elsie.nci.nih.gov/src/zic.c')
-rw-r--r-- | elsie.nci.nih.gov/src/zic.c | 233 |
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; |