summaryrefslogtreecommitdiff
path: root/lib/libc/time/asctime.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/time/asctime.c')
-rw-r--r--lib/libc/time/asctime.c99
1 files changed, 76 insertions, 23 deletions
diff --git a/lib/libc/time/asctime.c b/lib/libc/time/asctime.c
index 15bcb448cac..5e22f919b72 100644
--- a/lib/libc/time/asctime.c
+++ b/lib/libc/time/asctime.c
@@ -4,8 +4,8 @@
*/
#if defined(LIBC_SCCS) && !defined(lint) && !defined(NOID)
-static char elsieid[] = "@(#)asctime.c 7.9";
-static char rcsid[] = "$OpenBSD: asctime.c,v 1.7 2000/01/06 08:24:17 d Exp $";
+static char elsieid[] = "@(#)asctime.c 7.22";
+static char rcsid[] = "$OpenBSD: asctime.c,v 1.8 2004/10/18 22:33:43 millert Exp $";
#endif /* LIBC_SCCS and not lint */
/*LINTLIBRARY*/
@@ -14,14 +14,51 @@ static char rcsid[] = "$OpenBSD: asctime.c,v 1.7 2000/01/06 08:24:17 d Exp $";
#include "tzfile.h"
#include "thread_private.h"
+#if STRICTLY_STANDARD_ASCTIME
+#define ASCTIME_FMT "%.3s %.3s%3d %.2d:%.2d:%.2d %ld\n"
+#define ASCTIME_FMT_B ASCTIME_FMT
+#else /* !STRICTLY_STANDARD_ASCTIME */
/*
-** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, Second Edition, 1996-07-12.
+** 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
+** spaces before the newline to get the newline in the traditional place.
+*/
+#define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4ld\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 %ld\n"
+#endif /* !STRICTLY_STANDARD_ASCTIME */
-char *
-asctime_r(timeptr, buf)
+#define STD_ASCTIME_BUF_SIZE 26
+/*
+** Big enough for something such as
+** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n
+** (two three-character abbreviations, five strings denoting integers,
+** seven explicit spaces, two explicit colons, a newline,
+** and a trailing ASCII nul).
+** The values above are for systems where an int is 32 bits and are provided
+** as an example; the define below calculates the maximum for the system at
+** hand.
+*/
+#define MAX_ASCTIME_BUF_SIZE (2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1)
+
+static char *
+asctime3(timeptr, buf, bufsize)
register const struct tm * timeptr;
char * buf;
+int bufsize;
{
static const char wday_name[][3] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
@@ -32,7 +69,8 @@ char * buf;
};
register const char * wn;
register const char * mn;
- int size;
+ long year;
+ int len;
if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
wn = "???";
@@ -40,40 +78,55 @@ char * buf;
if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
mn = "???";
else mn = mon_name[timeptr->tm_mon];
- /*
- ** The X3J11-suggested format is
- ** "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"
- ** Since the .2 in 02.2d is ignored, we drop it.
- */
- /*
- * P1003 8.3.5.2 says that asctime_r() can only assume at most
- * a 26 byte buffer. *XXX*
- */
- size = snprintf(buf, 26, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
+ year = timeptr->tm_year + (long) TM_YEAR_BASE;
+ len = snprintf(buf, bufsize,
+ ((year >= -999 && year <= 9999) ? ASCTIME_FMT : ASCTIME_FMT_B),
wn, mn,
timeptr->tm_mday, timeptr->tm_hour,
timeptr->tm_min, timeptr->tm_sec,
TM_YEAR_BASE + timeptr->tm_year);
- if (size >= 26)
+ if (len < bufsize) {
+ return buf;
+ } else {
+#ifdef EOVERFLOW
+ errno = EOVERFLOW;
+#else /* !defined EOVERFLOW */
+ errno = EINVAL;
+#endif /* !defined EOVERFLOW */
return NULL;
- return buf;
+ }
+}
+
+/*
+** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition.
+*/
+
+char *
+asctime_r(timeptr, buf)
+register const struct tm * timeptr;
+char * buf;
+{
+ /*
+ ** P1003 8.3.5.2 says that asctime_r() can only assume at most
+ ** a 26 byte buffer.
+ */
+ return asctime3(timeptr, buf, STD_ASCTIME_BUF_SIZE);
}
/*
-** A la X3J11, with core dump avoidance.
+** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition.
*/
char *
asctime(timeptr)
const struct tm * timeptr;
{
- /* asctime_r won't exceed this buffer: */
- static char result[26];
+ static char result[MAX_ASCTIME_BUF_SIZE];
_THREAD_PRIVATE_KEY(asctime);
- char *resultp = (char*) _THREAD_PRIVATE(asctime, result, NULL);
+ char *resultp = (char *)_THREAD_PRIVATE(asctime, result, NULL);
if (resultp == NULL)
return NULL;
else
- return asctime_r(timeptr, resultp);
+ return asctime3(timeptr, resultp, sizeof(result));
}