Reactos
at master 197 lines 6.7 kB view raw
1// 2// asctime.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// The asctime() family of functions, which convert a tm struct into a string. 7// 8#include <corecrt_internal_securecrt.h> 9#include <corecrt_internal_time.h> 10 11#define _ASCBUFSIZE 26 12 13 14 15//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 16// 17// asctime_s and _wasctime_s 18// 19//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 20template <typename Character> 21static Character* __cdecl common_asctime_s_write_value( 22 _Out_writes_(2) Character* p, 23 int const value, 24 bool const zero_fill 25 ) throw() 26{ 27 if (value >= 10 || zero_fill) 28 { 29 *p++ = static_cast<Character>('0' + value / 10); 30 } 31 else 32 { 33 *p++ = ' '; 34 } 35 36 *p++ = static_cast<Character>('0' + value % 10); 37 return p; 38} 39 40 41 42// Converts a time structure (tm) into an ASCII string. The string is always 43// exactly 26 characters long, in the form Tue May 1 02:34:55 1984\n\0. The 44// buffer 'size_in_chars' must be at least 26. The string is generated into the 45// buffer. On success, zero is returned and the buffer contains the time string; 46// on failure, an error code is returned and the contents of the buffer are 47// indeterminate. 48template <typename Character> 49_Success_(return == 0) 50static errno_t __cdecl common_asctime_s( 51 _Out_writes_z_(size_in_chars) _Post_readable_size_(_ASCBUFSIZE) Character* const buffer, 52 _In_range_(>=, _ASCBUFSIZE) size_t const size_in_chars, 53 tm const* const tm_value 54 ) throw() 55{ 56 _VALIDATE_RETURN_ERRCODE( 57 buffer != nullptr && size_in_chars > 0, 58 EINVAL 59 ) 60 61 _RESET_STRING(buffer, size_in_chars); 62 63 _VALIDATE_RETURN_ERRCODE(size_in_chars >= _ASCBUFSIZE, EINVAL) 64 _VALIDATE_RETURN_ERRCODE(tm_value != nullptr, EINVAL) 65 _VALIDATE_RETURN_ERRCODE(tm_value->tm_year >= 0, EINVAL) 66 67 // Month, hour, minute, and second are zero-based 68 _VALIDATE_RETURN_ERRCODE(tm_value->tm_mon >= 0 && tm_value->tm_mon <= 11, EINVAL) 69 _VALIDATE_RETURN_ERRCODE(tm_value->tm_hour >= 0 && tm_value->tm_hour <= 23, EINVAL) 70 _VALIDATE_RETURN_ERRCODE(tm_value->tm_min >= 0 && tm_value->tm_min <= 59, EINVAL) 71 _VALIDATE_RETURN_ERRCODE(tm_value->tm_sec >= 0 && tm_value->tm_sec <= 60, EINVAL) // including leap second 72 _VALIDATE_RETURN_ERRCODE(tm_value->tm_wday >= 0 && tm_value->tm_wday <= 6, EINVAL) 73 74 _VALIDATE_RETURN_ERRCODE(__crt_time_is_day_valid(tm_value->tm_year, tm_value->tm_mon, tm_value->tm_mday), EINVAL) 75 76 Character* buffer_it = buffer; 77 78 // Copy the day name into the buffer: 79 char const* const day_first = __dnames + tm_value->tm_wday * 3; 80 char const* const day_last = day_first + 3; 81 for (char const* day_it = day_first; day_it != day_last; ++day_it) 82 *buffer_it++ = static_cast<Character>(*day_it); 83 84 *buffer_it++ = static_cast<Character>(' '); 85 86 // Copy the month name into the buffer: 87 char const* const month_first = __mnames + tm_value->tm_mon * 3; 88 char const* const month_last = month_first + 3; 89 for (char const* month_it = month_first; month_it != month_last; ++month_it) 90 *buffer_it++ = static_cast<Character>(*month_it); 91 92 *buffer_it++ = static_cast<Character>(' '); 93 94 // Copy the day of the month (1 - 31) into the buffer: 95 buffer_it = common_asctime_s_write_value(buffer_it, tm_value->tm_mday, false); 96 *buffer_it++ = static_cast<Character>(' '); 97 98 // Copy the time into the buffer in HH:MM:SS form: 99 buffer_it = common_asctime_s_write_value(buffer_it, tm_value->tm_hour, true); 100 *buffer_it++ = static_cast<Character>(':'); 101 buffer_it = common_asctime_s_write_value(buffer_it, tm_value->tm_min, true); 102 *buffer_it++ = static_cast<Character>(':'); 103 buffer_it = common_asctime_s_write_value(buffer_it, tm_value->tm_sec, true); 104 *buffer_it++ = static_cast<Character>(' '); 105 106 // Copy the four-digit year into the buffer: 107 buffer_it = common_asctime_s_write_value(buffer_it, __crt_get_century(tm_value->tm_year), true); 108 buffer_it = common_asctime_s_write_value(buffer_it, __crt_get_2digit_year(tm_value->tm_year), true); 109 110 // And that's it... 111 *buffer_it++ = static_cast<Character>('\n'); 112 *buffer_it++ = static_cast<Character>('\0'); 113 114 return 0; 115} 116 117extern "C" errno_t __cdecl asctime_s( 118 char* const buffer, 119 size_t const size_in_chars, 120 tm const* const tm_value 121 ) 122{ 123 return common_asctime_s(buffer, size_in_chars, tm_value); 124} 125 126extern "C" errno_t __cdecl _wasctime_s( 127 wchar_t* const buffer, 128 size_t const size_in_chars, 129 tm const* const tm_value 130 ) 131{ 132 return common_asctime_s(buffer, size_in_chars, tm_value); 133} 134 135 136 137//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 138// 139// asctime and _wasctime 140// 141//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 142// Utility functions used by common_asctime to get the per-thread actime buffer. 143static char** common_asctime_get_ptd_buffer(char) throw() 144{ 145 __acrt_ptd* const ptd = __acrt_getptd_noexit(); 146 if (ptd == nullptr) 147 return nullptr; 148 149 return &ptd->_asctime_buffer; 150} 151 152static wchar_t** common_asctime_get_ptd_buffer(wchar_t) throw() 153{ 154 __acrt_ptd* const ptd = __acrt_getptd_noexit(); 155 if (ptd == nullptr) 156 return nullptr; 157 158 return &ptd->_wasctime_buffer; 159} 160 161// Converts a time structure (tm) into an ASCII string. The string is always 162// exactly 26 characters long, in the form Tue May 1 02:34:55 1984\n\0. 163// The return value is a pointer to a per-thread buffer containing the 164// generated time string. 165template <typename Character> 166_Success_(return != 0) 167_Ret_writes_z_(26) 168static Character* __cdecl common_asctime(tm const* const tm_value) throw() 169{ 170 static Character static_buffer[_ASCBUFSIZE]; 171 172 Character** ptd_buffer_address = common_asctime_get_ptd_buffer(Character()); 173 if (ptd_buffer_address != nullptr && *ptd_buffer_address == nullptr) 174 { 175 *ptd_buffer_address = _calloc_crt_t(Character, _ASCBUFSIZE).detach(); 176 } 177 178 Character* const buffer = ptd_buffer_address != nullptr && *ptd_buffer_address != nullptr 179 ? *ptd_buffer_address 180 : static_buffer; 181 182 errno_t const status = common_asctime_s(buffer, _ASCBUFSIZE, tm_value); 183 if (status != 0) 184 return nullptr; 185 186 return buffer; 187} 188 189extern "C" char* __cdecl asctime(tm const* const tm_value) 190{ 191 return common_asctime<char>(tm_value); 192} 193 194extern "C" wchar_t* __cdecl _wasctime(tm const* const tm_value) 195{ 196 return common_asctime<wchar_t>(tm_value); 197}