Module Name: src Committed By: christos Date: Tue Apr 28 17:00:24 UTC 2015
Modified Files: src/lib/libc/time: Makefile NEWS private.h tz-link.htm zic.c Removed Files: src/lib/libc/time: ialloc.c scheck.c Log Message: welcome to tzcode 2015d (zic performance improvements and cleanups) To generate a diff of this commit: cvs rdiff -u -r1.27 -r1.28 src/lib/libc/time/Makefile cvs rdiff -u -r1.10 -r1.11 src/lib/libc/time/NEWS cvs rdiff -u -r1.9 -r0 src/lib/libc/time/ialloc.c cvs rdiff -u -r1.39 -r1.40 src/lib/libc/time/private.h cvs rdiff -u -r1.12 -r0 src/lib/libc/time/scheck.c cvs rdiff -u -r1.21 -r1.22 src/lib/libc/time/tz-link.htm cvs rdiff -u -r1.52 -r1.53 src/lib/libc/time/zic.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/time/Makefile diff -u src/lib/libc/time/Makefile:1.27 src/lib/libc/time/Makefile:1.28 --- src/lib/libc/time/Makefile:1.27 Tue Mar 24 16:01:18 2015 +++ src/lib/libc/time/Makefile Tue Apr 28 13:00:24 2015 @@ -5,7 +5,7 @@ PACKAGE= tzcode # Version numbers of the code and data distributions. -VERSION= 2015b +VERSION= 2015d # Email address for bug reports. BUGEMAIL= t...@iana.org @@ -120,6 +120,7 @@ LDLIBS= # -DHAVE_STDINT_H=1 if you have a pre-C99 compiler with "stdint.h" # -DHAVE_STRFTIME_L=1 if <time.h> declares locale_t and strftime_l # This defaults to 0 if _POSIX_VERSION < 200809, 1 otherwise. +# -DHAVE_STRDUP=0 if your system lacks the strdup function # -DHAVE_SYMLINK=0 if your system lacks the symlink function # -DHAVE_SYS_STAT_H=0 if your compiler lacks a "sys/stat.h" # -DHAVE_SYS_WAIT_H=0 if your compiler lacks a "sys/wait.h" @@ -150,18 +151,18 @@ LDLIBS= # $(GCC_DEBUG_FLAGS) if you are using GCC and want lots of checking GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-common -fstrict-aliasing \ -Wall -Wextra \ - -Wbad-function-cast -Wcast-align -Wcast-qual \ + -Wbad-function-cast -Wcast-align -Wdate-time \ -Wdeclaration-after-statement \ + -Wdouble-promotion \ -Wformat=2 -Winit-self -Wjump-misses-init \ - -Wmissing-declarations -Wmissing-noreturn -Wmissing-prototypes \ - -Wnested-externs -Wno-address -Wno-cast-qual \ - -Wno-format-nonliteral -Wno-sign-compare -Wno-sign-conversion \ - -Wno-type-limits \ - -Wno-unused-parameter -Woverlength-strings -Wpointer-arith \ + -Wlogical-op -Wmissing-prototypes -Wnested-externs \ + -Wold-style-definition -Woverlength-strings -Wpointer-arith \ -Wshadow -Wstrict-prototypes -Wsuggest-attribute=const \ -Wsuggest-attribute=format -Wsuggest-attribute=noreturn \ -Wsuggest-attribute=pure -Wtrampolines \ - -Wwrite-strings + -Wunused -Wwrite-strings \ + -Wno-address -Wno-format-nonliteral -Wno-sign-compare \ + -Wno-type-limits -Wno-unused-parameter # # If you want to use System V compatibility code, add # -DUSG_COMPAT @@ -331,13 +332,13 @@ AR= ar # ':' on typical hosts; 'ranlib' on the ancient hosts that still need ranlib. RANLIB= : -TZCOBJS= zic.o scheck.o ialloc.o +TZCOBJS= zic.o TZDOBJS= zdump.o localtime.o asctime.o DATEOBJS= date.o localtime.o strftime.o asctime.o LIBSRCS= localtime.c asctime.c difftime.c LIBOBJS= localtime.o asctime.o difftime.o HEADERS= tzfile.h private.h -NONLIBSRCS= zic.c zdump.c scheck.c ialloc.c +NONLIBSRCS= zic.c zdump.c NEWUCBSRCS= date.c strftime.c SOURCES= $(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) \ tzselect.ksh workman.sh @@ -655,9 +656,7 @@ zonenames: $(TDATA) asctime.o: private.h tzfile.h date.o: private.h difftime.o: private.h -ialloc.o: private.h localtime.o: private.h tzfile.h -scheck.o: private.h strftime.o: private.h tzfile.h zdump.o: version.h zic.o: private.h tzfile.h version.h Index: src/lib/libc/time/NEWS diff -u src/lib/libc/time/NEWS:1.10 src/lib/libc/time/NEWS:1.11 --- src/lib/libc/time/NEWS:1.10 Tue Mar 24 16:01:18 2015 +++ src/lib/libc/time/NEWS Tue Apr 28 13:00:24 2015 @@ -1,5 +1,79 @@ News for the tz database +Release 2015d - 2015-04-24 08:09:46 -0700 + + Changes affecting future time stamps + + Egypt will not observe DST in 2015 and will consider canceling it + permanently. For now, assume no DST indefinitely. + (Thanks to Ahmed Nazmy and Tim Parenti.) + + Changes affecting past time stamps + + America/Whitehorse switched from UTC-9 to UTC-8 on 1967-05-28, not + 1966-07-01. Also, Yukon's time zone history is documented better. + (Thanks to Brian Inglis and Dennis Ferguson.) + + Change affecting past and future time zone abbreviations + + The abbreviations for Hawaii-Aleutian standard and daylight times + have been changed from HAST/HADT to HST/HDT, as per US Government + Printing Office style. This affects only America/Adak since 1983, + as America/Honolulu was already using the new style. + + Changes affecting code + + zic has some minor performance improvements. + + +Release 2015c - 2015-04-11 08:55:55 -0700 + + Changes affecting future time stamps + + Egypt's spring-forward transition is at 24:00 on April's last Thursday, + not 00:00 on April's last Friday. 2015's transition will therefore be on + Thursday, April 30 at 24:00, not Friday, April 24 at 00:00. Similar fixes + apply to 2026, 2037, 2043, etc. (Thanks to Steffen Thorsen.) + + Changes affecting past time stamps + + The following changes affect some pre-1991 Chile-related time stamps + in America/Santiago, Antarctica/Palmer, and Pacific/Easter. + + The 1910 transition was January 10, not January 1. + + The 1918 transition was September 10, not September 1. + + The UTC-4 time observed from 1932 to 1942 is now considered to be + standard time, not year-round DST. + + Santiago observed DST (UTC-3) from 1946-07-15 through 1946-08-31, + then reverted to standard time, then switched its time zone to + UTC-5 on 1947-04-01. + + Assume transitions before 1968 were at 00:00, since we have no data + saying otherwise. + + The spring 1988 transition was 1988-10-09, not 1988-10-02. + The fall 1990 transition was 1990-03-11, not 1990-03-18. + + Assume no UTC offset change for Pacific/Easter on 1890-01-01, + and omit all transitions on Pacific/Easter from 1942 through 1946 + since we have no data suggesting that they existed. + + One more zone has been turned into a link, as it differed + from an existing zone only for older time stamps. As usual, + this change affects UTC offsets in pre-1970 time stamps only. + The zone's old contents have been moved to the 'backzone' file. + The affected zone is America/Montreal. + + Changes affecting commentary + + Mention the TZUpdater tool. + + Mention "The Time Now". (Thanks to Brandon Ramsey.) + + Release 2015b - 2015-03-19 23:28:11 -0700 Changes affecting future time stamps Index: src/lib/libc/time/private.h diff -u src/lib/libc/time/private.h:1.39 src/lib/libc/time/private.h:1.40 --- src/lib/libc/time/private.h:1.39 Tue Mar 24 16:01:18 2015 +++ src/lib/libc/time/private.h Tue Apr 28 13:00:24 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: private.h,v 1.39 2015/03/24 20:01:18 christos Exp $ */ +/* $NetBSD: private.h,v 1.40 2015/04/28 17:00:24 christos Exp $ */ #ifndef PRIVATE_H #define PRIVATE_H @@ -54,6 +54,10 @@ #define HAVE_SETTIMEOFDAY 3 #endif /* !defined HAVE_SETTIMEOFDAY */ +#ifndef HAVE_STRDUP +#define HAVE_STRDUP 1 +#endif + #ifndef HAVE_SYMLINK #define HAVE_SYMLINK 1 #endif /* !defined HAVE_SYMLINK */ @@ -467,14 +471,6 @@ time_t time2posix_z(timezone_t __restric #endif /* -** Private function declarations. -*/ - -char * icatalloc(char * old, const char * new); -char * icpyalloc(const char * string); -const char * scheck(const char * string, const char * format); - -/* ** Finally, some convenience items. */ Index: src/lib/libc/time/tz-link.htm diff -u src/lib/libc/time/tz-link.htm:1.21 src/lib/libc/time/tz-link.htm:1.22 --- src/lib/libc/time/tz-link.htm:1.21 Sat Jan 31 13:55:17 2015 +++ src/lib/libc/time/tz-link.htm Tue Apr 28 13:00:24 2015 @@ -8,7 +8,7 @@ <meta http-equiv="Content-type" content='text/html; charset="UTF-8"'> <meta name="DC.Creator" content="Eggert, Paul"> <meta name="DC.Contributor" content="Olson, Arthur David"> -<meta name="DC.Date" content="2015-01-29"> +<meta name="DC.Date" content="2015-03-25"> <meta name="DC.Description" content="Sources of information about time zones and daylight saving time"> <meta name="DC.Identifier" @@ -194,6 +194,7 @@ multiple time zones.</li> <li><a href="http://www.zeitverschiebung.net/en/">Time Difference</a> calculates the current time difference between locations.</li> <li><a href="http://www.wx-now.com">Weather Now</a> lists the weather too.</li> +<li><a href="http://www.thetimenow.com">The Time Now</a> also lists weather.</li> <li><a href="http://worldtime.io">worldtime.io</a> also contains data about time zone boundaries; it supports queries via place names and shows location maps.</li> @@ -282,6 +283,10 @@ and from <abbr title="Common Locale Data into an <abbr>ICU</abbr>-specific format. <abbr>ICU</abbr> is freely available under a <abbr>BSD</abbr>-style license.</li> +<li>The <a +href="http://www.oracle.com/technetwork/java/javase/tzupdater-readme-136440.html">TZUpdater +tool</a> compiles <code><abbr>tz</abbr></code> source into the format used by +Oracle Java.</li> <li><a href="http://www.joda.org/joda-time/">Joda-Time – Java date and time <abbr title="Application Program Interface">API</abbr></a> contains a class Index: src/lib/libc/time/zic.c diff -u src/lib/libc/time/zic.c:1.52 src/lib/libc/time/zic.c:1.53 --- src/lib/libc/time/zic.c:1.52 Tue Oct 7 18:14:46 2014 +++ src/lib/libc/time/zic.c Tue Apr 28 13:00:24 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: zic.c,v 1.52 2014/10/07 22:14:46 christos Exp $ */ +/* $NetBSD: zic.c,v 1.53 2015/04/28 17:00:24 christos Exp $ */ /* ** This file is in the public domain, so clarified as of ** 2006-07-17 by Arthur David Olson. @@ -10,7 +10,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: zic.c,v 1.52 2014/10/07 22:14:46 christos Exp $"); +__RCSID("$NetBSD: zic.c,v 1.53 2015/04/28 17:00:24 christos Exp $"); #endif /* !defined lint */ #include "private.h" @@ -41,8 +41,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; @@ -381,18 +379,40 @@ size_product(size_t nitems, size_t items 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 * +zic_malloc(size_t size) +{ + return memcheck(malloc(size)); +} + +static void * +zic_realloc(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) @@ -404,7 +424,7 @@ growalloc(void *ptr, size_t itemsize, in if ((amax - 1) / 3 * 2 < *nitems_alloc) memory_exhausted(_("int overflow")); *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1; - return erealloc(ptr, size_product(*nitems_alloc, itemsize)); + return zic_realloc(ptr, size_product(*nitems_alloc, itemsize)); } } @@ -647,6 +667,11 @@ componentcheck(char const *name, char co { 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" @@ -699,6 +724,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 = zic_malloc(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) { @@ -707,20 +747,8 @@ dolink(const char *const fromfield, cons 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. @@ -744,6 +772,8 @@ dolink(const char *const fromfield, cons if (result != 0) { const char *s = fromfield; const char *t; + char *p; + size_t dotdots = 0; char * symlinkcontents = NULL; do @@ -752,16 +782,16 @@ dolink(const char *const fromfield, cons && ! 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 + = zic_malloc(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")); + warning(_("hard link failed, symbolic link used")); free(symlinkcontents); } if (result != 0) { @@ -841,7 +871,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; @@ -1036,6 +1066,7 @@ gethms(char const *string, char const *e { zic_t hh; int mm, ss, sign; + char xs; if (string == NULL || *string == '\0') return 0; @@ -1045,12 +1076,12 @@ gethms(char const *string, char const *e 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; } @@ -1228,6 +1259,7 @@ inleap(char **const fields, const int nf int month, day; zic_t dayoff, tod; zic_t t; + char xs; if (nfields != LEAP_FIELDS) { error(_("wrong number of fields on Leap line")); @@ -1235,7 +1267,7 @@ inleap(char **const fields, const int nf } dayoff = 0; cp = fields[LP_YEAR]; - if (sscanf(cp, scheck(cp, "%"SCNdZIC), &year) != 1) { + if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) { /* ** Leapin' Lizards! */ @@ -1270,7 +1302,7 @@ inleap(char **const fields, const int nf ++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; @@ -1356,6 +1388,7 @@ rulesub(struct rule *const rp, const cha const char * cp; char * dp; char * ep; + char xs; if ((lp = byword(monthp, mon_names)) == NULL) { error(_("invalid month name")); @@ -1407,7 +1440,7 @@ rulesub(struct rule *const rp, const cha _("%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; } @@ -1429,7 +1462,7 @@ rulesub(struct rule *const rp, const cha _("%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; } @@ -1482,7 +1515,7 @@ rulesub(struct rule *const rp, const cha } 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")); @@ -1556,10 +1589,10 @@ writezone(const char *const name, const int leapcnt32, leapi32; int timecnt32, timei32; 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)); + zic_t *ats = zic_malloc(size_product(timecnt, sizeof *ats + 1)); void *typesptr = ats + timecnt; unsigned char *types = typesptr; @@ -1643,9 +1676,7 @@ writezone(const char *const name, const --leapcnt32; ++leapi32; } - fullname = erealloc(fullname, - strlen(directory) + 1 + strlen(name) + 1); - (void) sprintf(fullname, "%s/%s", directory, name); /* XXX: sprintf is safe */ + fullname = relname(directory, name); /* ** Remove old file, if any, to snap links. */ @@ -1864,15 +1895,16 @@ writezone(const char *const name, const (void) fprintf(fp, "\n%s\n", string); close_file(fp, fullname); free(ats); + free(fullname); } -static void +static size_t doabbr(char *const abbr, const int abbrlen, const char *const format, const char *const letters, bool isdst, bool doquotes) { char * cp; char * slashp; - int len; + size_t len; slashp = strchr(format, '/'); if (slashp == NULL) { @@ -1885,18 +1917,18 @@ doabbr(char *const abbr, const int abbrl (void) 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 @@ -1908,17 +1940,18 @@ updateminmax(const zic_t x) max_year = x; } -static bool +static int stringoffset(char *result, zic_t offset) { int hours; int minutes; 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; @@ -1927,15 +1960,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 @@ -1945,7 +1978,6 @@ stringrule(char *result, const struct ru zic_t tod = rp->r_tod; int compat = 0; - result = end(result); if (rp->r_dycode == DC_DOM) { int month, total; @@ -1956,9 +1988,9 @@ stringrule(char *result, const struct ru 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 { int week; int wday = rp->r_wday; @@ -1985,16 +2017,16 @@ stringrule(char *result, const struct ru } 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) @@ -2035,6 +2067,8 @@ stringzone(char *result, const int resul const char * abbrvar; int compat = 0; int c; + size_t len; + int offsetlen; struct rule stdr, dstr; result[0] = '\0'; @@ -2102,31 +2136,37 @@ stringzone(char *result, const int resul if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0)) return -1; abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; - doabbr(result, resultlen, zp->z_format, abbrvar, false, true); - if (! stringoffset(end(result), -zp->z_gmtoff)) { + len = doabbr(result, resultlen, 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), resultlen - strlen(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))) { + len += doabbr(result + len, resultlen - 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; } - (void) strcat(result, ","); - c = stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff); + 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; @@ -2163,9 +2203,9 @@ outzone(const struct zone *const zpfirst max_abbr_len = 2 + max_format_len + max_abbrvar_len; max_envvar_len = 2 * max_abbr_len + 5 * 9; - startbuf = emalloc(max_abbr_len + 1); - ab = emalloc(max_abbr_len + 1); - envvar = emalloc(max_envvar_len + 1); + startbuf = zic_malloc(max_abbr_len + 1); + ab = zic_malloc(max_abbr_len + 1); + envvar = zic_malloc(max_envvar_len + 1); INITIALIZE(untiltime); INITIALIZE(starttime); /* @@ -2582,7 +2622,7 @@ yearistype(const int year, const char *c if (type == NULL || *type == '\0') return true; - buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type)); + buf = zic_realloc(buf, 132 + strlen(yitcommand) + strlen(type)); (void)sprintf(buf, "%s %d %s", yitcommand, year, type); /* XXX: sprintf is safe */ result = system(buf); if (WIFEXITED(result)) switch (WEXITSTATUS(result)) { @@ -2708,7 +2748,7 @@ getfields(char *cp) if (cp == NULL) return NULL; - array = emalloc(size_product(strlen(cp) + 1, sizeof *array)); + array = zic_malloc(size_product(strlen(cp) + 1, sizeof *array)); nsubs = 0; for ( ; ; ) { while (is_space(*cp)) @@ -2737,26 +2777,36 @@ getfields(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); + 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; }