blob: 4cdfd13a8c10e53151780c826f1f103f286ed998 [file] [log] [blame]
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001/* asctime and asctime_r a la POSIX and ISO C, except pad years before 1000. */
2
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003/*
4** This file is in the public domain, so clarified as of
5** 1996-06-05 by Arthur David Olson.
6*/
7
8/*
9** Avoid the temptation to punt entirely to strftime;
10** the output of strftime is supposed to be locale specific
11** whereas the output of asctime is supposed to be constant.
12*/
13
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080014/*LINTLIBRARY*/
15
16#include "private.h"
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000017#include <stdio.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080018
19/*
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080020** All years associated with 32-bit time_t values are exactly four digits long;
21** some years associated with 64-bit time_t values are not.
22** Vintage programs are coded for years that are always four digits long
23** and may assume that the newline always lands in the same place.
24** For years that are less than four digits, we pad the output with
25** leading zeroes to get the newline in the traditional place.
26** The -4 ensures that we get four characters of output even if
27** we call a strftime variant that produces fewer characters for some years.
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000028** The ISO C and POSIX standards prohibit padding the year,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080029** but many implementations pad anyway; most likely the standards are buggy.
30*/
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010031static char const ASCTIME_FMT[] = "%s %s%3d %.2d:%.2d:%.2d %-4s\n";
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080032/*
33** For years that are more than four digits we put extra spaces before the year
34** so that code trying to overwrite the newline won't end up overwriting
35** a digit within a year and truncating the year (operating on the assumption
36** that no output is better than wrong output).
37*/
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010038static char const ASCTIME_FMT_B[] = "%s %s%3d %.2d:%.2d:%.2d %s\n";
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080039
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010040enum { STD_ASCTIME_BUF_SIZE = 26 };
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080041/*
42** Big enough for something such as
43** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n
44** (two three-character abbreviations, five strings denoting integers,
45** seven explicit spaces, two explicit colons, a newline,
Elliott Hughes9fb22a32015-10-07 17:13:40 -070046** and a trailing NUL byte).
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080047** The values above are for systems where an int is 32 bits and are provided
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010048** as an example; the size expression below is a bound for the system at
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080049** hand.
50*/
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010051static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080052
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010053/* A similar buffer for ctime.
54 C89 requires that they be the same buffer.
55 This requirement was removed in C99, so support it only if requested,
56 as support is more likely to lead to bugs in badly written programs. */
57#if SUPPORT_C89
58# define buf_ctime buf_asctime
59#else
60static char buf_ctime[sizeof buf_asctime];
61#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080062
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080063char *
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010064asctime_r(struct tm const *restrict timeptr, char *restrict buf)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080065{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000066 static const char wday_name[][4] = {
Elliott Hughesce4783c2013-07-12 17:31:11 -070067 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
68 };
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000069 static const char mon_name[][4] = {
Elliott Hughesce4783c2013-07-12 17:31:11 -070070 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
71 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
72 };
73 register const char * wn;
74 register const char * mn;
75 char year[INT_STRLEN_MAXIMUM(int) + 2];
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010076 char result[sizeof buf_asctime];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080077
Elliott Hughesce4783c2013-07-12 17:31:11 -070078 if (timeptr == NULL) {
79 errno = EINVAL;
80 return strcpy(buf, "??? ??? ?? ??:??:?? ????\n");
81 }
82 if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
83 wn = "???";
84 else wn = wday_name[timeptr->tm_wday];
85 if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
86 mn = "???";
87 else mn = mon_name[timeptr->tm_mon];
88 /*
89 ** Use strftime's %Y to generate the year, to avoid overflow problems
90 ** when computing timeptr->tm_year + TM_YEAR_BASE.
91 ** Assume that strftime is unaffected by other out-of-range members
92 ** (e.g., timeptr->tm_mday) when processing "%Y".
93 */
Elliott Hughes9fb22a32015-10-07 17:13:40 -070094 strftime(year, sizeof year, "%Y", timeptr);
Elliott Hughesce4783c2013-07-12 17:31:11 -070095 /*
96 ** We avoid using snprintf since it's not available on all systems.
97 */
Elliott Hughes9fb22a32015-10-07 17:13:40 -070098 snprintf(result, sizeof(result), /* Android change: use snprintf. */
Elliott Hughesce4783c2013-07-12 17:31:11 -070099 ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
100 wn, mn,
101 timeptr->tm_mday, timeptr->tm_hour,
102 timeptr->tm_min, timeptr->tm_sec,
103 year);
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100104 if (strlen(result) < STD_ASCTIME_BUF_SIZE
105 || buf == buf_ctime || buf == buf_asctime)
Elliott Hughesce4783c2013-07-12 17:31:11 -0700106 return strcpy(buf, result);
107 else {
Elliott Hughesce4783c2013-07-12 17:31:11 -0700108 errno = EOVERFLOW;
Elliott Hughesce4783c2013-07-12 17:31:11 -0700109 return NULL;
110 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800111}
112
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800113char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700114asctime(register const struct tm *timeptr)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800115{
Elliott Hughesce4783c2013-07-12 17:31:11 -0700116 return asctime_r(timeptr, buf_asctime);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800117}
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100118
119char *
120ctime_r(const time_t *timep, char *buf)
121{
122 struct tm mytm;
123 struct tm *tmp = localtime_r(timep, &mytm);
124 return tmp ? asctime_r(tmp, buf) : NULL;
125}
126
127char *
128ctime(const time_t *timep)
129{
130 return ctime_r(timep, buf_ctime);
131}