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