Home | History | Annotate | Line # | Download | only in time
asctime.c revision 1.29
      1  1.29  christos /*	$NetBSD: asctime.c,v 1.29 2023/09/16 18:40:26 christos Exp $	*/
      2  1.25  christos 
      3  1.25  christos /* asctime and asctime_r a la POSIX and ISO C, except pad years before 1000.  */
      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.29  christos __RCSID("$NetBSD: asctime.c,v 1.29 2023/09/16 18:40:26 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.25  christos ** The ISO C and POSIX standards prohibit padding the year,
     47  1.13   mlelstv ** but many implementations pad anyway; most likely the standards are buggy.
     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.13   mlelstv /*
     62  1.13   mlelstv ** Big enough for something such as
     63  1.13   mlelstv ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648     -2147483648\n
     64  1.13   mlelstv ** (two three-character abbreviations, five strings denoting integers,
     65  1.13   mlelstv ** seven explicit spaces, two explicit colons, a newline,
     66  1.19  christos ** and a trailing NUL byte).
     67  1.13   mlelstv ** The values above are for systems where an int is 32 bits and are provided
     68  1.28  christos ** as an example; the size expression below is a bound for the system at
     69  1.13   mlelstv ** hand.
     70  1.13   mlelstv */
     71  1.28  christos static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1];
     72  1.13   mlelstv 
     73  1.29  christos /* A similar buffer for ctime.
     74  1.29  christos    C89 requires that they be the same buffer.
     75  1.29  christos    This requirement was removed in C99, so support it only if requested,
     76  1.29  christos    as support is more likely to lead to bugs in badly written programs.  */
     77  1.29  christos #if SUPPORT_C89
     78  1.29  christos # define buf_ctime buf_asctime
     79  1.29  christos #else
     80  1.29  christos static char buf_ctime[sizeof buf_asctime];
     81  1.29  christos #endif
     82  1.29  christos 
     83  1.29  christos #ifndef __LIBC12_SOURCE__
     84   1.1       jtc char *
     85  1.29  christos asctime_r(struct tm const *restrict timeptr, char *restrict buf)
     86   1.1       jtc {
     87  1.22  christos 	static const char	wday_name[][4] = {
     88   1.1       jtc 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
     89   1.1       jtc 	};
     90  1.22  christos 	static const char	mon_name[][4] = {
     91   1.1       jtc 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
     92   1.1       jtc 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
     93   1.1       jtc 	};
     94  1.18  christos 	const char *	wn;
     95  1.18  christos 	const char *	mn;
     96  1.13   mlelstv 	char			year[INT_STRLEN_MAXIMUM(int) + 2];
     97  1.28  christos 	char result[sizeof buf_asctime];
     98   1.1       jtc 
     99  1.14  christos 	if (timeptr == NULL) {
    100  1.14  christos 		errno = EINVAL;
    101  1.14  christos 		return strcpy(buf, "??? ??? ?? ??:??:?? ????\n");
    102  1.14  christos 	}
    103   1.1       jtc 	if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
    104   1.1       jtc 		wn = "???";
    105   1.1       jtc 	else	wn = wday_name[timeptr->tm_wday];
    106   1.1       jtc 	if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
    107   1.1       jtc 		mn = "???";
    108   1.1       jtc 	else	mn = mon_name[timeptr->tm_mon];
    109   1.1       jtc 	/*
    110  1.13   mlelstv 	** Use strftime's %Y to generate the year, to avoid overflow problems
    111  1.13   mlelstv 	** when computing timeptr->tm_year + TM_YEAR_BASE.
    112  1.13   mlelstv 	** Assume that strftime is unaffected by other out-of-range members
    113  1.13   mlelstv 	** (e.g., timeptr->tm_mday) when processing "%Y".
    114   1.1       jtc 	*/
    115  1.13   mlelstv 	(void) strftime(year, sizeof year, "%Y", timeptr);
    116  1.13   mlelstv 	(void) snprintf(result,
    117  1.13   mlelstv 		sizeof(result),
    118  1.13   mlelstv 		((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
    119   1.1       jtc 		wn, mn,
    120   1.1       jtc 		timeptr->tm_mday, timeptr->tm_hour,
    121   1.1       jtc 		timeptr->tm_min, timeptr->tm_sec,
    122  1.13   mlelstv 		year);
    123  1.29  christos 	if (strlen(result) < STD_ASCTIME_BUF_SIZE
    124  1.29  christos 	    || buf == buf_ctime || buf == buf_asctime)
    125  1.14  christos 		return strcpy(buf, result);
    126  1.14  christos 	else {
    127  1.13   mlelstv 		errno = EOVERFLOW;
    128  1.13   mlelstv 		return NULL;
    129  1.13   mlelstv 	}
    130   1.7    kleink }
    131   1.7    kleink 
    132   1.7    kleink char *
    133  1.15       abs asctime(const struct tm *timeptr)
    134   1.7    kleink {
    135  1.13   mlelstv 	return asctime_r(timeptr, buf_asctime);
    136   1.1       jtc }
    137  1.29  christos 
    138  1.29  christos #endif /* !__LIBC12_SOURCE__ */
    139  1.29  christos 
    140  1.29  christos char *
    141  1.29  christos ctime_rz(timezone_t sp, const time_t *timep, char *buf)
    142  1.29  christos {
    143  1.29  christos   struct tm mytm;
    144  1.29  christos   struct tm *tmp = localtime_rz(sp, timep, &mytm);
    145  1.29  christos   return tmp ? asctime_r(tmp, buf) : NULL;
    146  1.29  christos }
    147  1.29  christos 
    148  1.29  christos char *
    149  1.29  christos ctime_r(const time_t *timep, char *buf)
    150  1.29  christos {
    151  1.29  christos   struct tm mytm;
    152  1.29  christos   struct tm *tmp = localtime_r(timep, &mytm);
    153  1.29  christos   return tmp ? asctime_r(tmp, buf) : NULL;
    154  1.29  christos }
    155  1.29  christos 
    156  1.29  christos char *
    157  1.29  christos ctime(const time_t *timep)
    158  1.29  christos {
    159  1.29  christos   return ctime_r(timep, buf_ctime);
    160  1.29  christos }
    161