[PROPOSED PATCH 1/3] Remove need for ialloc.c
One of its functions, icpyalloc, duplicates the now-standard function strdup, and we might as well use the standard function. Its other function, icatalloc, is used only in O(N**2) algorithms that can be rewritten to be O(N). * Makefile: Mention HAVE_STRDUP in commentary. (TZCOBJS): Remove ialloc.o. (NONLIBSRCS): Remove ialloc.c. (ialloc.o): Remove. * ialloc.c: Remove. * private.h (HAVE_STRDUP): New macro, defaulting to 1. (icatalloc, icpyalloc): Remove decls. * zic.c (end): Remove. (strdup) [!HAVE_STRDUP]: New function. (memcheck): Arg is no longer a const pointer, since the result isn't. (emalloc, erealloc, ecpyalloc): Now functions, not macros. (ecpyalloc): Use strdup, not icpyalloc. (ecatalloc): Remove. All callers changed. (componentcheck): Check that file name components are nonempty; otherwise, relname might return nonsense. (relname): New function. (dolink, itsdir, writezone): Use it. (dolink, stringrule, stringzone): Rewrite to avoid O(N**2) algorithm involving 'strcat' and 'end'. (writezone): Use local, not static, to store fullname, and free it before returning. (doabbr, stringoffset): Return strlen of result. --- Makefile | 6 +-- ialloc.c | 32 ------------ private.h | 6 ++- zic.c | 175 +++++++++++++++++++++++++++++++++++++------------------------- 4 files changed, 113 insertions(+), 106 deletions(-) delete mode 100644 ialloc.c diff --git a/Makefile b/Makefile index 9a571e5..af52b36 100644 --- a/Makefile +++ b/Makefile @@ -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" @@ -330,13 +331,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 scheck.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 scheck.c NEWUCBSRCS= date.c strftime.c SOURCES= $(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) \ tzselect.ksh workman.sh @@ -654,7 +655,6 @@ 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 diff --git a/ialloc.c b/ialloc.c deleted file mode 100644 index e228db5..0000000 --- a/ialloc.c +++ /dev/null @@ -1,32 +0,0 @@ -/* -** This file is in the public domain, so clarified as of -** 2006-07-17 by Arthur David Olson. -*/ - -/*LINTLIBRARY*/ - -#include "private.h" - -char * -icatalloc(char *const old, const char *const new) -{ - register char * result; - register int oldsize, newsize; - - newsize = (new == NULL) ? 0 : strlen(new); - if (old == NULL) - oldsize = 0; - else if (newsize == 0) - return old; - else oldsize = strlen(old); - if ((result = realloc(old, oldsize + newsize + 1)) != NULL) - if (new != NULL) - strcpy(result + oldsize, new); - return result; -} - -char * -icpyalloc(const char *const string) -{ - return icatalloc(NULL, string); -} diff --git a/private.h b/private.h index de9c13e..05316a1 100644 --- a/private.h +++ b/private.h @@ -42,6 +42,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 */ @@ -452,8 +456,6 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE; ** Private function declarations. */ -char * icatalloc(char * old, const char * new); -char * icpyalloc(const char * string); const char * scheck(const char * string, const char * format); /* diff --git a/zic.c b/zic.c index 5d0501d..b28d5c3 100644 --- a/zic.c +++ b/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; @@ -1547,7 +1577,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 +1663,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 +1878,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 +1900,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 +1923,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 +1943,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 +1961,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 +1971,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 +2000,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 +2049,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 +2118,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; -- 2.1.0
Its function 'scheck' can be done more efficiently inline. * Makefile (TZCOBJS): Remove scheck.o. (NONLIBSRCS): Remove scheck.c. (scheck.o): Remove. * private.h (scheck): Remove decl. * scheck.c: Remove. * zic.c (gethms, inleap, rulesub): Instead of scheck, use sscanf directly, with %c appended to the format to detect excess input. --- Makefile | 5 ++--- private.h | 6 ------ scheck.c | 64 --------------------------------------------------------------- zic.c | 21 ++++++++++++--------- 4 files changed, 14 insertions(+), 82 deletions(-) delete mode 100644 scheck.c diff --git a/Makefile b/Makefile index af52b36..cd585be 100644 --- a/Makefile +++ b/Makefile @@ -331,13 +331,13 @@ AR= ar # ':' on typical hosts; 'ranlib' on the ancient hosts that still need ranlib. RANLIB= : -TZCOBJS= zic.o scheck.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 +NONLIBSRCS= zic.c zdump.c NEWUCBSRCS= date.c strftime.c SOURCES= $(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) \ tzselect.ksh workman.sh @@ -656,7 +656,6 @@ asctime.o: private.h tzfile.h date.o: private.h difftime.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 diff --git a/private.h b/private.h index 05316a1..61cf922 100644 --- a/private.h +++ b/private.h @@ -453,12 +453,6 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE; #endif /* -** Private function declarations. -*/ - -const char * scheck(const char * string, const char * format); - -/* ** Finally, some convenience items. */ diff --git a/scheck.c b/scheck.c deleted file mode 100644 index 8bd01a8..0000000 --- a/scheck.c +++ /dev/null @@ -1,64 +0,0 @@ -/* -** This file is in the public domain, so clarified as of -** 2006-07-17 by Arthur David Olson. -*/ - -/*LINTLIBRARY*/ - -#include "private.h" - -const char * -scheck(const char *const string, const char *const format) -{ - register char * fbuf; - register const char * fp; - register char * tp; - register int c; - register const char * result; - char dummy; - - result = ""; - if (string == NULL || format == NULL) - return result; - fbuf = malloc(2 * strlen(format) + 4); - if (fbuf == NULL) - return result; - fp = format; - tp = fbuf; - - /* - ** Copy directives, suppressing each conversion that is not - ** already suppressed. Scansets containing '%' are not - ** supported; e.g., the conversion specification "%[%]" is not - ** supported. Also, multibyte characters containing a - ** non-leading '%' byte are not supported. - */ - while ((*tp++ = c = *fp++) != '\0') { - if (c != '%') - continue; - if (is_digit(*fp)) { - char const *f = fp; - char *t = tp; - do { - *t++ = c = *f++; - } while (is_digit(c)); - if (c == '$') { - fp = f; - tp = t; - } - } - *tp++ = '*'; - if (*fp == '*') - ++fp; - if ((*tp++ = *fp++) == '\0') - break; - } - - *(tp - 1) = '%'; - *tp++ = 'c'; - *tp = '\0'; - if (sscanf(string, fbuf, &dummy) != 1) - result = format; - free(fbuf); - return result; -} diff --git a/zic.c b/zic.c index b28d5c3..ce3576b 100644 --- a/zic.c +++ b/zic.c @@ -1053,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; @@ -1062,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; } @@ -1245,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")); @@ -1252,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! */ @@ -1287,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; @@ -1377,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")); @@ -1428,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; } @@ -1450,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; } @@ -1503,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")); -- 2.1.0
* NEWS: Mention performance improvements. * zic.c (time_overflow): New function. (oadd, tadd): Use it. (tadd): Use fewer comparisons. --- NEWS | 4 ++++ zic.c | 36 +++++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index 2baf42f..58ec0a6 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,10 @@ Unreleased, experimental changes 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 diff --git a/zic.c b/zic.c index ce3576b..636649b 100644 --- a/zic.c +++ b/zic.c @@ -2758,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; } /* -- 2.1.0
participants (1)
-
Paul Eggert