Home | History | Annotate | Line # | Download | only in time
asctime.c revision 1.31
      1  1.31  christos /*	$NetBSD: asctime.c,v 1.31 2024/09/11 13:50:34 christos Exp $	*/
      2  1.25  christos 
      3  1.31  christos /* asctime a la ISO C.  */
      4   1.3       jtc 
      5   1.3       jtc /*
      6   1.3       jtc ** This file is in the public domain, so clarified as of
      7  1.13   mlelstv ** 1996-06-05 by Arthur David Olson.
      8  1.13   mlelstv */
      9  1.13   mlelstv 
     10  1.13   mlelstv /*
     11  1.13   mlelstv ** Avoid the temptation to punt entirely to strftime;
     12  1.13   mlelstv ** the output of strftime is supposed to be locale specific
     13  1.13   mlelstv ** whereas the output of asctime is supposed to be constant.
     14   1.3       jtc */
     15   1.2       jtc 
     16   1.6  christos #include <sys/cdefs.h>
     17  1.11   msaitoh #if defined(LIBC_SCCS) && !defined(lint)
     18   1.6  christos #if 0
     19  1.14  christos static char	elsieid[] = "@(#)asctime.c	8.5";
     20   1.6  christos #else
     21  1.31  christos __RCSID("$NetBSD: asctime.c,v 1.31 2024/09/11 13:50:34 christos Exp $");
     22   1.6  christos #endif
     23  1.11   msaitoh #endif /* LIBC_SCCS and not lint */
     24   1.1       jtc 
     25   1.1       jtc /*LINTLIBRARY*/
     26   1.1       jtc 
     27   1.9    kleink #include "namespace.h"
     28   1.1       jtc #include "private.h"
     29  1.22  christos #include <stdio.h>
     30   1.1       jtc 
     31  1.29  christos #ifndef __LIBC12_SOURCE__
     32  1.29  christos 
     33   1.7    kleink #ifdef __weak_alias
     34  1.10   mycroft __weak_alias(asctime_r,_asctime_r)
     35   1.7    kleink #endif
     36   1.7    kleink 
     37   1.7    kleink /*
     38  1.13   mlelstv ** All years associated with 32-bit time_t values are exactly four digits long;
     39  1.13   mlelstv ** some years associated with 64-bit time_t values are not.
     40  1.13   mlelstv ** Vintage programs are coded for years that are always four digits long
     41  1.13   mlelstv ** and may assume that the newline always lands in the same place.
     42  1.13   mlelstv ** For years that are less than four digits, we pad the output with
     43  1.13   mlelstv ** leading zeroes to get the newline in the traditional place.
     44  1.13   mlelstv ** The -4 ensures that we get four characters of output even if
     45  1.13   mlelstv ** we call a strftime variant that produces fewer characters for some years.
     46  1.31  christos ** This conforms to recent ISO C and POSIX standards, which say behavior
     47  1.31  christos ** is undefined when the year is less than 1000 or greater than 9999.
     48  1.13   mlelstv */
     49  1.28  christos static char const ASCTIME_FMT[] = "%s %s%3d %.2d:%.2d:%.2d %-4s\n";
     50  1.13   mlelstv /*
     51  1.13   mlelstv ** For years that are more than four digits we put extra spaces before the year
     52  1.13   mlelstv ** so that code trying to overwrite the newline won't end up overwriting
     53  1.13   mlelstv ** a digit within a year and truncating the year (operating on the assumption
     54  1.13   mlelstv ** that no output is better than wrong output).
     55  1.13   mlelstv */
     56  1.28  christos static char const ASCTIME_FMT_B[] = "%s %s%3d %.2d:%.2d:%.2d     %s\n";
     57  1.13   mlelstv 
     58  1.28  christos enum { STD_ASCTIME_BUF_SIZE = 26 };
     59  1.29  christos #endif
     60  1.29  christos 
     61  1.31  christos /* Publish asctime_r and ctime_r only when supporting older POSIX.  */
     62  1.31  christos #if SUPPORT_POSIX2008
     63  1.31  christos # define asctime_static
     64  1.31  christos #else
     65  1.31  christos # define asctime_static static
     66  1.31  christos # undef asctime_r
     67  1.31  christos # undef ctime_r
     68  1.31  christos # define asctime_r static_asctime_r
     69  1.31  christos # define ctime_r static_ctime_r
     70  1.31  christos #endif
     71  1.31  christos 
     72  1.13   mlelstv /*
     73  1.13   mlelstv ** Big enough for something such as
     74  1.13   mlelstv ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648     -2147483648\n
     75  1.13   mlelstv ** (two three-character abbreviations, five strings denoting integers,
     76  1.13   mlelstv ** seven explicit spaces, two explicit colons, a newline,
     77  1.19  christos ** and a trailing NUL byte).
     78  1.13   mlelstv ** The values above are for systems where an int is 32 bits and are provided
     79  1.28  christos ** as an example; the size expression below is a bound for the system at
     80  1.13   mlelstv ** hand.
     81  1.13   mlelstv */
     82  1.30  christos static char buf_ctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1];
     83  1.13   mlelstv 
     84  1.31  christos #ifndef __LIBC12_SOURCE__
     85  1.29  christos /* A similar buffer for ctime.
     86  1.29  christos    C89 requires that they be the same buffer.
     87  1.29  christos    This requirement was removed in C99, so support it only if requested,
     88  1.29  christos    as support is more likely to lead to bugs in badly written programs.  */
     89  1.29  christos #if SUPPORT_C89
     90  1.30  christos # define buf_asctime buf_ctime
     91  1.29  christos #else
     92  1.30  christos static char buf_asctime[sizeof buf_ctime];
     93  1.29  christos #endif
     94  1.29  christos 
     95  1.31  christos 
     96  1.31  christos asctime_static
     97   1.1       jtc char *
     98  1.29  christos asctime_r(struct tm const *restrict timeptr, char *restrict buf)
     99   1.1       jtc {
    100  1.22  christos 	static const char	wday_name[][4] = {
    101   1.1       jtc 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    102   1.1       jtc 	};
    103  1.22  christos 	static const char	mon_name[][4] = {
    104   1.1       jtc 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
    105   1.1       jtc 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    106   1.1       jtc 	};
    107  1.18  christos 	const char *	wn;
    108  1.18  christos 	const char *	mn;
    109  1.13   mlelstv 	char			year[INT_STRLEN_MAXIMUM(int) + 2];
    110  1.30  christos 	char result[sizeof buf_ctime];
    111   1.1       jtc 
    112  1.14  christos 	if (timeptr == NULL) {
    113  1.14  christos 		errno = EINVAL;
    114  1.14  christos 		return strcpy(buf, "??? ??? ?? ??:??:?? ????\n");
    115  1.14  christos 	}
    116   1.1       jtc 	if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
    117   1.1       jtc 		wn = "???";
    118   1.1       jtc 	else	wn = wday_name[timeptr->tm_wday];
    119   1.1       jtc 	if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
    120   1.1       jtc 		mn = "???";
    121   1.1       jtc 	else	mn = mon_name[timeptr->tm_mon];
    122   1.1       jtc 	/*
    123  1.13   mlelstv 	** Use strftime's %Y to generate the year, to avoid overflow problems
    124  1.13   mlelstv 	** when computing timeptr->tm_year + TM_YEAR_BASE.
    125  1.13   mlelstv 	** Assume that strftime is unaffected by other out-of-range members
    126  1.13   mlelstv 	** (e.g., timeptr->tm_mday) when processing "%Y".
    127   1.1       jtc 	*/
    128  1.13   mlelstv 	(void) strftime(year, sizeof year, "%Y", timeptr);
    129  1.13   mlelstv 	(void) snprintf(result,
    130  1.13   mlelstv 		sizeof(result),
    131  1.13   mlelstv 		((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
    132   1.1       jtc 		wn, mn,
    133   1.1       jtc 		timeptr->tm_mday, timeptr->tm_hour,
    134   1.1       jtc 		timeptr->tm_min, timeptr->tm_sec,
    135  1.13   mlelstv 		year);
    136  1.29  christos 	if (strlen(result) < STD_ASCTIME_BUF_SIZE
    137  1.29  christos 	    || buf == buf_ctime || buf == buf_asctime)
    138  1.14  christos 		return strcpy(buf, result);
    139  1.14  christos 	else {
    140  1.13   mlelstv 		errno = EOVERFLOW;
    141  1.13   mlelstv 		return NULL;
    142  1.13   mlelstv 	}
    143   1.7    kleink }
    144   1.7    kleink 
    145   1.7    kleink char *
    146  1.15       abs asctime(const struct tm *timeptr)
    147   1.7    kleink {
    148  1.13   mlelstv 	return asctime_r(timeptr, buf_asctime);
    149   1.1       jtc }
    150  1.31  christos #endif /* !__LIBC12_SOURCE__ */
    151  1.29  christos 
    152  1.29  christos 
    153  1.29  christos char *
    154  1.29  christos ctime_rz(timezone_t sp, const time_t *timep, char *buf)
    155  1.29  christos {
    156  1.29  christos   struct tm mytm;
    157  1.29  christos   struct tm *tmp = localtime_rz(sp, timep, &mytm);
    158  1.29  christos   return tmp ? asctime_r(tmp, buf) : NULL;
    159  1.29  christos }
    160  1.29  christos 
    161  1.31  christos asctime_static
    162  1.29  christos char *
    163  1.29  christos ctime_r(const time_t *timep, char *buf)
    164  1.29  christos {
    165  1.29  christos   struct tm mytm;
    166  1.29  christos   struct tm *tmp = localtime_r(timep, &mytm);
    167  1.29  christos   return tmp ? asctime_r(tmp, buf) : NULL;
    168  1.29  christos }
    169  1.29  christos 
    170  1.29  christos char *
    171  1.29  christos ctime(const time_t *timep)
    172  1.29  christos {
    173  1.29  christos   return ctime_r(timep, buf_ctime);
    174  1.29  christos }
    175