C89 requires that localtime(...) == gmtime(...) when both are successful, and similarly for asctime(...) == ctime(...). This can lead to bugs in badly-written programs, so continue to support it only if compiling with -DSUPPORT_C89, since the requirement was removed in C99. * Makefile, NEWS: Mention this. * asctime.c (buf_ctime): New macro or (if !SUPPORT_C89) static variable. (asctime_r): Check for it. (ctime): Use it. * localtime.c (tm) [!SUPPORT_C89]: Use three instances of this variable instead of one. * private.h (SUPPORT_C89): Default to 0. --- Makefile | 2 ++ NEWS | 13 +++++++++++++ asctime.c | 16 +++++++++++++--- localtime.c | 15 +++++++++++++++ private.h | 4 ++++ 5 files changed, 47 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index f0cbf7f..63f3b5c 100644 --- a/Makefile +++ b/Makefile @@ -245,6 +245,8 @@ LDLIBS= # -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers # with external linkage, e.g., applications cannot define 'localtime'. # -Dssize_t=long on hosts like MS-Windows that lack ssize_t +# -DSUPPORT_C89 if you build or run tzcode on a C89 platform; this option +# is obsolescent and is planned to be removed when C99+ is required. # -DSUPPRESS_TZDIR to not prepend TZDIR to file names; this has # security implications and is not recommended for general use # -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires; diff --git a/NEWS b/NEWS index 701e490..9cb175e 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,18 @@ News for the tz database +Unreleased, experimental changes + + Briefly: + tzcode no longer supports C89 unless built with -DSUPPORT_C89 + + Changes to code + + tzcode no longer supports C89 by default. To build or run in a + C89 environment, compile with -DSUPPORT_C89, a transitional aid + that is planned to be removed in a near-future version, when C99 + or later will be required. + + Release 2022g - 2022-11-29 08:58:31 -0800 Briefly: diff --git a/asctime.c b/asctime.c index c001621..c84fe8c 100644 --- a/asctime.c +++ b/asctime.c @@ -50,6 +50,16 @@ enum { STD_ASCTIME_BUF_SIZE = 26 }; */ static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1]; +/* A similar buffer for ctime. + C89 requires that they be the same buffer. + This requirement was removed in C99, so support it only if requested, + as support is more likely to lead to bugs in badly-written programs. */ +#if SUPPORT_C89 +# define buf_ctime buf_asctime +#else +static char buf_ctime[sizeof buf_asctime]; +#endif + char * asctime_r(register const struct tm *timeptr, char *buf) { @@ -91,7 +101,8 @@ asctime_r(register const struct tm *timeptr, char *buf) timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec, year); - if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime) + if (strlen(result) < STD_ASCTIME_BUF_SIZE + || buf == buf_ctime || buf == buf_asctime) return strcpy(buf, result); else { errno = EOVERFLOW; @@ -116,6 +127,5 @@ ctime_r(const time_t *timep, char *buf) char * ctime(const time_t *timep) { - struct tm *tmp = localtime(timep); - return tmp ? asctime(tmp) : NULL; + return ctime_r(timep, buf_ctime); } diff --git a/localtime.c b/localtime.c index cb34a9e..f8a0a6e 100644 --- a/localtime.c +++ b/localtime.c @@ -186,9 +186,14 @@ static int lcl_is_set; ** ctime, gmtime, localtime] return values in one of two static ** objects: a broken-down time structure and an array of char. ** Thanks to Paul Eggert for noting this. +** +** This requirement was removed in C99, so support it only if requested, +** as support is more likely to lead to bugs in badly-written programs. */ +#if SUPPORT_C89 static struct tm tm; +#endif #if 2 <= HAVE_TZNAME + TZ_TIME_T char * tzname[2] = { @@ -1648,6 +1653,9 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname) struct tm * localtime(const time_t *timep) { +#if !SUPPORT_C89 + static struct tm tm; +#endif return localtime_tzset(timep, &tm, true); } @@ -1694,6 +1702,9 @@ gmtime_r(const time_t *timep, struct tm *tmp) struct tm * gmtime(const time_t *timep) { +#if !SUPPORT_C89 + static struct tm tm; +#endif return gmtime_r(timep, &tm); } @@ -1703,6 +1714,10 @@ struct tm * offtime(const time_t *timep, long offset) { gmtcheck(); + +#if !SUPPORT_C89 + static struct tm tm; +#endif return gmtsub(gmtptr, timep, offset, &tm); } diff --git a/private.h b/private.h index 4a1f667..c22354a 100644 --- a/private.h +++ b/private.h @@ -704,6 +704,10 @@ extern int daylight; extern long altzone; #endif +#ifndef SUPPORT_C89 +# define SUPPORT_C89 0 +#endif + /* ** The STD_INSPIRED functions are similar, but most also need ** declarations if time_tz is defined. -- 2.38.1