"Olson, Arthur David (NIH/NCI)" <olsona@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 {