diff options
Diffstat (limited to 'elsie.nci.nih.gov/src/zic.c')
-rw-r--r-- | elsie.nci.nih.gov/src/zic.c | 232 |
1 files changed, 141 insertions, 91 deletions
diff --git a/elsie.nci.nih.gov/src/zic.c b/elsie.nci.nih.gov/src/zic.c index 5d0501d..636649b 100644 --- a/elsie.nci.nih.gov/src/zic.c +++ b/elsie.nci.nih.gov/src/zic.c @@ -31,8 +31,6 @@ typedef int_fast64_t zic_t; #define MKDIR_UMASK 0755 #endif -#define end(cp) (strchr((cp), '\0')) - struct rule { const char * r_filename; int r_linenum; @@ -368,18 +366,40 @@ size_product(size_t nitems, size_t itemsize) return nitems * itemsize; } +#if !HAVE_STRDUP +static char * +strdup(char const *str) +{ + char *result = malloc(strlen(str) + 1); + return result ? strcpy(result, str) : result; +} +#endif + static ATTRIBUTE_PURE void * -memcheck(void *const ptr) +memcheck(void *ptr) { if (ptr == NULL) memory_exhausted(strerror(errno)); return ptr; } -#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 * +emalloc(size_t size) +{ + return memcheck(malloc(size)); +} + +static void * +erealloc(void *ptr, size_t size) +{ + return memcheck(realloc(ptr, size)); +} + +static char * +ecpyalloc (char const *str) +{ + return memcheck(strdup(str)); +} static void * growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc) @@ -634,6 +654,11 @@ componentcheck(char const *name, char const *component, { 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 (0 < component_len && component_len <= 2 && component[0] == '.' && component_end[-1] == '.') { fprintf(stderr, _("%s: file name '%s' contains" @@ -686,6 +711,21 @@ namecheck(const char *name) componentcheck(name, component, cp); } +static char * +relname(char const *dir, char const *base) +{ + if (*base == '/') + return ecpyalloc(base); + else { + size_t dir_len = strlen(dir); + bool needs_slash = dir_len && dir[dir_len - 1] != '/'; + char *result = emalloc(dir_len + needs_slash + strlen(base) + 1); + result[dir_len] = '/'; + strcpy(result + dir_len + needs_slash, base); + return memcpy(result, dir, dir_len); + } +} + static void dolink(const char *const fromfield, const char *const tofield) { @@ -694,20 +734,8 @@ dolink(const char *const fromfield, const char *const tofield) register int fromisdir; namecheck(tofield); - if (fromfield[0] == '/') - fromname = ecpyalloc(fromfield); - else { - fromname = ecpyalloc(directory); - fromname = ecatalloc(fromname, "/"); - fromname = ecatalloc(fromname, fromfield); - } - if (tofield[0] == '/') - toname = ecpyalloc(tofield); - else { - toname = ecpyalloc(directory); - toname = ecatalloc(toname, "/"); - toname = ecatalloc(toname, tofield); - } + fromname = relname(directory, fromfield); + toname = relname(directory, tofield); /* ** We get to be careful here since ** there's a fair chance of root running us. @@ -731,6 +759,8 @@ dolink(const char *const fromfield, const char *const tofield) if (result != 0) { const char *s = fromfield; const char *t; + char *p; + size_t dotdots = 0; register char * symlinkcontents = NULL; do @@ -739,13 +769,13 @@ dolink(const char *const fromfield, const char *const tofield) && ! strncmp (fromfield, tofield, ++s - fromfield)); - for (s = tofield + (t - fromfield); - (s = strchr(s, '/')); - s++) - symlinkcontents = - ecatalloc(symlinkcontents, - "../"); - symlinkcontents = ecatalloc(symlinkcontents, t); + for (s = tofield + (t - fromfield); *s; s++) + dotdots += *s == '/'; + symlinkcontents + = emalloc(3 * dotdots + strlen(t) + 1); + for (p = symlinkcontents; dotdots-- != 0; p += 3) + memcpy(p, "../", 3); + strcpy(p, t); result = symlink(symlinkcontents, toname); if (result == 0) warning(_("hard link failed, symbolic link used")); @@ -828,7 +858,7 @@ itsdir(const char *const name) return S_ISDIR(st.st_mode) != 0; #else { - char *nameslashdot = ecatalloc(ecpyalloc(name), "/."); + char *nameslashdot = relname(name, "."); res = stat(nameslashdot, &st); free(nameslashdot); return res == 0; @@ -1023,6 +1053,7 @@ gethms(char const *string, char const *errstring, bool signable) { zic_t hh; int mm, ss, sign; + char xs; if (string == NULL || *string == '\0') return 0; @@ -1032,12 +1063,12 @@ gethms(char const *string, char const *errstring, bool signable) sign = -1; ++string; } else sign = 1; - if (sscanf(string, scheck(string, "%"SCNdZIC), &hh) == 1) + if (sscanf(string, "%"SCNdZIC"%c", &hh, &xs) == 1) mm = ss = 0; - else if (sscanf(string, scheck(string, "%"SCNdZIC":%d"), &hh, &mm) == 2) + else if (sscanf(string, "%"SCNdZIC":%d%c", &hh, &mm, &xs) == 2) ss = 0; - else if (sscanf(string, scheck(string, "%"SCNdZIC":%d:%d"), - &hh, &mm, &ss) != 3) { + else if (sscanf(string, "%"SCNdZIC":%d:%d%c", &hh, &mm, &ss, &xs) + != 3) { error("%s", errstring); return 0; } @@ -1215,6 +1246,7 @@ inleap(register char ** const fields, const int nfields) int month, day; zic_t dayoff, tod; zic_t t; + char xs; if (nfields != LEAP_FIELDS) { error(_("wrong number of fields on Leap line")); @@ -1222,7 +1254,7 @@ inleap(register char ** const fields, const int nfields) } dayoff = 0; cp = fields[LP_YEAR]; - if (sscanf(cp, scheck(cp, "%"SCNdZIC), &year) != 1) { + if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) { /* ** Leapin' Lizards! */ @@ -1257,7 +1289,7 @@ inleap(register char ** const fields, const int nfields) ++j; } cp = fields[LP_DAY]; - if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || + if (sscanf(cp, "%d%c", &day, &xs) != 1 || day <= 0 || day > len_months[isleap(year)][month]) { error(_("invalid day of month")); return; @@ -1347,6 +1379,7 @@ rulesub(register struct rule *const rp, register const char * cp; register char * dp; register char * ep; + char xs; if ((lp = byword(monthp, mon_names)) == NULL) { error(_("invalid month name")); @@ -1398,7 +1431,7 @@ rulesub(register struct rule *const rp, _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); exit(EXIT_FAILURE); - } else if (sscanf(cp, scheck(cp, "%"SCNdZIC), &rp->r_loyear) != 1) { + } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) { error(_("invalid starting year")); return; } @@ -1420,7 +1453,7 @@ rulesub(register struct rule *const rp, _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); exit(EXIT_FAILURE); - } else if (sscanf(cp, scheck(cp, "%"SCNdZIC), &rp->r_hiyear) != 1) { + } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) { error(_("invalid ending year")); return; } @@ -1473,7 +1506,7 @@ rulesub(register struct rule *const rp, } rp->r_wday = lp->l_value; } - if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || + if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 || rp->r_dayofmonth <= 0 || (rp->r_dayofmonth > len_months[1][rp->r_month])) { error(_("invalid day of month")); @@ -1547,7 +1580,7 @@ writezone(const char *const name, const char *const string, char version) register int leapcnt32, leapi32; register int timecnt32, timei32; register int pass; - static char * fullname; + char * fullname; static const struct tzhead tzh0; static struct tzhead tzh; zic_t *ats = emalloc(size_product(timecnt, sizeof *ats + 1)); @@ -1633,9 +1666,7 @@ writezone(const char *const name, const char *const string, char version) --leapcnt32; ++leapi32; } - fullname = erealloc(fullname, - strlen(directory) + 1 + strlen(name) + 1); - sprintf(fullname, "%s/%s", directory, name); + fullname = relname(directory, name); /* ** Remove old file, if any, to snap links. */ @@ -1850,15 +1881,16 @@ writezone(const char *const name, const char *const string, char version) fprintf(fp, "\n%s\n", string); close_file(fp, fullname); free(ats); + free(fullname); } -static void +static size_t doabbr(char *const abbr, const char *const format, const char *const letters, bool isdst, bool doquotes) { register char * cp; register char * slashp; - register int len; + register size_t len; slashp = strchr(format, '/'); if (slashp == NULL) { @@ -1871,18 +1903,18 @@ doabbr(char *const abbr, const char *const format, const char *const letters, memcpy(abbr, format, slashp - format); abbr[slashp - format] = '\0'; } + len = strlen(abbr); if (!doquotes) - return; + return len; for (cp = abbr; is_alpha(*cp); cp++) continue; - len = strlen(abbr); if (len > 0 && *cp == '\0') - return; + return len; abbr[len + 2] = '\0'; abbr[len + 1] = '>'; - for ( ; len > 0; --len) - abbr[len] = abbr[len - 1]; + memmove(abbr + 1, abbr, len); abbr[0] = '<'; + return len + 2; } static void @@ -1894,17 +1926,18 @@ updateminmax(const zic_t x) max_year = x; } -static bool +static int stringoffset(char *result, zic_t offset) { register int hours; register int minutes; register int seconds; + bool negative = offset < 0; + int len = negative; - result[0] = '\0'; - if (offset < 0) { - strcpy(result, "-"); + if (negative) { offset = -offset; + result[0] = '-'; } seconds = offset % SECSPERMIN; offset /= SECSPERMIN; @@ -1913,15 +1946,15 @@ stringoffset(char *result, zic_t offset) hours = offset; if (hours >= HOURSPERDAY * DAYSPERWEEK) { result[0] = '\0'; - return false; + return 0; } - sprintf(end(result), "%d", hours); + len += sprintf(result + len, "%d", hours); if (minutes != 0 || seconds != 0) { - sprintf(end(result), ":%02d", minutes); + len += sprintf(result + len, ":%02d", minutes); if (seconds != 0) - sprintf(end(result), ":%02d", seconds); + len += sprintf(result + len, ":%02d", seconds); } - return true; + return len; } static int @@ -1931,7 +1964,6 @@ stringrule(char *result, const struct rule *const rp, const zic_t dstoff, register zic_t tod = rp->r_tod; register int compat = 0; - result = end(result); if (rp->r_dycode == DC_DOM) { register int month, total; @@ -1942,9 +1974,9 @@ stringrule(char *result, const struct rule *const rp, const zic_t dstoff, total += len_months[0][month]; /* Omit the "J" in Jan and Feb, as that's shorter. */ if (rp->r_month <= 1) - sprintf(result, "%d", total + rp->r_dayofmonth - 1); + result += sprintf(result, "%d", total + rp->r_dayofmonth - 1); else - sprintf(result, "J%d", total + rp->r_dayofmonth); + result += sprintf(result, "J%d", total + rp->r_dayofmonth); } else { register int week; register int wday = rp->r_wday; @@ -1971,16 +2003,16 @@ stringrule(char *result, const struct rule *const rp, const zic_t dstoff, } else return -1; /* "cannot happen" */ if (wday < 0) wday += DAYSPERWEEK; - sprintf(result, "M%d.%d.%d", - rp->r_month + 1, week, wday); + result += sprintf(result, "M%d.%d.%d", + rp->r_month + 1, week, wday); } if (rp->r_todisgmt) tod += gmtoff; if (rp->r_todisstd && rp->r_stdoff == 0) tod += dstoff; if (tod != 2 * SECSPERMIN * MINSPERHOUR) { - strcat(result, "/"); - if (! stringoffset(end(result), tod)) + *result++ = '/'; + if (! stringoffset(result, tod)) return -1; if (tod < 0) { if (compat < 2013) @@ -2020,6 +2052,8 @@ stringzone(char *result, const struct zone *const zpfirst, const int zonecount) register const char * abbrvar; register int compat = 0; register int c; + size_t len; + int offsetlen; struct rule stdr, dstr; result[0] = '\0'; @@ -2087,30 +2121,36 @@ 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; - doabbr(result, zp->z_format, abbrvar, false, true); - if (! stringoffset(end(result), -zp->z_gmtoff)) { + len = doabbr(result, zp->z_format, abbrvar, false, true); + offsetlen = stringoffset(result + len, -zp->z_gmtoff); + if (! offsetlen) { result[0] = '\0'; return -1; } + len += offsetlen; if (dstrp == NULL) 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))) { - result[0] = '\0'; - return -1; - } - strcat(result, ","); - c = stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff); + len += doabbr(result + len, zp->z_format, dstrp->r_abbrvar, true, true); + if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) { + offsetlen = stringoffset(result + len, + -(zp->z_gmtoff + dstrp->r_stdoff)); + if (! offsetlen) { + result[0] = '\0'; + return -1; + } + len += offsetlen; + } + result[len++] = ','; + c = stringrule(result + len, dstrp, dstrp->r_stdoff, zp->z_gmtoff); if (c < 0) { result[0] = '\0'; return -1; } if (compat < c) compat = c; - strcat(result, ","); - c = stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff); + len += strlen(result + len); + result[len++] = ','; + c = stringrule(result + len, stdrp, dstrp->r_stdoff, zp->z_gmtoff); if (c < 0) { result[0] = '\0'; return -1; @@ -2718,28 +2758,38 @@ getfields(register char *cp) return array; } +static _Noreturn void +time_overflow(void) +{ + error(_("time overflow")); + exit(EXIT_FAILURE); +} + static ATTRIBUTE_PURE zic_t oadd(const zic_t t1, const zic_t t2) { - if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) { - error(_("time overflow")); - exit(EXIT_FAILURE); - } + if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) + time_overflow(); return t1 + t2; } static ATTRIBUTE_PURE zic_t tadd(const zic_t t1, const zic_t t2) { - if (t1 == max_time && t2 > 0) - return max_time; - if (t1 == min_time && t2 < 0) - return min_time; - if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) { - error(_("time overflow")); - exit(EXIT_FAILURE); - } - return t1 + t2; + if (t1 < 0) { + if (t2 < min_time - t1) { + if (t1 != min_time) + time_overflow(); + return min_time; + } + } else { + if (max_time - t1 < t2) { + if (t1 != max_time) + time_overflow(); + return max_time; + } + } + return t1 + t2; } /* |