Instead, allocate a longer buffer, exiting if memory is exhausted. * zdump.c (abbrev, abbrevsize, loab, loabsize): New static vars. (saveabbr): New function. (main, loab): Use the new function and variables. (abbr): Arg is now a pointer-to-const, for saveabbr. --- zdump.c | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/zdump.c b/zdump.c index f5a4dff..76b3453 100644 --- a/zdump.c +++ b/zdump.c @@ -212,7 +212,7 @@ static char * progname; static bool warned; static bool errout; -static char *abbr(struct tm *); +static char *abbr(struct tm const *); static intmax_t delta(struct tm *, struct tm *) ATTRIBUTE_PURE; static void dumptime(struct tm const *); static time_t hunt(char *, time_t, time_t); @@ -359,6 +359,36 @@ abbrok(const char *const abbrp, const char *const zone) warned = errout = true; } +/* Extensible buffers for time zone abbreviations of the current and + low-boundary probes. */ +static char *abbrev; +static size_t abbrevsize; +static char *loab; +static size_t loabsize; + +/* Save into *BUF (of size *BUFALLOC) the time zone abbreviation of TMP. + Exit on memory allocation failure. */ +static void +saveabbr(char **buf, size_t *bufalloc, struct tm const *tmp) +{ + char const *ab = abbr(tmp); + size_t ablen = strlen(ab); + if (*bufalloc <= ablen) { + free(*buf); + + /* Make the new buffer at least twice as long as the old, + to avoid O(N**2) behavior on repeated calls. */ + *bufalloc = sumsize(*bufalloc, ablen + 1); + + *buf = malloc(*bufalloc); + if (! *buf) { + perror(progname); + exit(EXIT_FAILURE); + } + } + strcpy(*buf, ab); +} + static void close_file(FILE *stream) { @@ -500,8 +530,6 @@ main(int argc, char *argv[]) } for (i = optind; i < argc; ++i) { - static char buf[MAX_STRING_LENGTH]; - settimezone(argv[i]); if (! (vflag | Vflag)) { show(argv[i], now, false); @@ -519,7 +547,7 @@ main(int argc, char *argv[]) tmp = my_localtime(&t); if (tmp != NULL) { tm = *tmp; - strncpy(buf, abbr(&tm), (sizeof buf) - 1); + saveabbr(&abbrev, &abbrevsize, &tm); } for ( ; ; ) { newt = (t < absolute_max_time - SECSPERDAY / 2 @@ -533,14 +561,13 @@ main(int argc, char *argv[]) if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : (delta(&newtm, &tm) != (newt - t) || newtm.tm_isdst != tm.tm_isdst || - strcmp(abbr(&newtm), buf) != 0)) { + strcmp(abbr(&newtm), abbrev) != 0)) { newt = hunt(argv[i], t, newt); newtmp = localtime(&newt); if (newtmp != NULL) { newtm = *newtmp; - strncpy(buf, - abbr(&newtm), - (sizeof buf) - 1); + saveabbr(&abbrev, &abbrevsize, + &newtm); } } t = newt; @@ -612,12 +639,11 @@ hunt(char *name, time_t lot, time_t hit) register struct tm * lotmp; struct tm tm; register struct tm * tmp; - char loab[MAX_STRING_LENGTH]; lotmp = my_localtime(&lot); if (lotmp != NULL) { lotm = *lotmp; - strncpy(loab, abbr(&lotm), (sizeof loab) - 1); + saveabbr(&loab, &loabsize, &lotm); } for ( ; ; ) { time_t diff = hit - lot; @@ -705,7 +731,7 @@ show(char *zone, time_t t, bool v) } static char * -abbr(struct tm *tmp) +abbr(struct tm const *tmp) { register char * result; static char nada; -- 1.9.1