xref: /reactos/sdk/lib/crt/time/asctime.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:   LGPL, See LGPL.txt in the top level directory
3  * PROJECT:     ReactOS CRT library
4  * FILE:        lib/sdk/crt/time/asctime.c
5  * PURPOSE:     Implementation of asctime(), _asctime_s()
6  * PROGRAMERS:  Timo Kreuzer
7  */
8 #include <precomp.h>
9 #include <tchar.h>
10 #include <time.h>
11 #include "bitsfixup.h"
12 
13 #define DAYSPERWEEK 7
14 #define MONSPERYEAR 12
15 #define HUNDREDYEAROFFSET 19
16 
17 static const _TCHAR wday_name[DAYSPERWEEK][5] =
18 {
19     _T("Sun "), _T("Mon "), _T("Tue "), _T("Wed "),
20     _T("Thu "), _T("Fri "), _T("Sat ")
21 };
22 
23 static const _TCHAR mon_name[MONSPERYEAR][5] =
24 {
25     _T("Jan "), _T("Feb "), _T("Mar "), _T("Apr "), _T("May "), _T("Jun "),
26     _T("Jul "), _T("Aug "), _T("Sep "), _T("Oct "), _T("Nov "), _T("Dec ")
27 };
28 
29 #ifdef _UNICODE
30 typedef unsigned long long _TCHAR4;
31 typedef unsigned long _TCHAR2;
32 #else
33 typedef unsigned long _TCHAR4;
34 typedef unsigned short _TCHAR2;
35 #endif
36 
37 #pragma pack(push,1)
38 typedef union
39 {
40     _TCHAR text[26];
41     struct
42     {
43         _TCHAR4 WeekDay;
44         _TCHAR4 Month;
45         _TCHAR2 Day;
46         _TCHAR Space1;
47         _TCHAR2 Hour;
48         _TCHAR Sep1;
49         _TCHAR2 Minute;
50         _TCHAR Sep2;
51         _TCHAR2 Second;
52         _TCHAR Space2;
53         _TCHAR2 Year[2];
54         _TCHAR lb;
55         _TCHAR zt;
56     };
57 } timebuf_t;
58 #pragma pack(pop)
59 
60 FORCEINLINE
61 _TCHAR2
62 IntToChar2(int x)
63 {
64     union
65     {
66         _TCHAR2 char2;
67         _TCHAR array[2];
68     } u;
69 
70     u.array[0] = '0' + (x / 10);
71     u.array[1] = '0' + (x % 10);
72 
73     return u.char2;
74 }
75 
76 static __inline
77 void
78 FillBuf(timebuf_t *buf, const struct tm *ptm)
79 {
80     /* Format looks like this:
81      * "Sun Mar 01 12:34:56 1902\n\0" */
82     buf->WeekDay = *(_TCHAR4*)wday_name[ptm->tm_wday];
83     buf->Month = *(_TCHAR4*)mon_name[ptm->tm_mon];
84     buf->Day = IntToChar2(ptm->tm_mday);
85     buf->Space1 = ' ';
86     buf->Hour = IntToChar2(ptm->tm_hour);
87     buf->Sep1 = ':';
88     buf->Minute = IntToChar2(ptm->tm_min);
89     buf->Sep2 = ':';
90     buf->Second = IntToChar2(ptm->tm_sec);
91     buf->Space2 = ' ';
92     buf->Year[0] = IntToChar2(ptm->tm_year / 100 + HUNDREDYEAROFFSET);
93     buf->Year[1] = IntToChar2(ptm->tm_year % 100);
94     buf->lb = '\n';
95     buf->zt = '\0';
96 }
97 
98 /******************************************************************************
99  * \name _tasctime_s
100  * \brief Converts a local time into a string and returns a pointer to it.
101  * \param buffer Buffer that receives the string (26 characters).
102  * \param numberOfElements Size of the buffer in characters.
103  * \param time Pointer to the UTC time.
104  */
105 errno_t
106 _tasctime_s(
107     _TCHAR* buffer,
108     size_t numberOfElements,
109     const struct tm *ptm)
110 {
111     /* Validate parameters */
112     if (!buffer || numberOfElements < 26 || !ptm ||
113         (unsigned int)ptm->tm_sec > 59 ||
114         (unsigned int)ptm->tm_min > 59 ||
115         (unsigned int)ptm->tm_hour > 23 ||
116         (unsigned int)ptm->tm_mday > 31 ||
117         (unsigned int)ptm->tm_mon > 11 ||
118         (unsigned int)ptm->tm_year > 2038 ||
119         (unsigned int)ptm->tm_wday > 6 ||
120         (unsigned int)ptm->tm_yday > 365)
121     {
122 #if 0
123         _invalid_parameter(NULL,
124 #ifdef UNICODE
125                             L"_wasctime",
126 #else
127                             L"asctime",
128 #endif
129                            _CRT_WIDE(__FILE__),
130                            __LINE__,
131                            0);
132 #endif
133         return EINVAL;
134     }
135 
136     /* Fill the buffer */
137     FillBuf((timebuf_t*)buffer, ptm);
138 
139     return 0;
140 }
141 
142 /******************************************************************************
143  * \name _tasctime
144  * \brief Converts a UTC time into a string and returns a pointer to it.
145  * \param ptm Pointer to the UTC time.
146  * \remarks The string is stored in thread local buffer, shared between
147  *          ctime, gmtime and localtime (32 and 64 bit versions).
148  */
149 _TCHAR *
150 _tasctime(const struct tm *ptm)
151 {
152     thread_data_t *data = msvcrt_get_thread_data();
153     _TCHAR *pstr;
154 
155 #ifndef _UNICODE
156     pstr = data->asctime_buffer;
157 #else
158     pstr = data->wasctime_buffer;
159 #endif
160 
161     if(!pstr)
162         pstr = malloc(sizeof(struct tm));
163 
164     /* Fill the buffer */
165     FillBuf((timebuf_t*)pstr, ptm);
166 
167     return pstr;
168 }
169