Strftime's %C and %y formats versus wide-ranging tm_year valu es
Paul Eggert
eggert at CS.UCLA.EDU
Fri Oct 15 19:02:52 UTC 2004
"Olson, Arthur David (NIH/NCI)" <olsona at dc37a.nci.nih.gov> writes:
> Below might be a simpler asctime.c fix.
It's simpler, but I'd like to handle overflow nicely even if
STRICTLY_STANDARD_ASCTIME is defined. Also, the "%-4s" in ASCTIME_FMT
bothers me, as the "-4" shouldn't be needed.
How about this further patch? It shortens asctime.c further (assuming
the two asctime.c patches you've already sent). Aside from fixing the
STRICTLY_STANDARD_ASCTIME overflow glitch, this patch avoids some
byte-scanning and some duplicated format-string contents, and changes
"digits" to "bytes" in a few comments referring to contents that might
include "-".
===================================================================
RCS file: RCS/asctime.c,v
retrieving revision 2004.3.1.3
retrieving revision 2004.3.0.5
diff -c -r2004.3.1.3 -r2004.3.0.5
*** asctime.c 2004/10/14 21:34:12 2004.3.1.3
--- asctime.c 2004/10/15 18:53:52 2004.3.0.5
***************
*** 15,44 ****
#include "tzfile.h"
#if STRICTLY_STANDARD_ASCTIME
! #define ASCTIME_FMT "%.3s %.3s%3d %.2d:%.2d:%.2d %s\n"
! #define ASCTIME_FMT_B ASCTIME_FMT
#else /* !STRICTLY_STANDARD_ASCTIME */
/*
** Some systems only handle "%.2d"; others only handle "%02d";
** "%02.2d" makes (most) everybody happy.
** At least some versions of gcc warn about the %02.2d; ignore the warning.
*/
/*
** All years associated with 32-bit time_t values are exactly four digits long;
** some years associated with 64-bit time_t values are not.
! ** Vintage programs are coded for years that are always four digits long
** and may assume that the newline always lands in the same place.
! ** For years that are less than four digits, we pad the output with
** leading zeroes to get the newline in the traditional place.
! */
! #define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4s\n"
! /*
! ** For years that are more than four digits we put extra spaces before the year
** so that code trying to overwrite the newline won't end up overwriting
** a digit within a year and truncating the year (operating on the assumption
** that no output is better than wrong output).
*/
! #define ASCTIME_FMT_B "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %s\n"
#endif /* !STRICTLY_STANDARD_ASCTIME */
#define STD_ASCTIME_BUF_SIZE 26
--- 15,44 ----
#include "tzfile.h"
#if STRICTLY_STANDARD_ASCTIME
! #define ASCTIME_FMT "%.3s %.3s%3d %.2d:%.2d:%.2d "
! #define SMALL_YEAR_FMT "%d\n"
! #define LARGE_YEAR_TFMT "%Y\n"
#else /* !STRICTLY_STANDARD_ASCTIME */
/*
** Some systems only handle "%.2d"; others only handle "%02d";
** "%02.2d" makes (most) everybody happy.
** At least some versions of gcc warn about the %02.2d; ignore the warning.
*/
+ #define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d "
/*
** All years associated with 32-bit time_t values are exactly four digits long;
** some years associated with 64-bit time_t values are not.
! ** Vintage programs are coded for years that are always four bytes long
** and may assume that the newline always lands in the same place.
! ** For years that are less than four bytes, we pad the output with
** leading zeroes to get the newline in the traditional place.
! ** For years that are more than four bytes we put extra spaces before the year
** so that code trying to overwrite the newline won't end up overwriting
** a digit within a year and truncating the year (operating on the assumption
** that no output is better than wrong output).
*/
! #define SMALL_YEAR_FMT "%-4d\n"
! #define LARGE_YEAR_TFMT " %Y\n"
#endif /* !STRICTLY_STANDARD_ASCTIME */
#define STD_ASCTIME_BUF_SIZE 26
***************
*** 72,80 ****
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
register const char * wn;
register const char * mn;
- char year[INT_STRLEN_MAXIMUM(int) + 2];
char result[MAX_ASCTIME_BUF_SIZE];
if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
--- 72,80 ----
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
+ register char * pt;
register const char * wn;
register const char * mn;
char result[MAX_ASCTIME_BUF_SIZE];
if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
***************
*** 83,113 ****
if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
mn = "???";
else mn = mon_name[timeptr->tm_mon];
- #if STRICTLY_STANDARD_ASCTIME
- /*
- ** Be strict, potential overflow problems included.
- ** In an ideal world, this code is never going to be used.
- */
- (void) sprintf(year, "%d", timeptr->tm_year + TM_YEAR_BASE);
- #else /* !STRICTLY_STANDARD_ASCTIME */
- /*
- ** Use strftime's %Y to generate the year, to avoid overflow problems
- ** when computing timeptr->tm_year + TM_YEAR_BASE.
- ** Assume that strftime is unaffected by other out-of-range members
- ** (e.g., timeptr->tm_mday) when processing "%Y".
- */
- (void) strftime(year, sizeof year, "%Y", timeptr);
- #endif /* !STRICTLY_STANDARD_ASCTIME */
/*
** We avoid using snprintf since it's not available on all systems.
*/
! (void) sprintf(result,
! ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
wn, mn,
timeptr->tm_mday, timeptr->tm_hour,
! timeptr->tm_min, timeptr->tm_sec,
! year);
! if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime) {
(void) strcpy(buf, result);
return buf;
} else {
--- 83,111 ----
if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
mn = "???";
else mn = mon_name[timeptr->tm_mon];
/*
** We avoid using snprintf since it's not available on all systems.
*/
! pt = result + sprintf(result,
! ASCTIME_FMT,
wn, mn,
timeptr->tm_mday, timeptr->tm_hour,
! timeptr->tm_min, timeptr->tm_sec);
! if (-999 - TM_YEAR_BASE <= timeptr->tm_year
! && timeptr->tm_year <= 9999 - TM_YEAR_BASE)
! pt += sprintf(pt,
! SMALL_YEAR_FMT, timeptr->tm_year + TM_YEAR_BASE);
! else
! /*
! ** Use strftime's %Y to generate the year, to avoid overflow
! ** problems when computing timeptr->tm_year + TM_YEAR_BASE.
! ** Assume that strftime is unaffected by other out-of-range
! ** members (e.g., timeptr->tm_mday) when processing "%Y".
! */
! pt += strftime(pt,
! sizeof LARGE_YEAR_TFMT + INT_STRLEN_MAXIMUM(int) - 1,
! LARGE_YEAR_TFMT, timeptr);
! if (pt < result + STD_ASCTIME_BUF_SIZE || buf == buf_asctime) {
(void) strcpy(buf, result);
return buf;
} else {
More information about the tz
mailing list